summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.html11
-rw-r--r--play.js35
-rw-r--r--rules.js94
3 files changed, 99 insertions, 41 deletions
diff --git a/play.html b/play.html
index 28f7d30..ba7f5f4 100644
--- a/play.html
+++ b/play.html
@@ -116,13 +116,12 @@ main[data-scenario="5"] {
.flip .slot_sticks {
justify-content: start;
+ flex-direction: column-reverse;
}
.flip .slot_cubes {
align-content: start;
}
-.table_reserve .slot_sticks { display: none }
-.table_reserve .slot_cubes { display: none }
.table_reserve .slot_dice { display: none }
.stick {
@@ -148,6 +147,10 @@ main[data-scenario="5"] {
--lo-pink: hsl(359, 81%, 68%);
--lo-blue: hsl(211, 78%, 42%);
--lo-dkblue: hsl(240, 69%, 47%);
+
+ --gray: hsl(0, 0%, 90%);
+ --lo-gray: hsl(0, 0%, 75%);
+ --hi-gray: hsl(0, 0%, 100%);
}
.red .stick { background-color: var(--red); }
@@ -160,6 +163,8 @@ main[data-scenario="5"] {
.blue .stick { border-color: var(--hi-blue) var(--lo-blue) var(--lo-blue) var(--hi-blue); }
.dkblue .stick { border-color: var(--hi-dkblue) var(--lo-dkblue) var(--lo-dkblue) var(--hi-dkblue); }
+.hit.stick { background-color: var(--gray); border-color: var(--hi-gray) var(--lo-gray) var(--lo-gray) var(--hi-gray); }
+
.table_pool {
margin: 12px;
height: 36px;
@@ -238,9 +243,9 @@ main[data-scenario="5"] {
}
.die.action { box-shadow: 0 0 0 1px #333, 0 0 0px 3px white; }
-.card.action { box-shadow: 0 0 0 3px whitesmoke; }
.card.selected { box-shadow: 0 0 0px 3px gold; }
.card.target { box-shadow: 0 0 0px 3px black; }
+.card.action { box-shadow: 0 0 0 3px whitesmoke; }
.action_type.action {
border-color: white;
diff --git a/play.js b/play.js
index 9aa02db..d4c02ff 100644
--- a/play.js
+++ b/play.js
@@ -20,6 +20,7 @@ let ui = {
dice: [],
sticks: [],
+ hit_sticks: [],
cubes: [],
}
@@ -209,7 +210,7 @@ function create_formation_card(id) {
function fill_card_row(top, parent, list) {
parent.replaceChildren()
for (let id of list) {
- let i, n
+ let i, n, x
if (!ui.cards[id])
ui.cards[id] = create_formation_card(id)
@@ -225,7 +226,15 @@ function fill_card_row(top, parent, list) {
add_cube(ui.slot_cubes[id])
n = map_get(view.sticks, id, 0)
- for (let i = 0; i < n; ++i)
+ x = 0
+ if (view.selected === id)
+ x = view.self
+ if (view.target === id)
+ x = view.hits
+ console.log("STICKS", id, x, n)
+ for (let i = 0; i < x; ++i)
+ add_hit_stick(ui.slot_sticks[id])
+ for (let i = x; i < n; ++i)
add_stick(ui.slot_sticks[id])
}
}
@@ -250,6 +259,16 @@ function add_stick(parent) {
throw Error("OUT OF CUBES ERROR")
}
+function add_hit_stick(parent) {
+ for (let i = 0; i < 80; ++i) {
+ if (ui.hit_sticks[i].parentElement === null) {
+ parent.appendChild(ui.hit_sticks[i])
+ return
+ }
+ }
+ throw Error("OUT OF CUBES ERROR")
+}
+
function on_update() {
let p1 = 0, p2 = 1
if (player === "First")
@@ -269,6 +288,8 @@ function on_update() {
e.remove()
for (let e of ui.sticks)
e.remove()
+ for (let e of ui.hit_sticks)
+ e.remove()
for (let i = 0; i < view.morale[0]; ++i)
add_cube(ui.morale[p1])
@@ -308,10 +329,14 @@ function on_update() {
for (let e of animation_registry)
animate_position(e)
+ action_button("attack", "Attack")
action_button("bombard", "Bombard")
+ action_button("command", "Command")
+ action_button("screen", "Screen")
+ action_button("counterattack", "Counterattack")
+ action_button("absorb", "Absorb")
action_button("roll", "Roll")
action_button("pass", "Pass")
- action_button("done", "Done")
action_button("end_turn", "End turn")
action_button("undo", "Undo")
}
@@ -321,8 +346,10 @@ for (let i = 0; i < 10; ++i) {
// register_animation(ui.cubes[i], 500)
}
-for (let i = 0; i < 80; ++i)
+for (let i = 0; i < 80; ++i) {
ui.sticks[i] = create_div("stick")
+ ui.hit_sticks[i] = create_div("stick hit")
+}
for (let i = 0; i < 12; ++i) {
ui.dice[i] = register_action(create_div("die d0"), "die", i)
diff --git a/rules.js b/rules.js
index 3438f70..9fbb6e8 100644
--- a/rules.js
+++ b/rules.js
@@ -9,6 +9,7 @@
// TODO: manual "pursuit" ?
// TODO: allow placing dice on full special formations?
+// TODO: fizzle when action says to take cards from other dice?
const data = require("./data.js")
@@ -83,6 +84,10 @@ exports.view = function (state, player) {
morale: game.morale,
front: game.front,
reserve: game.reserve,
+ selected: game.selected,
+ target: game.target,
+ hits: game.hits,
+ self: game.self,
}
if (game.state === "game_over") {
@@ -133,8 +138,6 @@ states.game_over = {
exports.setup = function (seed, scenario, options) {
// TODO: "Random"
- console.log("SETUP", scenario)
-
scenario = parseInt(scenario)
scenario = data.scenarios.findIndex(s => s.number === scenario)
if (scenario < 0)
@@ -163,12 +166,18 @@ exports.setup = function (seed, scenario, options) {
// cubes (map special formation -> count)
cubes: [],
- morale: [ info.players[0].morale, info.players[1].morale ],
+ morale: [ info.players[0].morale || -1, info.players[1].morale || -1 ],
front: [ [], [], ],
reserve: [ [], [] ],
// dice value placed on what card
placed: [],
+
+ // current action
+ selected: -1,
+ target: -1,
+ hits: 0,
+ self: 0,
}
function setup_formation(front, reserve, c) {
@@ -305,10 +314,10 @@ function set_dice_value(d, v) {
function is_card_in_play(c) {
return (
- set_has(game.players[0].front, c) ||
- set_has(game.players[1].front, c) ||
- set_has(game.players[0].reserve, c) ||
- set_has(game.players[1].reserve, c)
+ set_has(game.front[0], c) ||
+ set_has(game.front[1], c) ||
+ set_has(game.reserve[0], c) ||
+ set_has(game.reserve[1], c)
)
}
@@ -317,24 +326,25 @@ function is_card_attack_with_target_in_play(c) {
if (a.type === "Attack") {
for (let t of a.target_list)
if (is_card_in_play(c))
- return false
+ return true
}
}
+ return false
}
function check_impossible_to_attack_victory() {
let p = player_index()
- for (let c of game.players[p].front)
+ for (let c of game.front[p])
if (is_card_attack_with_target_in_play(c))
return false
- for (let c of game.players[p].reserve)
+ for (let c of game.reserve[p])
if (is_card_attack_with_target_in_play(c))
return false
return true
}
function check_morale_loss(p) {
- return game.players[0].morale === 0
+ return game.morale[0] === 0
}
// === ROLL PHASE ===
@@ -790,7 +800,7 @@ states.place = {
states.place_on_card = {
prompt() {
let card = data.cards[game.selected]
- view.selected = game.selected
+ // XXX view.selected = game.selected
view.prompt = "Place dice on " + card.name + "."
gen_place_dice_select_card()
@@ -811,8 +821,10 @@ states.place_on_card = {
die(d) {
push_undo()
place_dice_take[data.cards[game.selected].dice](game.selected, d)
- if (!can_place_dice(game.selected))
+ if (!can_place_dice(game.selected)) {
+ game.selected = -1
game.state = "place"
+ }
},
end_turn() {
end_roll_phase()
@@ -979,7 +991,7 @@ function can_take_any_action() {
function goto_action_phase() {
if (check_impossible_to_attack_victory()) {
- if (player === P1)
+ if (player_index() === 0)
goto_game_over(P2, P1 + " has no more attacks!")
else
goto_game_over(P1, P2 + " has no more attacks!")
@@ -1076,7 +1088,7 @@ function goto_take_action(c, ix) {
game.action = ix
switch (a.type) {
case "Attack":
- game.state = "attack"
+ goto_attack()
break
case "Bombard":
game.state = "bombard"
@@ -1125,9 +1137,8 @@ states.bombard = {
}
function format_attack_result() {
- let a = current_action()
- let hits = get_attack_hits(game.selected, a)
- let self = get_attack_self(game.selected, a)
+ let hits = game.hits
+ let self = game.self
if (hits !== 1 && self > 0)
return ` ${hits} hits. ${self} self.`
if (hits === 1 && self > 0)
@@ -1139,19 +1150,23 @@ function format_attack_result() {
return ""
}
+function goto_attack(c) {
+ let a = current_action()
+ game.state = "attack"
+ game.target = find_target_of_attack(a)
+ game.hits = get_attack_hits(game.selected, a)
+ game.self = get_attack_self(game.selected, a)
+}
+
states.attack = {
prompt() {
- let t = find_target_of_attack(current_action())
- view.prompt = "Attack " + card_name(t) + "." + format_attack_result()
- view.selected = game.selected
- gen_action_card(t)
+ view.prompt = "Attack " + card_name(game.target) + "." + format_attack_result()
+ // XXX view.selected = game.selected
+ gen_action_card(game.target)
+ view.actions.attack = 1
},
card(c) {
log(card_name(game.selected) + " attacked " + card_name(c) + ".")
- let a = current_action()
- game.target = c
- game.hits = get_attack_hits(game.selected, a)
- game.self = get_attack_self(game.selected, a)
if (can_opponent_react()) {
clear_undo()
set_opponent_active()
@@ -1165,8 +1180,11 @@ states.attack = {
function resume_attack() {
apply_hits(game.hits)
apply_self(game.self)
- game.hits = game.self = 0
pay_for_action(game.selected)
+
+ game.hits = game.self = 0
+ game.selected = -1
+ game.target = -1
end_action_phase()
}
@@ -1174,17 +1192,15 @@ states.command = {
prompt() {
let t = find_target_of_command(current_action())
view.prompt = "Bring " + card_name(t) + " out of reserve."
- view.selected = game.selected
+ // XXX view.selected = game.selected
gen_action_card(t)
},
card(c) {
log(card_name(game.selected) + " commanded " + card_name(c) + " out of reserve.")
- console.log("PRE COMMAND", JSON.stringify(game))
let p = player_index()
array_remove_item(game.reserve[p], c)
set_add(game.front[p], c)
pay_for_action(game.selected)
- console.log("POST COMMAND", JSON.stringify(game))
end_action_phase()
},
}
@@ -1256,8 +1272,8 @@ function can_take_reaction(c, a) {
states.react = {
prompt() {
view.prompt = card_name(game.selected) + " attacks " + card_name(game.target) + "! " + format_attack_result()
- view.selected = game.selected
- view.target = game.target
+ // XXX view.selected = game.selected
+ // XXX view.target = game.target
let voluntary = true
let p = player_index()
@@ -1320,9 +1336,19 @@ function goto_screen(c, a) {
log(card_name(c) + " screened.")
game.reacted = 1
pay_for_action(c)
+
+ switch (a.effect)
+ {
+ default:
+ throw new Error("invalid screen effect: " + a.effect)
+ case "":
+ game.hits = 0
+ game.self = 0
+ break
+ }
+
set_opponent_active()
- pay_for_action(game.selected)
- end_action_phase()
+ resume_attack()
}
function goto_absorb(c, a) {