summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.html24
-rw-r--r--play.js89
-rw-r--r--rules.js79
3 files changed, 147 insertions, 45 deletions
diff --git a/play.html b/play.html
index b8bd053..121d5d6 100644
--- a/play.html
+++ b/play.html
@@ -248,18 +248,18 @@ body.shift .mat .card:hover {
z-index: 2;
}
-#p1_global, #p2_global {
+#p1_capabilities, #p2_capabilities {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
-#p1_global {
+#p1_capabilities {
margin-left: 24px;
justify-content: start;
}
-#p2_global {
+#p2_capabilities {
margin-right: 24px;
justify-content: end;
}
@@ -542,6 +542,16 @@ body.shift .mat .card:hover {
box-shadow: 0 0 8px #ff06;
}
+.locale_markers {
+ position: absolute;
+ pointer-events: none;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-items: center;
+ gap: 4px;
+}
+
#veche { position: absolute; }
.veche_label {
@@ -625,8 +635,8 @@ body.shift .mat .card:hover {
width: 32px;
height: 64px;
background-image: url(images/legate.svg);
- top: 1585px;
- left: 180px;
+ top: 1580px;
+ left: 170px;
filter: drop-shadow(0px 2px 4px #0004);
}
@@ -1021,8 +1031,8 @@ body.shift .marker:hover { transform: scale(2); z-index: 200; }
</div>
<div class="tuck_under_map">
-<div id="p1_global" class="global"></div>
-<div id="p2_global" class="global"></div>
+<div id="p1_capabilities"></div>
+<div id="p2_capabilities"></div>
</div>
<div id="plan" class="hide">
diff --git a/play.js b/play.js
index 44efe00..a986c9a 100644
--- a/play.js
+++ b/play.js
@@ -1,5 +1,8 @@
"use strict"
+// TODO: put card elements in capability containers, not c1/c2 specials
+// TODO: held events, this_turn events
+
const MAP_DPI = 75
const round = Math.round
@@ -49,6 +52,22 @@ function max_plan_length() {
}
}
+function set_has(set, item) {
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return true
+ }
+ return false
+}
+
function pack1_get(word, n) {
return (word >>> n) & 1
}
@@ -155,7 +174,7 @@ function count_vp2() {
}
function is_card_in_use(c) {
- if (view.global_cards.includes(c))
+ if (view.capabilities.includes(c))
return true
if (view.lords.cards.includes(c))
return true
@@ -242,6 +261,7 @@ const locale_xy = []
const ui = {
locale: [],
locale_extra: [],
+ locale_markers: [],
lord_cylinder: [],
lord_service: [],
lord_mat: [],
@@ -261,8 +281,8 @@ const ui = {
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"),
- p2_global: document.getElementById("p2_global"),
+ p1_capabilities: document.getElementById("p1_capabilities"),
+ p2_capabilities: document.getElementById("p2_capabilities"),
command: document.getElementById("command"),
turn: document.getElementById("turn"),
vp1: document.getElementById("vp1"),
@@ -588,6 +608,47 @@ function update_locale(loc) {
ui.locale[loc].classList.toggle("action", is_locale_action(loc))
if (ui.locale_extra[loc])
ui.locale_extra[loc].classList.toggle("action", is_locale_action(loc))
+
+ ui.locale_markers[loc].replaceChildren()
+
+ if (set_has(view.ravaged, loc)) {
+ let cn
+ if (is_p1_locale(loc))
+ cn = "marker small ravaged russian"
+ else
+ cn = "marker small ravaged teutonic"
+ ui.locale_markers[loc].appendChild(get_cached_element(cn))
+ }
+
+ if (set_has(view.conquered, loc)) {
+ let cn
+ if (is_p1_locale(loc))
+ cn = "marker square conquered russian"
+ else
+ cn = "marker square conquered teutonic"
+ for (let i = 0; i < data.locales[loc].vp; ++i)
+ ui.locale_markers[loc].appendChild(get_cached_element(cn))
+ }
+
+ if (set_has(view.castles, loc)) {
+ let cn
+ if (is_p1_locale(loc))
+ cn = "marker rectangle castle russian"
+ else
+ cn = "marker rectangle castle teutonic"
+ ui.locale_markers[loc].appendChild(get_cached_element(cn))
+ }
+
+ if (view.sieges[loc]) {
+ let cn
+ // TODO: castle?
+ if (is_p1_locale(loc))
+ cn = "marker square siege russian"
+ else
+ cn = "marker square siege teutonic"
+ for (let i = 0; i < view.sieges[loc]; ++i)
+ ui.locale_markers[loc].appendChild(get_cached_element(cn))
+ }
}
function update_plan() {
@@ -662,16 +723,16 @@ function update_arts_of_war() {
}
}
- ui.p1_global.replaceChildren()
+ ui.p1_capabilities.replaceChildren()
for_each_teutonic_arts_of_war(c => {
- if (view.global_cards.includes(c))
- ui.p1_global.appendChild(ui.arts_of_war[c])
+ if (view.capabilities.includes(c))
+ ui.p1_capabilities.appendChild(ui.arts_of_war[c])
})
- ui.p2_global.replaceChildren()
+ ui.p2_capabilities.replaceChildren()
for_each_russian_arts_of_war(c => {
- if (view.global_cards.includes(c))
- ui.p2_global.appendChild(ui.arts_of_war[c])
+ if (view.capabilities.includes(c))
+ ui.p2_capabilities.appendChild(ui.arts_of_war[c])
})
for (let ix = 0; ix < data.lords.length; ++ix) {
@@ -892,6 +953,15 @@ function build_map() {
e.addEventListener("mouseleave", on_blur)
document.getElementById("locales").appendChild(e)
}
+
+ e = ui.locale_markers[ix] = document.createElement("div")
+ e.className = "locale_markers " + locale.type + " " + region
+ x = (locale.box.x + locale.box.w / 2) * MAP_DPI / 300 - 196/2
+ y = (locale.box.y + locale.box.h * 0) * MAP_DPI / 300 - 8
+ e.style.top = y + "px"
+ e.style.left = x + "px"
+ e.style.width = 196 + "px"
+ document.getElementById("pieces").appendChild(e)
})
let x = 160
@@ -954,5 +1024,4 @@ 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")
diff --git a/rules.js b/rules.js
index 7174a26..2382103 100644
--- a/rules.js
+++ b/rules.js
@@ -9,6 +9,9 @@ const RUSSIANS = "Russians"
const P1 = TEUTONS
const P2 = RUSSIANS
+// NOTE: With Hidden Mats option, the player order of feed/pay may matter.
+const FEED_PAY_DISBAND = false // feed, pay, disband in one go
+
let game = null
let view = null
let states = {}
@@ -351,7 +354,7 @@ function is_levy_phase() {
}
function is_card_in_use(c) {
- if (set_has(game.global_cards, c))
+ if (set_has(game.capabilities, c))
return true
if (game.lords.cards.includes(c))
return true
@@ -482,10 +485,14 @@ exports.setup = function (seed, scenario, options) {
stack: [],
turn: 0,
+
p1_hand: [],
p2_hand: [],
p1_plan: [],
p2_plan: [],
+ events: [], // this levy/this campaign cards
+ capabilities: [], // global capabilities
+
lords: {
locale: Array(lord_count).fill(NOWHERE),
service: Array(lord_count).fill(NEVER),
@@ -500,10 +507,11 @@ exports.setup = function (seed, scenario, options) {
legate: NOWHERE,
veche_vp: 0,
veche_coin: 0,
+
conquered: [],
ravaged: [],
castles: [],
- global_cards: [],
+ sieges: {},
command: NOBODY,
who: NOBODY,
@@ -730,14 +738,14 @@ function setup_pleskau_quickstart() {
logi("Capability T3")
set_lord_capability(LORD_YAROSLAV, 0, find_arts_of_war("T3"))
- set_add(game.global_cards, find_arts_of_war("T13"))
+ set_add(game.capabilities, find_arts_of_war("T13"))
game.legate = LOC_DORPAT
log_h2("Russians Muster")
log_h3("Vladislav")
logi("Capability R8")
- set_add(game.global_cards, find_arts_of_war("R8"))
+ set_add(game.capabilities, find_arts_of_war("R8"))
logi(`Domash at %${LOC_NOVGOROD}`)
muster_lord(LORD_DOMASH, LOC_NOVGOROD)
logii("Boat")
@@ -1051,7 +1059,7 @@ states.muster_capability = {
push_undo()
logi(`Capability #${c}`)
if (!data.cards[c].lords) {
- set_add(game.global_cards, c)
+ set_add(game.capabilities, c)
} else {
if (get_lord_capability(game.who, 0) < 0)
set_lord_capability(game.who, 0, c)
@@ -1123,7 +1131,6 @@ states.campaign_plan = {
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)
@@ -1237,9 +1244,12 @@ function goto_feed() {
end_feed()
}
+// TODO: feed_self
+// TODO: feed_other
+
states.feed = {
prompt() {
- view.prompt = "You must Feed your who Moved or Fought."
+ view.prompt = "You must Feed lords who Moved or Fought."
for (let lord = first_friendly_lord; lord <= last_friendly_lord; ++lord)
if (get_lord_moved(lord))
gen_action_lord(lord)
@@ -1283,11 +1293,15 @@ states.feed_lord = {
}
function end_feed() {
- set_active_enemy()
- if (game.active === P2)
- goto_feed()
- else
+ if (FEED_PAY_DISBAND) {
goto_pay()
+ } else {
+ set_active_enemy()
+ if (game.active === P2)
+ goto_feed()
+ else
+ goto_pay()
+ }
}
// === LEVY & CAMPAIGN: PAY ===
@@ -1345,11 +1359,8 @@ states.pay_lord = {
}
function end_pay() {
- set_active_enemy()
- if (game.active === P2)
- goto_pay()
- else
- goto_disband()
+ // NOTE: We can combine Pay & Disband steps because disband is mandatory only.
+ goto_disband()
}
// === LEVY & CAMPAIGN: DISBAND ===
@@ -1372,7 +1383,10 @@ states.disband = {
function end_disband() {
set_active_enemy()
if (game.active === P2) {
- goto_disband()
+ if (FEED_PAY_DISBAND)
+ goto_feed()
+ else
+ goto_pay()
} else {
if (is_levy_phase())
goto_levy_muster()
@@ -1507,7 +1521,7 @@ exports.view = function(state, current) {
legate: game.legate,
veche_vp: game.veche_vp,
veche_coin: game.veche_coin,
- global_cards: game.global_cards,
+ capabilities: game.capabilities,
conquered: game.conquered,
ravaged: game.ravaged,
castles: game.castles,
@@ -1517,6 +1531,8 @@ exports.view = function(state, current) {
where: game.where,
}
+ view.sieges = { 0: 3, [LOC_NOVGOROD]: 2, [LOC_PSKOV]: 1 }
+
if (game.state === 'game_over') {
view.prompt = game.victory
} else if (current === 'Observer' || (game.active !== current && game.active !== BOTH)) {
@@ -1581,7 +1597,8 @@ function pack4_set(word, n, x) {
}
// Sorted array treated as Set (for JSON)
-function set_index(set, item) {
+
+function set_has(set, item) {
let a = 0
let b = set.length - 1
while (a <= b) {
@@ -1592,13 +1609,9 @@ function set_index(set, item) {
else if (item > x)
a = m + 1
else
- return m
+ return true
}
- return -1
-}
-
-function set_has(set, item) {
- return set_index(set, item) >= 0
+ return false
}
function set_add(set, item) {
@@ -1618,9 +1631,19 @@ function set_add(set, item) {
}
function set_delete(set, item) {
- let i = set_index(set, item)
- if (i >= 0)
- set.splice(i, 1)
+ let a = 0
+ let b = set.length - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = set[m]
+ if (item < x)
+ b = m - 1
+ else if (item > x)
+ a = m + 1
+ else
+ return array_remove(set, m)
+ }
+ return set
}
function set_clear(set) {