summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-07-02 01:26:40 +0200
committerTor Andersson <tor@ccxvii.net>2023-07-07 19:05:52 +0200
commit9952652c7c14c4b3e46d5110202112df048f499a (patch)
tree1595ef3aad9612706d294ca7e55cbf8813df41e7
parent285606d4c3fec57d501c66b46a48e730e71d0f6a (diff)
downloadtime-of-crisis-9952652c7c14c4b3e46d5110202112df048f499a.tar.gz
Frumentarii and Spiculum.
-rw-r--r--rules.js208
1 files changed, 180 insertions, 28 deletions
diff --git a/rules.js b/rules.js
index ed56611..b16070c 100644
--- a/rules.js
+++ b/rules.js
@@ -1662,6 +1662,12 @@ function goto_take_actions() {
game.placed = 0
if (is_emperor_player())
set_placed_governor(ITALIA)
+
+ if (game.frumentarii & (1 << game.current)) {
+ game.frumentarii &= ~(1 << game.current)
+ game.count = 2
+ game.state = "frumentarii"
+ }
}
states.take_actions = {
@@ -3022,6 +3028,7 @@ function play_force_march() {
}
states.force_march_who = {
+ inactive: "Force March",
prompt() {
prompt("Force March: Choose an army you command...")
for (let i = 0; i < 6; ++i) {
@@ -3043,6 +3050,7 @@ states.force_march_who = {
}
states.force_march = {
+ inactive: "Force March",
prompt() {
prompt("Force March: Move Army or Initiate Battle.")
@@ -3138,6 +3146,28 @@ function play_frumentarii() {
game.frumentarii |= (1 << game.current)
}
+states.frumentarii = {
+ inactive: "Frumentarii",
+ prompt() {
+ prompt("Frumentarii: Draw 2 cards.")
+ let hand = current_hand()
+ let draw = current_draw()
+ for (let c of draw)
+ gen_action_card(c)
+ },
+ card(c) {
+ push_undo()
+ let hand = current_hand()
+ let draw = current_draw()
+ set_delete(draw, c)
+ set_add(hand, c)
+ if (draw.length === 0)
+ flip_discard_to_available()
+ if (--game.count === 0)
+ game.state = "take_actions"
+ },
+}
+
// CARD: Mobile Vulgus
function can_play_mobile_vulgus() {
@@ -3156,6 +3186,7 @@ function play_mobile_vulgus() {
}
states.mobile_vulgus_where = {
+ inactive: "Mobile Vulgus",
prompt() {
prompt("Mobile Vulgus: Choose a province...")
view.color = POPULACE
@@ -3175,6 +3206,7 @@ states.mobile_vulgus_where = {
}
states.mobile_vulgus = {
+ inactive: "Mobile Vulgus",
prompt() {
prompt("Mobile Vulgus: " + game.pip + " populace. Reduce support in " + REGION_NAME[game.where] + ".")
let n = get_support(game.where) * 2 + count_units_in_capital(game.where)
@@ -3218,17 +3250,19 @@ function play_demagogue() {
// === COMBAT ===
function play_flanking_maneuver() {
+ log("Flanking Maneuver.")
game.combat.flanking = 1
}
function play_cavalry() {
+ log("Cavalry.")
game.combat.cavalry = 1
}
function play_spiculum() {
game.combat.spiculum = 1
+ game.combat.castra_used = 0
game.state = "spiculum"
- // TODO
}
function goto_battle_vs_general(where, attacker, target) {
@@ -3252,7 +3286,14 @@ function goto_battle(type, where, attacker, target) {
log_h2("Battle in %" + where)
spend_military(1)
game.where = where
- game.combat = { type, attacker, target, killed: 0 }
+ game.combat = {
+ type, attacker, target,
+ cavalry: 0, flanking: 0, spiculum: 0,
+ castra_used: 0,
+ dtaken: 0, ataken: 0, staken: 0,
+ dhits: 0, ahits: 0, shits: 0,
+ killed: 0,
+ }
game.state = "initiate_battle"
if (attacker >= 0) {
if (is_general_inside_capital(attacker))
@@ -3307,16 +3348,16 @@ states.initiate_battle = {
prompt() {
prompt("Initiate Battle against " + format_battle_target() + " in " + REGION_NAME[game.where] + ".")
- if (!game.combat.flanking && has_card_event(CARD_M3)) {
- view.prompt += " Flanking Maneuver?"
- gen_card_event(CARD_M3)
- }
-
if (!game.combat.cavalry && has_card_event(CARD_M2X)) {
view.prompt += " Cavalry?"
gen_card_event(CARD_M2X)
}
+ if (!game.combat.flanking && has_card_event(CARD_M3)) {
+ view.prompt += " Flanking Maneuver?"
+ gen_card_event(CARD_M3)
+ }
+
if (!game.combat.spiculum && has_card_event(CARD_M4X)) {
view.prompt += " Spiculum?"
gen_card_event(CARD_M4X)
@@ -3326,7 +3367,6 @@ states.initiate_battle = {
},
card(c) {
push_undo()
- log(card_event_name(c) + ".")
set_add(game.used, c)
play_card_event(c)
},
@@ -3340,6 +3380,23 @@ states.initiate_battle = {
},
}
+states.spiculum = {
+ show_battle: true,
+ inactive: "Spiculum",
+ prompt() {
+ prompt("Spiculum: Roll two dice hitting on 3+ before the battle.")
+ view.actions.roll = 1
+ },
+ roll() {
+ clear_undo()
+ log_h3("SPICULUM")
+ game.combat.shits = roll_spiculum_dice()
+ log("Total hits: " + game.combat.shits)
+ log_br()
+ goto_assign_spiculum_hits()
+ },
+}
+
function format_hits() {
let s = "Defender rolled " + game.combat.ahits + " hit"
if (game.combat.ahits !== 1)
@@ -3369,9 +3426,6 @@ states.flanking_maneuver = {
}
function roll_combat_dice() {
- game.combat.dtaken = 0
- game.combat.ataken = 0
-
log_h3("DEFENDER")
game.combat.ahits = roll_defender_dice()
log("Total hits: " + game.combat.ahits)
@@ -3454,25 +3508,49 @@ function roll_barbarian_dice(tribe) {
return roll_dice(n, 4)
}
+function roll_spiculum_dice() {
+ let n = roll_dice(2, 3 + get_roman_drm())
+ if (n > 0) {
+ if (game.combat.type === "militia" && has_militia_castra(game.where)) {
+ log("Castra reduces 1 hit")
+ game.combat.castra_used = 1
+ n -= 1
+ }
+ if (game.combat.type === "general" && has_general_castra(game.combat.target)) {
+ log("Castra reduces 1 hit")
+ game.combat.castra_used = 1
+ n -= 1
+ }
+ if (game.combat.type === "barbarians" && get_barbarian_location(SHAPUR) === game.where) {
+ log("Shapur I reduces 1 hit")
+ game.combat.castra_used = 1
+ n -= 1
+ }
+ }
+ return n
+}
+
function roll_attacker_dice() {
let n = get_plague_hits()
if (game.combat.attacker < 0)
n += roll_militia_dice()
else
n += roll_general_dice(game.combat.attacker)
- if (game.combat.type === "militia" && has_militia_castra(game.where)) {
- log("Castra reduces 1 hit")
- n -= 1
- }
- if (game.combat.type === "general" && has_general_castra(game.combat.target)) {
- log("Castra reduces 1 hit")
- n -= 1
- }
- if (game.combat.type === "barbarians" && get_barbarian_location(SHAPUR) === game.where) {
- log("Shapur I reduces 1 hit")
- n -= 1
+ if (n > 0 && !game.combat.castra_used) {
+ if (game.combat.type === "militia" && has_militia_castra(game.where)) {
+ log("Castra reduces 1 hit")
+ n -= 1
+ }
+ if (game.combat.type === "general" && has_general_castra(game.combat.target)) {
+ log("Castra reduces 1 hit")
+ n -= 1
+ }
+ if (game.combat.type === "barbarians" && get_barbarian_location(SHAPUR) === game.where) {
+ log("Shapur I reduces 1 hit")
+ n -= 1
+ }
}
- return Math.max(0, n)
+ return n
}
function roll_defender_dice() {
@@ -3609,6 +3687,22 @@ function has_hits_on_defender() {
return false
}
+function has_spiculum_hits() {
+ if (game.combat.staken < game.combat.shits) {
+ switch (game.combat.type) {
+ case "militia":
+ return has_hits_militia()
+ case "rival_emperor":
+ return has_hits_rival_emperor(game.combat.target)
+ case "barbarians":
+ return has_hits_barbarians(game.combat.target)
+ case "general":
+ return has_hits_general(game.combat.target)
+ }
+ }
+ return false
+}
+
function goto_assign_hits() {
goto_assign_hits_on_attacker()
}
@@ -3627,6 +3721,16 @@ function goto_assign_hits_on_defender() {
game.state = "combat_victory"
}
+function goto_assign_spiculum_hits() {
+ if (has_spiculum_hits())
+ game.state = "assign_spiculum_hits"
+ else if (is_defender_eliminated())
+ // In case Spiculum eliminates defender...
+ game.state = "combat_victory"
+ else
+ game.state = "initiate_battle"
+}
+
states.assign_hits_on_attacker = {
show_battle: true,
get inactive() { return "Combat. " + format_hits() },
@@ -3703,6 +3807,52 @@ states.assign_hits_on_defender = {
}
}
+states.assign_spiculum_hits = {
+ show_battle: true,
+ get inactive() { return "Spiculum. " + game.combat.shits + " hits." },
+ prompt() {
+ prompt("Spiculum: " + game.combat.shits + " hits.")
+ switch (game.combat.type) {
+ case "militia":
+ gen_hits_militia()
+ break
+ case "rival_emperor":
+ gen_hits_rival_emperor(game.combat.target)
+ break
+ case "barbarians":
+ gen_hits_barbarians(game.combat.target)
+ break
+ case "general":
+ gen_hits_general(game.combat.target)
+ break
+ }
+ },
+ militia(where) {
+ push_undo()
+ game.combat.staken += 1
+ eliminate_militia(where)
+ goto_assign_spiculum_hits()
+ },
+ legion(id) {
+ push_undo()
+ game.combat.staken += 1
+ assign_hit_to_legion(id)
+ goto_assign_spiculum_hits()
+ },
+ barbarian(id) {
+ push_undo()
+ game.combat.staken += 1
+ eliminate_barbarian(id)
+ goto_assign_spiculum_hits()
+ },
+ rival_emperor(id) {
+ push_undo()
+ game.combat.staken += 1
+ eliminate_rival_emperor(id)
+ goto_assign_spiculum_hits()
+ }
+}
+
function is_attacker_eliminated() {
if (game.selected_general < 0)
return !has_militia(game.where)
@@ -3735,9 +3885,7 @@ states.combat_victory = {
let ae = is_attacker_eliminated()
if (de && ae)
prompt("Combat: There is no winner.")
- else if (de || game.combat.dtaken > game.combat.ataken)
- prompt("Combat: You win the battle!")
- else if (game.combat.dtaken === game.combat.ataken && game.combat.cavalry)
+ else if (de || game.combat.dtaken + game.combat.staken + game.combat.cavalry > game.combat.ataken)
prompt("Combat: You win the battle!")
else
prompt("Combat: Defenders win the battle!")
@@ -3755,7 +3903,7 @@ function goto_combat_victory() {
let ae = is_attacker_eliminated()
if (de && ae)
goto_combat_no_victory()
- else if (de || game.combat.dtaken > game.combat.ataken)
+ else if (de || game.combat.dtaken + game.combat.staken + game.combat.cavalry > game.combat.ataken)
goto_combat_victory_attacker()
else
goto_combat_victory_defender()
@@ -3906,6 +4054,7 @@ states.free_increase_support_level = {
}
states.triumph = {
+ inactive: "Combat",
prompt() {
prompt("Combat: You may play Triumph.")
gen_card_event(CARD_S4X)
@@ -4398,7 +4547,10 @@ states.refill_hand = {
prompt("End of Turn: Draw cards.")
let hand = current_hand()
let draw = current_draw()
- if (hand.length < 5 && draw.length > 0) {
+ let n = 5
+ if (game.frumentarii & (1 << game.current))
+ n = 3
+ if (hand.length < n && draw.length > 0) {
for (let c of draw)
gen_action_card(c)
} else {