summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--const.js2
-rw-r--r--events.txt34
-rw-r--r--play.css10
-rw-r--r--play.js13
-rw-r--r--rules.js448
5 files changed, 490 insertions, 17 deletions
diff --git a/const.js b/const.js
index d0cebea..90862ef 100644
--- a/const.js
+++ b/const.js
@@ -34,4 +34,4 @@ const SOP_LIMITED_COMMAND = 1
const SOP_COMMAND_DECREE = 2
const SOP_EVENT_OR_COMMAND = 3
const SOP_PASS = 4
-const INELIGIBLE = 5 \ No newline at end of file
+const INELIGIBLE = 5
diff --git a/events.txt b/events.txt
index 3268551..8d29a20 100644
--- a/events.txt
+++ b/events.txt
@@ -55,16 +55,42 @@ SHADED 9
log "NOT IMPLEMENTED"
EVENT 10
- log "NOT IMPLEMENTED"
+ current DS
+ prompt "Move up to 4 Delhi Sultanate Units into adjacent Provinces."
+ piece_undo_opt 4 is_ds_unit(p)
+ prompt "Move Delhi Sultanate Unit into an adjacent space."
+ space_no_undo 1 is_adjacent(s, piece_space(game.vm.p))
+ move
+ endspace
+ endpiece
+ resources DS -5
SHADED 10
- log "NOT IMPLEMENTED"
+ prompt "Move any Qasbah to Spaces containing Governors."
+ piece_opt all is_qasbah(p)
+ space 1 has_governor(s) && !has_qasbah(s)
+ move
+ endspace
+ endpiece
+ prompt "Add up to 2 Troops in each Space with a Qasbah."
+ space_opt all has_qasbah(s)
+ place_opt DS TROOPS
+ place_opt DS TROOPS
+ endspace
EVENT 11
- log "NOT IMPLEMENTED"
+ prompt "Place up to two Mongol Invaders in each of Mtn Passes and Punjab."
+ space_opt 2 (s === S_PUNJAB || s === S_MOUNTAIN_PASSES)
+ place MI TROOPS
+ place_opt MI TROOPS
+ endspace
SHADED 11
- log "NOT IMPLEMENTED"
+ current DS
+ prompt "Remove 4 Mongol Invaders."
+ piece 4 is_mongol_invader(p)
+ remove
+ endpiece
EVENT 12
log "NOT IMPLEMENTED"
diff --git a/play.css b/play.css
index 3dd09a0..5d7a90a 100644
--- a/play.css
+++ b/play.css
@@ -353,8 +353,8 @@ path.campaign { stroke: black; stroke-dasharray: 4 4; }
}
#unshaded_event {
- left: 3px;
- right: 3px;
+ left: 10px;
+ right: 10px;
top: 200px;
height: 70px;
border-radius: 12px;
@@ -363,11 +363,15 @@ path.campaign { stroke: black; stroke-dasharray: 4 4; }
#shaded_event {
left: 3px;
right: 3px;
- bottom: 4px;
+ bottom: 3px;
height: 80px;
border-radius: 12px;
}
+#this_card.card_10 #unshaded_event { height: 80px; }
+#this_card.card_10 #shaded_event { height: 69px; }
+
+
/* TOKEN IMAGES */
.token.tributary { background-color: #2a2c26 }
diff --git a/play.js b/play.js
index e180cd0..9872564 100644
--- a/play.js
+++ b/play.js
@@ -1046,6 +1046,15 @@ function on_update() {
// Influence
layout_influence()
+ // Select Faction
+ action_button("ds", "Delhi Sultanate")
+ action_button("bk", "Bahmani Kingdom")
+ action_button("ve", "Vijayanagara Empire")
+
+ confirm_action_button("choose_ds", "Delhi Sultanate", "Choose Delhi Sultanate to execute this event?")
+ confirm_action_button("choose_bk", "Bahmani Kingdom", "Choose Bahmani Kingdom to execute this event?")
+ confirm_action_button("choose_ve", "Vijayanagara Empire", "Choose Vijayanagara Empire to execute this event?")
+
// SOP buttons
action_button("command_decree", "Command & Decree")
action_button("event_command", "Event or Command")
@@ -1102,10 +1111,12 @@ function on_update() {
action_button("skip", "Skip")
action_button("next", "Next")
- action_button("undo", "Undo")
+ action_button("end_event", "End Event")
action_button("end_of_turn", "End your turn")
action_button("end_return", "End Influence Shift")
+ action_button("undo", "Undo")
+
return
diff --git a/rules.js b/rules.js
index 0336d77..d73afc4 100644
--- a/rules.js
+++ b/rules.js
@@ -52,6 +52,9 @@ const SINGLE_EVENTS = [26]
const first_piece = data.first_piece
const last_piece = data.last_piece
+const all_first_piece = 0
+const all_last_piece = 103
+
const first_space = S_ANDHRA
const last_space = S_PUNJAB
const last_province = S_TAMILAKAM
@@ -255,7 +258,7 @@ exports.setup = function (seed, scenario, _options) {
}
function setup_deck() {
- game.deck = [ 1, 37, 2, 41, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ]
+ game.deck = [ 10, 37, 11, 2, 41, 3, 4, 5, 6, 7, 8, 9, 10, 1, 12, 13, 14 ]
}
function setup_standard() {
@@ -2366,11 +2369,15 @@ function has_valid_support_attackers(s, faction) {
}
function gen_place_piece(faction, type) {
+ console.log("GEN_PLACE ", faction, type)
+ let can_place = false
for_each_piece(faction, type, p => {
if (piece_space(p) === AVAILABLE) {
gen_action_piece(p)
+ can_place = true
}
})
+ return can_place
}
function move_all_faction_piece_from(faction, type, from, to) {
@@ -2447,6 +2454,34 @@ function piece_type(p) {
throw "IMPOSSIBLE"
}
+function has_governor(s) {
+ return has_piece(s, DS, ELITE)
+}
+
+function has_qasbah(s) {
+ return has_piece(s, DS, DISC)
+}
+
+function is_adjacent(a, b) {
+ return set_has(SPACES[a].adjacent, b)
+}
+
+function is_piece(p, faction, type) {
+ return p >= first_piece[faction][type] && p <= last_piece[faction][type]
+}
+
+function is_mongol_invader(p) {
+ return piece_faction(p) === MI
+}
+
+function is_ds_unit(p) {
+ return (is_piece(p, DS, ELITE) || is_piece(p, DS, TROOPS))
+}
+
+function is_qasbah(p) {
+ return piece_name(p) === "Qasbah"
+}
+
/* CAVALRY */
function available_cavalry() {
@@ -2647,6 +2682,34 @@ function gen_action_token(t) {
gen_action("token", t)
}
+function gen_choose_faction(faction) {
+ if (game.current === faction) {
+ switch (faction) {
+ case DS:
+ view.actions.ds = 1
+ break
+ case BK:
+ view.actions.bk = 1
+ break
+ case VE:
+ view.actions.ve = 1
+ break
+ }
+ } else {
+ switch (faction) {
+ case DS:
+ view.actions.choose_ds = 1
+ break
+ case BK:
+ view.actions.choose_bk = 1
+ break
+ case VE:
+ view.actions.choose_ve= 1
+ break
+ }
+ }
+}
+
/* LOGGING */
function log(msg) {
@@ -3096,6 +3159,27 @@ function object_group_by(items, callback) {
// === ITERATORS AND ACTION GENERATORS ===
+function auto_place_piece(s, faction, type) {
+ if (can_place_piece(s, faction, type)) {
+ let p = find_piece(AVAILABLE, faction, type)
+ if (p >= 0) {
+ place_piece(p, s)
+ return true
+ }
+ }
+ return false
+}
+
+function can_place_piece(s, faction, type) {
+ return can_stack_piece(s, faction, type) && has_piece(AVAILABLE, faction, type)
+}
+
+function can_stack_piece(s, faction, type) {
+ if (type === DISC)
+ return !has_piece(s, faction, type)
+ return true
+}
+
function for_each_piece(faction, type, f) {
let p0 = first_piece[faction][type]
let p1 = last_piece[faction][type]
@@ -3136,10 +3220,8 @@ function gen_any_event() {
if (set_has(SINGLE_EVENTS, this_card())) {
view.actions.event = 1
} else {
- console.log("GEN ANY EVENT!")
view.actions.unshaded = 1
view.actions.shaded = 1
- console.log(view.actions)
}
}
@@ -3195,11 +3277,89 @@ function goto_vm(proc) {
vm_exec()
}
+function vm_current() {
+ if (vm_operand(1) !== game.current)
+ game.state = "vm_current"
+ else
+ vm_next()
+}
+
+states.vm_current = {
+ prompt() {
+ let list = vm_operand(1)
+ event_prompt("Select Faction.")
+ if (Array.isArray(list)) {
+ if (list.includes(DS))
+ gen_choose_faction(DS)
+ if (list.includes(BK))
+ gen_choose_faction(BK)
+ if (list.includes(VE))
+ gen_choose_faction(VE)
+ } else {
+ if (list === DS)
+ gen_choose_faction(DS)
+ if (list === BK)
+ gen_choose_faction(BK)
+ if (list === VE)
+ gen_choose_faction(VE)
+ }
+ },
+ choose_ds() {
+ this.ds()
+ },
+ choose_bk() {
+ this.bk()
+ },
+ choose_ve() {
+ this.ve()
+ },
+ ds() {
+ if (game.current !== DS)
+ clear_undo()
+ game.current = DS
+ log_transfer(faction_name[game.current] + "...")
+ vm_next()
+ },
+ bk() {
+ if (game.current !== BK)
+ clear_undo()
+ game.current = BK
+ log_transfer(faction_name[game.current] + "...")
+ vm_next()
+ },
+ ve() {
+ if (game.current !== VE)
+ clear_undo()
+ game.current = VE
+ log_transfer(faction_name[game.current] + "...")
+ vm_next()
+ }
+}
+
+
function vm_exec() {
vm_inst(0)()
}
+function vm_goto(cmd, nop, dir, step) {
+ let balance = 1
+ while (balance > 0) {
+ game.vm.ip += dir
+ if (vm_inst(0) === cmd)
+ --balance
+ if (vm_inst(0) === nop)
+ ++balance
+ if (game.vm.ip < 0 || game.vm.ip > CODE[game.vm.fp].length)
+ throw "ERROR"
+ }
+ game.vm.ip += step
+ vm_exec()
+}
+
function vm_inst(a) {
+ console.log("In vm_inst with ", a)
+ console.log(game.vm)
+ console.log(CODE[game.vm.fp])
return CODE[game.vm.fp][game.vm.ip][a]
}
@@ -3208,6 +3368,12 @@ function vm_log() {
vm_next()
}
+function vm_move() {
+ log("Moved " + piece_name(game.vm.p) + " to S" + game.vm.s + " from S" + piece_space(game.vm.p) + ".")
+ place_piece(game.vm.p, game.vm.s)
+ vm_next()
+}
+
function vm_next() {
game.vm.ip ++
vm_exec()
@@ -3220,6 +3386,28 @@ function vm_operand(a) {
return x
}
+function vm_prompt() {
+ if (game.vm.prompt)
+ game.vm._prompt = game.vm.prompt
+ game.vm.prompt = game.vm.ip
+ vm_next()
+}
+
+function pop_vm_prompt() {
+ if (game.vm._prompt) {
+ game.vm.prompt = game.vm._prompt
+ delete game.vm._prompt
+ } else {
+ game.vm.prompt = 0
+ }
+}
+
+function vm_remove() {
+ log("Removed " + piece_name(game.vm.p) + " from S" + piece_space(game.vm.p) + ".")
+ remove_piece(game.vm.p)
+ vm_next()
+}
+
function vm_return() {
game.state = "vm_return"
}
@@ -3232,6 +3420,223 @@ states.vm_return = {
end_event,
}
+// VM: SPACE
+
+function vm_space() {
+ let n = vm_inst(3)
+ let f = vm_inst(4)
+ if (can_vm_space(n, f)) {
+ game.state = "vm_space"
+ } else {
+ pop_vm_prompt()
+ game.vm.ss = []
+ game.vm.s = -1
+ vm_goto(vm_endspace, vm_space, 1, 1)
+ }
+}
+
+function vm_endspace() {
+ vm_goto(vm_space, vm_endspace, -1, 0)
+}
+
+
+function can_vm_space(n, f) {
+ if (game.vm.ss.length < n)
+ for (let s = first_space; s <= last_space; ++s)
+ if (!set_has(game.vm.ss, s) && f(s))
+ return true
+ return false
+}
+
+states.vm_space = {
+ prompt() {
+ let f = vm_inst(4)
+ view.who = game.vm.p
+ event_prompt()
+ for (let s = first_space; s <= last_space; ++s)
+ if (!set_has(game.vm.ss, s) && f(s))
+ gen_action_space(s)
+ if (game.vm.ss.length >= vm_inst(2))
+ view.actions.skip = 1
+ },
+ space(s) {
+ if (vm_inst(1))
+ push_undo()
+ set_add(game.vm.ss, s)
+ game.vm.s = s
+ vm_next()
+ },
+ skip() {
+ if (vm_inst(1))
+ push_undo()
+ game.vm.opt = 1
+ vm_goto(vm_endspace, vm_space, 1, 1)
+ },
+}
+
+// VM: PIECE ITERATOR
+
+function vm_piece() {
+ console.log("IN VM_PIECE", can_vm_piece())
+ if (can_vm_piece()) {
+ game.state = "vm_piece"
+ } else {
+ pop_vm_prompt()
+ game.vm.pp = []
+ game.vm.p = -1
+ vm_goto(vm_endpiece, vm_piece, 1, 1)
+ }
+}
+
+function vm_endpiece() {
+ vm_goto(vm_piece, vm_endpiece, -1, 0)
+}
+
+function can_vm_piece() {
+ let f = vm_inst(4)
+ if (game.vm.pp.length < vm_inst(3))
+ for (let p = all_first_piece; p <= all_last_piece; ++p)
+ if (piece_space(p) >= 0 && !set_has(game.vm.pp, p) && f(p, piece_space(p)))
+ return true
+ return false
+}
+
+states.vm_piece = {
+ prompt() {
+ let f = vm_inst(4)
+ if (game.vm.s >= 0)
+ view.where = game.vm.s
+ event_prompt()
+ for (let p = all_first_piece; p <= all_last_piece; ++p)
+ if (piece_space(p) >= 0 && !set_has(game.vm.pp, p) && f(p, piece_space(p)))
+ gen_action_piece(p)
+ if (game.vm.pp.length >= vm_inst(2))
+ view.actions.skip = 1
+ },
+ piece(p) {
+ if (vm_inst(1))
+ push_undo()
+ set_add(game.vm.pp, p)
+ game.vm.p = p
+ vm_next()
+ },
+ skip() {
+ if (vm_inst(1))
+ push_undo()
+ game.vm.opt = 1
+ vm_goto(vm_endpiece, vm_piece, 1, 1)
+ },
+}
+
+
+// VM: PLACE PIECE
+
+function vm_auto_place() {
+ let faction = vm_operand(3)
+ let type = vm_operand(4)
+ if (auto_place_piece(game.vm.s, faction, type)) {
+ log("Placed " + PIECE_FACTION_TYPE_NAME[faction][type] + " in S" + game.vm.s + ".")
+ vm_next()
+ } else {
+ vm_place()
+ }
+}
+
+function vm_place() {
+ if (can_vm_place())
+ game.state = "vm_place"
+ else
+ vm_next()
+}
+
+function can_vm_place_imp(s, faction, type) {
+ if (!can_stack_piece(s, faction, type))
+ return false
+ if (game.current === faction)
+ return true
+ return has_piece(AVAILABLE, faction, type)
+}
+
+function can_vm_place() {
+ let faction = vm_operand(3)
+ let type = vm_operand(4)
+ if (typeof faction === "object" && typeof type === "object") {
+ for (let f of faction)
+ for (let t of type)
+ if (can_vm_place_imp(game.vm.s, f, t))
+ return true
+ } else if (typeof faction === "object") {
+ for (let f of faction)
+ if (can_vm_place_imp(game.vm.s, f, type))
+ return true
+ } else if (typeof type === "object") {
+ for (let t of type)
+ if (can_vm_place_imp(game.vm.s, faction, t))
+ return true
+ } else {
+ if (can_vm_place_imp(game.vm.s, faction, type))
+ return true
+ }
+ return false
+}
+
+states.vm_place = {
+ prompt() {
+ let skip = vm_inst(2)
+ let faction = vm_operand(3)
+ let type = vm_operand(4)
+ let where = SPACE_NAME[game.vm.s]
+ let possible = false
+ view.where = game.vm.s
+
+ event_prompt(`Place ${PIECE_FACTION_TYPE_NAME[faction][type]} in ${where}.`)
+ if (gen_place_piece(faction, type))
+ possible = true
+ if (skip || !possible)
+ view.actions.skip = 1
+ },
+ piece(p) {
+ if (vm_inst(1))
+ push_undo()
+ log("Placed " + piece_name(p) + " in S" + game.vm.s + ".")
+ place_piece(p, game.vm.s)
+ vm_next()
+ },
+ skip() {
+ if (vm_inst(1))
+ push_undo()
+ if (vm_inst(2)) // only flag as optional if opcode is opt
+ game.vm.opt = 1
+ else
+ log("Did not place piece in S" + game.vm.s + ".")
+ vm_next()
+ },
+}
+
+// VM : RESOURCES
+
+function vm_resources() {
+ game.state = "vm_resources"
+}
+
+states.vm_resources = {
+ prompt() {
+ let f = vm_operand(1)
+ let n = vm_operand(2)
+ if (n >= 0)
+ event_prompt(`${faction_name[f]} +${n} Resources.`)
+ else
+ event_prompt(`${faction_name[f]} ${n} Resources.`)
+ gen_action_resources(f)
+ },
+ resources(f) {
+ let n = vm_operand(2)
+ log_resources(f, n)
+ add_resources(f, n)
+ vm_next()
+ },
+}
+
// === CONST ===
// Factions
@@ -3269,7 +3674,8 @@ const SOP_LIMITED_COMMAND = 1
const SOP_COMMAND_DECREE = 2
const SOP_EVENT_OR_COMMAND = 3
const SOP_PASS = 4
-const INELIGIBLE = 5// === CONST ===
+const INELIGIBLE = 5
+// === CONST ===
const CODE = []
@@ -3383,25 +3789,51 @@ CODE[9 * 2 + 1] = [
// EVENT 10
CODE[10 * 2 + 0] = [
- [ vm_log, "NOT IMPLEMENTED" ],
+ [ vm_current, DS ],
+ [ vm_prompt, "Move up to 4 Delhi Sultanate Units into adjacent Provinces." ],
+ [ vm_piece, true, 0, 4, (p,s)=>is_ds_unit(p) ],
+ [ vm_prompt, "Move Delhi Sultanate Unit into an adjacent space." ],
+ [ vm_space, false, 1, 1, (s)=>is_adjacent(s, piece_space(game.vm.p)) ],
+ [ vm_move ],
+ [ vm_endspace ],
+ [ vm_endpiece ],
+ [ vm_resources, DS, -5 ],
[ vm_return ],
]
// SHADED 10
CODE[10 * 2 + 1] = [
- [ vm_log, "NOT IMPLEMENTED" ],
+ [ vm_prompt, "Move any Qasbah to Spaces containing Governors." ],
+ [ vm_piece, false, 0, 999, (p,s)=>is_qasbah(p) ],
+ [ vm_space, true, 1, 1, (s)=>has_governor(s) && !has_qasbah(s) ],
+ [ vm_move ],
+ [ vm_endspace ],
+ [ vm_endpiece ],
+ [ vm_prompt, "Add up to 2 Troops in each Space with a Qasbah." ],
+ [ vm_space, true, 0, 999, (s)=>has_qasbah(s) ],
+ [ vm_place, false, 1, DS, TROOPS ],
+ [ vm_place, false, 1, DS, TROOPS ],
+ [ vm_endspace ],
[ vm_return ],
]
// EVENT 11
CODE[11 * 2 + 0] = [
- [ vm_log, "NOT IMPLEMENTED" ],
+ [ vm_prompt, "Place up to two Mongol Invaders in each of Mtn Passes and Punjab." ],
+ [ vm_space, true, 0, 2, (s)=>(s === S_PUNJAB || s === S_MOUNTAIN_PASSES) ],
+ [ vm_place, false, 0, MI, TROOPS ],
+ [ vm_place, false, 1, MI, TROOPS ],
+ [ vm_endspace ],
[ vm_return ],
]
// SHADED 11
CODE[11 * 2 + 1] = [
- [ vm_log, "NOT IMPLEMENTED" ],
+ [ vm_current, DS ],
+ [ vm_prompt, "Remove 4 Mongol Invaders." ],
+ [ vm_piece, false, 4, 4, (p,s)=>is_mongol_invader(p) ],
+ [ vm_remove ],
+ [ vm_endpiece ],
[ vm_return ],
]