diff options
author | Joël Simoneau <simoneaujoel@gmail.com> | 2025-02-19 22:48:29 -0500 |
---|---|---|
committer | Joël Simoneau <simoneaujoel@gmail.com> | 2025-02-19 22:48:29 -0500 |
commit | e0840225f0fa64a46c07c5ffea67330c2e64a504 (patch) | |
tree | 3aa411fde1f330b525b588756ed25adb5b26eb8a | |
parent | 872422f7f3ba799e840a1a799fb6a307b2f29302 (diff) | |
download | vijayanagara-e0840225f0fa64a46c07c5ffea67330c2e64a504.tar.gz |
Clean-up attack
-rw-r--r-- | play.css | 37 | ||||
-rw-r--r-- | play.html | 7 | ||||
-rw-r--r-- | play.js | 75 | ||||
-rw-r--r-- | rules.js | 39 |
4 files changed, 138 insertions, 20 deletions
@@ -72,7 +72,7 @@ header.your_turn.ve { background-color: #ffbf32 } /* COMBAT TABLE */ .player_pool { - width: 500px; + width: 375px; background-color: #0003; padding: 8px; border-radius: 24px; @@ -80,11 +80,9 @@ header.your_turn.ve { background-color: #ffbf32 } } .player_name { - color: antiquewhite; - text-shadow: 0 0 3px goldenrod; + color: rgb(31, 27, 23); font-size: 20px; text-align: center; - font-style: italic; font-family: "Source Serif"; padding: 4px; } @@ -190,6 +188,37 @@ header.your_turn.ve { background-color: #ffbf32 } #map.hide_pieces #pieces { display: none; } #map.hide_tokens #tokens { display: none; } +/* BATTLE */ + +#attack_table { + position: absolute; + scroll-margin: 20px; + z-index: 200; + box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.5); + border: 1px solid black; + min-width: 425px; + background-color: #d6c4a9; +} + +@media (max-width: 400px) { + #attack_table { + min-width: 90vw; + min-width: 90dvw; + } +} + +#attack_header { background-color: brown; color: gold } +#attack_header { + list-style: none; + cursor: move; + padding: 2px 8px; + line-height: 24px; + min-height: 24px; + text-align: center; + font-weight: bold; + font-size: 18px; +} + /* SPACES */ path { fill: none; stroke-width: 4; } @@ -57,10 +57,11 @@ <div id="table"> -<details id="combat_table" class="hide"> +<div id="attack_table" class="hide"> + <summary id="attack_header">Attack in $NAME</summary> <div id="attacker" class="player_pool"> - <div id="name_attack" class="player_name">Attacker</div> + <div id="name_attacker" class="player_name">Attacker</div> <div id="pool_a" class="table_pool attacker"></div> </div> <div id="defender" class="player_pool defender"> @@ -68,7 +69,7 @@ <div id="name_defender" class="player_name">Defender</div> </div> -</details> +</div> <div id="mapwrap"> <div id="map"> @@ -8,6 +8,8 @@ const first_piece = data.first_piece const last_piece = data.last_piece const last_cavalry = 9 +const faction_name = [ "Delhi Sultanate", "Bahmani Kingdom", "Vijayanagara Empire", "Mongol Invaders" ] + // :r !python3 tools/genlayout.py const LAYOUT = { "Andhra DS": [785, 1014], @@ -469,7 +471,11 @@ let ui = { document.getElementById("pool_a"), document.getElementById("pool_d"), ], - dice: [] + dice: [], + attack_table: document.getElementById("attack_table"), + attack_header: document.getElementById("attack_header"), + attack_attacker: document.getElementById("name_attacker"), + attack_defender: document.getElementById("name_defender"), } function create(t, p, ...c) { @@ -525,6 +531,9 @@ function init_ui() { ui.unshaded_event.onmouseenter = on_focus_unshaded_event ui.unshaded_event.onmouseleave = on_focus_this_event + // Make combat table draggable + dragElement(ui.attack_table) + // player cavalry tokens for (let i = 0; i <= LAST_CAVALRY; ++i) { let e = null @@ -866,12 +875,68 @@ function make_card_class_name(c) { else return "card card_" + c + " u" + data.card_unshaded_lines[c] + " s" + data.card_shaded_lines[c] } -S_VE_AVAILABLE + function update_player_active(name, x) { if (roles[name]) roles[name].element.classList.toggle("active", x) } +function update_dice_box() { + ui.attack_header.textContent = "Attack in " + data.space_name[view.attack.where] + ui.attack_attacker.textContent = "Attacker - " + faction_name[view.attack.attacker] + ui.attack_defender.textContent = "Defender - " + faction_name[view.attack.target] + + if (ui.attack_table.classList.contains("hide")) + show_dice_box(ui.attack_table) +} + +function show_dice_box(box) { + box.classList.remove("hide") + box.classList.add("show") + box.style.top = null + box.style.left = null + // box.setAttribute("open", true) + + // calculate size + let w = box.clientWidth + let h = box.clientHeight + + // center where possible + let x = 500 + let y = 500 + + box.style.top = y + "px" + box.style.left = x + "px" +} + +function dragElement(elmnt) { + var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; + ui.attack_header.onmousedown = dragMouseDown; + + function dragMouseDown(e) { + e.preventDefault(); + pos3 = e.clientX; + pos4 = e.clientY; + document.onmouseup = closeDragElement; + document.onmousemove = elementDrag; + } + + function elementDrag(e) { + e.preventDefault(); + pos1 = pos3 - e.clientX; + pos2 = pos4 - e.clientY; + pos3 = e.clientX; + pos4 = e.clientY; + elmnt.style.top = (elmnt.offsetTop - pos2) + "px"; + elmnt.style.left = (elmnt.offsetLeft - pos1) + "px"; + } + + function closeDragElement() { + document.onmouseup = null; + document.onmousemove = null; + } +} + let once = true function on_update() { if (once) { @@ -885,6 +950,12 @@ function on_update() { case "VE": ui.favicon.href = "images/Flags_VE.png"; break } + // Dice rolling + if (view.dice.reduce((sum, num) => sum + num, 0) > 0) + update_dice_box() + else + ui.attack_table.classList.add("hide") + ui.header.classList.toggle("ds", view.current === DS) ui.header.classList.toggle("bk", view.current === BK) ui.header.classList.toggle("ve", view.current === VE) @@ -127,6 +127,14 @@ exports.view = function (state, role) { dice: game.dice, } + if (game.cmd && game.cmd.attacker) { + view.attack = { + where: game.cmd.where, + attacker: game.cmd.attacker, + target: game.cmd.target + } + } + if (game.result) { view.prompt = game.victory } else if (!is_current_role(role)) { @@ -1036,7 +1044,7 @@ function attack_use_cavalry(d) { } else if (is_a_die && !is_attacker) { screen_die(d) } else if (!is_a_die && !is_attacker) { - charge_die[d] + charge_die(d) } } @@ -1214,7 +1222,7 @@ function goto_attack_cavalry() { states.attack_cavalry = { prompt() { - view.prompt = "Attack: Use cavalry to..." + view.prompt = "Attack: Use cavalry to Charge your dice or Screen your opponent's dice." view.who = game.cmd.selected let curr_die = [0, 1, 2, 3, 4, 5] @@ -1232,7 +1240,6 @@ states.attack_cavalry = { log(`${faction_acronyms[game.current]} is using Cavalry.`) game.cmd.cavalry = true } - attack_use_cavalry(d) }, next() { @@ -1251,25 +1258,30 @@ function get_attack_victor() { } function goto_attack_casualties(step) { + let next_state if (step === "target") { game.current = game.cmd.target game.cmd.count = game.cmd.a_hit - game.state = "attack_casualties" + next_state = "attack_casualties" } else if (step === "attacker") { game.current = game.cmd.attacker game.cmd.count = game.cmd.d_hit - game.state = "attack_casualties" + next_state = "attack_casualties" } + + if (game.cmd.count > 0) + game.state = next_state + else + end_attack_casualties() } states.attack_casualties = { prompt() { - if ( game.cmd.count > 0 && game.cmd.selected.filter(p => piece_faction(p) === game.current).length > 0 ) { - view.prompt = `Attack: ${faction_acronyms[game.current]} must remove ${game.cmd.count} pieces as casualties.` + view.prompt = `Attack: Must remove ${game.cmd.count} pieces as casualties.` for (let p of game.cmd.selected) if (piece_faction(p) === game.current) @@ -1286,16 +1298,21 @@ states.attack_casualties = { game.cmd.count -= 1 }, next() { - if (game.current === game.cmd.target) - goto_attack_casualties("attacker") - else - goto_attack_resolution() + end_attack_casualties() } } +function end_attack_casualties() { + if (game.current === game.cmd.target) + goto_attack_casualties("attacker") + else + goto_attack_resolution() +} + function goto_attack_resolution() { if (is_rebel_faction(game.cmd.target) && is_rebel_faction(game.cmd.attacker)) console.log("Implement shift") + game.dice = [0, 0, 0, 0, 0, 0] game.state = "attack" } |