diff options
-rw-r--r-- | play.html | 200 | ||||
-rw-r--r-- | play.js | 188 | ||||
-rw-r--r-- | rules.js | 157 |
3 files changed, 438 insertions, 107 deletions
@@ -42,7 +42,7 @@ header.your_turn { background-color: orange; } font-variant-numeric: tabular-nums; } -/* DIALOGS */ +/* ARTS OF WAR */ #arts_of_war { background-color: white; @@ -75,6 +75,63 @@ header.your_turn { background-color: orange; } gap: 12px; } +/* PLAN */ + +#plan { + background-color: white; + border: 1px solid black; + position: fixed; + top: 84px; + left: 36px; + box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.5); + z-index: 51; + user-select: none; +} + +#plan_header { + font-weight: bold; + cursor: move; + border-bottom: 1px solid black; + background-color: lightsteelblue; + padding: 3px 1em; +} + +#plan_list { + display: flex; + flex-wrap: wrap; + gap: 12px; + padding: 12px; + height: 260px; +} + +#plan_actions { + display: flex; + flex-wrap: wrap; + padding: 12px; + gap: 12px; + height: 130px; + justify-content: center; + flex-wrap: wrap; +} + +#plan_list { + background-color: slategray; +} + +#plan_actions { + border-top: 2px dotted white; + background-color: slategray; +} + +body.Russians #plan_actions .teutonic { display: none } +body.Teutons #plan_actions .russian { display: none } + +#plan_actions .card { + width: 93px; + height: 130px; + background-size: 93px 130px; +} + /* MATS */ .court { @@ -113,7 +170,7 @@ header.your_turn { background-color: orange; } .mat .c1, .mat .c2 { position: absolute; width: 186px; - height: 261px; + height: 260px; background-color: green; } @@ -369,9 +426,9 @@ body.shift .mat .card:hover { } .card { - background-size: 186px 261px; + background-size: 186px 260px; width: 186px; - height: 261px; + height: 260px; border-radius: 8px; transition: 100ms; } @@ -772,7 +829,6 @@ body.shift .marker:hover { transform: scale(2); z-index: 200; } .card.russian.aow_back{background-image:url(cards.1x/aow_russian_back.jpg)} .card.teutonic.aow_back{background-image:url(cards.1x/aow_teutonic_back.jpg)} - .card.aow_0{background-image:url(cards.1x/aow_teutonic_01.jpg)} .card.aow_1{background-image:url(cards.1x/aow_teutonic_02.jpg)} .card.aow_2{background-image:url(cards.1x/aow_teutonic_03.jpg)} @@ -794,7 +850,6 @@ body.shift .marker:hover { transform: scale(2); z-index: 200; } .card.aow_18{background-image:url(cards.1x/aow_teutonic_none.jpg)} .card.aow_19{background-image:url(cards.1x/aow_teutonic_none.jpg)} .card.aow_20{background-image:url(cards.1x/aow_teutonic_none.jpg)} - .card.aow_21{background-image:url(cards.1x/aow_russian_01.jpg)} .card.aow_22{background-image:url(cards.1x/aow_russian_02.jpg)} .card.aow_23{background-image:url(cards.1x/aow_russian_03.jpg)} @@ -819,17 +874,14 @@ body.shift .marker:hover { transform: scale(2); z-index: 200; } .card.teutonic.cc_back{background-image:url(cards.1x/cc_teutonic_back.jpg)} .card.russian.cc_back{background-image:url(cards.1x/cc_russian_back.jpg)} - .card.teutonic.cc_pass{background-image:url(cards.1x/cc_teutonic_pass.jpg)} .card.russian.cc_pass{background-image:url(cards.1x/cc_russian_pass.jpg)} - .card.cc_lord_0{background-image:url(cards.1x/cc_teutonic_andreas.jpg)} .card.cc_lord_1{background-image:url(cards.1x/cc_teutonic_heinrich.jpg)} .card.cc_lord_2{background-image:url(cards.1x/cc_teutonic_hermann.jpg)} .card.cc_lord_3{background-image:url(cards.1x/cc_teutonic_knud_and_abel.jpg)} .card.cc_lord_4{background-image:url(cards.1x/cc_teutonic_rudolf.jpg)} .card.cc_lord_5{background-image:url(cards.1x/cc_teutonic_yaroslav.jpg)} - .card.cc_lord_6{background-image:url(cards.1x/cc_russian_aleksandr.jpg)} .card.cc_lord_7{background-image:url(cards.1x/cc_russian_andrey.jpg)} .card.cc_lord_8{background-image:url(cards.1x/cc_russian_domash.jpg)} @@ -838,67 +890,69 @@ body.shift .marker:hover { transform: scale(2); z-index: 200; } .card.cc_lord_11{background-image:url(cards.1x/cc_russian_vladislav.jpg)} @media (min-resolution: 97dpi) { -.card.russian.aow_back{background-image:url(cards.1x/aow_russian_back.jpg)} -.card.teutonic.aow_back{background-image:url(cards.1x/aow_teutonic_back.jpg)} -.card.aow_0{background-image:url(cards.1x/aow_russian_01.jpg)} -.card.aow_1{background-image:url(cards.1x/aow_russian_02.jpg)} -.card.aow_2{background-image:url(cards.1x/aow_russian_03.jpg)} -.card.aow_3{background-image:url(cards.1x/aow_russian_04.jpg)} -.card.aow_4{background-image:url(cards.1x/aow_russian_05.jpg)} -.card.aow_5{background-image:url(cards.1x/aow_russian_06.jpg)} -.card.aow_6{background-image:url(cards.1x/aow_russian_07.jpg)} -.card.aow_7{background-image:url(cards.1x/aow_russian_08.jpg)} -.card.aow_8{background-image:url(cards.1x/aow_russian_09.jpg)} -.card.aow_9{background-image:url(cards.1x/aow_russian_10.jpg)} -.card.aow_10{background-image:url(cards.1x/aow_russian_11.jpg)} -.card.aow_11{background-image:url(cards.1x/aow_russian_12.jpg)} -.card.aow_12{background-image:url(cards.1x/aow_russian_13.jpg)} -.card.aow_13{background-image:url(cards.1x/aow_russian_14.jpg)} -.card.aow_14{background-image:url(cards.1x/aow_russian_15.jpg)} -.card.aow_15{background-image:url(cards.1x/aow_russian_16.jpg)} -.card.aow_16{background-image:url(cards.1x/aow_russian_17.jpg)} -.card.aow_17{background-image:url(cards.1x/aow_russian_18.jpg)} -.card.aow_18{background-image:url(cards.1x/aow_russian_none.jpg)} -.card.aow_19{background-image:url(cards.1x/aow_russian_none.jpg)} -.card.aow_20{background-image:url(cards.1x/aow_russian_none.jpg)} -.card.aow_21{background-image:url(cards.1x/aow_teutonic_01.jpg)} -.card.aow_22{background-image:url(cards.1x/aow_teutonic_02.jpg)} -.card.aow_23{background-image:url(cards.1x/aow_teutonic_03.jpg)} -.card.aow_24{background-image:url(cards.1x/aow_teutonic_04.jpg)} -.card.aow_25{background-image:url(cards.1x/aow_teutonic_05.jpg)} -.card.aow_26{background-image:url(cards.1x/aow_teutonic_06.jpg)} -.card.aow_27{background-image:url(cards.1x/aow_teutonic_07.jpg)} -.card.aow_28{background-image:url(cards.1x/aow_teutonic_08.jpg)} -.card.aow_29{background-image:url(cards.1x/aow_teutonic_09.jpg)} -.card.aow_30{background-image:url(cards.1x/aow_teutonic_10.jpg)} -.card.aow_31{background-image:url(cards.1x/aow_teutonic_11.jpg)} -.card.aow_32{background-image:url(cards.1x/aow_teutonic_12.jpg)} -.card.aow_33{background-image:url(cards.1x/aow_teutonic_13.jpg)} -.card.aow_34{background-image:url(cards.1x/aow_teutonic_14.jpg)} -.card.aow_35{background-image:url(cards.1x/aow_teutonic_15.jpg)} -.card.aow_36{background-image:url(cards.1x/aow_teutonic_16.jpg)} -.card.aow_37{background-image:url(cards.1x/aow_teutonic_17.jpg)} -.card.aow_38{background-image:url(cards.1x/aow_teutonic_18.jpg)} -.card.aow_39{background-image:url(cards.1x/aow_teutonic_none.jpg)} -.card.aow_40{background-image:url(cards.1x/aow_teutonic_none.jpg)} -.card.aow_41{background-image:url(cards.1x/aow_teutonic_none.jpg)} - -.card.cc_russian_back{background-image:url(cards.2x/cc_russian_back.jpg)} -.card.cc_russian_aleksandr{background-image:url(cards.2x/cc_russian_aleksandr.jpg)} -.card.cc_russian_andrey{background-image:url(cards.2x/cc_russian_andrey.jpg)} -.card.cc_russian_domash{background-image:url(cards.2x/cc_russian_domash.jpg)} -.card.cc_russian_gavrilo{background-image:url(cards.2x/cc_russian_gavrilo.jpg)} -.card.cc_russian_karelians{background-image:url(cards.2x/cc_russian_karelians.jpg)} -.card.cc_russian_vladislav{background-image:url(cards.2x/cc_russian_vladislav.jpg)} -.card.cc_russian_pass{background-image:url(cards.2x/cc_russian_pass.jpg)} -.card.cc_teutonic_back{background-image:url(cards.2x/cc_teutonic_back.jpg)} -.card.cc_teutonic_andreas{background-image:url(cards.2x/cc_teutonic_andreas.jpg)} -.card.cc_teutonic_heinrich{background-image:url(cards.2x/cc_teutonic_heinrich.jpg)} -.card.cc_teutonic_hermann{background-image:url(cards.2x/cc_teutonic_hermann.jpg)} -.card.cc_teutonic_knud_and_abel{background-image:url(cards.2x/cc_teutonic_knud_and_abel.jpg)} -.card.cc_teutonic_rudolf{background-image:url(cards.2x/cc_teutonic_rudolf.jpg)} -.card.cc_teutonic_yaroslav{background-image:url(cards.2x/cc_teutonic_yaroslav.jpg)} -.card.cc_teutonic_pass{background-image:url(cards.2x/cc_teutonic_pass.jpg)} + +.card.russian.aow_back{background-image:url(cards.2x/aow_russian_back.jpg)} +.card.teutonic.aow_back{background-image:url(cards.2x/aow_teutonic_back.jpg)} +.card.aow_0{background-image:url(cards.2x/aow_russian_01.jpg)} +.card.aow_1{background-image:url(cards.2x/aow_russian_02.jpg)} +.card.aow_2{background-image:url(cards.2x/aow_russian_03.jpg)} +.card.aow_3{background-image:url(cards.2x/aow_russian_04.jpg)} +.card.aow_4{background-image:url(cards.2x/aow_russian_05.jpg)} +.card.aow_5{background-image:url(cards.2x/aow_russian_06.jpg)} +.card.aow_6{background-image:url(cards.2x/aow_russian_07.jpg)} +.card.aow_7{background-image:url(cards.2x/aow_russian_08.jpg)} +.card.aow_8{background-image:url(cards.2x/aow_russian_09.jpg)} +.card.aow_9{background-image:url(cards.2x/aow_russian_10.jpg)} +.card.aow_10{background-image:url(cards.2x/aow_russian_11.jpg)} +.card.aow_11{background-image:url(cards.2x/aow_russian_12.jpg)} +.card.aow_12{background-image:url(cards.2x/aow_russian_13.jpg)} +.card.aow_13{background-image:url(cards.2x/aow_russian_14.jpg)} +.card.aow_14{background-image:url(cards.2x/aow_russian_15.jpg)} +.card.aow_15{background-image:url(cards.2x/aow_russian_16.jpg)} +.card.aow_16{background-image:url(cards.2x/aow_russian_17.jpg)} +.card.aow_17{background-image:url(cards.2x/aow_russian_18.jpg)} +.card.aow_18{background-image:url(cards.2x/aow_russian_none.jpg)} +.card.aow_19{background-image:url(cards.2x/aow_russian_none.jpg)} +.card.aow_20{background-image:url(cards.2x/aow_russian_none.jpg)} +.card.aow_21{background-image:url(cards.2x/aow_teutonic_01.jpg)} +.card.aow_22{background-image:url(cards.2x/aow_teutonic_02.jpg)} +.card.aow_23{background-image:url(cards.2x/aow_teutonic_03.jpg)} +.card.aow_24{background-image:url(cards.2x/aow_teutonic_04.jpg)} +.card.aow_25{background-image:url(cards.2x/aow_teutonic_05.jpg)} +.card.aow_26{background-image:url(cards.2x/aow_teutonic_06.jpg)} +.card.aow_27{background-image:url(cards.2x/aow_teutonic_07.jpg)} +.card.aow_28{background-image:url(cards.2x/aow_teutonic_08.jpg)} +.card.aow_29{background-image:url(cards.2x/aow_teutonic_09.jpg)} +.card.aow_30{background-image:url(cards.2x/aow_teutonic_10.jpg)} +.card.aow_31{background-image:url(cards.2x/aow_teutonic_11.jpg)} +.card.aow_32{background-image:url(cards.2x/aow_teutonic_12.jpg)} +.card.aow_33{background-image:url(cards.2x/aow_teutonic_13.jpg)} +.card.aow_34{background-image:url(cards.2x/aow_teutonic_14.jpg)} +.card.aow_35{background-image:url(cards.2x/aow_teutonic_15.jpg)} +.card.aow_36{background-image:url(cards.2x/aow_teutonic_16.jpg)} +.card.aow_37{background-image:url(cards.2x/aow_teutonic_17.jpg)} +.card.aow_38{background-image:url(cards.2x/aow_teutonic_18.jpg)} +.card.aow_39{background-image:url(cards.2x/aow_teutonic_none.jpg)} +.card.aow_40{background-image:url(cards.2x/aow_teutonic_none.jpg)} +.card.aow_41{background-image:url(cards.2x/aow_teutonic_none.jpg)} + +.card.teutonic.cc_back{background-image:url(cards.2x/cc_teutonic_back.jpg)} +.card.russian.cc_back{background-image:url(cards.2x/cc_russian_back.jpg)} +.card.teutonic.cc_pass{background-image:url(cards.2x/cc_teutonic_pass.jpg)} +.card.russian.cc_pass{background-image:url(cards.2x/cc_russian_pass.jpg)} +.card.cc_lord_0{background-image:url(cards.2x/cc_teutonic_andreas.jpg)} +.card.cc_lord_1{background-image:url(cards.2x/cc_teutonic_heinrich.jpg)} +.card.cc_lord_2{background-image:url(cards.2x/cc_teutonic_hermann.jpg)} +.card.cc_lord_3{background-image:url(cards.2x/cc_teutonic_knud_and_abel.jpg)} +.card.cc_lord_4{background-image:url(cards.2x/cc_teutonic_rudolf.jpg)} +.card.cc_lord_5{background-image:url(cards.2x/cc_teutonic_yaroslav.jpg)} +.card.cc_lord_6{background-image:url(cards.2x/cc_russian_aleksandr.jpg)} +.card.cc_lord_7{background-image:url(cards.2x/cc_russian_andrey.jpg)} +.card.cc_lord_8{background-image:url(cards.2x/cc_russian_domash.jpg)} +.card.cc_lord_9{background-image:url(cards.2x/cc_russian_gavrilo.jpg)} +.card.cc_lord_10{background-image:url(cards.2x/cc_russian_karelians.jpg)} +.card.cc_lord_11{background-image:url(cards.2x/cc_russian_vladislav.jpg)} + } </style> @@ -910,6 +964,12 @@ body.shift .marker:hover { transform: scale(2); z-index: 200; } <div id="arts_of_war_list"></div> </div> +<div id="plan" class="hide"> +<div id="plan_header">Plan</div> +<div id="plan_list"></div> +<div id="plan_actions"></div> +</div> + <header> <div id="toolbar"> <div class="menu"> @@ -24,6 +24,31 @@ const SLED = 4 const BOAT = 5 const SHIP = 6 +const SUMMER = 0 +const EARLY_WINTER = 1 +const LATE_WINTER = 2 +const RASPUTITSA = 3 + +const SEASONS = [ + null, + SUMMER, SUMMER, EARLY_WINTER, EARLY_WINTER, LATE_WINTER, LATE_WINTER, RASPUTITSA, RASPUTITSA, + SUMMER, SUMMER, EARLY_WINTER, EARLY_WINTER, LATE_WINTER, LATE_WINTER, RASPUTITSA, RASPUTITSA, + null +] + +function current_season() { + return SEASONS[view.turn >> 1] +} + +function max_plan_length() { + switch (current_season()) { + case SUMMER: return 6 + case EARLY_WINTER: return 4 + case LATE_WINTER: return 4 + case RASPUTITSA: return 5 + } +} + function pack1_get(word, n) { return (word >>> n) & 1 } @@ -37,6 +62,10 @@ function is_lord_action(lord) { return !!(view.actions && view.actions.lord && view.actions.lord.includes(lord)) } +function is_plan_action(lord) { + return !!(view.actions && view.actions.plan && view.actions.plan.includes(lord)) +} + function is_service_action(lord) { return !!(view.actions && view.actions.service && view.actions.service.includes(lord)) } @@ -61,6 +90,34 @@ const last_p1_locale = 23 const first_p2_locale = 24 const last_p2_locale = 52 +let used_cache = {} +let unused_cache = {} + +function get_cached_element(className) { + if (!(className in unused_cache)) { + unused_cache[className] = [] + used_cache[className] = [] + } + if (unused_cache[className].length > 0) { + let elt = unused_cache[className].pop() + used_cache[className].push(elt) + return elt + } + let elt = document.createElement("div") + elt.className = className + used_cache[className].push(elt) + return elt +} + +function restart_cache() { + for (let k in used_cache) { + let u = used_cache[k] + let uu = unused_cache[k] + while (u.length > 0) + uu.push(u.pop()) + } +} + function is_p1_locale(loc) { return loc >= first_p1_locale && loc <= last_p1_locale } @@ -197,6 +254,11 @@ const ui = { arts_of_war: [], boxes: {}, veche: document.getElementById("veche"), + plan_dialog: document.getElementById("plan"), + plan_list: document.getElementById("plan_list"), + plan_actions: document.getElementById("plan_actions"), + plan_list_cards: [], + plan_action_cards: [], arts_of_war_dialog: document.getElementById("arts_of_war"), arts_of_war_list: document.getElementById("arts_of_war_list"), p1_global: document.getElementById("p1_global"), @@ -240,56 +302,63 @@ function toggle_pieces() { function on_click_locale(evt) { if (evt.button === 0) { - let id = evt.target.my_locale + let id = evt.target.my_id send_action('locale', id) } } function on_focus_locale(evt) { - let id = evt.target.my_locale + let id = evt.target.my_id document.getElementById("status").textContent = `(${id}) ${data.locales[id].name} - ${data.locales[id].type}` } function on_click_cylinder(evt) { if (evt.button === 0) { - let id = evt.target.my_lord + let id = evt.target.my_id send_action('lord', id) } } function on_click_arts_of_war(evt) { if (evt.button === 0) { - let id = evt.target.my_arts_of_war + let id = evt.target.my_id send_action('arts_of_war', id) } } +function on_click_plan(evt) { + if (evt.button === 0) { + let id = evt.target.my_id + send_action('plan', id) + } +} + function on_focus_cylinder(evt) { - let id = evt.target.my_lord + let id = evt.target.my_id document.getElementById("status").textContent = `(${id}) ${data.lords[id].full_name} [${data.lords[id].command}] - ${data.lords[id].title}` } function on_click_lord_service_marker(evt) { if (evt.button === 0) { - let id = evt.target.my_lord + let id = evt.target.my_id send_action('lord_service', id) } } function on_focus_lord_service_marker(evt) { - let id = evt.target.my_lord + let id = evt.target.my_id document.getElementById("status").textContent = `(${id}) ${data.lords[id].full_name} - ${data.lords[id].title}` } function on_click_vassal_service_marker(evt) { if (evt.button === 0) { - let id = evt.target.my_vassal + let id = evt.target.my_id send_action('vassal', id) } } function on_focus_vassal_service_marker(evt) { - let id = evt.target.my_vassal + let id = evt.target.my_id let vassal = data.vassals[id] let lord = data.lords[vassal.lord] document.getElementById("status").textContent = `(${id}) ${lord.name} / ${vassal.name}` @@ -521,6 +590,57 @@ function update_locale(loc) { ui.locale_extra[loc].classList.toggle("action", is_locale_action(loc)) } +function update_plan() { + if (view.plan) { + ui.plan_dialog.classList.remove("hide") + for (let i = 0; i < 6; ++i) { + if (i < view.plan.length) { + let lord = view.plan[i] + if (lord < 0) { + if (player === "Teutons") + ui.plan_list_cards[i].className = "card teutonic cc_pass" + else + ui.plan_list_cards[i].className = "card russian cc_pass" + } else { + if (lord < 6) + ui.plan_list_cards[i].className = "card teutonic cc_lord_" + lord + else + ui.plan_list_cards[i].className = "card russian cc_lord_" + lord + } + } else if (i < max_plan_length()) { + if (player === "Teutons") + ui.plan_list_cards[i].className = "card teutonic cc_back" + else + ui.plan_list_cards[i].className = "card russian cc_back" + } else { + ui.plan_list_cards[i].className = "hide" + } + } + for (let lord = 0; lord < 12; ++lord) { + if (is_plan_action(lord)) { + ui.plan_action_cards[lord].classList.add("action") + ui.plan_action_cards[lord].classList.remove("disabled") + } else { + ui.plan_action_cards[lord].classList.remove("action") + ui.plan_action_cards[lord].classList.add("disabled") + } + } + if (is_plan_action(-1)) { + ui.plan_action_pass_p1.classList.add("action") + ui.plan_action_pass_p1.classList.remove("disabled") + ui.plan_action_pass_p2.classList.add("action") + ui.plan_action_pass_p2.classList.remove("disabled") + } else { + ui.plan_action_pass_p1.classList.remove("action") + ui.plan_action_pass_p1.classList.add("disabled") + ui.plan_action_pass_p2.classList.remove("action") + ui.plan_action_pass_p2.classList.add("disabled") + } + } else { + ui.plan_dialog.classList.add("hide") + } +} + function update_arts_of_war() { if (view.actions && view.actions.arts_of_war) { ui.arts_of_war_dialog.classList.remove("hide") @@ -570,6 +690,8 @@ function update_arts_of_war() { } function on_update() { + restart_cache() + locale_layout.fill(0) calendar_layout.fill(0) @@ -633,6 +755,7 @@ function on_update() { ui.vp2.className = `marker circle victory russian v${vp2>>1}` } + update_plan() update_arts_of_war() action_button("ship", "Ship") @@ -644,6 +767,7 @@ function on_update() { action_button("done", "Done") action_button("unfed", "Unfed") + action_button("end_plan", "End plan") action_button("end_feed", "End feed") action_button("end_pay", "End pay") action_button("end_disband", "End disband") @@ -681,10 +805,41 @@ function build_lord_mat(lord, ix, side, name) { function build_arts_of_war(side, c) { let card = ui.arts_of_war[c] = document.createElement("div") card.className = `card ${side} aow_${c}` - card.my_arts_of_war = c + card.my_id = c card.addEventListener("mousedown", on_click_arts_of_war) } +function build_plan() { + let elt + for (let i = 0; i < 6; ++i) { + elt = document.createElement("div") + elt.className = "hide" + ui.plan_list_cards.push(elt) + ui.plan_list.appendChild(elt) + } + for (let lord = 0; lord < 12; ++lord) { + let side = lord < 6 ? "teutonic" : "russian" + elt = document.createElement("div") + elt.className = `card ${side} cc_lord_${lord}` + elt.my_id = lord + elt.addEventListener("mousedown", on_click_plan) + ui.plan_action_cards.push(elt) + ui.plan_actions.appendChild(elt) + } + + ui.plan_action_pass_p1 = elt = document.createElement("div") + elt.className = `card teutonic cc_pass` + elt.my_id = -1 + elt.addEventListener("mousedown", on_click_plan) + ui.plan_actions.appendChild(elt) + + ui.plan_action_pass_p2 = elt = document.createElement("div") + elt.className = `card russian cc_pass` + elt.my_id = -1 + elt.addEventListener("mousedown", on_click_plan) + ui.plan_actions.appendChild(elt) +} + function build_map() { data.locales.forEach((locale, ix) => { let e = ui.locale[ix] = document.createElement("div") @@ -715,7 +870,7 @@ function build_map() { e.style.top = y + "px" e.style.width = w + "px" e.style.height = h + "px" - e.my_locale = ix + e.my_id = ix e.addEventListener("mousedown", on_click_locale) e.addEventListener("mouseenter", on_focus_locale) e.addEventListener("mouseleave", on_blur) @@ -731,7 +886,7 @@ function build_map() { e.style.left = (cx - ew/2) + "px" e.style.width = ew + "px" e.style.height = eh + "px" - e.my_locale = ix + e.my_id = ix e.addEventListener("mousedown", on_click_locale) e.addEventListener("mouseenter", on_focus_locale) e.addEventListener("mouseleave", on_blur) @@ -744,7 +899,7 @@ function build_map() { data.lords.forEach((lord, ix) => { let e = ui.lord_cylinder[ix] = document.createElement("div") e.className = "cylinder lord " + clean_name(lord.side) + " " + clean_name(lord.name) + " hide" - e.my_lord = ix + e.my_id = ix e.addEventListener("mousedown", on_click_cylinder) e.addEventListener("mouseenter", on_focus_cylinder) e.addEventListener("mouseleave", on_blur) @@ -752,7 +907,7 @@ function build_map() { e = ui.lord_service[ix] = document.createElement("div") e.className = "service_marker lord image" + lord.image + " " + clean_name(lord.side) + " " + clean_name(lord.name) + " hide" - e.my_lord = ix + e.my_id = ix e.addEventListener("mousedown", on_click_lord_service_marker) e.addEventListener("mouseenter", on_focus_lord_service_marker) e.addEventListener("mouseleave", on_blur) @@ -767,7 +922,7 @@ function build_map() { let lord = data.lords[vassal.lord] let e = ui.vassal_service[ix] = document.createElement("div") e.className = "service_marker vassal image" + vassal.image + " " + clean_name(lord.side) + " " + clean_name(vassal.name) + " hide" - e.my_vassal = ix + e.my_id = ix e.addEventListener("mousedown", on_click_vassal_service_marker) e.addEventListener("mouseenter", on_focus_vassal_service_marker) e.addEventListener("mouseleave", on_blur) @@ -788,6 +943,8 @@ function build_map() { document.getElementById("boxes").appendChild(e) } + build_plan() + for (let c = 0; c < 21; ++c) build_arts_of_war("teutonic", c) for (let c = 21; c < 42; ++c) @@ -797,4 +954,5 @@ function build_map() { build_map() // drag_element_with_mouse("#battle", "#battle_header") drag_element_with_mouse("#arts_of_war", "#arts_of_war_header") +drag_element_with_mouse("#plan", "#plan_header") scroll_with_middle_mouse("main") @@ -171,6 +171,11 @@ function current_turn_name() { // === GAME STATE === +const first_p1_lord = 0 +const last_p1_lord = 5 +const first_p2_lord = 6 +const last_p2_lord = 11 + let first_friendly_lord = 0 let last_friendly_lord = 5 let first_enemy_lord = 6 @@ -182,11 +187,16 @@ function update_aliases() { last_friendly_lord = 5 first_enemy_lord = 6 last_enemy_lord = 11 - } else { + } else if (game.active === P2) { first_friendly_lord = 6 last_friendly_lord = 11 first_enemy_lord = 0 last_enemy_lord = 5 + } else { + first_friendly_lord = -1 + last_friendly_lord = -1 + first_enemy_lord = -1 + last_enemy_lord = -1 } } @@ -211,7 +221,7 @@ function pop_state() { function set_active(new_active) { if (game.active !== new_active) { game.active = new_active - update_active_aliases() + update_aliases() } } @@ -696,6 +706,8 @@ function setup_pleskau_quickstart() { add_lord_assets(LORD_GAVRILO, CART, 1) add_lord_assets(LORD_VLADISLAV, BOAT, 1) + log_h1("Levy " + current_turn_name()) + log_h2("Teutons Muster") log_h3("Knud & Abel") @@ -742,10 +754,12 @@ function setup_pleskau_quickstart() { game.veche_coin += 1 + goto_campaign_plan() + game.p1_plan = [ LORD_YAROSLAV, LORD_RUDOLF, LORD_HERMANN, LORD_HERMANN, LORD_RUDOLF, LORD_HERMANN ] game.p2_plan = [ LORD_GAVRILO, LORD_VLADISLAV, LORD_DOMASH, LORD_GAVRILO, LORD_DOMASH, LORD_DOMASH ] - goto_command_activation() + // goto_command_activation() } states.setup_lords = { @@ -811,10 +825,10 @@ function goto_levy_muster() { function end_levy_muster() { game.lords.moved = 0 set_active_enemy() - if (game.active === P1) - goto_levy_call_to_arms() - else + if (game.active === P2) goto_levy_muster() + else + goto_levy_call_to_arms() } states.levy_muster = { @@ -1059,13 +1073,80 @@ function end_levy_call_to_arms() { // === CAMPAIGN: PLAN === function goto_campaign_plan() { - game.active = BOTH + game.turn++ + + log_h1("Campaign " + current_turn_name()) + + set_active(BOTH) game.state = 'campaign_plan' game.p1_plan = [] game.p2_plan = [] + + // TODO: define lieutenants +} + +function max_plan_length() { + switch (current_season()) { + case SUMMER: return 6 + case EARLY_WINTER: return 4 + case LATE_WINTER: return 4 + case RASPUTITSA: return 5 + } +} + +function count_cards_in_plan(plan, lord) { + let n = 0 + for (let c of plan) + if (c === lord) + ++n + return n } states.campaign_plan = { + prompt(current) { + view.prompt = "Create your plan." + let plan = (current === P1) ? game.p1_plan : game.p2_plan + view.plan = plan + if (plan.length < max_plan_length()) { + view.actions.end_plan = 0 + if (count_cards_in_plan(plan, -1) < 3) + gen_action_plan(-1) + for (let lord = 0; lord <= last_lord; ++lord) { + console.log("campaign_plan", lord, current) + if (lord >= first_p1_lord && lord <= last_p1_lord && current !== P1) + continue + if (lord >= first_p2_lord && lord <= last_p2_lord && current !== P2) + continue + if (is_lord_on_map(lord) && count_cards_in_plan(plan, lord) < 3) + gen_action_plan(lord) + } + } else { + view.actions.end_plan = 1 + } + if (plan.length > 0) + view.actions.undo = 1 + else + view.actions.undo = 0 + }, + plan(lord, current) { + let plan = (current === P1) ? game.p1_plan : game.p2_plan + plan.push(lord) + }, + undo(_, current) { + let plan = (current === P1) ? game.p1_plan : game.p2_plan + plan.length-- + }, + end_plan(_, current) { + console.log("active", game.active) + if (game.active === BOTH) { + if (current === P1) + set_active(P2) + else + set_active(P1) + } else { + end_campaign_plan() + } + }, } function end_campaign_plan() { @@ -1076,23 +1157,41 @@ function end_campaign_plan() { // === CAMPAIGN: COMMAND ACTIVATION === function goto_command_activation() { - if (game.active === P1) - game.command = game.p1_plan.shift() - else - game.command = game.p2_plan.shift() - if (game.command === undefined) { + if (game.p2_plan.length === 0) { game.command = NOBODY goto_end_campaign() + return + } + + if (game.p2_plan.length > game.p1_plan.length) { + set_active(P2) + game.command = game.p2_plan.shift() + } else { + set_active(P1) + game.command = game.p1_plan.shift() + } + + if (game.command === -1) { + log_h2("Pass") + goto_command_activation() } else { - game.who = game.command goto_actions() } } +function goto_end_campaign() { + // TODO: end game check + game.turn++ + goto_levy_arts_of_war() +} + // === CAMPAIGN: ACTIONS === function goto_actions() { + log_h2(lord_name[game.command]) + game.state = 'actions' + game.who = game.command game.count = data.lords[game.command].command } @@ -1106,13 +1205,17 @@ states.actions = { view.prompt = `${lord_name[game.who]} has ${game.count}x actions.` view.actions.end_actions = 1 }, + end_actions() { + clear_undo() + end_actions() + }, } // === CAMPAIGN: FEED === function has_friendly_lord_who_moved_or_fought() { - for (let lord of game.moved) - if (is_friendly_lord(lord)) + for (let lord = first_friendly_lord; lord <= last_friendly_lord; ++lord) + if (get_lord_moved(lord)) return true return false } @@ -1126,8 +1229,8 @@ function goto_feed() { states.feed = { prompt() { view.prompt = "You must Feed your who Moved or Fought." - for (let lord of game.moved) - if (is_friendly_lord(lord)) + for (let lord = first_friendly_lord; lord <= last_friendly_lord; ++lord) + if (get_lord_moved(lord)) gen_action_lord(lord) view.actions.end_feed = 1 }, @@ -1170,7 +1273,9 @@ states.feed_lord = { function end_feed() { set_active_enemy() - if (game.active === P1) + if (game.active === P2) + goto_feed() + else goto_pay() } @@ -1230,7 +1335,9 @@ states.pay_lord = { function end_pay() { set_active_enemy() - if (game.active === P1) + if (game.active === P2) + goto_pay() + else goto_disband() } @@ -1253,7 +1360,9 @@ states.disband = { function end_disband() { set_active_enemy() - if (game.active === P1) { + if (game.active === P2) { + goto_disband() + } else { if (is_levy_phase()) goto_levy_muster() else @@ -1265,7 +1374,6 @@ function end_disband() { function goto_remove_markers() { game.lords.moved = 0 - set_active_enemy() goto_command_activation() } @@ -1371,6 +1479,10 @@ function gen_action_arts_of_war(c) { gen_action('arts_of_war', c) } +function gen_action_plan(lord) { + gen_action('plan', lord) +} + exports.view = function(state, current) { load_state(state) @@ -1389,13 +1501,14 @@ exports.view = function(state, current) { ravaged: game.ravaged, castles: game.castles, command: game.command, + plan: null, who: game.who, where: game.where, } if (game.state === 'game_over') { view.prompt = game.victory - } else if (current === 'Observer' || (current !== game.active && current !== BOTH)) { + } else if (current === 'Observer' || (game.active !== current && game.active !== BOTH)) { let inactive = states[game.state].inactive || game.state view.prompt = `Waiting for ${game.active} \u2014 ${inactive}...` } else { |