From 52c4d3435cb5b7f1378b849375f8dbe6834fb1ba Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 27 Jun 2023 00:29:22 +0200 Subject: Battle -> Combat. Card tooltips. --- rules.js | 284 ++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 143 insertions(+), 141 deletions(-) (limited to 'rules.js') diff --git a/rules.js b/rules.js index c529fbc..e1aba4d 100644 --- a/rules.js +++ b/rules.js @@ -2,15 +2,7 @@ /* TODO ----- -striped backgorund for "Played" when not your turn - -hover over event card name for popup - -combine flags - -[ ] combat battle screen - splay stack / dialog for watching contents and taking hits [ ] killed leader stash for buy/trash phase [ ] emperor variant (and tokens) @@ -1029,18 +1021,18 @@ function roll_dice_no_reroll(count, target) { function eliminate_barbarian(id) { let tribe = get_barbarian_tribe(id) - if (is_barbarian_leader(id) && game.battle) { + if (is_barbarian_leader(id) && game.combat) { if (id === CNIVA) { log("Cniva killed!") - game.battle.killed |= CNIVA_BONUS + game.combat.killed |= CNIVA_BONUS } if (id === ARDASHIR) { log("Ardashir killed!") - game.battle.killed |= ARDASHIR_BONUS + game.combat.killed |= ARDASHIR_BONUS } if (id === SHAPUR) { log("Shapur killed!") - game.battle.killed |= SHAPUR_BONUS + game.combat.killed |= SHAPUR_BONUS } set_barbarian_location(id, AVAILABLE) } else { @@ -1051,8 +1043,8 @@ function eliminate_barbarian(id) { function eliminate_rival_emperor(id) { log(RIVAL_EMPEROR_NAME[id] + " killed!") - if (game.battle) - game.battle.killed |= (1 << id) + if (game.combat) + game.combat.killed |= (1 << id) set_rival_emperor_location(id, AVAILABLE) } @@ -1137,7 +1129,7 @@ states.setup_province = { capital(where) { push_undo() - log(PLAYER_NAME[game.current] + " in %" + where + ".") + log(PLAYER_NAME[game.current] + " selected %" + where + ".") set_governor_location(game.current * 6 + 0, where) @@ -1499,7 +1491,6 @@ states.crisis_barbarian_leader = { gen_action_region(game.where) }, region(where) { - logi("Barbarian leader in %" + where + ".") set_barbarian_location(game.count, where) goto_take_actions() }, @@ -1520,7 +1511,6 @@ states.crisis_rival_emperor = { gen_action_region(game.where) }, region(where) { - logi("Rival emperor in %" + where + ".") set_rival_emperor_location(game.count, where) goto_take_actions() }, @@ -1571,7 +1561,6 @@ states.palmyra_allies = { }, barbarian(id) { push_undo() - logi(BARBARIAN_NAME[id] + " in %" + get_barbarian_location(id)) eliminate_barbarian(id) if (--game.count === 0) goto_take_actions() @@ -1602,7 +1591,7 @@ states.ludi_saeculares = { }, card(c) { push_undo() - logi("Discarded " + card_name(c)) + logi("Discard " + card_name(c)) set_delete(current_hand(), c) set_add(current_discard(), c) award_legacy(game.current, "Ludi Saeculares", 2 * card_value(c)) @@ -2108,7 +2097,7 @@ function increase_support(where) { } function remove_governor(where) { - log("Removed governor from %" + where + ".") + log("Remove governor from %" + where + ".") eliminate_militia(where) set_mobs(where, 0) @@ -2453,7 +2442,9 @@ states.move_army_at_sea = { } function move_army_to(who, to) { - log("Move Army to %" + to + ".") + let from = get_general_location(who) + + log("Move Army from %" + from + " to %" + to + ".") remove_general_castra(who) @@ -2486,7 +2477,7 @@ function enter_capital() { } } - if (game.battle) + if (game.combat) end_battle() } @@ -2509,7 +2500,7 @@ states.occupy_seat_of_power_1 = { }, region(where) { push_undo() - log("Removed Seat of Power in %" + where + ".") + log("Remove Seat of Power in %" + where + ".") remove_seat_of_power(where) remove_governor(where) resume_occupy_seat_of_power() @@ -2527,7 +2518,7 @@ states.occupy_seat_of_power_2 = { }, region(where) { push_undo() - log("Removed Breakaway in %" + where + ".") + log("Remove Breakaway in %" + where + ".") remove_breakaway(where) resume_occupy_seat_of_power() }, @@ -2542,7 +2533,7 @@ states.occupy_breakaway = { }, region(where) { push_undo() - log("Removed Breakaway in %" + where + ".") + log("Remove Breakaway in %" + where + ".") remove_breakaway(where) remove_governor(where) goto_replace_pretender() @@ -2571,7 +2562,7 @@ states.replace_pretender_governor = { }, governor(id) { push_undo() - log("Replaced Governor in %" + game.where + ".") + log("Replace Governor in %" + game.where + ".") set_governor_location(id, game.where) game.state = "take_actions" }, @@ -2849,11 +2840,11 @@ states.mob = { function auto_remove_pretender_empire(seat) { let pretender = get_province_governor(seat) / 6 | 0 - log("Removed Seat of Power in %" + seat + ".") + log("Remove Seat of Power in %" + seat + ".") remove_seat_of_power(seat) for (let where = 1; where < 12; ++where) { if (is_breakaway(where) && (get_province_governor(where) / 6 | 0) === pretender) { - log("Removed Breakaway in %" + where + ".") + log("Remove Breakaway in %" + where + ".") remove_breakaway(where) } } @@ -2926,7 +2917,7 @@ states.pretender_breakaway = { // === COMBAT === function play_flanking_maneuver() { - game.battle.flanking = 1 + game.combat.flanking = 1 } function goto_battle_vs_general(where, attacker, target) { @@ -2950,8 +2941,8 @@ function goto_battle(type, where, attacker, target) { log_h2("Battle in %" + where) spend_military(1) game.where = where - game.battle = { type, attacker, target, flanking: 0, killed: 0 } - game.state = "battle" + game.combat = { type, attacker, target, flanking: 0, killed: 0 } + game.state = "initiate_battle" if (attacker >= 0) { if (is_general_inside_capital(attacker)) remove_militia_castra(where) @@ -2991,20 +2982,20 @@ function gen_initiate_battle(where) { } function format_battle_target() { - switch (game.battle.type) { + switch (game.combat.type) { case "militia": return PLAYER_NAME[get_province_player(game.where)] + " militia" - case "barbarians": return BARBARIAN_NAME[game.battle.target] - case "general": return PLAYER_NAME[game.battle.target / 6 | 0] + " army" - case "rival_emperor": return RIVAL_EMPEROR_NAME[game.battle.target] + case "barbarians": return BARBARIAN_NAME[game.combat.target] + case "general": return PLAYER_NAME[game.combat.target / 6 | 0] + " army" + case "rival_emperor": return RIVAL_EMPEROR_NAME[game.combat.target] } } -states.battle = { +states.initiate_battle = { show_battle: true, inactive: "Combat", prompt() { prompt("Initiate Battle against " + format_battle_target() + " in " + REGION_NAME[game.where] + ".") - if (!game.battle.flanking && has_card_event(CARD_M3)) { + if (!game.combat.flanking && has_card_event(CARD_M3)) { view.prompt += " You may play Flanking Maneuver." gen_card_event(CARD_M3) } @@ -3019,7 +3010,7 @@ states.battle = { roll() { clear_undo() roll_combat_dice() - if (game.battle.flanking) + if (game.combat.flanking) game.state = "flanking_maneuver" else goto_assign_hits() @@ -3027,11 +3018,11 @@ states.battle = { } function format_hits() { - let s = "Defender rolled " + game.battle.ahits + " hit" - if (game.battle.ahits !== 1) + let s = "Defender rolled " + game.combat.ahits + " hit" + if (game.combat.ahits !== 1) s += "s" - s += ", attacker rolled " + game.battle.dhits + " hit" - if (game.battle.dhits !== 1) + s += ", attacker rolled " + game.combat.dhits + " hit" + if (game.combat.dhits !== 1) s += "s" return s } @@ -3039,7 +3030,6 @@ function format_hits() { states.flanking_maneuver = { show_battle: true, get inactive() { return "Flanking Maneuver. " + format_hits() }, - inactive: "Flanking Maneuver", prompt() { prompt("Flanking Maneuver: " + format_hits() + ".") view.actions.pass = 1 @@ -3056,24 +3046,24 @@ states.flanking_maneuver = { } function roll_combat_dice() { - game.battle.dtaken = 0 - game.battle.ataken = 0 + game.combat.dtaken = 0 + game.combat.ataken = 0 - log_h4("DEFENDER") - game.battle.ahits = roll_defender_dice() - log("Total " + game.battle.ahits + " hits!") + log_h3("DEFENDER") + game.combat.ahits = roll_defender_dice() + log("Total hits: " + game.combat.ahits) log_br() - log_h4("ATTACKER") - game.battle.dhits = roll_attacker_dice() - log("Total " + game.battle.dhits + " hits!") + log_h3("ATTACKER") + game.combat.dhits = roll_attacker_dice() + log("Total hits: " + game.combat.dhits) log_br() } function roll_flanking_maneuver_dice() { - log_h4("FLANKING MANEUVER") - game.battle.dhits = roll_attacker_dice() - log("Total " + game.battle.dhits + " hits!") + log_h3("FLANKING MANEUVER") + game.combat.dhits = roll_attacker_dice() + log("Total " + game.combat.dhits + " hits!") log_br() } @@ -3083,13 +3073,6 @@ function roll_general_dice(general) { let drm = get_roman_drm() - log(PLAYER_NAME[general/6|0]) - - if (is_general_inside_capital(general) && has_militia(game.where)) { - log("Militia") - n += roll_dice(1, 5 + drm) - } - let full_strength = 0 let reduced = 0 for (let id = 0; id < LEGION_COUNT; ++id) { @@ -3104,6 +3087,7 @@ function roll_general_dice(general) { log("Legions") n += roll_dice(full_strength, 3 + drm) } + if (reduced > 0) { log("Reduced Legions") n += roll_dice(reduced, 5 + drm) @@ -3118,6 +3102,11 @@ function roll_general_dice(general) { n += roll_dice(barbarians, 4 + drm) } + if (is_general_inside_capital(general) && has_militia(game.where)) { + log("Militia") + n += roll_dice(1, 5 + drm) + } + return n } @@ -3127,7 +3116,7 @@ function roll_militia_dice() { } function roll_rival_emperor_dice() { - log("Rival Emperor") + log(RIVAL_EMPEROR_NAME[game.combat.target]) return roll_dice(3, 4) } @@ -3144,20 +3133,20 @@ function roll_barbarian_dice(tribe) { function roll_attacker_dice() { let n = get_plague_hits() - if (game.battle.attacker < 0) + if (game.combat.attacker < 0) n += roll_militia_dice() else - n += roll_general_dice(game.battle.attacker) - if (game.battle.type === "militia" && has_militia_castra(game.where)) { + 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.battle.type === "general" && has_general_castra(game.battle.target)) { + if (game.combat.type === "general" && has_general_castra(game.combat.target)) { log("Castra reduces 1 hit") n -= 1 } - if (game.battle.type === "barbarians" && get_barbarian_location(SHAPUR) === game.where) { - log("Shapur I reduced 1 hit") + if (game.combat.type === "barbarians" && get_barbarian_location(SHAPUR) === game.where) { + log("Shapur I reduces 1 hit") n -= 1 } return Math.max(0, n) @@ -3165,7 +3154,7 @@ function roll_attacker_dice() { function roll_defender_dice() { let n = get_plague_hits() - switch (game.battle.type) { + switch (game.combat.type) { case "militia": n += roll_militia_dice() break @@ -3173,10 +3162,11 @@ function roll_defender_dice() { n += roll_rival_emperor_dice() break case "barbarians": - n += roll_barbarian_dice(game.battle.target) + n += roll_barbarian_dice(game.combat.target) break case "general": - n += roll_general_dice(game.battle.target) + log(PLAYER_NAME[game.combat.target/6|0]) + n += roll_general_dice(game.combat.target) break } return Math.max(0, n) @@ -3271,26 +3261,26 @@ function gen_hits_general(general) { } function has_hits_on_attacker() { - if (game.battle.ataken < game.battle.ahits) { - if (game.battle.attacker < 0) + if (game.combat.ataken < game.combat.ahits) { + if (game.combat.attacker < 0) return has_hits_militia() else - return has_hits_general(game.battle.attacker) + return has_hits_general(game.combat.attacker) } return false } function has_hits_on_defender() { - if (game.battle.dtaken < game.battle.dhits) { - switch (game.battle.type) { + if (game.combat.dtaken < game.combat.dhits) { + switch (game.combat.type) { case "militia": return has_hits_militia() case "rival_emperor": - return has_hits_rival_emperor(game.battle.target) + return has_hits_rival_emperor(game.combat.target) case "barbarians": - return has_hits_barbarians(game.battle.target) + return has_hits_barbarians(game.combat.target) case "general": - return has_hits_general(game.battle.target) + return has_hits_general(game.combat.target) } } return false @@ -3319,26 +3309,26 @@ states.assign_hits_on_attacker = { get inactive() { return "Combat. " + format_hits() }, prompt() { prompt("Combat: " + format_hits() + ".") - if (game.battle.attacker < 0) + if (game.combat.attacker < 0) gen_hits_militia() else - gen_hits_general(game.battle.attacker) + gen_hits_general(game.combat.attacker) }, militia(where) { push_undo() - game.battle.ataken += 1 + game.combat.ataken += 1 eliminate_militia(where) goto_assign_hits_on_attacker() }, legion(id) { push_undo() - game.battle.ataken += 1 + game.combat.ataken += 1 assign_hit_to_legion(id) goto_assign_hits_on_attacker() }, barbarian(id) { push_undo() - game.battle.ataken += 1 + game.combat.ataken += 1 eliminate_barbarian(id) goto_assign_hits_on_attacker() }, @@ -3349,42 +3339,42 @@ states.assign_hits_on_defender = { get inactive() { return "Combat. " + format_hits() }, prompt() { prompt("Combat: " + format_hits() + ".") - switch (game.battle.type) { + switch (game.combat.type) { case "militia": gen_hits_militia() break case "rival_emperor": - gen_hits_rival_emperor(game.battle.target) + gen_hits_rival_emperor(game.combat.target) break case "barbarians": - gen_hits_barbarians(game.battle.target) + gen_hits_barbarians(game.combat.target) break case "general": - gen_hits_general(game.battle.target) + gen_hits_general(game.combat.target) break } }, militia(where) { push_undo() - game.battle.dtaken += 1 + game.combat.dtaken += 1 eliminate_militia(where) goto_assign_hits_on_defender() }, legion(id) { push_undo() - game.battle.dtaken += 1 + game.combat.dtaken += 1 assign_hit_to_legion(id) goto_assign_hits_on_defender() }, barbarian(id) { push_undo() - game.battle.dtaken += 1 + game.combat.dtaken += 1 eliminate_barbarian(id) goto_assign_hits_on_defender() }, rival_emperor(id) { push_undo() - game.battle.dtaken += 1 + game.combat.dtaken += 1 eliminate_rival_emperor(id) goto_assign_hits_on_defender() } @@ -3398,18 +3388,18 @@ function is_attacker_eliminated() { } function is_defender_eliminated() { - switch (game.battle.type) { + switch (game.combat.type) { case "militia": return !has_militia(game.where) case "rival_emperor": - return get_rival_emperor_location(game.battle.target) === AVAILABLE + return get_rival_emperor_location(game.combat.target) === AVAILABLE case "barbarians": if (is_province(game.where)) - return find_barbarian_of_tribe(game.where, game.battle.target) < 0 + return find_barbarian_of_tribe(game.where, game.combat.target) < 0 else - return find_active_barbarian_of_tribe(game.where, game.battle.target) < 0 + return find_active_barbarian_of_tribe(game.where, game.combat.target) < 0 case "general": - return get_general_location(game.battle.target) === AVAILABLE + return get_general_location(game.combat.target) === AVAILABLE } return false } @@ -3422,7 +3412,7 @@ states.combat_victory = { let ae = is_attacker_eliminated() if (de && ae) prompt("Combat: There is no winner.") - else if (de || game.battle.dtaken > game.battle.ataken) + else if (de || game.combat.dtaken > game.combat.ataken) prompt("Combat: You win the battle!") else prompt("Combat: Defenders win the battle!") @@ -3440,7 +3430,7 @@ function goto_combat_victory() { let ae = is_attacker_eliminated() if (de && ae) goto_combat_no_victory() - else if (de || game.battle.dtaken > game.battle.ataken) + else if (de || game.combat.dtaken > game.combat.ataken) goto_combat_victory_attacker() else goto_combat_victory_defender() @@ -3464,40 +3454,40 @@ function award_legacy_summary(p, reason, n) { function goto_combat_no_victory() { log("Both sides eliminated.") - game.battle.killed = 0 + game.combat.killed = 0 end_battle() } function goto_combat_victory_defender() { - game.battle.killed = 0 - if (game.battle.type === "general") - award_legacy(game.battle.target / 6 | 0, "Victory", 2) - else if (game.battle.type === "militia") + game.combat.killed = 0 + if (game.combat.type === "general") + award_legacy(game.combat.target / 6 | 0, "Victory", 2) + else if (game.combat.type === "militia") award_legacy(get_province_player(game.where), "Victory", 2) - else if (game.battle.type === "barbarians") - log(BARBARIAN_NAME[game.battle.target] + " won.") - else if (game.battle.type === "rival_emperor") - log(RIVAL_EMPEROR_NAME[game.battle.target] + " won.") + else if (game.combat.type === "barbarians") + log(BARBARIAN_NAME[game.combat.target] + " won.") + else if (game.combat.type === "rival_emperor") + log(RIVAL_EMPEROR_NAME[game.combat.target] + " won.") end_battle() } function goto_combat_victory_attacker() { - if (game.battle.type === "barbarians") { - award_legacy(game.current, "Victory", 2 + game.battle.dtaken) + if (game.combat.type === "barbarians") { + award_legacy(game.current, "Victory", 2 + game.combat.dtaken) // Surviving Barbarians go home (to active) - let tribe = get_barbarian_tribe(game.battle.target) + let tribe = get_barbarian_tribe(game.combat.target) for (let id = first_barbarian[tribe]; id <= last_barbarian[tribe]; ++id) - if (get_barbarian_location(id) === game.battle) + if (get_barbarian_location(id) === game.combat) set_barbarian_location(id, BARBARIAN_HOMELAND[tribe]) } else { award_legacy(game.current, "Victory", 2) } // Defending Romans must retreat into province - if (game.battle.type === "general") { - set_general_outside_capital(game.battle.target) - remove_general_castra(game.battle.target) + if (game.combat.type === "general") { + set_general_outside_capital(game.combat.target) + remove_general_castra(game.combat.target) } if (can_enter_capital(game.where)) @@ -3530,17 +3520,17 @@ function end_battle() { if (game.selected_general >= 0 && get_general_location(game.selected_general) === AVAILABLE) game.selected_general = -1 - if (game.battle.killed) { + if (game.combat.killed) { if (can_free_increase_support_level(game.where)) { game.state = "free_increase_support_level" return } else { log("Kept for cost reduction.") - game.killed |= game.battle.killed + game.killed |= game.combat.killed } } - game.battle = null + game.combat = null game.state = "take_actions" } @@ -3559,14 +3549,14 @@ states.free_increase_support_level = { region(where) { push_undo() increase_support(where) - game.battle = null + game.combat = null game.state = "take_actions" }, keep() { push_undo() log("Kept for cost reduction.") - game.killed |= game.battle.killed - game.battle = null + game.killed |= game.combat.killed + game.combat = null game.state = "take_actions" }, } @@ -3635,7 +3625,7 @@ states.support_check = { region(where) { push_undo() game.count |= (1 << where) - log("Reduced support level in %" + where + ".") + log("Reduce support level in %" + where + ".") reduce_support(where) resume_support_check() }, @@ -3662,7 +3652,7 @@ states.support_check_emperor = { region(where) { push_undo() game.count |= (1 << where) - log("Reduced support level in %" + where + ".") + log("Reduce support level in %" + where + ".") reduce_support(where) goto_support_check_mobs() }, @@ -3703,7 +3693,7 @@ states.support_check_mobs = { function goto_expand_pretender_empire() { for (let where = 1; where < 12; ++where) { if (is_expand_pretender_province(where)) { - log_h4("Expand Pretender Empire") + log_h3("Expand Pretender Empire") game.state = "expand_pretender_empire" return } @@ -3732,7 +3722,7 @@ states.expand_pretender_empire = { // === GAIN LEGACY === function goto_gain_legacy() { - log_h4("Gain Legacy") + log_h3("Gain Legacy") if (is_only_pretender_player()) award_legacy_summary(game.current, "Pretender", count_own_breakaway_provinces()) @@ -3802,10 +3792,11 @@ function count_political_points() { } function goto_buy_trash_cards() { - //log_h4("Played") - //logi(game.played.map(c=>card_name(c)).join(", ")) log_br() - log("Played " + game.played.map(c=>card_name(c)).join(", ") + ".") + if (game.played.length > 0) + log("Played " + game.played.map(c=>card_name(c)).join(", ") + ".") + else + log("Played no cards.") log_br() let discard = current_discard() @@ -3834,7 +3825,7 @@ states.buy_trash_discard = { }, card(c) { push_undo() - log("Discarded " + card_name(c) + ".") + log("Discard " + card_name(c) + ".") set_delete(current_hand(), c) set_add(current_discard(), c) }, @@ -3918,14 +3909,14 @@ states.buy_trash = { card(c) { push_undo() if (set_has(current_discard(), c)) { - log("Trashed " + card_name(c) + ".") + log("Trash " + card_name(c) + ".") set_delete(current_discard(), c) game.pp -= 3 } else { let military_bonus = has_military_card_bonus() let senate_bonus = has_senate_card_bonus() - log("Bought " + card_name(c) + ".") + log("Buy " + card_name(c) + ".") set_add(current_discard(), c) set_delete(find_market_with_card(c), c) @@ -4108,7 +4099,7 @@ function vp_tie(p) { } function goto_game_end() { - log_h2("Game End") + log_h1("Game End") game.crisis[0] = -1 game.crisis[1] = 0 @@ -4116,11 +4107,27 @@ function goto_game_end() { game.crisis[3] = 0 game.crisis[4] = 0 + log_h3("Emperor Turns") + game.current = game.first + do { + logi(game.emperor_turns[game.current] + " " + PLAYER_NAME[game.current]) + game.current = next_player() + } while (game.current !== game.first) + + log_br() + let cutoff = award_emperor_turns(10, 1000) cutoff = award_emperor_turns(6, cutoff) cutoff = award_emperor_turns(3, cutoff) award_emperor_turns(0, cutoff) + log_h3("Final Legacy") + game.current = game.first + do { + logi(game.legacy[game.current] + " " + PLAYER_NAME[game.current]) + game.current = next_player() + } while (game.current !== game.first) + let victor = game.legacy.map((legacy,p) => [vp_tie(p),p]).sort((a,b) => b[0] - a[0])[0][1] goto_game_over(PLAYER_NAME[victor], PLAYER_NAME[victor] + " won!") @@ -4214,7 +4221,7 @@ exports.setup = function (seed, scenario, options) { battled: 0, mbattled: 0, killed: 0, - battle: null, + combat: null, provinces: new Array(3 * player_count).fill(1), governors: new Array(6 * player_count).fill(UNAVAILABLE), @@ -4329,9 +4336,9 @@ exports.view = function (state, player_name) { emperor_turns: game.emperor_turns, } - if (game.battle && states[game.state].show_battle) { - view.battle = game.battle - view.battle_region = game.where + if (game.combat && states[game.state].show_battle) { + view.combat = game.combat + view.combat_region = game.where } if (game.state === "game_over") { @@ -4386,11 +4393,6 @@ function log_h2(msg) { } function log_h3(msg) { - log_br() - log(".h3 " + msg) -} - -function log_h4(msg) { log_br() log(msg) } -- cgit v1.2.3