summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-12-27 01:30:55 +0100
committerTor Andersson <tor@ccxvii.net>2023-02-18 13:02:38 +0100
commit1a1c5531d9729d744584ca150c929befb6c0908f (patch)
tree3c1347766cc90e655e10ede2b035833ff34f9204 /rules.js
parenta346336ed81fdeca831b326043b82ab865b214cf (diff)
downloadnevsky-1a1c5531d9729d744584ca150c929befb6c0908f.tar.gz
Take hits.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js249
1 files changed, 212 insertions, 37 deletions
diff --git a/rules.js b/rules.js
index c0e8979..db17a41 100644
--- a/rules.js
+++ b/rules.js
@@ -83,6 +83,10 @@ const MEN_AT_ARMS = 4
const MILITIA = 5
const SERFS = 6
+const FORCE_TYPE_NAME = [ "knights", "sergeants", "light horse", "asiatic horse", "men-at-arms", "militia", "serfs" ]
+const FORCE_PROTECTION = [ 4, 3, 1, 1, 3, 1, 0 ]
+const FORCE_EVADE = [ 0, 0, 0, 3, 0, 0, 0 ]
+
// asset types
const PROV = 0
const COIN = 1
@@ -92,7 +96,7 @@ const SLED = 4
const BOAT = 5
const SHIP = 6
-const asset_type_name = [ "prov", "coin", "loot", "cart", "sled", "boat", "ship" ]
+const ASSET_TYPE_NAME = [ "prov", "coin", "loot", "cart", "sled", "boat", "ship" ]
// battle array
const A1 = 0 // attackers
@@ -3828,7 +3832,7 @@ function list_spoils() {
for (let type = 0; type < 7; ++type) {
let n = get_spoils(type)
if (n > 0)
- list.push(`${n} ${asset_type_name[type]}`)
+ list.push(`${n} ${ASSET_TYPE_NAME[type]}`)
}
if (list.length > 0)
return list.join(", ")
@@ -5216,18 +5220,17 @@ function has_rear_strike_choice() {
return GROUPS[s][1][r] !== 0
}
-
-function goto_start_strike() {
- game.battle.step = 0
- goto_strike()
+function format_group(g) {
+ return g.map(p=>lord_name[game.battle.array[p]]).join(", ")
}
-function goto_next_strike() {
- game.battle.step++
- if (game.battle.step >= 6)
- goto_new_round()
+function format_hits() {
+ if (game.battle.h2 > 0 && game.battle.h1 > 0)
+ return `${game.battle.h2} crossbow hits and ${game.battle.h1} hits`
+ else if (game.battle.h2 > 0)
+ return `${game.battle.h2} crossbow hits`
else
- goto_strike()
+ return `${game.battle.h1} hits`
}
function debug_battle_array(f, r) {
@@ -5312,14 +5315,28 @@ function count_storm_hits(ix, lord, step) {
}
}
+function goto_start_strike() {
+ game.battle.step = 0
+ goto_strike()
+}
+
+function goto_next_strike() {
+ game.battle.step++
+ if (game.battle.step >= 6)
+ goto_new_round()
+ else
+ goto_strike()
+}
+
function goto_strike() {
let s = game.battle.step & 1
-
if (s)
set_active_attacker()
else
set_active_defender()
+ log_h4(battle_step_name[game.battle.step])
+
// TODO: garrison hits
game.battle.ah1 = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
game.battle.ah2 = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
@@ -5350,6 +5367,7 @@ function goto_select_strike_group() {
if (game.battle.groups.length === 0)
goto_next_strike()
else
+ // TODO: select if 1
game.state = "select_strike_group"
}
@@ -5398,53 +5416,154 @@ function select_strike_group(i) {
game.battle.h2 = (game.battle.h2 >> 1)
}
+ log(`${format_group(game.battle.sg)} struck ${format_group(game.battle.hg)} for ${format_hits()}`)
+
set_active_enemy()
- goto_select_hit_group()
+ goto_select_hit_lord()
return
}
-function goto_select_hit_group() {
- if (game.battle.hg.length > 0) {
- game.state = "select_hit_group"
+function goto_select_hit_lord() {
+ if (game.battle.hg.length > 1) {
+ game.state = "select_hit_lord"
} else {
- game.who = game.battle.array[game.battle.hg[0]]
- game.state = "hit_lord"
+ select_hit_lord(game.battle.array[game.battle.hg[0]])
}
}
-function format_hits() {
- if (game.battle.h2 > 0 && game.battle.h1 > 0)
- return `${game.battle.h2} crossbow hits and ${game.battle.h1} hits`
- else if (game.battle.h2 > 0)
- return `${game.battle.h2} crossbow hits`
- else
- return `${game.battle.h1} hits`
-}
-
-states.select_hit_group = {
+states.select_hit_lord = {
prompt() {
view.prompt = `${battle_step_name[game.battle.step]}: Select Lord to take ${format_hits()}.`
for (let pos of game.battle.hg)
gen_action_battle_lord(game.battle.array[pos])
},
battle_lord(lord) {
- game.who = lord
- game.state = "hit_lord"
+ select_hit_lord(lord)
},
}
+function select_hit_lord(lord) {
+ // TODO: walls
+ game.who = lord
+ game.state = "hit_lord"
+}
+
+function has_lord_routed(lord) {
+ return game.pieces.forces[lord] === 0
+}
+
+function rout_lord(lord) {
+ log(`L${lord} routed!`)
+ for (let p = 0; p < 12; ++p)
+ if (game.battle.array[p] === lord)
+ game.battle.array[p] = NOBODY
+ set_add(game.battle.routed, lord)
+}
+
+function resume_hit_lord() {
+ if ((game.battle.h1 === 0 && game.battle.h2 === 0) || has_lord_routed(game.who))
+ end_hit_lord()
+}
+
+function rout_unit(lord, type) {
+ add_lord_forces(lord, type, -1)
+ add_lord_routed_forces(lord, type, 1)
+}
+
+function action_hit_lord(lord, type) {
+ let protection = FORCE_PROTECTION[type]
+ let evade = FORCE_EVADE[type]
+
+ // TODO: manual choice
+ let ap = (game.battle.h2 > 0) ? 2 : 0
+
+ if (evade > 0 && !game.battle.storm) {
+ let die = roll_die()
+ if (die <= evade) {
+ log(`${FORCE_TYPE_NAME[type]} evade ${die} <= ${evade}`)
+ } else {
+ log(`${FORCE_TYPE_NAME[type]} evade ${die} > ${evade}`)
+ rout_unit(lord, type)
+ }
+ } else if (protection > 0) {
+ let die = roll_die()
+ if (die <= protection - ap) {
+ log(`${FORCE_TYPE_NAME[type]} protection ${die} <= ${protection - ap}`)
+ } else {
+ log(`${FORCE_TYPE_NAME[type]} protection ${die} > ${protection - ap}`)
+ rout_unit(lord, type)
+ }
+ } else {
+ log(`${FORCE_TYPE_NAME[type]} unprotected`)
+ rout_unit(lord, type)
+ }
+
+ // TODO: manual choice
+ if (game.battle.h2)
+ game.battle.h2--
+ else
+ game.battle.h1--
+
+ if (has_lord_routed(lord)) {
+ rout_lord(lord)
+ // TODO: remaining hits!
+ }
+
+ resume_hit_lord()
+}
+
states.hit_lord = {
prompt() {
- view.prompt = `${battle_step_name[game.battle.step]}: Assign ${format_hits()}.`
- view.actions.pass = 1
+ view.prompt = `${battle_step_name[game.battle.step]}: Assign ${format_hits()} to units.`
+ view.who = game.who
+
+ // TODO: h1 or h2
+
+ let lord = game.who
+ if (get_lord_forces(lord, KNIGHTS) > 0)
+ gen_action_knights(lord)
+ if (get_lord_forces(lord, SERGEANTS) > 0)
+ gen_action_sergeants(lord)
+ if (get_lord_forces(lord, LIGHT_HORSE) > 0)
+ gen_action_light_horse(lord)
+ if (get_lord_forces(lord, ASIATIC_HORSE) > 0)
+ gen_action_asiatic_horse(lord)
+ if (get_lord_forces(lord, MEN_AT_ARMS) > 0)
+ gen_action_men_at_arms(lord)
+ if (get_lord_forces(lord, MILITIA) > 0)
+ gen_action_militia(lord)
+ if (get_lord_forces(lord, SERFS) > 0)
+ gen_action_serfs(lord)
},
- pass() {
- game.who = NOBODY
- set_active_enemy()
- goto_select_strike_group()
+ knights(lord) {
+ action_hit_lord(lord, KNIGHTS)
+ },
+ sergeants(lord) {
+ action_hit_lord(lord, SERGEANTS)
+ },
+ light_horse(lord) {
+ action_hit_lord(lord, LIGHT_HORSE)
+ },
+ asiatic_horse(lord) {
+ action_hit_lord(lord, ASIATIC_HORSE)
+ },
+ men_at_arms(lord) {
+ action_hit_lord(lord, MEN_AT_ARMS)
+ },
+ militia(lord) {
+ action_hit_lord(lord, MILITIA)
+ },
+ serfs(lord) {
+ action_hit_lord(lord, SERFS)
},
}
+function end_hit_lord() {
+ game.who = NOBODY
+ set_active_enemy()
+ goto_select_strike_group()
+}
+
// === BATTLE: NEW ROUND ===
function goto_new_round() {
@@ -6568,7 +6687,7 @@ function prompt_wastage(lord) {
function action_wastage(lord, type) {
push_undo()
- log(`L${lord} discarded ${asset_type_name[type]}.`)
+ log(`L${lord} discarded ${ASSET_TYPE_NAME[type]}.`)
set_lord_moved(lord, 0)
add_lord_assets(lord, type, -1)
}
@@ -6874,6 +6993,62 @@ function gen_action_ship(lord) {
gen_action("ship", lord)
}
+function gen_action_knights(lord) {
+ gen_action("knights", lord)
+}
+
+function gen_action_sergeants(lord) {
+ gen_action("sergeants", lord)
+}
+
+function gen_action_light_horse(lord) {
+ gen_action("light_horse", lord)
+}
+
+function gen_action_asiatic_horse(lord) {
+ gen_action("asiatic_horse", lord)
+}
+
+function gen_action_men_at_arms(lord) {
+ gen_action("men_at_arms", lord)
+}
+
+function gen_action_militia(lord) {
+ gen_action("militia", lord)
+}
+
+function gen_action_serfs(lord) {
+ gen_action("serfs", lord)
+}
+
+function gen_action_routed_knights(lord) {
+ gen_action("routed_knights", lord)
+}
+
+function gen_action_routed_sergeants(lord) {
+ gen_action("routed_sergeants", lord)
+}
+
+function gen_action_routed_light_horse(lord) {
+ gen_action("routed_light_horse", lord)
+}
+
+function gen_action_routed_asiatic_horse(lord) {
+ gen_action("routed_asiatic_horse", lord)
+}
+
+function gen_action_routed_men_at_arms(lord) {
+ gen_action("routed_men_at_arms", lord)
+}
+
+function gen_action_routed_militia(lord) {
+ gen_action("routed_militia", lord)
+}
+
+function gen_action_routed_serfs(lord) {
+ gen_action("routed_serfs", lord)
+}
+
exports.view = function (state, current) {
load_state(state)