diff options
-rw-r--r-- | play.html | 38 | ||||
-rw-r--r-- | play.js | 92 | ||||
-rw-r--r-- | rules.js | 138 |
3 files changed, 171 insertions, 97 deletions
@@ -34,21 +34,32 @@ padding: 2px 8px; } -#log .ind { +#log .t { + text-align: right; + background-color: wheat; + margin: 8px 0; +} + +#log .i1 { padding-left: 20px; } +#log .i2 { + padding-left: 32px; +} + #log .i { font-style: italic; } -#log .blue { background-color: blue; } -#log .dkblue { background-color: navy; } -#log .red { background-color: red; } -#log .pink { background-color: pink; } +#log .n { padding: 0 3px } +#log .blue { background-color: aliceblue; } +#log .dkblue { background-color: skyblue; } +#log .red { background-color: pink; } +#log .pink { background-color: mistyrose; } -.role.blue, .role.dkblue { background-color: #8bf } -.role.red, .role.pink { background-color: #f88 } +.role.blue { background-color: #8bf } +.role.red { background-color: #f88 } main { background-color: #666; @@ -270,6 +281,19 @@ body.shift .number { display: block; } box-shadow: 0 0 0 1px #333, 1px 2px 3px 1px #0004; } +.mini { + display: inline-block; + vertical-align: -3px; + width: 12px; + height: 12px; + border-width: 1px; + background-size: 600% 100%; + background-repeat: no-repeat; + background-image: url(images/die_black_pips.svg); + background-color: #ccc; + border: 1px solid black; +} + .d0 { background-position: -100% 0 } .d1 { background-position: 0% 0; } .d2 { background-position: 20% 0; } @@ -3,6 +3,7 @@ /* global data, view, send_action, action_button, player */ const wing_name = [ "red", "pink", "blue", "dkblue" ] +const side_color = [ "red", "red", "blue", "blue" ] const reactions = [ "Screen", "Counterattack", "Absorb" ] let ui = { @@ -357,8 +358,8 @@ function on_update() { let w1 = data.cards[view.front[0][0]].wing let w2 = data.cards[view.front[1][0]].wing - ui.role_panel[0].className = "role " + wing_name[w1] - ui.role_panel[1].className = "role " + wing_name[w2] + ui.role_panel[0].className = "role " + side_color[w1] + ui.role_panel[1].className = "role " + side_color[w2] ui.role_name[0].textContent = data.scenarios[view.scenario].players[0].name ui.role_name[1].textContent = data.scenarios[view.scenario].players[1].name @@ -454,37 +455,37 @@ for (let i = 0; i < 12; ++i) { } const ICONS = { - D0: '<span class="die black d0"></span>', - D1: '<span class="die black d1"></span>', - D2: '<span class="die black d2"></span>', - D3: '<span class="die black d3"></span>', - D4: '<span class="die black d4"></span>', - D5: '<span class="die black d5"></span>', - D6: '<span class="die black d6"></span>', - R1: '<span class="die red d1"></span>', - R2: '<span class="die red d2"></span>', - R3: '<span class="die red d3"></span>', - R4: '<span class="die red d4"></span>', - R5: '<span class="die red d5"></span>', - R6: '<span class="die red d6"></span>', - P1: '<span class="die pink d1"></span>', - P2: '<span class="die pink d2"></span>', - P3: '<span class="die pink d3"></span>', - P4: '<span class="die pink d4"></span>', - P5: '<span class="die pink d5"></span>', - P6: '<span class="die pink d6"></span>', - B1: '<span class="die blue d1"></span>', - B2: '<span class="die blue d2"></span>', - B3: '<span class="die blue d3"></span>', - B4: '<span class="die blue d4"></span>', - B5: '<span class="die blue d5"></span>', - B6: '<span class="die blue d6"></span>', - K1: '<span class="die dkblue d1"></span>', - K2: '<span class="die dkblue d2"></span>', - K3: '<span class="die dkblue d3"></span>', - K4: '<span class="die dkblue d4"></span>', - K5: '<span class="die dkblue d5"></span>', - K6: '<span class="die dkblue d6"></span>', + D0: '<span class="mini black d0"></span>', + D1: '<span class="mini black d1"></span>', + D2: '<span class="mini black d2"></span>', + D3: '<span class="mini black d3"></span>', + D4: '<span class="mini black d4"></span>', + D5: '<span class="mini black d5"></span>', + D6: '<span class="mini black d6"></span>', + R1: '<span class="mini red d1"></span>', + R2: '<span class="mini red d2"></span>', + R3: '<span class="mini red d3"></span>', + R4: '<span class="mini red d4"></span>', + R5: '<span class="mini red d5"></span>', + R6: '<span class="mini red d6"></span>', + P1: '<span class="mini pink d1"></span>', + P2: '<span class="mini pink d2"></span>', + P3: '<span class="mini pink d3"></span>', + P4: '<span class="mini pink d4"></span>', + P5: '<span class="mini pink d5"></span>', + P6: '<span class="mini pink d6"></span>', + B1: '<span class="mini blue d1"></span>', + B2: '<span class="mini blue d2"></span>', + B3: '<span class="mini blue d3"></span>', + B4: '<span class="mini blue d4"></span>', + B5: '<span class="mini blue d5"></span>', + B6: '<span class="mini blue d6"></span>', + K1: '<span class="mini dkblue d1"></span>', + K2: '<span class="mini dkblue d2"></span>', + K3: '<span class="mini dkblue d3"></span>', + K4: '<span class="mini dkblue d4"></span>', + K5: '<span class="mini dkblue d5"></span>', + K6: '<span class="mini dkblue d6"></span>', } function sub_icon(match) { @@ -492,9 +493,10 @@ function sub_icon(match) { } function sub_card(match) { - let wing = "" - let name = match - return `<span class="${wing}">${name}</span>` + let c = parseInt(match.substring(1)) + let wing = wing_name[data.cards[c].wing] + let name = data.cards[c].name + return `<span class="n ${wing}">${name}</span>` } function on_log(text) { @@ -507,14 +509,26 @@ function on_log(text) { text = text.substring(4) p.className = "h2" } - else if (text.match(/^>/)) { - text = text.substring(1) - p.className = "ind" + else if (text.match(/^\.t0/)) { + text = data.scenarios[view.scenario].players[0].name + p.className = "t" + } + else if (text.match(/^\.t1/)) { + text = data.scenarios[view.scenario].players[1].name + p.className = "t" } else if (text.match(/^\.i /)) { text = text.substring(3) p.className = "i" } + else if (text.match(/^>>/)) { + text = text.substring(2) + p.className = "i2" + } + else if (text.match(/^>/)) { + text = text.substring(1) + p.className = "i1" + } text = text.replace(/\bC\d+\b/g, sub_card) text = text.replace(/\b[DPRBK]\d\b/g, sub_icon) @@ -380,6 +380,7 @@ exports.setup = function (seed, scenario, options) { // dice value placed on what card rolled: 0, placed: [], + summary: 0, // current action routed: [ 0, 0 ], @@ -533,7 +534,7 @@ function set_sticks(c, n) { } function move_sticks(from, to, n) { - log(`Moved ${n} sticks from C${from} to C${to}.`) // TODO? + // log(`Moved ${n} sticks from C${from} to C${to}.`) // TODO? set_sticks(from, get_sticks(from) - n) set_sticks(to, get_sticks(to) + n) } @@ -575,7 +576,7 @@ function remove_dice(c) { } function take_all_dice(from, to) { - log("Take dice from " + from + " to " + to + ".") + log("Dice from C" + from) for (let i = 0; i < 12; ++i) { if (get_dice_location(i) === from) { set_dice_location(i, to) @@ -584,7 +585,7 @@ function take_all_dice(from, to) { } function take_one_die(from, to) { - log("One die from " + from + " to " + to + ".") + log("Die from C" + from) for (let i = 0; i < 12; ++i) { if (get_dice_location(i) === from) { set_dice_location(i, to) @@ -596,7 +597,7 @@ function take_one_die(from, to) { } function take_wild_die(from, to) { - log("Wild die from " + from + " to " + to + ".") + log("Wild die from C" + from) for (let i = 0; i < 12; ++i) { if (get_dice_location(i) === from) { set_dice_location(i, to) @@ -620,27 +621,26 @@ function rout_card(c) { let p = find_card_owner(c) game.lost[p] += get_sticks(c) game.lost[p] += get_shift_sticks(c) - log(c + " routed.") + log("C" + c + " routed.") eliminate_card(c) } function pursue_card(c) { let p = find_card_owner(c) - log(c + " pursued.") game.lost[p] += get_shift_sticks(c) // TODO ? eliminate_card(c) } function retire_card(c) { let p = find_card_owner(c) - log(c + " retired.") game.lost[p] += get_shift_sticks(c) // TODO ? eliminate_card(c) } function remove_card(c) { let p = find_card_owner(c) - log(c + " removed.") + + log("C" + c + " removed.") game.lost[p] += get_shift_sticks(c) // TODO ? @@ -669,22 +669,6 @@ function pay_for_action(c) { remove_dice(c) } -function get_player_dice_value(p, i) { - return game.dice[p * 12 + i * 2] -} - -function get_player_dice_location(p, i) { - return game.dice[p * 12 + i * 2 + 1] -} - -function set_player_dice_value(p, i, v) { - game.dice[p * 12 + i * 2] = v -} - -function set_player_dice_location(p, i, v) { - game.dice[p * 12 + i * 2 + 1] = v -} - function get_dice_value(d) { return game.dice[d * 2] } @@ -840,13 +824,13 @@ function check_victory() { function is_pool_die(i, v) { let p = player_index() - return get_player_dice_location(p, i) < 0 && get_player_dice_value(p, i) === v + return get_dice_location(p * 6 + i) < 0 && get_dice_value(p * 6 + i) === v } function is_pool_die_range(i, lo, hi) { let p = player_index() - if (get_player_dice_location(p, i) < 0) { - let v = get_player_dice_value(p, i) + if (get_dice_location(p * 6 + i) < 0) { + let v = get_dice_value(p * 6 + i) return v >= lo && v <= hi } return false @@ -1273,7 +1257,7 @@ function check_full_house(c) { function gen_pool_die(v) { let p = player_index() for (let i = 0; i < 6; ++i) - if (get_player_dice_location(p, i) < 0 && get_player_dice_value(p, i) === v) + if (get_dice_location(p * 6 + i) < 0 && get_dice_value(p * 6 + i) === v) gen_action_die(p * 6 + i) } @@ -1341,8 +1325,10 @@ function gen_full_house(c) { function find_and_take_single(c, v) { let p = player_index() for (let i = 0; i < 6; ++i) { - if (get_player_dice_location(p, i) < 0 && get_player_dice_value(p, i) === v) { - set_player_dice_location(p, i, c) + let d = p * 6 + i + if (get_dice_location(d) < 0 && get_dice_value(d) === v) { + set_dice_location(d, c) + game.summary |= (1 << d) return } } @@ -1351,6 +1337,7 @@ function find_and_take_single(c, v) { function take_single(c, d) { set_dice_location(d, c) + game.summary |= (1 << d) map_set(game.placed, c, get_dice_value(d)) } @@ -1467,16 +1454,25 @@ states.roll = { } function roll_dice_in_pool() { - game.rolled = 0 + let rolled = [] + if (game.reacted === player_index()) game.reacted = -1 + let p = player_index() for (let i = 0; i < 6; ++i) { - if (get_player_dice_location(p, i) < 0) { - set_player_dice_value(p, i, random(6) + 1) - game.rolled++ + if (get_dice_location(p * 6 + i) < 0) { + let v = random(6) + 1 + set_dice_value(p * 6 + i, v) + rolled.push(v) } } + + log("Roll") + log(">" + rolled.map(d => "D" + d).join(" ")) + + game.rolled = rolled.length + game.summary = 0 game.state = "place" } @@ -1544,6 +1540,20 @@ function end_roll_phase() { game.selected = -1 + if (game.placed.length > 0) { + log("Placed") + for (let i = 0; i < game.placed.length; i += 2) { + let c = game.placed[i] + let s = [] + for (let d = 0; d < 12; ++d) + if (game.summary & (1 << d)) + if (get_dice_location(d) === c) + s.push("D" + get_dice_value(d)) + log(">C" + c) + log(">>" + s.join(" ")) + } + } + // Remove placed dice to add cube on special cards. for (let c of game.front[player_index()]) { let s = data.cards[c].special @@ -1556,8 +1566,8 @@ function end_roll_phase() { // Blank out unused dice. let p = player_index() for (let i = 0; i < 6; ++i) - if (get_player_dice_location(p, i) < 0) - set_player_dice_value(p, i, 0) + if (get_dice_location(p * 6 + i) < 0) + set_dice_value(p * 6 + i, 0) if (game.scenario === S26_PEACH_ORCHARD) { if (player_index() === 0) { @@ -1995,6 +2005,8 @@ function count_cards_remaining_from_wing(w) { function goto_start_turn() { let p = player_index() + log(".t" + p) + if (check_impossible_to_attack_victory()) return @@ -2134,6 +2146,9 @@ states.action = { retire(c) { push_undo() + log("C" + c) + log("> Retire") + if (game.scenario === S38_FLEURUS) { if (c === S38_LUXEMBOURGS_HORSE) { if (is_card_in_play(S38_GOURNAYS_HORSE)) @@ -2273,13 +2288,20 @@ states.shift_to = { }, card(c) { game.target2 = c - move_sticks(game.selected, game.target2, 1) + + set_sticks(game.selected, get_sticks(game.selected) - 1) + set_shift_sticks(game.target2, get_shift_sticks(game.target2) + 1) + if (get_sticks(game.selected) === 1) this.next() }, next() { // TODO: skip action phase? - log(`Shifted ${get_shift_sticks(game.target2)} sticks from C${game.selected} to C${game.target2}.`) + + log(`Shift ${get_shift_sticks(game.target2)}`) + log(">C" + game.selected) + log(">C" + game.target2) + end_action_phase() }, } @@ -2353,7 +2375,9 @@ states.s42_marlborough = { } function goto_null(c) { - log("Fizzled " + card_number(c)) + log("Null") + log(">C" + c) + pay_for_action(c) end_action_phase() } @@ -2462,7 +2486,9 @@ states.bombard = { view.actions.bombard = 1 }, bombard() { - log(card_name(game.selected) + " bombarded.") + log("Bombard") + log(">C" + c) + let opp = 1 - player_index() game.morale[opp] -- pay_for_action(game.selected) @@ -2702,7 +2728,10 @@ states.attack = { view.actions.attack = 1 }, attack() { - log(card_name(game.selected) + " attacked " + card_name(game.target) + ".") + log("Attack") + log(">C" + game.selected) + log(">C" + game.target) + if (can_opponent_react()) { clear_undo() set_opponent_active() @@ -2826,7 +2855,10 @@ states.command = { gen_action_card(t) }, card(c) { - log(card_name(game.selected) + " commanded " + card_name(c) + " out of reserve.") + log("Command") + log(">C" + game.selected) + log(">C" + c) + let p = player_index() set_delete(game.reserve[p], c) set_add(game.front[p], c) @@ -2903,7 +2935,6 @@ states.s38_retreat_to_nivelles_2 = { }, } - // === REACTION === function can_opponent_react() { @@ -3124,7 +3155,9 @@ states.screen = { view.actions.screen = 1 }, screen() { - log(card_name(game.target) + " screened.") + log("Screen") + log(">C" + game.target) + pay_for_action(game.target) if (card_has_rule(game.target, "remove_after_screen")) @@ -3199,7 +3232,9 @@ states.absorb = { view.actions.absorb = 1 }, absorb() { - log(card_name(game.target) + " absorbed.") + log("Absorb") + log(">C" + game.target) + pay_for_action(game.target) end_reaction() }, @@ -3262,7 +3297,9 @@ states.counterattack = { view.actions.counterattack = 1 }, counterattack() { - log(card_name(game.target) + " counterattacked.") + log("Counterattack") + log(">C" + game.target) + pay_for_action(game.target) end_reaction() }, @@ -3479,18 +3516,17 @@ states.routing = { }, card(c) { if (should_rout_card(c)) { - log(card_name(c) + " routed.") let p = find_card_owner(c) game.routed[p] += data.cards[c].morale rout_card(c) } else if (should_retire_card(c)) { - log(card_name(c) + " retired.") + log("C" + c + " retired.") retire_card(c) } else if (should_pursue(c)) { - log(card_name(c) + " pursued.") + log("C" + c) + log(">Pursuit") pursue_card(c) } else { - log(card_name(c) + " removed.") remove_card(c) } resume_routing() @@ -3592,7 +3628,7 @@ function end_reserve() { } function bring_out_of_reserve(c) { - log(card_name(c) + " came out of reserve.") + log("C" + c + " came out of reserve.") let p = find_card_owner(c) set_delete(game.reserve[p], c) set_add(game.front[p], c) |