summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.css11
-rw-r--r--play.html3
-rw-r--r--play.js18
-rw-r--r--rules.js158
4 files changed, 133 insertions, 57 deletions
diff --git a/play.css b/play.css
index 2fbf2b2..f4cc859 100644
--- a/play.css
+++ b/play.css
@@ -1,5 +1,6 @@
header { background-color: hsl(39, 25%, 75%); }
#replay_panel { background-color: hsl(39, 25%, 75%);; }
+
#log { background-color: hsl(50, 50%, 92%); }
#log .h1 { background-color: #803a3c; color: gold; text-shadow: 0 0 1px white; }
#log .h2 { background-color: hsl(45, 30%, 70%); }
@@ -10,15 +11,19 @@ body.French header.your_turn { background-color: hsl(195, 72%, 75%); }
body.Coalition header.your_turn { background-color: white; }
#role_Coalition .role_name { background-color: white; }
-#log { padding-top: 0 }
#log .h1 { font-weight: bold; padding-top:2px; padding-bottom:2px; }
#log .h2 { padding-top:1px; padding-bottom:1px; }
#log .h3 { padding-top:1px; padding-bottom:1px; }
-#log .h1, .h2, .h3 { margin: 9px 0; text-align: center; }
+#log .h1, #log .h2, #log .h3 { text-align: center; }
+#log .h1, #log .h2, #log .h3 { margin: 2px 0; }
+#log .h1, #log .h2, #log .h3 { border-top: 1px solid #000a; border-bottom: 1px solid #000a; }
#log div { padding-left: 20px; text-indent: -12px; }
#log div.i { padding-left: 32px; text-indent: -12px; }
+#log .tip { cursor: pointer }
+#log .tip:hover { text-decoration: underline }
+
#log span.french { background-color: hsl(195, 72%, 90%); padding: 0 2px }
#log span.anglo { background-color: white; padding: 0 2px }
#log span.prussian { background-color: gainsboro; padding: 0 2px }
@@ -344,7 +349,7 @@ div.french.tip, div.anglo.tip, div.prussian.tip {
#log .dice {
display: inline-block;
- vertical-align: -2px;
+ vertical-align: -3px;
width: 12px;
height: 12px;
background-size: 600% 100%;
diff --git a/play.html b/play.html
index ea54426..2a17eed 100644
--- a/play.html
+++ b/play.html
@@ -23,9 +23,6 @@
<a class="menu_item" href="info/charts.html" target="_blank">Charts</a>
<div class="resign menu_separator"></div>
<div class="resign menu_item" onclick="confirm_resign()">Resign</div>
- <div class="menu_separator"></div>
- <div class="menu_item" onclick="send_save()">&#x1F41E; Save</div>
- <div class="menu_item" onclick="send_restore()">&#x1F41E; Restore</div>
</div>
</div>
<div class="icon_button" onclick="toggle_pieces()"><img src="/images/earth-africa-europe.svg"></div>
diff --git a/play.js b/play.js
index b0228af..dd6984b 100644
--- a/play.js
+++ b/play.js
@@ -472,7 +472,7 @@ function on_click_piece_tip(id) {
ui.pieces[id].scrollIntoView({ block:"center", inline:"center", behavior:"smooth" })
}
-const DICE = {
+const DICE_TEXT = {
D0: '[0]',
D1: '[1]',
D2: '[2]',
@@ -482,6 +482,16 @@ const DICE = {
D6: '[6]',
}
+const DICE = {
+ D0: '<span class="dice d0"></span>',
+ D1: '<span class="dice d1"></span>',
+ D2: '<span class="dice d2"></span>',
+ D3: '<span class="dice d3"></span>',
+ D4: '<span class="dice d4"></span>',
+ D5: '<span class="dice d5"></span>',
+ D6: '<span class="dice d6"></span>',
+}
+
function sub_dice(match) {
return DICE[match]
}
@@ -493,7 +503,7 @@ function sub_hex(match, p1) {
n = x + " (" + n + ")"
else
n = x
- return `<span class="hextip" onmouseenter="on_focus_hex_tip(${x})" onmouseleave="on_blur_hex_tip(${x})" onclick="on_click_hex_tip(${x})">${n}</span>`
+ return `<span class="tip" onmouseenter="on_focus_hex_tip(${x})" onmouseleave="on_blur_hex_tip(${x})" onclick="on_click_hex_tip(${x})">${n}</span>`
}
function sub_piece(match, p1) {
@@ -525,8 +535,8 @@ function on_log(text) {
text = text.replace(/P(\d+)/g, sub_piece)
text = text.replace(/\bD\d\b/g, sub_dice)
- text = text.replace(/French/g, '<span class="french">French</span>')
- text = text.replace(/Coalition/g, '<span class="anglo">Coalition</span>')
+ text = text.replace(/^French/g, '<span class="french">French</span>')
+ text = text.replace(/^Coalition/g, '<span class="anglo">Coalition</span>')
if (text.match(/^\.h1 /)) {
text = text.substring(4)
diff --git a/rules.js b/rules.js
index 2620444..96f3017 100644
--- a/rules.js
+++ b/rules.js
@@ -1,11 +1,6 @@
"use strict"
-// TODO - auto-update ZOC
-
-// TODO: tooltips and log coloring?
-// TODO: map names
-// TODO: unit names
-// TODO: fix counters and map graphics
+// TODO: show VP in player list
const P1 = "French"
const P2 = "Coalition"
@@ -20,6 +15,17 @@ exports.scenarios = [ "June 16", "June 15" ]
const data = require("./data")
+const TURN_NAME = [
+ "June 15 A.M.",
+ "June 15 P.M.",
+ "June 16 A.M.",
+ "June 16 P.M.",
+ "June 17 A.M.",
+ "June 17 P.M.",
+ "June 18 A.M.",
+ "June 18 P.M.",
+]
+
const last_hex = 1000 + (data.map.rows - 1) * 100 + (data.map.cols - 1)
const p1_forbidden = data.map.forbidden[0]
@@ -459,7 +465,7 @@ function count_french_reinforcements() {
function init_turn() {
let die
- log(".h1 Turn " + game.turn)
+ log_h1("Turn " + game.turn + " \u2013 " + TURN_NAME[game.turn-1])
bring_on_reinforcements()
@@ -496,20 +502,21 @@ function init_turn() {
}
}
- if (game.rain > 0)
+ if (game.rain > 0) {
log("Artillery Ricochet Ineffective.")
+ }
}
function goto_command_phase() {
- log(".h2 Command")
+ log_h2("Command")
goto_hq_placement_step()
}
// === A: HQ PLACEMENT STEP ===
function goto_hq_placement_step() {
- log(".h3 Place HQ")
+ log_h3("Place HQ")
game.active = P1
game.state = "place_hq"
for (let p of p1_hqs) {
@@ -533,7 +540,7 @@ function log_hq_placement_step(hqs) {
function end_hq_placement_step() {
if (game.active === P1) {
log_hq_placement_step(p1_hqs)
- log("")
+ logbr()
game.active = P2
} else {
log_hq_placement_step(p2_hqs)
@@ -630,7 +637,7 @@ function goto_return_blown() {
if (piece_hex(p) === BLOWN)
blown = true
if (blown)
- log(".h3 Return Blown Units")
+ log_h3("Return Blown Units")
game.active = P2
resume_return_blown_1()
@@ -673,7 +680,6 @@ function resume_return_blown_2() {
states.return_blown_who = {
inactive: "return blown corps",
prompt() {
- prompt("Return a blown corps.")
let done = true
for (let p of friendly_corps()) {
if (piece_hex(p) === BLOWN) {
@@ -681,8 +687,12 @@ states.return_blown_who = {
done = false
}
}
- if (done)
+ if (done) {
+ prompt("Finished returning blown corps.")
view.actions.end_step = 1
+ } else {
+ prompt("Return a blown corps.")
+ }
},
piece(p) {
push_undo()
@@ -751,7 +761,7 @@ function goto_cavalry_corps_recovery_step() {
// === D: DETACHMENT PLACEMENT STEP ===
function goto_detachment_placement_step() {
- log(".h3 Detachments")
+ log_h3("Detachments")
game.active = P1
begin_detachment_placement_step()
}
@@ -775,7 +785,7 @@ function begin_detachment_placement_step() {
function end_detachment_placement_step() {
if (game.active === P1) {
- log("")
+ logbr()
game.active = P2
begin_detachment_placement_step()
} else {
@@ -850,8 +860,7 @@ states.place_detachment_hq = {
states.place_detachment_who = {
inactive: "place detachments",
prompt() {
- prompt("Place an available detachment.")
- prompt("Place a detachment for " + piece_name(game.target) + ".")
+ prompt("Choose a detachment for " + piece_name(game.target) + ".")
gen_action_piece(game.target)
@@ -917,7 +926,7 @@ states.place_detachment_where = {
// === E: DETACHMENT RECALL STEP ===
function goto_detachment_recall_step() {
- log(".h3 Recall")
+ log_h3("Recall")
game.active = P1
game.state = "detachment_recall_step"
}
@@ -963,7 +972,7 @@ function goto_organization_phase() {
if (n < 3) {
if (piece_hex(HILL_2) === SWAPPED && piece_hex(HILL_1) !== ELIMINATED) {
- log(".h3 Line of Communication Angst")
+ log_h3("Line of Communication Angst")
log("P" + HILL_2 + " substituted.")
set_piece_hex(HILL_2, piece_hex(HILL_1))
set_piece_mode(HILL_2, piece_mode(HILL_1))
@@ -972,7 +981,7 @@ function goto_organization_phase() {
}
} else {
if (piece_hex(HILL_1) === SWAPPED && piece_hex(HILL_2) !== ELIMINATED) {
- log(".h3 Line of Communication Angst")
+ log_h3("Line of Communication Angst")
log("P" + HILL_1 + " substituted.")
set_piece_hex(HILL_1, piece_hex(HILL_2))
set_piece_mode(HILL_1, piece_mode(HILL_2))
@@ -981,8 +990,6 @@ function goto_organization_phase() {
}
}
- log(".h2 Organization")
-
// F: ADVANCE FORMATION
game.active = P1
for (let p of friendly_infantry_corps())
@@ -1017,7 +1024,7 @@ function can_withdraw_any() {
}
function goto_withdrawal() {
- log(".h3 Withdrawal")
+ log_h3("Withdrawal")
game.remain = 0
game.active = P2
next_withdrawal()
@@ -1151,7 +1158,7 @@ function can_move_any() {
}
function goto_movement_phase() {
- log(".h2 Movement")
+ log_h2("Movement")
game.remain = 0
game.active = P2
next_movement()
@@ -1189,7 +1196,7 @@ function pass_movement() {
set_next_player()
if (can_move_any()) {
- game.remain = roll_die()
+ let die = roll_die()
let n = 0
for (let p of friendly_corps()) {
@@ -1199,10 +1206,10 @@ function pass_movement() {
++n
}
- log("Rolled D" + game.remain + " + " + n + " Corps not in ZOC/ZOI.")
- log("")
+ log(">D" + die + " + " + n + " more moves.")
- game.remain += n
+ game.remain = die + n
+ logbr()
} else {
log(game.active + " passed.")
end_movement()
@@ -1351,6 +1358,17 @@ states.movement_to = {
search_move(game.who)
let from = piece_hex(game.who)
+
+ if (from === REINFORCEMENTS) {
+ from = find_reinforcement_hex(game.who)
+ if (Array.isArray(from)) {
+ if (!hex_has_any_piece(from[0], all_corps))
+ from = from[0]
+ else
+ from = from[1]
+ }
+ }
+
set_piece_hex(game.who, x)
log("P" + game.who + "\nfrom " + from + "\nto " + x)
@@ -1374,7 +1392,7 @@ states.movement_to = {
if (game.turn === 2 && game.active === P2)
--game.prussian_moves
- log("")
+ logbr()
next_movement()
},
}
@@ -1769,7 +1787,7 @@ function can_attack_any() {
}
function goto_attack_phase() {
- log(".h2 Attack")
+ log_h2("Attack")
game.remain = 0
game.active = P2
next_attack()
@@ -1795,7 +1813,7 @@ function next_attack() {
}
function pass_attack() {
- log("")
+ log_h3("Pass")
log(game.active + " passed.")
if (game.remain > 0) {
end_attack()
@@ -1803,7 +1821,8 @@ function pass_attack() {
set_next_player()
if (can_attack_any()) {
game.remain = roll_die()
- log("Rolled D" + game.remain + ".")
+ //log("Rolled D" + game.remain + " more attacks.")
+ log(">D" + game.remain + " more attacks.")
} else {
log(game.active + " passed.")
end_attack()
@@ -1882,7 +1901,7 @@ states.attack_who = {
}
let where = piece_hex(p)
- log(".h3 " + where)
+ log_h3(where)
game.target = p
game.attack = piece_hex(game.target)
@@ -1949,13 +1968,13 @@ states.attack_support = {
if (can_support)
view.prompt += " Commit supporting cavalry?"
- view.actions.roll = 1
+ view.actions.next = 1
},
piece(p) {
push_undo()
game.count |= (1 << p)
},
- roll() {
+ next() {
clear_undo()
goto_defend_support()
},
@@ -1978,13 +1997,13 @@ states.defend_support = {
if (!(game.count & (1 << p)))
if (can_defend_cavalry_support(p))
gen_action_piece(p)
- view.actions.roll = 1
+ view.actions.next = 1
},
piece(p) {
push_undo()
game.count |= (1 << p)
},
- roll() {
+ next() {
clear_undo()
goto_resolve_attack()
},
@@ -2015,7 +2034,8 @@ function goto_resolve_attack() {
let a_die = roll_die()
- log("Attacker P" + a_unit)
+ log("P" + a_unit)
+ log(">D" + a_die + " Attack")
if (game.rain > 0)
a_drm += log_drm(-1, "Artillery Ricochet Ineffective")
@@ -2065,16 +2085,18 @@ function goto_resolve_attack() {
set_piece_mode(a_unit, 1)
- log(`>Roll D${a_die} + ${a_drm} = ${a_die+a_drm}`)
+ //log(`>Roll D${a_die} + ${a_drm} = ${a_die+a_drm}`)
+ //log(`>Roll D${a_die} + ${a_drm}`)
// DEFENDER DRM
- log("")
-
- log("Defender P" + d_unit)
+ logbr()
let d_die = roll_die()
+ log("P" + d_unit)
+ log(">D" + d_die + " Defend")
+
if (town && !piece_is_cavalry(d_unit))
d_drm += log_drm(1, "Town")
@@ -2103,13 +2125,23 @@ function goto_resolve_attack() {
if (!piece_is_detachment(d_unit))
set_piece_mode(d_unit, 1)
- log(`>Roll D${d_die} + ${d_drm} = ${d_die+d_drm}`)
+ //log(`>Roll D${d_die} + ${d_drm} = ${d_die+d_drm}`)
+ //log(`>Roll D${d_die} + ${d_drm}`)
// COMBAT RESULT TABLE
- log("")
let diff = (a_die + a_drm) - (d_die + d_drm)
+
+ logbr()
+
+/*
+ if (diff > 0)
+ log("Result +" + diff + ":")
+ else
+ log("Result " + diff + ":")
+*/
+
if (diff <= -5)
goto_eliminated_attacker()
else if (diff <= -3)
@@ -2128,12 +2160,14 @@ function goto_resolve_attack() {
function goto_stalemate() {
log("Stalemate.")
+ logbr()
// TODO: pause ?
goto_pursuit()
}
function goto_blown_attacker() {
log("Attacker blown.")
+ logbr()
if (piece_is_detachment(game.target))
game.state = "retreat_attacker"
else
@@ -2142,6 +2176,7 @@ function goto_blown_attacker() {
function goto_eliminated_attacker() {
log("Attacker eliminated.")
+ logbr()
if (piece_is_detachment(game.target))
game.state = "retreat_attacker"
else
@@ -2150,6 +2185,7 @@ function goto_eliminated_attacker() {
function goto_blown_defender() {
log("Defender blown.")
+ logbr()
set_next_player()
if (piece_is_detachment(game.target))
game.state = "eliminated_defender"
@@ -2159,17 +2195,20 @@ function goto_blown_defender() {
function goto_eliminated_defender() {
log("Defender eliminated.")
+ logbr()
set_next_player()
game.state = "eliminated_defender"
}
function goto_retreat_attacker() {
log("Attacker retreat")
+ logbr()
game.state = "retreat_attacker"
}
function goto_retreat_defender() {
log("Defender retreat.")
+ logbr()
set_next_player()
if (piece_is_detachment(game.target))
game.state = "recall_defender"
@@ -2344,6 +2383,8 @@ function goto_end_phase() {
function goto_victory_conditions() {
game.active = P1
+ log_h1("End of Game")
+
let vp1 = 0
let vp2 = 0
@@ -2502,7 +2543,7 @@ function setup_june_16() {
init_turn()
- log(".h2 Command")
+ log_h2("Command")
goto_detachment_placement_step()
}
@@ -2631,7 +2672,7 @@ function goto_game_over(result, victory) {
game.active = "None"
game.result = result
game.victory = victory
- log("")
+ logbr()
log(game.victory)
return false
}
@@ -2651,6 +2692,29 @@ function log(msg) {
game.log.push(msg)
}
+function logbr() {
+ if (game.log.length > 0 && game.log[game.log.length - 1] !== "")
+ game.log.push("")
+}
+
+function log_h1(msg) {
+ logbr()
+ log(".h1 " + msg)
+ logbr()
+}
+
+function log_h2(msg) {
+ logbr()
+ log(".h2 " + msg)
+ logbr()
+}
+
+function log_h3(msg) {
+ logbr()
+ log(".h3 " + msg)
+ logbr()
+}
+
function clear_undo() {
game.undo.length = 0
}