diff options
-rw-r--r-- | data.js | 22 | ||||
-rw-r--r-- | play.html | 1 | ||||
-rw-r--r-- | play.js | 33 | ||||
-rw-r--r-- | rules.js | 147 | ||||
-rw-r--r-- | tools/gendata.js | 6 |
5 files changed, 191 insertions, 18 deletions
@@ -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}, @@ -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 { @@ -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) @@ -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") |