diff options
-rw-r--r-- | play.html | 30 | ||||
-rw-r--r-- | play.js | 60 | ||||
-rw-r--r-- | rules.js | 170 |
3 files changed, 201 insertions, 59 deletions
@@ -14,6 +14,16 @@ </head> <style> +#log { background-color: whitesmoke; } +#log .h1 { font-weight: bold; padding-top:2px; padding-bottom:2px; margin: 8px 0; text-align: center; } +#log .h2 { padding-top:1px; padding-bottom:1px; text-align: center; } +#log .h1 { border-bottom: 1px solid #444; border-top: 1px solid #444; } +#log .h2 { border-bottom: 1px solid #444; border-top: 1px solid #444; } +#log .h1 { background-color: silver; } +#log .h2 { background-color: gainsboro; } +#log div { padding-left: 20px; text-indent: -12px; } +#log div.i { padding-left: 32px; text-indent: -12px; } + main { background-color: dimgray; } @@ -202,6 +212,26 @@ main { .small.flip.y5 { background-position: -34px -136px } .small.flip.y6 { background-position: -34px -170px } +#log .dice { + display: inline-block; + vertical-align: -2px; + width: 12px; + height: 12px; + background-size: 600% 100%; + background-repeat: no-repeat; + background-image: url(die_black_pips.svg); + background-color: #fff; + border: 1px solid #444; +} + +.d0 { background-position: -100% 0 } +.d1 { background-position: 0% 0; } +.d2 { background-position: 20% 0; } +.d3 { background-position: 40% 0; } +.d4 { background-position: 60% 0; } +.d5 { background-position: 80% 0; } +.d6 { background-position: 100% 0; } + </style> <body> @@ -347,5 +347,65 @@ function on_update() { action_button("undo", "Undo") } +const DICE = { + D0: '0', + D1: '1', + D2: '2', + D3: '3', + D4: '4', + D5: '5', + D6: '6', +} + +function sub_dice(match) { + return DICE[match] +} + +function sub_hex(match, p1) { + let x = p1 | 0 + let n = data.map.names[x] + if (n) + return x + " (" + n + ")" + return x +} + +function sub_piece(match, p1) { + let x = p1 | 0 + return data.pieces[x].name +} + +function on_log(text) { + let p = document.createElement("div") + + if (text.match(/^>/)) { + text = text.substring(1) + p.className = 'i' + } + + text = text.replace(/&/g, "&") + text = text.replace(/</g, "<") + text = text.replace(/>/g, ">") + + text = text.replace(/\b(\d\d\d\d)\b/g, sub_hex) + text = text.replace(/P(\d+)/g, sub_piece) + text = text.replace(/\bD\d\b/g, sub_dice) + + if (text.match(/^\.h1 /)) { + text = text.substring(4) + p.className = "h1" + } + else if (text.match(/^\.h2/)) { + text = text.substring(4) + p.className = "h2" + } + else if (text.match(/^\.h3/)) { + text = text.substring(4) + p.className = "h3" + } + + p.innerHTML = text + return p +} + build_hexes() scroll_with_middle_mouse("main") @@ -421,9 +421,9 @@ function update_zoc() { function goto_command_phase() { log("") - log("Turn " + game.turn) + log(".h1 Turn " + game.turn) log("") - log("Command Phase") + log(".h2 Command Phase") log("") bring_on_reinforcements() goto_hq_placement_step() @@ -840,7 +840,7 @@ function goto_organization_phase() { } log("") - log("Organization Phase") + log(".h2 Organization Phase") // F: ADVANCE FORMATION game.active = P1 @@ -878,23 +878,26 @@ function can_withdraw_any() { function goto_withdrawal() { log("") - log("Withdrawal.") - game.active = P1 - game.state = "withdrawal" + log(".h2 Withdrawal") game.remain = 0 - if (!can_withdraw_any()) - pass_withdrawal() + game.active = P2 + next_withdrawal() } function next_withdrawal() { game.state = "withdrawal" + if (game.remain === 0) { set_next_player() - if (!can_withdraw_any()) - pass_withdrawal() - } else if (--game.remain === 0) { - end_withdrawal() + } else { + if (--game.remain === 0) { + end_withdrawal() + return + } } + + if (!can_withdraw_any()) + pass_withdrawal() } function pass_withdrawal() { @@ -979,23 +982,74 @@ function bring_on_reinforcements() { set_piece_hex(p, BLOWN) } +function can_move_any() { + update_zoc() + for (let info of data.reinforcements) + if (info.turn === game.turn && info.side === game.active) + for (let p of info.list) + if (piece_hex(p) === REINFORCEMENTS) + return true + for (let p of friendly_cavalry_corps()) + if (piece_is_not_in_enemy_cav_zoc(p)) + return true + for (let p of friendly_infantry_corps()) + if (piece_is_not_in_enemy_zoc(p)) + return true + return false +} + function goto_movement_phase() { log("") - log("Movement Phase") + log(".h2 Movement Phase") log("") - game.active = P1 - game.state = "movement" game.remain = 0 + game.active = P2 + next_movement() } -// TODO: can move or auto-pass - function next_movement() { game.state = "movement" - if (game.remain === 0) + game.who = -1 + + if (game.remain === 0) { set_next_player() - else if (--game.remain === 0) + } else { + if (--game.remain === 0) { + end_movement() + return + } + } + + if (!can_move_any()) + pass_movement() +} + +function pass_movement() { + log(game.active + " passed movement.") + if (game.remain > 0) { end_movement() + } else { + update_zoc() + set_next_player() + + game.remain = roll_die() + log("Rolled D" + game.remain) + + let n = 0 + for (let p of friendly_corps()) { + if (piece_is_not_in_enemy_zoc_or_zoi(p)) + ++n + if (piece_hex(p) === REINFORCEMENTS) + ++n + } + + log(n + " Corps not in ZOC/ZOI") + + game.remain += n + + if (!can_move_any()) + pass_movement() + } } function end_movement() { @@ -1038,27 +1092,7 @@ states.movement = { game.state = "movement_to" }, pass() { - log(game.active + " passed movement.") - if (game.remain > 0) { - end_movement() - } else { - update_zoc() - set_next_player() - game.remain = roll_die() - log("Rolled D" + game.remain) - - let n = 0 - for (let p of friendly_corps()) { - if (piece_is_not_in_enemy_zoc_or_zoi(p)) - ++n - if (piece_hex(p) === REINFORCEMENTS) - ++n - } - - log(n + " Corps not in ZOC/ZOI") - - game.remain += n - } + pass_movement() }, } @@ -1386,26 +1420,53 @@ function search_retreat(result, here, from_list, n) { // === ATTACK PHASE === +function can_attack_any() { + for (let p of friendly_corps()) + if (piece_is_in_enemy_zoc(p)) + return true + return false +} + function goto_attack_phase() { log("") - log("Attack Phase") + log(".h2 Attack Phase") log("") - game.active = P1 - game.state = "attack" game.remain = 0 + game.active = P2 + next_attack() } -// TODO: can attack or auto-pass - function next_attack() { game.state = "attack" game.who = -1 game.target = -1 game.attack = 0 - if (game.remain === 0) + + if (game.remain === 0) { set_next_player() - else if (--game.remain === 0) + } else { + if (--game.remain === 0) { + end_attack() + return + } + } + + if (!can_attack_any()) + pass_attack() +} + +function pass_attack() { + log(game.active + " passed attack.") + if (game.remain > 0) { end_attack() + } else { + set_next_player() + game.remain = roll_die() + console.log("roll", game.remain) + log("Rolled D" + game.remain) + if (!can_attack_any()) + pass_attack() + } } function end_attack() { @@ -1427,19 +1488,10 @@ states.attack = { game.state = "attack_who" }, pass() { - log(game.active + " passed attack.") - if (game.remain > 0) { - end_attack() - } else { - set_next_player() - game.remain = roll_die() - log("Rolled D" + game.remain) - } + pass_attack() }, } -// === ATTACK - function can_attack_cavalry_support(p) { if (p === game.who) return false @@ -1481,7 +1533,7 @@ states.attack_who = { pop_undo() return } - log("Attacked " + p) + log("Attacked P" + p) game.target = p game.attack = piece_hex(game.target) begin_attack() @@ -1577,7 +1629,7 @@ function goto_resolve_attack() { let town = is_town_hex(d_hex) log("") - log("ATTACK H" + d_hex) + log("ATTACK " + d_hex) // ATTACKER DRM |