summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-12-03 17:14:51 +0100
committerTor Andersson <tor@ccxvii.net>2023-02-18 13:02:38 +0100
commita2e3d79e0a10bd93bc27862c3467d4aff848a56c (patch)
treea7d86945b2cae75717f6711577ce567f7ec5e460
parentf4affb436d3d6b67a7714ee511bdb2bc74346c75 (diff)
downloadnevsky-a2e3d79e0a10bd93bc27862c3467d4aff848a56c.tar.gz
Start marching.
-rw-r--r--data.js22
-rw-r--r--play.html1
-rw-r--r--play.js33
-rw-r--r--rules.js147
-rw-r--r--tools/gendata.js6
5 files changed, 191 insertions, 18 deletions
diff --git a/data.js b/data.js
index 295f99a..d782827 100644
--- a/data.js
+++ b/data.js
@@ -5,17 +5,17 @@ strongholds:[0,1,7,8,9,10,11,12,13,24,25,26,27,32,33,34,35,36],
locales:[
{"name":"Reval","type":"bishopric","stronghold":3,"walls":4,"vp":2,"region":"Danish Estonia","ways":[[5,25],[3,31]],"box":{"x":601,"y":3564,"w":206,"h":91}},
{"name":"Wesenberg","type":"castle","stronghold":2,"walls":4,"vp":1,"region":"Danish Estonia","ways":[[5,26],[17,30]],"box":{"x":1448,"y":3625,"w":304,"h":60}},
-{"name":"Narwia","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Danish Estonia","ways":[[7,0],[38,0],[49,0],[46,17],[6,27],[33,28]],"box":{"x":2371,"y":3549,"w":123,"h":31}},
+{"name":"Narwia","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Danish Estonia","ways":[[7,2],[38,2],[49,2],[46,17],[6,27],[33,28]],"box":{"x":2371,"y":3549,"w":123,"h":31}},
{"name":"Warbola","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Danish Estonia","ways":[[0,31],[4,32],[8,34]],"box":{"x":292,"y":3797,"w":142,"h":31}},
{"name":"Harrien","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Danish Estonia","ways":[[3,32],[17,33]],"box":{"x":567,"y":3983,"w":200,"h":100}},
{"name":"Revala","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Danish Estonia","ways":[[0,25],[1,26]],"box":{"x":1030,"y":3410,"w":200,"h":100}},
{"name":"Wierland","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Danish Estonia","ways":[[2,27],[23,29]],"box":{"x":1999,"y":3680,"w":200,"h":100}},
-{"name":"Dorpat","type":"bishopric","stronghold":3,"walls":4,"vp":2,"region":"Crusader Livonia","ways":[[2,0],[38,0],[49,0],[11,2],[12,2,3],[22,3],[23,35]],"box":{"x":1625,"y":4589,"w":253,"h":91}},
+{"name":"Dorpat","type":"bishopric","stronghold":3,"walls":4,"vp":2,"region":"Crusader Livonia","ways":[[12,0,3],[22,0],[2,2],[38,2],[49,2],[11,3],[23,35]],"box":{"x":1625,"y":4589,"w":253,"h":91}},
{"name":"Leal","type":"bishopric","stronghold":3,"walls":4,"vp":2,"region":"Crusader Livonia","ways":[[3,34],[15,36]],"box":{"x":108,"y":4266,"w":205,"h":91}},
{"name":"Riga","type":"bishopric","stronghold":3,"walls":4,"vp":2,"region":"Crusader Livonia","ways":[[13,8]],"box":{"x":273,"y":6231,"w":205,"h":91}},
{"name":"Adsel","type":"castle","stronghold":2,"walls":4,"vp":1,"region":"Crusader Livonia","ways":[[13,9],[18,43],[21,43],[14,44]],"box":{"x":1504,"y":5612,"w":185,"h":60}},
-{"name":"Fellin","type":"castle","stronghold":2,"walls":4,"vp":1,"region":"Crusader Livonia","ways":[[7,2],[12,2],[15,7],[17,7],[20,37]],"box":{"x":1013,"y":4583,"w":184,"h":61}},
-{"name":"Odenpäh","type":"castle","stronghold":2,"walls":4,"vp":1,"region":"Crusader Livonia","ways":[[7,2,3],[11,2],[22,3],[14,45]],"box":{"x":1378,"y":5103,"w":250,"h":61}},
+{"name":"Fellin","type":"castle","stronghold":2,"walls":4,"vp":1,"region":"Crusader Livonia","ways":[[7,3],[12,3],[15,7],[17,7],[20,37]],"box":{"x":1013,"y":4583,"w":184,"h":61}},
+{"name":"Odenpäh","type":"castle","stronghold":2,"walls":4,"vp":1,"region":"Crusader Livonia","ways":[[7,0,3],[22,0],[11,3],[14,45]],"box":{"x":1378,"y":5103,"w":250,"h":61}},
{"name":"Wenden","type":"castle","stronghold":2,"walls":4,"vp":1,"region":"Crusader Livonia","ways":[[9,8],[10,9],[19,39],[21,40]],"box":{"x":909,"y":5759,"w":232,"h":60}},
{"name":"Kirrumpäh","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[10,44],[12,45],[32,46]],"box":{"x":1877,"y":5389,"w":175,"h":30}},
{"name":"Pernau","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[11,7],[17,7],[8,36]],"box":{"x":517,"y":4580,"w":118,"h":30}},
@@ -25,7 +25,7 @@ locales:[
{"name":"Metsepole","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[20,38],[13,39]],"box":{"x":509,"y":5226,"w":200,"h":100}},
{"name":"Sackala","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[11,37],[19,38]],"box":{"x":617,"y":4769,"w":200,"h":100}},
{"name":"Tolowa","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[13,40],[16,41],[10,43],[18,43]],"box":{"x":1541,"y":5933,"w":200,"h":100}},
-{"name":"Ugaunia","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[7,3],[12,3],[49,47],[32,48]],"box":{"x":1957,"y":4940,"w":200,"h":100}},
+{"name":"Ugaunia","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[7,0],[12,0],[49,47],[32,48]],"box":{"x":1957,"y":4940,"w":200,"h":100}},
{"name":"Waiga","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Crusader Livonia","ways":[[6,29],[7,35]],"box":{"x":1535,"y":4113,"w":200,"h":100}},
{"name":"Novgorod","type":"novgorod","stronghold":3,"walls":3,"vp":3,"region":"Novgorodan Rus","ways":[[27,6],[47,6],[31,23],[41,61],[40,62]],"box":{"x":4318,"y":4315,"w":333,"h":112}},
{"name":"Ladoga","type":"city","stronghold":3,"walls":3,"vp":2,"region":"Novgorodan Rus","ways":[[31,22],[30,24],[44,58]],"box":{"x":4619,"y":2817,"w":238,"h":90}},
@@ -41,7 +41,7 @@ locales:[
{"name":"Porkhov","type":"fort","stronghold":1,"walls":3,"vp":1,"region":"Novgorodan Rus","ways":[[47,16],[37,69],[48,70]],"box":{"x":3515,"y":5467,"w":241,"h":63}},
{"name":"Velikiye Luki","type":"fort","stronghold":1,"walls":3,"vp":1,"region":"Novgorodan Rus","ways":[[28,14],[50,71]],"box":{"x":3706,"y":6347,"w":351,"h":61}},
{"name":"Dubrovno","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[47,15],[26,68],[35,69]],"box":{"x":3153,"y":5214,"w":161,"h":31}},
-{"name":"Gdov","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[2,0],[7,0],[49,0,1],[46,64]],"box":{"x":2427,"y":4149,"w":88,"h":30}},
+{"name":"Gdov","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[49,1,2],[2,2],[7,2],[46,64]],"box":{"x":2427,"y":4149,"w":88,"h":30}},
{"name":"Ostrov","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[26,10],[50,11],[18,49]],"box":{"x":2746,"y":5717,"w":115,"h":30}},
{"name":"Sablia","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[42,20],[24,62],[47,63]],"box":{"x":3788,"y":4541,"w":104,"h":31}},
{"name":"Tesovo","type":"town","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[42,21],[43,60],[24,61]],"box":{"x":3936,"y":4102,"w":121,"h":32}},
@@ -52,16 +52,16 @@ locales:[
{"name":"Plyussa River","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[2,17],[38,64],[42,65],[52,66]],"box":{"x":2829,"y":4234,"w":200,"h":100}},
{"name":"Shelon River","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[24,6],[27,6],[37,15],[35,16],[40,63]],"box":{"x":3654,"y":4864,"w":200,"h":100}},
{"name":"Sorot River","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[50,12],[35,70]],"box":{"x":3299,"y":5781,"w":200,"h":100}},
-{"name":"Uzmen","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[2,0],[7,0],[38,0,1],[26,4],[52,5],[22,47]],"box":{"x":2112,"y":4692,"w":200,"h":100}},
+{"name":"Uzmen","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[38,1,2],[2,2],[7,2],[26,4],[52,5],[22,47]],"box":{"x":2112,"y":4692,"w":200,"h":100}},
{"name":"Velikaya River","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[39,11],[48,12],[36,71]],"box":{"x":3029,"y":6090,"w":200,"h":100}},
{"name":"Vod","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[34,53],[30,54],[43,55]],"box":{"x":3488,"y":3345,"w":200,"h":100}},
{"name":"Zhelcha River","type":"region","stronghold":0,"walls":0,"vp":0,"region":"Novgorodan Rus","ways":[[49,5],[46,66],[26,67]],"box":{"x":2782,"y":4586,"w":200,"h":100}},
],
ways:[
-{"type":"waterway","locales":[2,7,38,49],"name":"Pleipat W"},
-{"type":"waterway","locales":[38,49],"name":"Pleipat E"},
-{"type":"waterway","locales":[7,11,12],"name":"Wirz"},
{"type":"trackway","locales":[7,12,22],"name":"Crossroads"},
+{"type":"waterway","locales":[38,49],"name":"Peipus E"},
+{"type":"waterway","locales":[2,7,38,49],"name":"Peipus W"},
+{"type":"waterway","locales":[7,11,12],"name":"Wirz"},
{"type":"waterway","locales":[26,49]},
{"type":"waterway","locales":[49,52]},
{"type":"waterway","locales":[24,27,47]},
@@ -137,7 +137,7 @@ lords:[
{"side":"Teutonic","name":"Hermann","full_name":"Hermann","title":"Bishop of Dorpat","seats":[7,12],"marshal":1,"fealty":4,"service":4,"lordship":3,"command":3,"forces":{"knights":1,"sergeants":1,"men_at_arms":1,"militia":1},"assets":{"transport":1,"coin":1,"prov":1},"ships":0,"vassals":[5,6,7],"image":2},
{"side":"Teutonic","name":"Knud & Abel","full_name":"Knud & Abel","title":"Princes of Denmark","seats":[0,null],"marshal":0,"fealty":2,"service":3,"lordship":3,"command":2,"forces":{"knights":1,"sergeants":1,"men_at_arms":2,"militia":1},"assets":{"ship":2,"prov":2},"ships":1,"vassals":[8,9,10],"image":3},
{"side":"Teutonic","name":"Rudolf","full_name":"Rudolf von Kassel","title":"Castellan of Wenden","seats":[13],"marshal":0,"fealty":5,"service":2,"lordship":1,"command":3,"forces":{"knights":1,"sergeants":1,"men_at_arms":1},"assets":{"transport":1,"prov":1},"ships":0,"vassals":[11,12,13],"image":4},
-{"side":"Teutonic","name":"Yaroslav","full_name":"Yaroslav","title":"Exile of Pskov","seats":[12,26],"marshal":0,"fealty":4,"service":2,"lordship":1,"command":2,"forces":{"knights":1,"light_horse":1,"men_at_arms":1},"assets":{"transport":1,"prov":1},"ships":0,"vassals":[14],"image":5},
+{"side":"Teutonic","name":"Yaroslav","full_name":"Yaroslav","title":"Exile of Pskov","seats":[12],"marshal":0,"fealty":4,"service":2,"lordship":1,"command":2,"forces":{"knights":1,"light_horse":1,"men_at_arms":1},"assets":{"transport":1,"prov":1},"ships":0,"vassals":[14],"image":5},
{"side":"Russian","name":"Aleksandr","full_name":"Aleksandr","title":"Prince of Novgorod","seats":[24,27],"marshal":2,"fealty":0,"service":6,"lordship":4,"command":3,"forces":{"knights":3,"men_at_arms":2},"assets":{"transport":2},"ships":1,"vassals":[15,16,17,18,19],"image":0},
{"side":"Russian","name":"Andrey","full_name":"Andrey","title":"Prince of Suzdal","seats":[24,27],"marshal":1,"fealty":4,"service":5,"lordship":3,"command":2,"forces":{"knights":3,"men_at_arms":2},"assets":{"transport":2},"ships":1,"vassals":[20,21,22,23],"image":1},
{"side":"Russian","name":"Domash","full_name":"Domash","title":"Tysyatskiy of Novgorod","seats":[24],"marshal":0,"fealty":4,"service":4,"lordship":2,"command":2,"forces":{"sergeants":1,"light_horse":1,"men_at_arms":2,"militia":1},"assets":{"transport":4,"prov":4},"ships":1,"vassals":[24,25,26],"image":2},
diff --git a/play.html b/play.html
index b6ad5fb..2796bf5 100644
--- a/play.html
+++ b/play.html
@@ -584,6 +584,7 @@ body.shift .mustered_vassals {
.locale.action {
border-color: white;
//box-shadow: 0 0 6px white, inset 0 0 6px 0px white;
+ z-index: 50;
}
.locale.region {
diff --git a/play.js b/play.js
index bd7207e..336de04 100644
--- a/play.js
+++ b/play.js
@@ -160,6 +160,10 @@ function is_locale_action(locale) {
return !!(view.actions && view.actions.locale && set_has(view.actions.locale, locale))
}
+function is_way_action(way) {
+ return !!(view.actions && view.actions.way && set_has(view.actions.way, way))
+}
+
function is_card_action(c) {
return !!(view.actions && view.actions.card && set_has(view.actions.card, c))
}
@@ -375,6 +379,7 @@ const ui = {
lord_capabilities: [],
cards: [],
boxes: {},
+ ways: [],
legate: document.getElementById("legate"),
veche: document.getElementById("veche"),
plan_dialog: document.getElementById("plan"),
@@ -438,6 +443,13 @@ function on_focus_locale(evt) {
document.getElementById("status").textContent = `(${id}) ${data.locales[id].name} - ${data.locales[id].type}`
}
+function on_click_way(evt) {
+ if (evt.button === 0) {
+ let id = evt.target.my_id
+ send_action('way', id)
+ }
+}
+
function on_click_cylinder(evt) {
if (evt.button === 0) {
let id = evt.target.my_id
@@ -1110,6 +1122,13 @@ function on_update() {
for (let loc = 0; loc < data.locales.length; ++loc)
update_locale(loc)
+ for (let way = 0; way < ui.ways.length; ++way) {
+ if (is_way_action(way))
+ ui.ways[way].classList.add("action")
+ else
+ ui.ways[way].classList.remove("action")
+ }
+
layout_calendar()
update_legate()
@@ -1247,6 +1266,13 @@ function build_plan() {
ui.plan_actions.appendChild(elt)
}
+function build_way(name, sel) {
+ let way = data.ways.findIndex(w => w.name === name)
+ ui.ways[way] = document.querySelector(sel)
+ ui.ways[way].my_id = way
+ ui.ways[way].addEventListener("mousedown", on_click_way)
+}
+
function build_map() {
data.locales.forEach((locale, ix) => {
let e = ui.locale[ix] = document.createElement("div")
@@ -1263,7 +1289,7 @@ function build_map() {
w += 16
h += 5
} else if (locale.type === 'region') {
- locale_xy[ix] = [ round(x + w / 2), round(y + h / 2) ]
+ locale_xy[ix] = [ round(x + w / 2), round(y + h / 2) - 32 ]
x -= 3
y -= 4
} else {
@@ -1359,6 +1385,11 @@ function build_map() {
document.getElementById("boxes").appendChild(e)
}
+ build_way("Crossroads", ".way.crossroads")
+ build_way("Peipus E", ".way.peipus-east")
+ build_way("Peipus W", ".way.peipus-north")
+ build_way("Wirz", ".way.wirz")
+
build_plan()
for (let c = 0; c < 21; ++c)
diff --git a/rules.js b/rules.js
index 7f8c055..72c97cc 100644
--- a/rules.js
+++ b/rules.js
@@ -657,7 +657,7 @@ function remove_siege_marker(loc) {
}
function remove_all_siege_markers(loc) {
- map_delete(game.locales.siege, loc)
+ map_delete(game.locales.sieges, loc)
}
function has_enemy_castle(loc) {
@@ -1936,8 +1936,145 @@ function can_action_march() {
function do_action_march() {
push_undo()
+ game.state = 'march'
+}
+
+function get_road(from, to) {
+ for (let road of data.locales[from].ways)
+ if (road[0] === to)
+ return road
+ return null
+}
+
+function has_two_ways(from, to) {
+ return get_road(from, to).length > 2
+}
+
+states.march = {
+ prompt() {
+ view.prompt = `March: Select destination.`
+
+ // TODO: Group March & lieutenants
+
+ let from = get_lord_locale(game.who)
+ for (let [to] of data.locales[from].ways)
+ gen_action_locale(to)
+ },
+ locale(to) {
+ push_undo()
+ let from = get_lord_locale(game.who)
+ let road = get_road(from, to)
+ if (road.length > 2) {
+ game.state = 'march_way'
+ game.where = to
+ } else {
+ march_lord(game.who, road[1], to)
+ }
+ },
+}
+
+states.march_way = {
+ prompt() {
+ view.prompt = `March: Select way.`
+
+ let from = get_lord_locale(game.who)
+ let to = game.where
+
+ let road = get_road(from, to)
+ for (let i = 1; i < road.length; ++i)
+ gen_action_way(road[i])
+ },
+ way(way) {
+ let from = get_lord_locale(game.who)
+ let to = game.where
+ game.where = NOWHERE
+ march_lord(game.who, way, to)
+ },
+}
+
+function march_lord(lord, way, to) {
+ // TODO: laden/unladen discard prov and loot
+ // game.state = 'march_laden'
+
+ let from = get_lord_locale(game.who)
+
+ if (data.ways[way].name)
+ log(`Marched via ${data.ways[way].name} to %${to}.`)
+ else
+ log(`Marched to %${to}.`)
+
+ if (is_trade_route(to))
+ conquer_trade_route(to)
+
+ if (is_unbesieged_enemy_stronghold(to))
+ add_siege_marker(to)
+
+ set_lord_locale(game.who, to)
set_lord_moved(game.who, 1)
- ++game.count
+
+ if (is_enemy_stronghold(from))
+ remove_all_siege_markers(from)
+
+ // TODO: lift siege
+ // TODO: stop and siege
+ // TODO: approach
+
+ game.count += 1
+ game.state = "actions"
+}
+
+states.march_laden = {
+ prompt() {
+ let from = get_lord_locale(game.who)
+ let prov = get_lord_assets(game.who, PROV)
+ let loot = get_lord_assets(game.who, LOOT)
+ let carts = get_lord_assets(game.who, CART)
+ let sleds = get_lord_assets(game.who, SLED)
+ let boats = get_lord_assets(game.who, BOAT)
+
+ // TODO: Group March & lieutenants
+
+ let laden = 0 // 0=unladen, 1=laden, 2=immobile
+
+ view.prompt = `March`
+
+ console.log(USABLE_TRANSPORT[current_season()])
+
+ if (laden > 0) {
+ if (loot > 0)
+ gen_action_loot(game.who)
+ if (prov > 0)
+ gen_action_prov(game.who)
+ }
+
+ if (laden === 0 || (laden === 1 && get_available_actions() >= 2)) {
+ }
+
+ },
+ prov(lord) {
+ push_undo()
+ drop_prov(lord)
+ },
+ loot(lord) {
+ push_undo()
+ drop_loot(lord)
+ },
+ locale(loc) {
+ push_undo()
+ log(`Sailed to %${loc}.`)
+
+ if (is_trade_route(loc))
+ conquer_trade_route(loc)
+
+ if (is_unbesieged_enemy_stronghold(loc))
+ add_siege_marker(loc)
+
+ set_lord_locale(game.who, loc)
+ set_lord_moved(game.who, 1)
+
+ use_all_actions()
+ game.state = "actions"
+ },
}
// === ACTION: SIEGE ===
@@ -2051,7 +2188,7 @@ states.tax = {
gen_action_locale(here)
},
locale(loc) {
- log(`Taxed at %${loc}`)
+ log(`Taxed %${loc}.`)
add_lord_assets(game.who, COIN, 1)
use_all_actions()
game.state = "actions"
@@ -2619,6 +2756,10 @@ function gen_action(action, argument) {
set_add(view.actions[action], argument)
}
+function gen_action_way(way) {
+ gen_action("way", way)
+}
+
function gen_action_locale(locale) {
gen_action("locale", locale)
}
diff --git a/tools/gendata.js b/tools/gendata.js
index 4d024a6..a003550 100644
--- a/tools/gendata.js
+++ b/tools/gendata.js
@@ -211,10 +211,10 @@ defloc("Novgorodan Rus", 0, "region", "Velikaya River")
defloc("Novgorodan Rus", 0, "region", "Vod")
defloc("Novgorodan Rus", 0, "region", "Zhelcha River")
-waterway("Dorpat, Narwia, Gdov, Uzmen").name = "Pleipat W"
-waterway("Gdov, Uzmen").name = "Pleipat E"
-waterway("Fellin, Dorpat, Odenpäh").name = "Wirz"
trackway("Dorpat, Odenpäh, Ugaunia").name = "Crossroads"
+waterway("Gdov, Uzmen").name = "Peipus E"
+waterway("Dorpat, Narwia, Gdov, Uzmen").name = "Peipus W"
+waterway("Fellin, Dorpat, Odenpäh").name = "Wirz"
waterway("Uzmen, Pskov")
waterway("Uzmen, Zhelcha River")