summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-06-18 14:31:32 +0200
committerTor Andersson <tor@ccxvii.net>2023-07-07 18:39:33 +0200
commit19fd5d79b8e58b6806bb711c2c53054f73b2a282 (patch)
treeb07ef2e730182b16dcf63a87b6a6f9369bb521fb
parent495090873cf62a1ca698cee18a2d292fc30aa292 (diff)
downloadtime-of-crisis-19fd5d79b8e58b6806bb711c2c53054f73b2a282.tar.gz
Lots of stuff.
-rw-r--r--play.css37
-rw-r--r--play.js15
-rw-r--r--rules.js724
3 files changed, 551 insertions, 225 deletions
diff --git a/play.css b/play.css
index 49885b1..a733f7f 100644
--- a/play.css
+++ b/play.css
@@ -53,6 +53,8 @@ body.p3 #crisis_table {
background-image: url(overlay_3p_75.jpg);
}
+body.Solo #.role { display: none }
+
svg {
position: absolute;
}
@@ -65,17 +67,23 @@ svg .region, svg .sea {
svg .region.action {
fill: gold;
- fill-opacity: 0.2;
+ fill-opacity: 0.1;
stroke: yellow;
+ stroke-opacity: 0.5;
+ stroke-width: 3px;
+}
+
+svg .region.selected {
+ stroke: gold;
stroke-opacity: 0.8;
stroke-width: 3px;
}
svg .sea.action {
- fill: blue;
- fill-opacity: 0.2;
- stroke: blue;
- stroke-opacity: 0.8;
+ fill: dodgerblue;
+ fill-opacity: 0.1;
+ stroke: dodgerblue;
+ stroke-opacity: 0.5;
stroke-width: 3px;
}
@@ -149,17 +157,6 @@ body.p2 #Aegyptus_NPG { display: block }
body.p2 #Syria_NPG { display: block }
body.p2 #Galatia_NPG { display: block }
-body.p3 #Hispania_Governor { display: none }
-body.p3 #Africa_Governor { display: none }
-body.p3 #Aegyptus_Governor { display: none }
-
-body.p2 #Britannia_Governor { display: none }
-body.p2 #Hispania_Governor { display: none }
-body.p2 #Africa_Governor { display: none }
-body.p2 #Aegyptus_Governor { display: none }
-body.p2 #Syria_Governor { display: none }
-body.p2 #Galatia_Governor { display: none }
-
/* COUNTERS */
.amphitheater, .basilica, .limes { background-color: #efebea; }
@@ -199,6 +196,14 @@ body.p2 #Galatia_Governor { display: none }
.yellow.action { box-shadow: 0 0 0 1px #553a00, 0 0 0 4px white; }
.green.action { box-shadow: 0 0 0 1px #033600, 0 0 0 4px white; }
+.selected { box-shadow: 0 0 0 3px black, 0 0 4px 6px white }
+.selected { box-shadow: 0 0 0 4px black }
+
+.red.selected { box-shadow: 0 0 0 1px #680000, 0 0 0 4px yellow; }
+.blue.selected { box-shadow: 0 0 0 1px #113854, 0 0 0 4px red; }
+.yellow.selected { box-shadow: 0 0 0 1px #553a00, 0 0 0 4px red; }
+.green.selected { box-shadow: 0 0 0 1px #033600, 0 0 0 4px yellow; }
+
#legion_0 { background-position: 0px 0px }
#legion_1 { background-position: -55px 0px }
#legion_2 { background-position: -110px 0px }
diff --git a/play.js b/play.js
index 6a08084..d030f1f 100644
--- a/play.js
+++ b/play.js
@@ -509,7 +509,6 @@ function on_update() {
stack_cache = {}
- ui.body.classList.toggle("p1", view.solo === 1)
ui.body.classList.toggle("p2", player_count === 2)
ui.body.classList.toggle("p3", player_count === 3)
ui.body.classList.toggle("p4", player_count === 4)
@@ -657,6 +656,10 @@ function on_update() {
}
}
+ for (let region = 0; region < 21; ++region) {
+ ui.regions[region].classList.toggle("selected", view.selected_region === region)
+ }
+
for (let region = 0; region < 12; ++region) {
if (has_militia(region)) {
let lone_militia = true
@@ -738,6 +741,7 @@ function on_update() {
avail_stack.push(e)
}
e.classList.toggle("unavailable", region === UNAVAILABLE)
+ e.classList.toggle("selected", view.selected_general === pi * 6 + ai)
}
layout_available(avail_stack, 63, pi * 625 + 0, 30)
}
@@ -748,7 +752,7 @@ function on_update() {
let id = 100 + 100 * pi + ai
let region = get_governor_location(first_governor[pi] + ai)
let e = ui.governors[pi][ai]
- if (region >= 1 && region < 12) {
+ if (region < 12) {
layout_governor(e, PLAYER_CLASS[pi], region)
} else {
if (region === AVAILABLE)
@@ -758,6 +762,7 @@ function on_update() {
avail_stack.push(e)
}
e.classList.toggle("unavailable", region === UNAVAILABLE)
+ e.classList.toggle("selected", view.selected_governor === pi * 6 + ai)
}
layout_available(avail_stack, 58, pi * 625 + 325, 27)
}
@@ -797,9 +802,9 @@ function on_update() {
}
ui.market.replaceChildren()
- for (let pile of view.market) {
- if (pile.length > 0)
- ui.market.appendChild(ui.cards[pile[0]])
+ for (let c of view.market) {
+ if (c > 0)
+ ui.market.appendChild(ui.cards[c])
}
for (let e of action_register)
diff --git a/rules.js b/rules.js
index da23666..af4bf3e 100644
--- a/rules.js
+++ b/rules.js
@@ -1,5 +1,7 @@
"use strict"
+// TODO: barbarian leaders -> barbarian list
+
var game
var view
const states = {}
@@ -269,6 +271,22 @@ function card_name(c) {
return "??"
}
+function card_cost(c) {
+ if (c >= CARD_M1[0] && c <= CARD_M1[1]) return 1
+ if (c >= CARD_M2[0] && c <= CARD_M2[1]) return 2
+ if (c >= CARD_M3[0] && c <= CARD_M3[1]) return 3
+ if (c >= CARD_M4[0] && c <= CARD_M4[1]) return 4
+ if (c >= CARD_S1[0] && c <= CARD_S1[1]) return 1
+ if (c >= CARD_S2[0] && c <= CARD_S2[1]) return 2
+ if (c >= CARD_S3[0] && c <= CARD_S3[1]) return 3
+ if (c >= CARD_S4[0] && c <= CARD_S4[1]) return 4
+ if (c >= CARD_P1[0] && c <= CARD_P1[1]) return 1
+ if (c >= CARD_P2[0] && c <= CARD_P2[1]) return 2
+ if (c >= CARD_P3[0] && c <= CARD_P3[1]) return 3
+ if (c >= CARD_P4[0] && c <= CARD_P4[1]) return 4
+ return "??"
+}
+
function card_event_name(c) {
if (c >= CARD_M1[0] && c <= CARD_M1[1]) return "None"
if (c >= CARD_M2[0] && c <= CARD_M2[1]) return "Castra"
@@ -368,7 +386,7 @@ function add_militia(province) { game.militia |= (1 << province) }
function remove_militia(province) { game.militia &= ~(1 << province) }
function has_mob(province) { return game.mobs[province] > 0 }
-function get_mobs(province) { return game.mobs[province] }
+function count_mobs(province) { return game.mobs[province] }
function add_one_mob(province) { game.mobs[province] ++ }
function remove_one_mob(province) { game.mobs[province] -- }
function remove_all_mobs(province) { game.mobs[province] = 0 }
@@ -441,20 +459,30 @@ function find_governor(f) {
return -1
}
-function some_general(f) {
- let n = game.legacy.length * 6
+function for_each_barbarian(f) {
+ let n = game.barbarians.length
for (let id = 0; id < n; ++id)
- if (f(id, get_general_location(id), is_general_inside_capital(id)))
- return true
- return false
+ f(id, get_barbarian_location(id), is_barbarian_inactive(id))
}
-function some_governor(f) {
- let n = game.legacy.length * 6
+function find_barbarian(f) {
+ let n = game.barbarians.length
for (let id = 0; id < n; ++id)
- if (f(id, get_governor_location(id)))
- return true
- return false
+ if (f(id, get_barbarian_location(id), is_barbarian_active(id)))
+ return id
+ return -1
+}
+
+function some_governor(f) {
+ return find_governor(f) >= 0
+}
+
+function some_general(f) {
+ return find_general(f) >= 0
+}
+
+function some_barbarian(f) {
+ return find_barbarian(f) >= 0
}
function next_player() {
@@ -480,7 +508,7 @@ function can_build_improvement(province) {
return true
}
-function update_italia_support() {
+function update_neutral_italia() {
if (is_neutral_province(ITALIA)) {
let n = 1
for (let s = 1; s < 12; ++s)
@@ -507,13 +535,35 @@ function can_enter_capital(where) {
// Occupied by opponent Militia
if (has_militia(where)) {
- if (!is_province_you_govern(where))
+ if (!is_own_province(where))
return false
}
return true
}
+function is_own_general(id) {
+ let a = game.current * 6
+ return id >= a && id < a + 6
+}
+
+function is_enemy_general(id) {
+ return id >= 0 && !is_own_general(id)
+}
+
+function is_own_governor(id) {
+ let a = game.current * 6
+ return id >= a && id < a + 6
+}
+
+function is_enemy_governor(id) {
+ return id >= 0 && !is_own_governor(id)
+}
+
+function is_capital_free_of_enemy(where) {
+ return is_enemy_general(get_capital_general(where))
+}
+
function get_province_governor(where) {
return find_governor((id, loc) => loc === where)
}
@@ -528,24 +578,53 @@ function is_neutral_province(where) {
return get_province_governor(where) < 0
}
-function is_province_you_govern(where) {
- let a = game.current * 6
- let id = get_province_governor(where)
- if (id >= a && id < a + 6)
+function has_active_barbarians(where) {
+ if (has_barbarian_leader(where))
return true
- return false
+ return some_barbarian((id, loc, active) => loc === where && active)
}
-function has_active_barbarians(where) {
- return false // TODO
+function has_barbarian_leader(where) {
+ for (let i = 0; i < 3; ++i)
+ if (game.barbarian_leaders[i] === where)
+ return true
+ return false
}
function has_rival_emperor(where) {
- return false // TODO
+ for (let i = 0; i < 3; ++i)
+ if (game.rival_emperors[i] === where)
+ return true
+ return false
+}
+
+function is_enemy_province(where) {
+ return is_enemy_governor(get_province_governor(where))
+}
+
+function is_own_province(where) {
+ return is_own_governor(get_province_governor(where))
+}
+
+function is_emperor(governor) {
+ let emperor = get_province_governor(ITALIA)
+ if (emperor >= 0 && governor >= 0)
+ return (emperor / 6 | 0) === (governor / 6 | 0)
+ return false
}
function has_enemy_army_in_capital(where) {
- return false // TODO
+ if (is_enemy_general(get_capital_general(where)))
+ return true
+ if (has_militia(where) && is_enemy_governor(get_province_governor(where)))
+ return true
+ return false
+}
+
+function has_enemy_army_in_province(where) {
+ if (some_general((id, loc) => loc === where && is_enemy_general(id)))
+ return true
+ return false
}
function spend_ip(type, n) {
@@ -553,7 +632,7 @@ function spend_ip(type, n) {
}
function can_place_governor(where) {
- if (is_province_you_govern(where))
+ if (is_own_province(where))
return false
// Recalled or already attempted to place.
if (has_placed_governor(where))
@@ -564,7 +643,7 @@ function can_place_governor(where) {
return true
}
-function find_active_barbarian(tribe) {
+function find_active_barbarian_at_home(tribe) {
let home = BARBARIAN_HOMELAND[tribe]
for (let i = 0; i < 10; ++i)
if (get_barbarian_location(tribe * 10 + i) === home)
@@ -606,7 +685,6 @@ function count_barbarians_in_province(tribe, where) {
return n
}
-
function count_legions_in_army(id) {
let n = 0
for (let i = 0; i < LEGION_COUNT; ++i)
@@ -637,6 +715,22 @@ function count_units_in_army(id) {
return n
}
+function count_own_provinces() {
+ let n = 0
+ for (let where = 0; where < 12; ++where)
+ if (is_own_province(where))
+ ++n
+ return n
+}
+
+function count_own_basilicas() {
+ let n = 0
+ for (let where = 0; where < 12; ++where)
+ if (is_own_province(where) && has_basilica(where))
+ ++n
+ return n
+}
+
function roll_dice(count, target) {
let hits = 0
console.log("roll_dice", count, target)
@@ -717,6 +811,24 @@ function goto_start_turn() {
}
function goto_upkeep() {
+ // TODO: manually remove Quaestor and Castra?
+ for (let i = 0; i < 6; ++i) {
+ let id = game.current * 6 + i
+ let where = get_governor_location(id)
+ if (is_province(where) && has_quaestor(where)) {
+ log("Removed Quaestor from S" + where)
+ remove_quaestor(where)
+ }
+ if (has_militia_castra(where)) {
+ log("Removed Castra from S" + where)
+ remove_militia_castra(where)
+ }
+ if (has_general_castra(id)) {
+ log("Removed Castra from S" + get_general_location(id))
+ remove_general_castra(id)
+ }
+ }
+
goto_crisis()
}
@@ -732,6 +844,8 @@ function goto_crisis() {
let sum = game.dice[0] + game.dice[1]
+ return goto_take_actions() // XXX
+
if (sum === 2)
return goto_ira_deorum()
if (sum === 12)
@@ -787,7 +901,7 @@ function goto_barbarian_crisis(tribe) {
function invade_with_active_barbarian(tribe, where) {
// TODO: move leaders first
- let b = find_active_barbarian(tribe)
+ let b = find_active_barbarian_at_home(tribe)
if (b >= 0)
set_barbarian_location(tribe * 10 + b, where)
}
@@ -829,9 +943,52 @@ function prompt(s) {
view.prompt = s
}
-function prompt_take_actions(label) {
+function prompt_take_actions(label, sel_gov, sel_gen) {
let [ mip, sip, pip ] = game.ip
+
prompt(`${label}: ${mip} Military, ${sip} Senate, ${pip} Populace.`)
+
+ if (sel_gov >= 0)
+ view.selected_governor = sel_gov
+ if (sel_gen >= 0)
+ view.selected_general = sel_gen
+
+ for (let c of current_hand())
+ gen_action_card(c)
+
+ for (let i = 0; i < 6; ++i) {
+ let id = game.current * 6 + i
+ if (id !== sel_gov) {
+ let where = get_governor_location(id)
+ if ((where === UNAVAILABLE) && (sip >= i))
+ gen_action_governor(id)
+ if ((where === AVAILABLE) && (sip >= 1))
+ gen_action_governor(id)
+ if (is_region(where) && (sip >= 2 || pip >= 2))
+ gen_action_governor(id)
+ }
+ }
+
+ for (let i = 0; i < 6; ++i) {
+ let id = game.current * 6 + i
+ if (id !== sel_gen) {
+ let where = get_general_location(id)
+ if (where === UNAVAILABLE && mip >= i)
+ gen_action_general(id)
+ if (where === AVAILABLE && mip >= 1)
+ gen_action_general(id)
+ if (is_region(where)) {
+ if (mip >= 1)
+ gen_action_general(id)
+ else if (is_province(where)) {
+ if (is_general_inside_capital(id) || can_enter_capital(where))
+ gen_action_general(id)
+ }
+ }
+ }
+ }
+
+ view.actions.end_actions = 1
}
function action_take_actions_card(c) {
@@ -843,11 +1000,23 @@ function action_take_actions_card(c) {
add_card_ip(c)
} else if (set_has(game.played, c)) {
log("TODO - use event")
- set_remove(game.played, c)
+ set_delete(game.played, c)
set_add(current_discard(), c)
}
}
+function action_take_actions_governor(id) {
+ push_undo()
+ game.who = id
+ game.state = "take_actions_governor"
+}
+
+function action_take_actions_general(id) {
+ push_undo()
+ game.who = id
+ game.state = "take_actions_general"
+}
+
function action_take_actions_end_actions() {
push_undo()
goto_support_check()
@@ -857,85 +1026,21 @@ states.take_actions = {
prompt() {
let player = game.current
let [ mip, sip, pip ] = game.ip
-
- prompt_take_actions("Take Actions")
- for (let c of current_hand())
- gen_action_card(c)
-
- for (let i = 0; i < 6; ++i) {
- let id = game.current * 6 + i
- let where = get_governor_location(id)
- if ((where === UNAVAILABLE) && (sip >= i))
- gen_action_governor(id)
- if ((where === AVAILABLE) && (sip >= 1))
- gen_action_governor(id)
- if (is_region(where) && (sip >= 1 || pip >= 1))
- gen_action_governor(id)
- }
-
- for (let i = 0; i < 6; ++i) {
- let id = game.current * 6 + i
- let where = get_general_location(id)
- if ((where === UNAVAILABLE) && (mip >= i))
- gen_action_general(id)
- if ((where === AVAILABLE) && (mip >= 1))
- gen_action_general(id)
- // if (is_region(where) && (mip >= 1))
- if (is_region(where) && (mip >= 1 || where <= 12))
- gen_action_general(id)
- }
-
- view.actions.end_actions = 1
+ prompt_take_actions("Take Actions", -1, -1)
},
- card: action_take_actions_card,
end_actions: action_take_actions_end_actions,
- governor(id) {
- push_undo()
- let where = get_governor_location(id)
- if (where === UNAVAILABLE) {
- spend_ip(SENATE, id % 6)
- set_governor_location(id, AVAILABLE)
- }
- else if (where === AVAILABLE) {
- game.who = id
- spend_ip(SENATE, 1)
- game.state = "place_governor_where"
- game.misc = { spend: 1, where: -1 }
- }
- else {
- game.who = id
- game.state = "take_actions_governor"
- }
- },
- general(id) {
- push_undo()
- let where = get_general_location(id)
- if (where === UNAVAILABLE) {
- spend_ip(MILITARY, id % 6)
- set_general_location(id, AVAILABLE)
- }
- else if (where === AVAILABLE) {
- spend_ip(MILITARY, 1)
- game.who = id
- game.state = "create_army"
- }
- else {
- game.who = id
- game.state = "take_actions_general"
- }
- },
+ card: action_take_actions_card,
+ governor: action_take_actions_governor,
+ general: action_take_actions_general,
}
states.take_actions_governor = {
prompt() {
let [ mip, sip, pip ] = game.ip
- let governor = game.who
+
let where = get_governor_location(game.who)
- prompt_take_actions("Take Governor Actions")
- for (let c of current_hand())
- gen_action_card(c)
- view.actions.done = 1
+ prompt_take_actions("Take Governor Actions", game.who, -1)
// Recruit Governor
if (where === UNAVAILABLE) {
@@ -949,21 +1054,20 @@ states.take_actions_governor = {
view.actions.place = 1
}
- if (where >= 0) {
+ if (is_province(where)) {
// Recall Governor
if (sip >= 2)
view.actions.recall = 1
// Increase Support Level
let support = game.support[where]
- if (support < 4 && where !== ITALIA) {
+ if (where !== ITALIA && support < 4) {
if (pip > support)
view.actions.support = 1
-
}
// Place Militia
- if (!has_militia(where)) {
+ if (!has_militia(where) && is_capital_free_of_enemy(where)) {
if (pip >= 2)
view.actions.militia = 1
}
@@ -982,14 +1086,19 @@ states.take_actions_governor = {
}
// TODO: Initiate Battle with Militia not stacked with General
+ if (has_militia(where) && !is_own_general(get_capital_general(where))) {
+ if (has_enemy_army_in_province(where))
+ if (mip >= 1)
+ view.actions.initiate_battle = 1
+ }
}
},
- card: action_take_actions_card,
+
end_actions: action_take_actions_end_actions,
- governor(id) {
- push_undo()
- game.state = "take_actions"
- },
+ card: action_take_actions_card,
+ governor: action_take_actions_governor,
+ general: action_take_actions_general,
+
recruit() {
push_undo()
log("Recruited Governor " + (game.who % 6) + ".")
@@ -999,7 +1108,7 @@ states.take_actions_governor = {
place() {
push_undo()
spend_ip(SENATE, 1)
- game.state = "place_governor"
+ game.state = "place_governor_where"
game.misc = { spend: 1 }
},
recall() {
@@ -1007,10 +1116,9 @@ states.take_actions_governor = {
let where = get_governor_location(game.who)
log("Recalled Governor from S" + where + ".")
spend_ip(SENATE, 2)
- set_governor_location(game.who, AVAILABLE)
- set_support(where, 1)
set_placed_governor(where)
- update_italia_support()
+ remove_governor(where)
+ update_neutral_italia()
},
support() {
push_undo()
@@ -1032,9 +1140,10 @@ states.take_actions_governor = {
game.state = "build_improvement"
spend_ip(POPULACE, 3)
},
- done() {
+ initiate_battle() {
push_undo()
- game.state = "take_actions"
+ game.state = "initiate_battle"
+ game.misc = { attacker: -1, where: get_governor_location(game.who) }
},
}
@@ -1043,12 +1152,7 @@ states.take_actions_general = {
let [ mip, sip, pip ] = game.ip
let where = get_general_location(game.who)
- prompt_take_actions("Take General Actions")
- for (let c of current_hand())
- gen_action_card(c)
- view.actions.done = 1
-
- gen_action_general(game.who)
+ prompt_take_actions("Take General Actions", -1, game.who)
// Recruit General
if (where === UNAVAILABLE) {
@@ -1062,9 +1166,9 @@ states.take_actions_general = {
view.actions.create_army = 1
}
- if (where >= 0) {
+ if (is_region(where)) {
// Add Legion to Army
- if (is_province_you_govern(where)) {
+ if (is_own_province(where)) {
let cost = count_legions_in_army(game.who) + 1
if (mip >= cost)
view.actions.add_legion_to_army = 1
@@ -1087,62 +1191,70 @@ states.take_actions_general = {
if (mip >= 1) {
for (let to of ADJACENT[where]) {
if (!is_sea(to))
- gen_action_region(to)
+ gen_move_to_region(to)
else if (mip >= 2)
- gen_action_region(to)
+ gen_move_to_region(to)
}
}
// Initiate Battle
+ if (has_enemy_army_in_province(where))
+ if (mip >= 1)
+ view.actions.initiate_battle = 1
- // Free Action: Enter/Leave capital
- if (where < 12) {
- if (is_general_inside_capital(game.who))
+ // Free Action: Enter/Leave Capital
+ if (is_province(where)) {
+ if (is_general_inside_capital(game.who)) {
view.actions.leave = 1
- else if (can_enter_capital(where))
+ } else if (can_enter_capital(where)) {
view.actions.enter = 1
+ gen_action_capital(where)
+ }
}
}
}
},
- card: action_take_actions_card,
+
end_actions: action_take_actions_end_actions,
- general(id) {
+ card: action_take_actions_card,
+ governor: action_take_actions_governor,
+ general: action_take_actions_general,
+
+ recruit() {
push_undo()
- game.state = "take_actions"
+ log("Recruited General " + (game.who % 6) + ".")
+ spend_ip(MILITARY, game.who % 6)
+ set_general_location(game.who, AVAILABLE)
},
- recruit() {
+ create_army() {
push_undo()
- let general = game.who
- log("Recruited General " + general + ".")
- spend_ip(MILITARY, general)
- set_piece_location(game.who, AVAILABLE)
+ spend_ip(MILITARY, 1)
+ game.state = "create_army"
},
add_legion_to_army() {
push_undo()
- let general = game.who
- let cost = count_legions_in_army(game.who) + 1
log("Added Legion to Army.")
+ let cost = count_legions_in_army(game.who) + 1
spend_ip(MILITARY, cost)
set_legion_location(find_unused_legion(), ARMY + game.who)
},
train_legions() {
push_undo()
- let general = game.who
- let i = find_reduced_legion_in_army(game.who)
log("Trained Legions.")
spend_ip(MILITARY, 1)
- set_legion_full_strength(i)
+ set_legion_full_strength(find_reduced_legion_in_army(game.who))
},
- create_army() {
+ region(to) {
push_undo()
- spend_ip(MILITARY, 1)
- game.state = "create_army"
+ move_army_to(game.who, to, false)
},
- region(to) {
+ capital(to) {
push_undo()
- move_army_to(game.who, to)
+ if (get_general_location(game.who) === to)
+ set_general_inside_capital(game.who)
+ else
+ move_army_to(game.who, to, true)
},
enter() {
push_undo()
@@ -1152,71 +1264,108 @@ states.take_actions_general = {
push_undo()
set_general_outside_capital(game.who)
},
- capital() {
- this.enter()
- },
- done() {
+ initiate_battle() {
push_undo()
- game.state = "take_actions"
+ game.state = "initiate_battle"
+ game.misc = { attacker: game.who, where: get_general_location(game.who) }
},
}
-states.place_governor_where = {
- prompt() {
- prompt("Place Governor.")
- for (let where = 0; where < 12; ++where) {
- if (can_place_governor(where))
- gen_action_region(where)
- }
- },
- region(where) {
- push_undo()
- game.misc.where = where
- game.state = "place_governor_spend"
- },
+// ACTION: PLACE GOVERNOR
+
+function reduce_support(where) {
+ if (game.support[where] === 1)
+ remove_governor(where)
+ else
+ game.support[where] -= 1
}
-// ACTION: PLACE GOVERNOR
+function increase_support(where) {
+ game.support[where] += 1
+}
-function place_governor(new_governor, where) {
- let support = get_support(where)
- let new_support = Math.max(1, support - 1)
+function remove_governor(where) {
+ log("Removed Governor from S" + where)
- // TODO: Italia support
+ remove_all_mobs(where)
let old_governor = get_province_governor(where)
- if (old_governor >= 0)
+ if (old_governor >= 0) {
+ set_governor_location(old_governor, AVAILABLE)
+ if (where !== ITALIA && is_emperor(old_governor))
+ reduce_support(ITALIA)
+ }
+
+ if (where !== ITALIA)
+ game.support[where] = 1
+
+ update_neutral_italia()
+}
+
+function place_governor(where, new_governor) {
+ remove_all_mobs(where)
+
+ let old_governor = get_province_governor(where)
+ if (old_governor >= 0) {
set_governor_location(old_governor, AVAILABLE)
+ if (where !== ITALIA && is_emperor(old_governor))
+ reduce_support(ITALIA)
+ }
set_governor_location(new_governor, where)
- set_support(where, new_support)
+ if (where === ITALIA)
+ game.support[where] = count_own_provinces()
+ else
+ game.support[where] = Math.max(1, game.support[where] - 1)
+
+ if (where !== ITALIA && is_emperor(new_governor))
+ increase_support(ITALIA)
+
+ update_neutral_italia()
}
function calc_needed_votes(where) {
let n = get_support(where) * 2 // base number of votes
let old_governor = get_province_governor(where)
- if (old_governor >= 0) {
- let old_player = old_governor / 6 | 0
- let army_general = get_capital_general(where)
- if (army_general >= 0) {
- let army_player = army_general / 6 | 0
- let army_size = count_units_in_army(army_general)
- if (army_player === old_player)
- n += army_size
- else if (army_player === game.current)
- n -= army_size
- }
- if (has_militia(where))
- n += 1
+ let old_player = (old_governor < 0) ? -1 : (old_governor / 6 | 0)
+ let army_general = get_capital_general(where)
+ if (army_general >= 0) {
+ let army_player = army_general / 6 | 0
+ let army_size = count_units_in_army(army_general)
+ console.log("VOTES", old_player, army_player, game.current)
+ if (army_player === old_player)
+ n += army_size
+ else if (army_player === game.current)
+ n -= army_size
}
+ if (has_militia(where))
+ n += 1
console.log("votes needed", where, n)
return Math.max(1, n)
}
+states.place_governor_where = {
+ prompt() {
+ prompt("Place Governor.")
+ view.selected_governor = game.who
+ for (let where = 0; where < 12; ++where) {
+ if (can_place_governor(where))
+ gen_action_region(where)
+ }
+ },
+ region(where) {
+ push_undo()
+ game.misc.where = where
+ game.state = "place_governor_spend"
+ },
+}
+
states.place_governor_spend = {
prompt() {
let [ mip, sip, pip ] = game.ip
let need = calc_needed_votes(game.misc.where)
+ view.selected_governor = game.who
+ view.selected_region = game.misc.where
prompt("Place Governor: " + game.misc.spend + " IP spent; " + need + " votes needed.")
if (sip >= 1)
view.actions.spend = 1
@@ -1235,6 +1384,9 @@ states.place_governor_spend = {
set_placed_governor(game.misc.where)
+ if (game.misc.where === ITALIA)
+ game.misc.spend += count_own_basilicas()
+
log("Place Governor in S" + game.misc.where)
if (is_neutral_province(game.misc.where))
have = roll_dice(game.misc.spend, 1)
@@ -1243,11 +1395,15 @@ states.place_governor_spend = {
else
have = roll_dice(game.misc.spend, 2)
- if (have >= need)
- place_governor(game.who, game.misc.where)
+ if (have >= need) {
+ logi("Success!")
+ place_governor(game.misc.where, game.who)
+ } else {
+ logi("Failed!")
+ }
game.misc = null
- game.state = "take_actions"
+ game.state = "take_actions_governor"
},
}
@@ -1256,6 +1412,7 @@ states.place_governor_spend = {
states.build_improvement = {
prompt() {
let where = get_governor_location(game.who)
+ view.selected_governor = game.who
prompt("Build Improvement.")
if (!has_amphitheater(where))
view.actions.amphitheater = 1
@@ -1308,41 +1465,81 @@ states.create_army = {
// ACTION: MOVE ARMY
+function gen_move_to_region(to) {
+ if (is_province(to) && can_enter_capital(to))
+ gen_action_capital(to)
+ gen_action_region(to)
+}
+
states.move_army_at_sea = {
prompt() {
- prompt("Move Army.")
let [ mip, sip, pip ] = game.ip
- let who = view.who = game.who
- let from = get_piece_location(who)
+ prompt("Move Army.")
+ view.selected_general = game.who
+ let from = get_general_location(game.who)
for (let to of ADJACENT[from]) {
if (is_sea(to)) {
if (mip >= 2)
- gen_action_region(to)
+ gen_move_to_region(to)
} else {
- gen_action_region(to)
+ gen_move_to_region(to)
}
}
},
region(to) {
push_undo()
- move_army_to(game.who, to)
+ move_army_to(game.who, to, false)
+ },
+ capital(to) {
+ push_undo()
+ move_army_to(game.who, to, true)
},
}
-function move_army_to(who, to) {
+function move_army_to(who, to, go_inside) {
log("Moved Army to S" + to + ".")
spend_ip(MILITARY, 1)
set_general_location(who, to)
- if (can_enter_capital(to))
+ if (can_enter_capital(to) && go_inside)
set_general_inside_capital(who)
if (is_sea(to))
game.state = "move_army_at_sea"
- else if (game.ip[MILITARY] > 0)
- game.state = "take_actions_general"
else
- game.state = "take_actions"
+ game.state = "take_actions_general"
+}
+
+// === ACTION: INITIATE BATTLE ===
+
+states.initiate_battle = {
+ prompt() {
+ prompt("Initiate Battle in " + REGION_NAME[game.misc.where] + "!")
+
+ for_each_general((id, loc) => {
+ if (loc === game.misc.where && is_enemy_general(id))
+ gen_action_general(id)
+ })
+
+ for_each_barbarian((id, loc) => {
+ if (loc === game.misc.where)
+ gen_action_barbarian(id)
+ })
+
+ if (is_enemy_province(game.misc.where)) {
+ if (has_militia(game.misc.where) && is_capital_free_of_enemy(where))
+ gen_action_militia(game.misc.where)
+ }
+ },
+ general(id) {
+ log("Initiate Battle vs Gen" + id)
+ },
+ barbarian(id) {
+ log("Initiate Battle vs B" + id)
+ },
+ militia(where) {
+ log("Initiate Battle vs Militia" + id)
+ },
}
// === SUPPORT CHECK ===
@@ -1365,23 +1562,138 @@ function goto_gain_legacy() {
// === BUY / TRASH CARDS ===
+function count_political_points() {
+ let pp = 0
+ for (let where = 0; where < 12; ++where) {
+ if (is_own_province(where)) {
+ pp += game.support[where]
+ pp -= game.mobs[where]
+ }
+ }
+ return pp
+}
+
function goto_buy_trash_cards() {
let discard = current_discard()
for (let c of game.played) {
set_add(discard, c)
}
game.played.length = 0
- game.state = "buy_trash_discard"
game.misc = {
count: 0,
- pp: 0,
+ pp: count_political_points(),
}
- goto_end_of_turn()
+ if (current_hand().length > 0)
+ game.state = "buy_trash_discard"
+ else
+ game.state = "buy_trash"
+}
+
+states.buy_trash_discard = {
+ prompt() {
+ prompt("You may discard any number of cards.")
+ for (let c of current_hand())
+ gen_action_card(c)
+ view.actions.done = 1
+ },
+ card(c) {
+ push_undo()
+ set_delete(current_hand(), c)
+ set_add(current_discard(), c)
+ },
+ done() {
+ push_undo()
+ game.state = "buy_trash"
+ },
+}
+
+function find_market_with_card(c) {
+ for (let m of game.market)
+ if (set_has(m, c))
+ return m
+ return null
+}
+
+states.buy_trash = {
+ prompt() {
+ prompt("Buy/Trash cards: " + game.misc.pp + "PP left.")
+ let nprov = count_own_provinces()
+ if (game.misc.pp >= 3) {
+ for (let c of current_discard())
+ gen_action_card(c)
+ }
+ for (let m of game.market) {
+ if (m.length > 0) {
+ let c = m[0]
+ let cost = card_cost(c)
+ if (cost > nprov)
+ cost *= 2
+ cost += game.misc.count
+ if (game.misc.pp >= cost)
+ gen_action_card(c)
+ }
+ }
+ view.actions.done = 1
+ },
+ card(c) {
+ push_undo()
+ if (set_has(current_discard(), c)) {
+ log("Trashed " + card_name(c))
+ set_delete(current_discard(), c)
+ game.misc.pp -= 3
+ } else {
+ log("Bought " + card_name(c))
+ set_add(current_discard(), c)
+ set_delete(find_market_with_card(c), c)
+ let cost = card_cost(c)
+ if (cost > count_own_provinces())
+ cost *= 2
+ cost += game.misc.count
+ game.misc.pp -= cost
+ game.misc.count += 1
+ }
+ },
+ done() {
+ push_undo()
+ goto_end_of_turn()
+ },
}
// === END OF TURN ===
function goto_end_of_turn() {
+ // TODO: add mobs
+ // TODO: flip inactive barbarians
+ game.state = "refill_hand"
+}
+
+states.refill_hand = {
+ prompt() {
+ view.prompt = "Refill your hand."
+ let hand = current_hand()
+ if (hand.length < 5) {
+ for (let c of current_draw())
+ gen_action_card(c)
+ } else {
+ view.actions.done = 1
+ }
+ },
+ card(c) {
+ push_undo()
+ set_delete(current_draw(), c)
+ set_add(current_hand(), c)
+ if (current_draw().length === 0) {
+ game.draw[game.current] = game.discard[game.current]
+ game.discard[game.current] = []
+ }
+ },
+ done() {
+ clear_undo()
+ end_refill_hand()
+ }
+}
+
+function end_refill_hand() {
game.current = next_player()
goto_start_turn()
}
@@ -1468,7 +1780,7 @@ exports.setup = function (seed, scenario, options) {
generals: new Array(6 * player_count).fill(UNAVAILABLE),
legions: new Array(LEGION_COUNT).fill(AVAILABLE),
barbarians: new Array(10 * tribe_count).fill(0),
- rivals: [ UNAVAILABLE, UNAVAILABLE, UNAVAILABLE ],
+ rival_emperors: [ UNAVAILABLE, UNAVAILABLE, UNAVAILABLE ],
barbarian_leaders: [ UNAVAILABLE, UNAVAILABLE, UNAVAILABLE ],
dice: [ 0, 0, 0, 0 ], // first two are crisis table dice, second two are barbarian homeland dice
@@ -1513,7 +1825,7 @@ exports.setup = function (seed, scenario, options) {
game.discard[player] = []
}
- update_italia_support()
+ update_neutral_italia()
game.first = game.current = random(player_count)
log("First Player is " + PLAYER_NAMES[game.first] + "!")
@@ -1579,13 +1891,13 @@ exports.view = function (state, player_name) {
generals: game.generals,
legions: game.legions,
barbarians: game.barbarians,
- rivals: game.rivals,
+ rival_emperors: game.rival_emperors,
barbarian_leaders: game.barbarian_leaders,
dice: game.dice,
events: game.active_events,
played: game.played,
- market: game.market,
+ market: game.market.map(m => m[0] | 0),
legacy: game.legacy,
emperor_turns: game.emperor_turns,
@@ -1678,6 +1990,10 @@ function gen_action_region(where) {
gen_action("region", where)
}
+function gen_action_capital(where) {
+ gen_action("capital", where)
+}
+
function gen_action_card(c) {
gen_action("card", c)
}