diff options
author | Tor Andersson <tor@ccxvii.net> | 2023-06-27 00:29:22 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2023-07-07 19:05:52 +0200 |
commit | 52c4d3435cb5b7f1378b849375f8dbe6834fb1ba (patch) | |
tree | 12baa1d44c6ae4831e992d71974f2d65c94dab6c | |
parent | 7dcd467b452f52e6831740d2cd85a7098a3984f6 (diff) | |
download | time-of-crisis-52c4d3435cb5b7f1378b849375f8dbe6834fb1ba.tar.gz |
Battle -> Combat. Card tooltips.
-rw-r--r-- | play.css | 61 | ||||
-rw-r--r-- | play.html | 2 | ||||
-rw-r--r-- | play.js | 171 | ||||
-rw-r--r-- | rules.js | 284 |
4 files changed, 293 insertions, 225 deletions
@@ -23,16 +23,17 @@ body.Blue .your_turn { background-color: hsl(207,67%,83%) } body.Yellow .your_turn { background-color: hsl(47,100%,78%) } body.Green .your_turn { background-color: hsl(99,36%,65%) } -#log .h1.p_red { background-color: hsl(354,85%,77%) } -#log .h1.p_blue { background-color: hsl(207,67%,83%) } -#log .h1.p_yellow { background-color: hsl(47,100%,78%) } -#log .h1.p_green { background-color: hsl(99,36%,70%) } +#log .h1.R { background-color: hsl(354,85%,77%) } +#log .h1.B { background-color: hsl(207,67%,83%) } +#log .h1.Y { background-color: hsl(47,100%,78%) } +#log .h1.G { background-color: hsl(99,36%,70%) } -#log img { height: 14px; vertical-align: -6px; } +#log span.M { color: hsl(358, 78%, 41%) } +#log span.S { color: hsl(206, 100%, 30%) } +#log span.P { color: hsl(44, 100%, 32%) } -#log span.M { color: #e31f26 } -#log span.S { color: #0066b3 } -#log span.P { color: hsl(44, 100%, 35%) } +#log .tip { cursor: default } +#log .tip:hover { text-decoration: underline; } #log { background-color: whitesmoke; } #log .h1 { background-color: silver; font-weight: bold; padding-top:2px; padding-bottom:2px; margin: 8px 0; text-align: center; } @@ -54,11 +55,6 @@ body.Green .your_turn { background-color: hsl(99,36%,65%) } background-repeat: no-repeat; } -#log img { - pointer-events: none; - vertical-align: -3px; -} - #log .white { background-image: url(images/die_black_pips.svg); background-color: #fff; @@ -444,22 +440,22 @@ body.p2 #npg_galatia { display: block } .sassanids.inactive { background-image: url(images/sassanids_inactive.png) } .neutral.governor { background-image: url(images/neutral_governor.png) } -#ardashir { background-image: url(images/ardashir.png) } -#cniva { background-image: url(images/cniva.png) } -#shapur { background-image: url(images/shapur.png) } -#ardashir.inactive { background-image: url(images/ardashir_back.png) } -#cniva.inactive { background-image: url(images/cniva_back.png) } -#shapur.inactive { background-image: url(images/shapur_back.png) } -#postumus { background-image: url(images/rival_postumus.png) } -#priest_king { background-image: url(images/rival_priest_king.png) } -#zenobia { background-image: url(images/rival_zenobia.png) } - -body.shift #ardashir { background-image: url(images/ardashir_back.png) } -body.shift #cniva { background-image: url(images/cniva_back.png) } -body.shift #shapur { background-image: url(images/shapur_back.png) } -body.shift #postumus { background-image: url(images/rival_back.png) } -body.shift #priest_king { background-image: url(images/rival_back.png) } -body.shift #zenobia { background-image: url(images/rival_back.png) } +.ardashir { background-image: url(images/ardashir.png) } +.cniva { background-image: url(images/cniva.png) } +.shapur { background-image: url(images/shapur.png) } +.ardashir.inactive { background-image: url(images/ardashir_back.png) } +.cniva.inactive { background-image: url(images/cniva_back.png) } +.shapur.inactive { background-image: url(images/shapur_back.png) } +.postumus { background-image: url(images/rival_postumus.png) } +.priest_king { background-image: url(images/rival_priest_king.png) } +.zenobia { background-image: url(images/rival_zenobia.png) } + +body.shift .ardashir { background-image: url(images/ardashir_back.png) } +body.shift .cniva { background-image: url(images/cniva_back.png) } +body.shift .shapur { background-image: url(images/shapur_back.png) } +body.shift .postumus { background-image: url(images/rival_back.png) } +body.shift .priest_king { background-image: url(images/rival_back.png) } +body.shift .zenobia { background-image: url(images/rival_back.png) } .blue.governor { background-image: url(images/blue_governor.png) } .green.governor { background-image: url(images/green_governor.png) } @@ -500,6 +496,13 @@ body.shift #zenobia { background-image: url(images/rival_back.png) } /* CARDS */ +#card_tip { + position: fixed; + z-index: 200; + right: 240px; + top: 60px; +} + .card { width: 250px; height: 350px; @@ -14,6 +14,8 @@ </head> <body class="p4"> +<div id="card_tip" class="hide"></div> + <header> <div id="toolbar"> <div class="menu"> @@ -57,31 +57,57 @@ const CARD_INDEX = [ 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, ] -const CARD_INFO = [ - { name: "M1", type: 0, cost: 1, event: "None" }, - { name: "S1", type: 1, cost: 1, event: "None" }, - { name: "P1", type: 2, cost: 1, event: "None" }, - { name: "M2", type: 0, cost: 2, event: "Castra" }, - { name: "S2", type: 1, cost: 2, event: "Tribute" }, - { name: "P2", type: 2, cost: 2, event: "Quaestor" }, - { name: "M2X", type: 0, cost: 2, event: "Cavalry" }, - { name: "S2X", type: 1, cost: 2, event: "Princeps Senatus" }, - { name: "P2X", type: 2, cost: 2, event: "Ambitus" }, - { name: "M3", type: 0, cost: 3, event: "Flanking Maneuver" }, - { name: "S3", type: 1, cost: 3, event: "Foederati" }, - { name: "P3", type: 2, cost: 3, event: "Mob" }, - { name: "M3X", type: 0, cost: 3, event: "Force March" }, - { name: "S3X", type: 1, cost: 3, event: "Frumentarii" }, - { name: "P3X", type: 2, cost: 3, event: "Mobile Vulgus" }, - { name: "M4", type: 0, cost: 4, event: "Praetorian Guard" }, - { name: "S4", type: 1, cost: 4, event: "Damnatio Memoriae" }, - { name: "S4B", type: 1, cost: 4, event: "Damnatio Memoriae (exp)" }, - { name: "P4", type: 2, cost: 4, event: "Pretender" }, - { name: "M4X", type: 0, cost: 4, event: "Spiculum" }, - { name: "S4X", type: 1, cost: 4, event: "Triumph" }, - { name: "P4X", type: 2, cost: 4, event: "Demagogue" }, +const CARD_CLASS = [ + "influence_m1", + "influence_s1", + "influence_p1", + "influence_m2", + "influence_s2", + "influence_p2", + "influence_m2x", + "influence_s2x", + "influence_p2x", + "influence_m3", + "influence_s3", + "influence_p3", + "influence_m3x", + "influence_s3x", + "influence_p3x", + "influence_m4", + "influence_s4", + "influence_s4b", + "influence_p4", + "influence_m4x", + "influence_s4x", + "influence_p4x", ] +const CARD_MAP = [ + "M1", + "S1", + "P1", + "M2(Castra)", + "S2(Tribute)", + "P2(Quaestor)", + "M2(Cavalry)", + "S2(Princeps Senatus)", + "P2(Ambitus)", + "M3(Flanking Maneuver)", + "S3(Foederati)", + "P3(Mob)", + "M3(Force March)", + "S3(Frumentarii)", + "P3(Mobile Vulgus)", + "M4(Praetorian Guard)", + "S4(Damnatio Memoriae)", + "S4(Damnatio Memoriae)", + "P4(Pretender)", + "M4(Spiculum)", + "S4(Triumph)", + "P4(Demagogue)", +] + + const EVENT_NAME = [ "None", "Plague of Cyprian", @@ -628,6 +654,7 @@ const LAYOUT_PATTERN = [ ] let ui = { + card_tip: document.getElementById("card_tip"), cards: [], event_cards: [], militia: [], @@ -813,8 +840,8 @@ function is_action(action, arg) { function on_init() { for (let c = 0; c < CARD_INDEX.length; ++c) { - let name = CARD_INFO[CARD_INDEX[c]].name - ui.cards[c] = create("div", { className: "card influence influence_" + name.toLowerCase(), my_action: "card", my_id: c }) + let name = CARD_CLASS[CARD_INDEX[c]] + ui.cards[c] = create("div", { className: "card influence " + name, my_action: "card", my_id: c }) } for (let e = 0; e <= 15; ++e) { @@ -835,17 +862,17 @@ function on_init() { } } - ui.rival_emperors[0] = create_piece(0, "rival_emperor", "rival_emperor", "postumus") - ui.rival_emperors[1] = create_piece(1, "rival_emperor", "rival_emperor", "priest_king") - ui.rival_emperors[2] = create_piece(2, "rival_emperor", "rival_emperor", "zenobia") + ui.rival_emperors[0] = create_piece(0, "rival_emperor", "rival_emperor postumus", "postumus") + ui.rival_emperors[1] = create_piece(1, "rival_emperor", "rival_emperor priest_king", "priest_king") + ui.rival_emperors[2] = create_piece(2, "rival_emperor", "rival_emperor zenobia", "zenobia") for (let tribe = 0; tribe < 5; ++tribe) for (let id = first_barbarian[tribe]; id <= last_barbarian[tribe]; ++id) ui.barbarians[id] = create_piece(id, "barbarian", BARBARIAN_CLASS[tribe]) - ui.barbarians[CNIVA].id = "cniva" - ui.barbarians[SHAPUR].id = "shapur" - ui.barbarians[ARDASHIR].id = "ardashir" + ui.barbarians[CNIVA].classList.add("cniva") + ui.barbarians[SHAPUR].classList.add("shapur") + ui.barbarians[ARDASHIR].classList.add("ardashir") for (let p = 0; p < 4; ++p) { for (let g = 0; g < 6; ++g) { @@ -891,7 +918,7 @@ function on_init() { let stack_count = new Array(21).fill(0) -let battle_width = 0 +let combat_width = 0 const BATTLE_MIN = 3 const BATTLE_H_MARGIN = 12 const BATTLE_V_MARGIN = 12 @@ -904,8 +931,8 @@ function layout_battle_stack(is_att, list, region) { if (region < 12) y -= 7 - if (list.length > battle_width) - battle_width = list.length + if (list.length > combat_width) + combat_width = list.length w = list.length * 60 + (list.length - 1) * BATTLE_H_GAP x -= w / 2 @@ -1010,15 +1037,15 @@ function layout_barbarian_dice(black, white, tribe) { } function is_battle_stack(region, type, id) { - if (view.battle_region !== region) + if (view.combat_region !== region) return false - if (type === "general" && view.battle.attacker === id) + if (type === "general" && view.combat.attacker === id) return true - if (type === "militia" && view.battle.attacker < 0) + if (type === "militia" && view.combat.attacker < 0) return true - if (type === "militia" && view.battle.type === "militia") + if (type === "militia" && view.combat.type === "militia") return true - return view.battle.type === type && view.battle.target === id + return view.combat.type === type && view.combat.target === id } function on_update() { @@ -1050,7 +1077,7 @@ function on_update() { ui.discard.replaceChildren() ui.market.replaceChildren() - battle_width = BATTLE_MIN + combat_width = BATTLE_MIN for (let pi = 0; pi < player_count; ++pi) { let legacy = view.legacy[pi] @@ -1249,9 +1276,9 @@ function on_update() { if (lone_militia) { if (is_battle_stack(region, "militia", region)) { if (has_militia_castra(region)) - layout_battle_stack(view.battle.attacker < 0, [ ui.mcastra[region], ui.militia[region] ], region) + layout_battle_stack(view.combat.attacker < 0, [ ui.mcastra[region], ui.militia[region] ], region) else - layout_battle_stack(view.battle.attacker < 0, [ ui.militia[region] ], region, true) + layout_battle_stack(view.combat.attacker < 0, [ ui.militia[region] ], region, true) } else { if (has_militia_castra(region)) layout_stack(-1, [ ui.mcastra[region], ui.militia[region] ], region, true, 16, 16) @@ -1320,7 +1347,7 @@ function on_update() { stack.push(ui.militia[region]) if (is_battle_stack(region, "general", pi * 6 + ai)) - layout_battle_stack(pi * 6 + ai === view.battle.attacker, stack, region) + layout_battle_stack(pi * 6 + ai === view.combat.attacker, stack, region) else layout_stack(pi * 6 + ai, stack, region, inside, 16, 16) } else { @@ -1362,13 +1389,13 @@ function on_update() { layout_available(avail_stack, 64, pi * 625 + 325, 27) } - if (view.battle) { - let [ x, y, w, h ] = LAYOUT_BATTLE[view.battle_region] - if (view.battle_region < 12) + if (view.combat) { + let [ x, y, w, h ] = LAYOUT_BATTLE[view.combat_region] + if (view.combat_region < 12) y -= 7 x += w >> 1 - w = battle_width * 60 + (battle_width - 1) * BATTLE_H_GAP + BATTLE_H_MARGIN * 2 + w = combat_width * 60 + (combat_width - 1) * BATTLE_H_GAP + BATTLE_H_MARGIN * 2 x -= w / 2 h = 120 + BATTLE_V_GAP + BATTLE_V_MARGIN * 2 @@ -1486,10 +1513,13 @@ function sub_region_name(match, p1) { return REGION_NAME[x] } +function sub_barbarian(match) { + return `<span class="tip" onmouseenter="on_focus_barbarian_tip('${match}')" onmouseleave="on_blur_tip()">${match}</span>` +} + function sub_event_name(match, p1) { let x = p1 | 0 - // TODO: tooltip? - return EVENT_NAME[x] + return `<span class="tip" onmouseenter="on_focus_event_tip(${x})" onmouseleave="on_blur_tip()">${EVENT_NAME[x]}</span>` } function sub_icon(match) { @@ -1497,11 +1527,13 @@ function sub_icon(match) { } function sub_card_1(match) { - return match + let x = CARD_MAP.indexOf(match) + return `<span class="tip ${match[0]}" onmouseenter="on_focus_influence_tip(${x})" onmouseleave="on_blur_tip()">${match}</span>` } function sub_card_x(match, p1, p2) { - return p1 + " " + p2 + let x = CARD_MAP.indexOf(match) + return `<span class="tip ${match[0]}" onmouseenter="on_focus_influence_tip(${x})" onmouseleave="on_blur_tip()">${p1} ${p2}</span>` } function on_log(text) { @@ -1516,9 +1548,18 @@ function on_log(text) { text = text.replace(/</g, "<") text = text.replace(/>/g, ">") + text = text.replace(/\bCniva\b/g, sub_barbarian) + text = text.replace(/\bShapur I\b/g, sub_barbarian) + text = text.replace(/\bArdashir\b/g, sub_barbarian) + text = text.replace(/\bPostumus\b/g, sub_barbarian) + text = text.replace(/\bZenobia\b/g, sub_barbarian) + text = text.replace(/\bPriest King\b/g, sub_barbarian) + text = text.replace(/%(\d+)/g, sub_region_name) text = text.replace(/\bE(\d+)/g, sub_event_name) + text = text.replace(/\b[BW]\d\b/g, sub_icon) + text = text.replace(/\b[MSP][1]\b/g, sub_card_1) text = text.replace(/\b([MSP][234])\(([^)]*)\)/g, sub_card_x) @@ -1529,19 +1570,19 @@ function on_log(text) { if (text.match(/^\.h1 Red/)) { text = text.substring(4) - p.className = "h1 p_red" + p.className = "h1 R" } else if (text.match(/^\.h1 Blue/)) { text = text.substring(4) - p.className = "h1 p_blue" + p.className = "h1 B" } else if (text.match(/^\.h1 Yellow/)) { text = text.substring(4) - p.className = "h1 p_yellow" + p.className = "h1 Y" } else if (text.match(/^\.h1 Green/)) { text = text.substring(4) - p.className = "h1 p_green" + p.className = "h1 G" } else if (text.match(/^\.h1/)) { text = text.substring(4) @@ -1560,6 +1601,26 @@ function on_log(text) { return p } +function on_focus_event_tip(c) { + ui.card_tip.className = "card event event_" + c +} + +function on_focus_influence_tip(x) { + ui.card_tip.className = "card influence " + CARD_CLASS[x] +} + +function on_focus_barbarian_tip(x) { + if (x === "Ardashir") ui.card_tip.className = "card event event_2" + if (x === "Priest King") ui.card_tip.className = "card event event_3" + if (x === "Shapur I") ui.card_tip.className = "card event event_5" + if (x === "Postumus") ui.card_tip.className = "card event event_6" + if (x === "Cniva") ui.card_tip.className = "card event event_8" + if (x === "Zenobia") ui.card_tip.className = "card event event_9" +} + +function on_blur_tip() { + ui.card_tip.className = "hide" +} on_init() scroll_with_middle_mouse("main") @@ -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") { @@ -4387,11 +4394,6 @@ function log_h2(msg) { function log_h3(msg) { log_br() - log(".h3 " + msg) -} - -function log_h4(msg) { - log_br() log(msg) } |