summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--events.txt8
-rw-r--r--play.css2
-rw-r--r--rules.js698
3 files changed, 332 insertions, 376 deletions
diff --git a/events.txt b/events.txt
index 4287c90..5f5f689 100644
--- a/events.txt
+++ b/events.txt
@@ -687,7 +687,7 @@ EVENT 46
prompt "Execute free Terror with any Guerrilla."
space 1 has_piece(s, game.current, GUERRILLA)
piece 1 is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA)
- free_terror
+ free_terror_with_piece
terror
terror_aid_cut
endpiece
@@ -719,7 +719,7 @@ SHADED 47
auto_place AUC GUERRILLA
prompt "Execute free Terror in CĂșcuta."
piece 1 is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_underground(p)
- free_terror
+ free_terror_with_piece
terror_aid_cut
endpiece
endspace
@@ -1038,7 +1038,7 @@ EVENT 63
endpiece
prompt "Free Terror with remaining Cartels Guerrilla."
piece 1 is_piece_in_event_space(p) && is_cartels_guerrilla(p)
- free_terror
+ free_terror_with_piece
endpiece
endspace
terror_aid_cut
@@ -1163,7 +1163,7 @@ SHADED 70
space all is_forest(s) && has_piece(s, game.current, GUERRILLA)
prompt "Free Terror with any 1 Guerrilla."
piece 1 is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA)
- free_terror
+ free_terror_with_piece
auto_resources (game.current) 3
endpiece
endspace
diff --git a/play.css b/play.css
index 912b43c..eb2e86d 100644
--- a/play.css
+++ b/play.css
@@ -24,6 +24,8 @@ main { background-color: #777; }
#log div { padding-left: 20px; text-indent: -12px; }
#log div.ind { padding-left: 32px; text-indent: -12px; }
+#log { font-variant-numeric: tabular-nums; }
+
.action { cursor: pointer }
.role.active span { text-decoration: underline; }
diff --git a/rules.js b/rules.js
index 58406ef..34ea98a 100644
--- a/rules.js
+++ b/rules.js
@@ -2,7 +2,6 @@
// TODO: rules material - reference 6.3.3 Drug Profits to 5.2.2 should be 4.5.3
-// TODO: compact game.memory array instead of president/aid/cylinder/resources/pieces/support/control
// TODO: clean up init_free_operation stuff
// TODO: check how often and where to push_undo
@@ -13,6 +12,15 @@
// TODO: don't auto-end 7th sf remove terror/sabotage (no undo suprise)
// TODO: don't auto-end free Rally with elite backing (no undo suprise)
+// TODO: Government -> Govt
+// TODO: Department -> Dept
+
+// TODO: patrol activate/assault - count up to cubes, not down
+// TODO: do_... -> goto_...
+
+// TODO: can_...operation - for space = ... check them all
+// can_rally - check that it is dept/city etc
+
const AUTOMATIC = true
let states = {}
@@ -934,12 +942,10 @@ function is_farc_zone(s) {
}
function add_farc_zone(s) {
- log(`FARC Zone in S${s}.`)
game.farc_zones |= (1 << s)
}
function remove_farc_zone(s) {
- log(`Removed Farc Zone from S${s}.`)
game.farc_zones &= ~(1 << s)
}
@@ -1242,7 +1248,6 @@ function is_active(p) {
}
function move_piece(p, s) {
- log(`Moved ${piece_name(p)} from S${piece_space(p)} to S${s}.`)
set_piece_space(p, s)
update_control()
}
@@ -1250,14 +1255,12 @@ function move_piece(p, s) {
function place_piece(p, s) {
if (piece_space(p) === AVAILABLE)
p = find_piece(AVAILABLE, piece_faction(p), piece_type(p))
- log(`Placed ${piece_name(p)} in S${s}.`)
set_underground(p)
set_piece_space(p, s)
update_control()
}
function remove_piece(p) {
- log(`Removed ${piece_name(p)} from S${piece_space(p)}.`)
if (is_any_guerrilla(p)) {
drop_held_shipments(p)
set_underground(p)
@@ -1267,13 +1270,11 @@ function remove_piece(p) {
}
function place_terror(s) {
- log(`Terror in S${s}.`)
if (count_terror_and_sabotage() < 40)
map_set(game.terror, s, map_get(game.terror, s, 0) + 1)
}
function remove_terror(s) {
- log(`Removed Terror from S${s}.`)
let n = map_get(game.terror, s, 0)
if (n > 1)
map_set(game.terror, s, n - 1)
@@ -1282,13 +1283,11 @@ function remove_terror(s) {
}
function place_sabotage(s) {
- log(`Sabotage in S${s}.`)
if (count_terror_and_sabotage() < 40)
set_add(game.sabotage, s)
}
function remove_sabotage(s) {
- log(`Removed Sabotage from S${s}.`)
set_delete(game.sabotage, s)
}
@@ -1309,7 +1308,6 @@ function find_available_shipment() {
}
function place_shipment(sh, p) {
- log(`Placed Shipment with ${faction_name[piece_faction(p)]} in S${piece_space(p)}.`)
game.shipments[sh] = p << 2
}
@@ -1365,7 +1363,7 @@ function is_shipment_held_by_faction(sh, f) {
}
function is_shipment_held_by_faction_in_space(sh, f, s) {
- return is_shipment_held(sh) && get_held_shipment_faction(sh) === f && piece_space(get_held_shipment_piece(sh)) == s
+ return is_shipment_held(sh) && get_held_shipment_faction(sh) === f && piece_space(get_held_shipment_piece(sh)) === s
}
function is_any_shipment_held_in_space(s) {
@@ -2189,7 +2187,7 @@ function goto_eligible() {
free: 0,
ship: 1,
spaces: [],
- pieces: [],
+ where: -1,
pass: 1
}
if (is_final_event_card() || did_option(SOP_1ST_OP_ONLY) || did_option(SOP_1ST_OP_AND_SA)) {
@@ -2201,6 +2199,18 @@ function goto_eligible() {
}
}
+function goto_ship_limop() {
+ game.state = "ship_limop"
+ game.op = {
+ limited: 1,
+ free: 1,
+ ship: 0,
+ spaces: [],
+ where: -1,
+ }
+ game.sa = 0
+}
+
states.eligible = {
disable_negotiation: true,
inactive: "Eligible Faction",
@@ -2237,18 +2247,6 @@ states.eligible = {
pass: goto_pass,
}
-function goto_ship_limop() {
- game.state = "ship_limop"
- game.op = {
- limited: 1,
- free: 1,
- ship: 0,
- spaces: [],
- pieces: [],
- }
- game.sa = 0
-}
-
states.ship_limop = {
disable_negotiation: true,
inactive: "Extra Limited Operation",
@@ -2319,24 +2317,6 @@ function gen_any_event() {
}
}
-function can_select_op_space(cost) {
- if (!game.op.free && game.resources[game.current] < cost)
- return false
- if (game.op.limited)
- return game.op.spaces.length === 0
- return true
-}
-
-function is_selected_op_space(s) {
- return set_has(game.op.spaces, s)
-}
-
-function select_op_space(s, cost) {
- set_add(game.op.spaces, s)
- if (!game.op.free)
- game.resources[game.current] -= cost
-}
-
function init_operation(type) {
push_undo()
move_cylinder_to_operation()
@@ -2345,17 +2325,20 @@ function init_operation(type) {
else
log_h2(faction_name[game.current] + " - " + type)
game.op.type = type
- game.op.spaces = []
}
-function init_free_operation(type) {
+function init_free_operation(type, s) {
log_h3("Free " + type)
game.op = {
type: type,
- limited: 1,
+ limited: s >= 0 ? 1 : 0,
free: 1,
ship: 0,
+ spaces: [],
+ where: s,
}
+ if (s >= 0)
+ set_add(game.op.spaces, s)
}
function prompt_end_op(cost) {
@@ -2370,16 +2353,31 @@ function prompt_end_op(cost) {
return (game.op.spaces.length > 0) ? 1 : 0
}
+function can_select_op_space(cost) {
+ if (!game.op.free && game.resources[game.current] < cost)
+ return false
+ if (game.op.limited)
+ return game.op.spaces.length === 0
+ return true
+}
+
+function is_selected_op_space(s) {
+ return set_has(game.op.spaces, s)
+}
+
+function select_op_space(s, cost) {
+ set_add(game.op.spaces, s)
+ if (!game.op.free)
+ game.resources[game.current] -= cost
+ game.op.where = s
+}
+
// OPERATION: TRAIN
function vm_free_train() {
- init_free_operation("Train")
- game.op.limited = 1
- select_op_space(game.vm.s, 0)
- game.op.where = game.vm.s
- game.op.count = 6
+ init_free_operation("Train", game.vm.s)
if (can_govt_train_place(game.op.where))
- game.state = "train_place"
+ goto_train_place()
else
game.state = "vm_train_base_or_civic"
}
@@ -2440,22 +2438,24 @@ function can_govt_train_civic_any() {
return false
}
+function gen_govt_special_activity_for_train() {
+ if (game.sa) {
+ view.actions.air_lift = can_air_lift() ? 1 : 0
+ view.actions.eradicate = can_eradicate() ? 1 : 0
+ }
+}
+
states.train = {
prompt() {
view.prompt = "Train: Select City or Department to place cubes."
- if (game.sa) {
- view.actions.air_lift = can_air_lift() ? 1 : 0
- view.actions.eradicate = can_eradicate() ? 1 : 0
- }
+ gen_govt_special_activity_for_train()
// Any Departments or Cities
- if (can_select_op_space(3)) {
+ if (can_select_op_space(3))
for (let s = first_space; s <= last_dept; ++s)
- if (can_govt_train_place(s))
- if (!is_selected_op_space(s))
- gen_action_space(s)
- }
+ if (!is_selected_op_space(s) && can_govt_train_place(s))
+ gen_action_space(s)
view.actions.base = can_govt_train_base_any() ? 1 : 0
view.actions.civic = can_govt_train_civic_any() ? 1 : 0
@@ -2464,80 +2464,76 @@ states.train = {
},
space(s) {
push_undo()
- log(`Train in S${s}.`)
select_op_space(s, 3)
- game.state = "train_place"
- game.op.where = s
- game.op.count = 6
+ goto_train_place()
},
base() {
push_undo()
- if (game.op.limited && game.op.spaces.length > 0) {
- game.op.where = game.op.spaces[0]
- game.op.count = 3
- game.state = "train_base_remove"
- } else {
+ if (game.op.limited && game.op.spaces.length > 0)
+ goto_train_base_remove(game.op.spaces[0])
+ else
game.state = "train_base"
- }
},
civic() {
push_undo()
if (game.op.limited && game.op.spaces.length > 0)
- do_train_civic_action(game.op.spaces[0])
+ goto_train_civic_action(game.op.spaces[0])
else
game.state = "train_civic"
},
end_train: end_operation,
}
+function resume_train() {
+ if (game.vm) {
+ if (can_govt_train_base(game.vm.s) || can_govt_train_civic(game.vm.s))
+ game.state = "vm_train_base_or_civic"
+ else
+ end_operation()
+ } else {
+ game.state = "train"
+ }
+}
+
+function goto_train_place() {
+ game.state = "train_place"
+ game.op.count = 6
+}
+
states.train_place = {
prompt() {
view.prompt = `Train in ${space_name[game.op.where]}: Place up to ${game.op.count} cubes.`
view.where = game.op.where
-
if (game.op.count > 0) {
gen_place_piece(game.op.where, GOVT, TROOPS)
gen_place_piece(game.op.where, GOVT, POLICE)
}
-
view.actions.next = 1
},
piece(p) {
place_piece(p, game.op.where)
- if (--game.op.count == 0)
- this.next()
+ if (--game.op.count === 0)
+ resume_train()
},
next() {
- game.op.count = 0
- if (game.vm) {
- if (can_govt_train_base(game.vm.s) || can_govt_train_civic(game.vm.s))
- game.state = "vm_train_base_or_civic"
- else
- end_operation()
- return
- }
- game.state = "train"
+ resume_train()
},
}
states.vm_train_base_or_civic = {
prompt() {
view.prompt = "Train: Build Base or buy Civic Action?"
-
view.actions.base = can_govt_train_base(game.vm.s) ? 1 : 0
view.actions.civic = can_govt_train_civic(game.vm.s) ? 1 : 0
-
view.actions.end_train = (game.op.spaces.length > 0) ? 1 : 0
},
base() {
push_undo()
- game.op.where = game.vm.s
- game.op.count = 3
- game.state = "train_base_remove"
+ goto_train_base_remove(game.vm.s)
},
civic() {
push_undo()
- do_train_civic_action()
+ goto_train_civic_action(game.vm.s)
},
end_train: end_operation,
}
@@ -2545,6 +2541,7 @@ states.vm_train_base_or_civic = {
states.train_base = {
prompt() {
view.prompt = "Train: Build Base."
+ gen_govt_special_activity_for_train()
for (let s = first_space; s <= last_dept; ++s)
if (can_govt_train_base(s))
if (is_selected_op_space(s) || can_select_op_space(3))
@@ -2554,12 +2551,16 @@ states.train_base = {
push_undo()
if (!is_selected_op_space(s))
select_op_space(s, 3)
- game.op.where = s
- game.op.count = 3
- game.state = "train_base_remove"
+ goto_train_base_remove(s)
},
}
+function goto_train_base_remove(s) {
+ game.op.where = s
+ game.op.count = 3
+ game.state = "train_base_remove"
+}
+
states.train_base_remove = {
prompt() {
view.prompt = `Train: Replace 3 cubes with a Base in ${space_name[game.op.where]}.`
@@ -2588,7 +2589,7 @@ states.train_base_place = {
},
}
-function do_train_civic_action(s) {
+function goto_train_civic_action(s) {
game.op.where = s
add_resources(GOVT, -3)
shift_support(s)
@@ -2601,6 +2602,7 @@ function do_train_civic_action(s) {
states.train_civic = {
prompt() {
view.prompt = `Train: Buy Civic Action.`
+ gen_govt_special_activity_for_train()
for (let s = first_space; s <= last_dept; ++s)
if (can_civic_action(s))
if (is_selected_op_space(s) || can_select_op_space(3))
@@ -2610,7 +2612,7 @@ states.train_civic = {
push_undo()
if (!is_selected_op_space(s))
select_op_space(s, 3)
- do_train_civic_action(s)
+ goto_train_civic_action(s)
},
end_train: end_operation,
}
@@ -2618,11 +2620,13 @@ states.train_civic = {
states.train_civic_buy = {
prompt() {
view.prompt = `Train: Buy Civic Action.`
+ gen_govt_special_activity_for_train()
gen_action_space(game.op.where)
+ view.actions.end_train = 1
},
space(s) {
push_undo()
- do_train_civic_action(s)
+ goto_train_civic_action(s)
},
end_train: end_operation,
}
@@ -2630,6 +2634,7 @@ states.train_civic_buy = {
states.train_done = {
prompt() {
view.prompt = "Train: All done."
+ gen_govt_special_activity_for_train()
view.actions.end_train = 1
},
end_train: end_operation,
@@ -2640,10 +2645,6 @@ states.train_done = {
function goto_patrol() {
init_operation("Patrol")
game.op.pieces = []
- goto_patrol1()
-}
-
-function goto_patrol1() {
if (!game.op.free && game.resources[GOVT] < 3)
game.state = "patrol_pay"
else
@@ -2688,34 +2689,12 @@ function can_patrol() {
return false
}
-function can_patrol_to(s) {
+function can_patrol_to(_) {
// TODO
return true
}
-states.patrol_limop = {
- prompt() {
- view.prompt = "Patrol: Select destination City or LoC."
-
- gen_govt_special_activity()
-
- for (let s = first_city; s <= last_city; ++s)
- gen_action_space(s)
- for (let s = first_loc; s <= last_loc; ++s)
- gen_action_space(s)
- },
- space(s) {
- push_undo()
-
- log(`S${s}.`)
-
- select_op_space(s, 0)
-
- game.op.limop_space = s // remember destination for assault
- game.op.where = s
- game.state = "patrol_limop_move"
- },
-}
+// OPERATION: PATROL - MOVE
function gen_patrol_move_limop(start) {
let queue = [ start ]
@@ -2742,23 +2721,6 @@ function gen_patrol_move_limop(start) {
}
}
-states.patrol_limop_move = {
- prompt() {
- view.prompt = `Patrol: Move cubes to ${space_name[game.op.where]}.`
- view.where = game.op.where
-
- gen_govt_special_activity()
-
- gen_patrol_move_limop(game.op.where)
-
- view.actions.next = 1
- },
- piece(p) {
- move_piece(p, game.op.where)
- },
- next: goto_patrol_activate,
-}
-
function gen_patrol_move(start) {
let queue = [ start ]
path_seen.fill(0)
@@ -2781,6 +2743,43 @@ function gen_patrol_move(start) {
}
}
+states.patrol_limop = {
+ prompt() {
+ view.prompt = "Patrol: Select destination City or LoC."
+
+ gen_govt_special_activity()
+
+ // TODO: check if can move
+ for (let s = first_city; s <= last_city; ++s)
+ gen_action_space(s)
+ for (let s = first_loc; s <= last_loc; ++s)
+ gen_action_space(s)
+ },
+ space(s) {
+ push_undo()
+ select_op_space(s, 0)
+ game.op.limop_space = s // remember destination for assault
+ game.state = "patrol_limop_move"
+ },
+}
+
+states.patrol_limop_move = {
+ prompt() {
+ view.prompt = `Patrol: Move cubes to ${space_name[game.op.where]}.`
+ view.where = game.op.where
+
+ gen_govt_special_activity()
+
+ gen_patrol_move_limop(game.op.where)
+
+ view.actions.next = 1
+ },
+ piece(p) {
+ move_piece(p, game.op.where)
+ },
+ next: goto_patrol_activate,
+}
+
states.patrol = {
prompt() {
view.prompt = "Patrol: Move cubes into or along LoCs and Cities."
@@ -2826,9 +2825,11 @@ states.patrol = {
next: goto_patrol_activate,
}
+// OPERATION: PATROL - ACTIVATE
+
function goto_patrol_activate() {
push_undo()
- game.op.spaces = []
+ game.op.spaces = [] // reset space list for activation
resume_patrol_activate()
}
@@ -2859,15 +2860,15 @@ states.patrol_activate = {
view.prompt = "Patrol: Activate Guerrillas in each LoC with cubes."
gen_govt_special_activity()
for (let s = first_loc; s <= last_loc; ++s)
- if (!set_has(game.op.spaces, s) && can_patrol_activate_space(s))
+ if (!is_selected_op_space(s) && can_patrol_activate_space(s))
gen_action_space(s)
view.actions.next = 1
},
space(s) {
push_undo()
- set_add(game.op.spaces, s)
- game.op.where = s
+ select_op_space(s, 0)
game.op.targeted = 0
+ // TODO count up
game.op.count = Math.min(count_cubes(s), count_any_underground_guerrillas(s))
game.state = "patrol_activate_space"
},
@@ -2891,6 +2892,7 @@ states.patrol_activate_space = {
piece(p) {
game.op.targeted |= target_faction(p)
set_active(p)
+ // TODO count up
if (--game.op.count === 0)
resume_patrol_activate()
},
@@ -2899,8 +2901,10 @@ states.patrol_activate_space = {
},
}
+// OPERATION: PATROL - ASSAULT
+
function goto_patrol_assault() {
- game.op.spaces = []
+ game.op.spaces = [] // reset space list for assault
if (can_patrol_assault())
game.state = "patrol_assault"
else
@@ -2942,22 +2946,19 @@ states.patrol_assault = {
if (can_patrol_assault_space(game.op.limop_space))
gen_action_space(game.op.limop_space)
} else {
- for (let s = first_loc; s <= last_loc; ++s) {
- if (is_selected_op_space(s))
- continue
- if (can_patrol_assault_space(s))
+ for (let s = first_loc; s <= last_loc; ++s)
+ if (!is_selected_op_space(s) && can_patrol_assault_space(s))
gen_action_space(s)
- }
}
view.actions.end_patrol = 1
},
space(s) {
push_undo()
- log(`Assault S${s}.`)
+ select_op_space(s, 0)
game.state = "patrol_assault_space"
- game.op.where = s
game.op.targeted = 0
+ // TODO count up
game.op.count = count_cubes(s)
},
end_patrol: end_operation,
@@ -2978,6 +2979,7 @@ states.patrol_assault_space = {
game.op.targeted |= target_faction(p)
remove_piece(p)
+ // TODO count up
if (--game.op.count === 0 || !has_assault_target(game.op.where)) {
end_patrol_assault_space()
transfer_or_drug_bust_shipments()
@@ -3005,21 +3007,19 @@ function goto_sweep() {
game.state = "sweep"
if (has_capability(S_CAP_OSPINA))
game.op.limited = 1
+ game.op.faction = 0
}
function vm_free_sweep() {
- init_free_operation("Sweep")
- game.state = "sweep_activate"
- game.op.where = game.vm.s
- do_sweep_activate()
+ init_free_operation("Sweep", game.vm.s)
+ game.op.faction = 0
+ goto_sweep_activate()
}
function vm_free_sweep_farc() {
- init_free_operation("Sweep")
- game.state = "sweep_activate"
+ init_free_operation("Sweep", game.vm.s)
game.op.faction = FARC
- game.op.where = game.vm.s
- do_sweep_activate()
+ goto_sweep_activate()
}
function can_sweep() {
@@ -3123,42 +3123,40 @@ states.sweep = {
if (has_capability(CAP_OSPINA))
cost = 1
- if (can_select_op_space(cost)) {
- for (let s = first_space; s <= last_dept; ++s) {
- if (is_selected_op_space(s))
- continue
- if (can_sweep_select(s))
+ if (can_select_op_space(cost))
+ for (let s = first_space; s <= last_dept; ++s)
+ if (!is_selected_op_space(s) && can_sweep_select(s))
gen_action_space(s)
- }
- }
view.actions.end_sweep = prompt_end_op(cost)
},
space(s) {
push_undo()
- log(`S${s}.`)
-
let cost = 3
if (has_capability(CAP_OSPINA))
cost = 1
select_op_space(s, cost)
- game.op.where = s
- game.op.targeted = 0
-
if (has_capability(CAP_NDSC))
game.op.ndsc = 1
if (can_sweep_move_cubes(s))
game.state = "sweep_move"
else
- do_sweep_activate()
+ goto_sweep_activate()
},
end_sweep: end_operation,
}
+function resume_sweep() {
+ if (game.vm)
+ end_operation()
+ else
+ game.state = "sweep"
+}
+
states.sweep_move = {
prompt() {
view.prompt = `Sweep: Move Troops into ${space_name[game.op.where]}.`
@@ -3179,13 +3177,11 @@ states.sweep_move = {
},
next() {
push_undo()
- do_sweep_activate()
+ goto_sweep_activate()
},
}
-function do_sweep_activate() {
- game.state = "sweep_activate"
-
+function goto_sweep_activate() {
let n_troops = count_pieces(game.op.where, GOVT, TROOPS)
let n_police = count_pieces(game.op.where, GOVT, POLICE)
@@ -3200,8 +3196,12 @@ function do_sweep_activate() {
if (is_forest(game.op.where))
game.op.count >>= 1
+ game.op.targeted = 0
+
if (game.op.count === 0 || !can_sweep_activate(game.op.where, game.op.faction))
- do_sweep_next()
+ resume_sweep()
+ else
+ game.state = "sweep_activate"
}
states.sweep_activate = {
@@ -3228,21 +3228,13 @@ states.sweep_activate = {
game.op.targeted |= target_faction(p)
set_active(p)
if (--game.op.count === 0 || !can_sweep_activate(game.op.where, game.op.faction))
- this.skip()
+ resume_sweep()
},
skip() {
- push_undo()
- do_sweep_next()
+ resume_sweep()
},
}
-function do_sweep_next() {
- if (game.vm)
- end_operation()
- else
- game.state = "sweep"
-}
-
// OPERATION: ASSAULT
function goto_assault() {
@@ -3250,41 +3242,31 @@ function goto_assault() {
game.state = "assault"
if (has_capability(S_CAP_TAPIAS))
game.op.limited = 1
+ game.op.faction = 0
}
function vm_free_assault() {
- init_free_operation("Assault")
- game.state = "assault_space"
- game.op.where = game.vm.s
- game.op.targeted = 0
- game.op.count = assault_kill_count(game.vm.s, 0)
+ init_free_operation("Assault", game.vm.s)
+ game.op.faction = 0
+ goto_assault_space()
}
function vm_free_assault_auc() {
- init_free_operation("Assault")
- game.state = "assault_space"
+ init_free_operation("Assault", game.vm.s)
game.op.faction = AUC
- game.op.where = game.vm.s
- game.op.targeted = 0
- game.op.count = assault_kill_count(game.vm.s, AUC)
+ goto_assault_space()
}
function vm_free_assault_farc() {
- init_free_operation("Assault")
- game.state = "assault_space"
+ init_free_operation("Assault", game.vm.s)
game.op.faction = FARC
- game.op.where = game.vm.s
- game.op.targeted = 0
- game.op.count = assault_kill_count(game.vm.s, FARC)
+ goto_assault_space()
}
function vm_free_assault_cartels() {
- init_free_operation("Assault")
- game.state = "assault_space"
+ init_free_operation("Assault", game.vm.s)
game.op.faction = CARTELS
- game.op.where = game.vm.s
- game.op.targeted = 0
- game.op.count = assault_kill_count(game.vm.s, CARTELS)
+ goto_assault_space()
}
function can_assault() {
@@ -3336,8 +3318,8 @@ function has_assault_target(s, target) {
return (
(!has_momentum(MOM_SENADO_FARC) && has_exposed_piece(s, FARC)) ||
- (!has_momentum(MOM_SENADO_AUC) && exposed_piece(s, AUC)) ||
- (!has_momentum(MOM_SENADO_CARTELS) && exposed_piece(s, CARTELS))
+ (!has_momentum(MOM_SENADO_AUC) && has_exposed_piece(s, AUC)) ||
+ (!has_momentum(MOM_SENADO_CARTELS) && has_exposed_piece(s, CARTELS))
)
}
@@ -3396,36 +3378,33 @@ states.assault = {
if (has_capability(CAP_TAPIAS))
cost = 1
- if (can_select_op_space(cost)) {
- for (let s = first_space; s <= last_dept; ++s) {
- if (is_selected_op_space(s))
- continue
- if (has_assault_target(s, game.op.faction) && assault_kill_count(s, game.op.faction) > 0)
+ if (can_select_op_space(cost))
+ for (let s = first_space; s <= last_space; ++s)
+ if (!is_selected_op_space(s) && can_assault_in_space(s))
gen_action_space(s)
- }
- }
view.actions.end_assault = prompt_end_op(cost)
},
space(s) {
push_undo()
- log(`S${s}.`)
-
let cost = 3
if (has_capability(CAP_TAPIAS))
cost = 1
select_op_space(s, cost)
- game.state = "assault_space"
- game.op.where = s
- game.op.targeted = 0
- game.op.count = assault_kill_count(s, game.op.faction)
+ goto_assault_space()
},
end_assault: end_operation,
}
+function goto_assault_space() {
+ game.state = "assault_space"
+ game.op.targeted = 0
+ game.op.count = assault_kill_count(game.vm.s, game.op.faction)
+}
+
states.assault_space = {
prompt() {
view.prompt = `Assault: Remove ${game.op.count} enemy pieces in ${space_name[game.op.where]}.`
@@ -3453,17 +3432,17 @@ states.assault_space = {
remove_piece(p)
if (--game.op.count === 0 || !has_assault_target(game.op.where, game.op.faction))
- this.skip()
+ end_assault_space()
},
- skip() {
- if (game.vm) {
- end_operation()
- transfer_or_drug_bust_shipments()
- return
- }
+ skip: end_assault_space,
+}
+
+function end_assault_space() {
+ if (game.vm)
+ end_operation()
+ else
game.state = "assault"
- transfer_or_drug_bust_shipments()
- },
+ transfer_or_drug_bust_shipments()
}
// OPERATION: RALLY
@@ -3474,18 +3453,14 @@ function goto_rally() {
}
function vm_free_rally() {
- init_free_operation("Rally")
- game.state = "rally_space"
- game.op.where = game.vm.s
- game.op.count = rally_count()
+ init_free_operation("Rally", game.vm.s)
+ goto_rally_space()
}
-function free_rally_elite_backing(s) {
- init_free_operation("Rally")
- game.state = "rally_space"
+function goto_free_rally_elite_backing(s) {
+ init_free_operation("Rally", s)
game.op.elite_backing = 1
- game.op.where = s
- game.op.count = 0
+ goto_rally_space()
}
function rally_count() {
@@ -3533,31 +3508,37 @@ states.rally = {
}
// Departments or Cities
- if (can_select_op_space(1)) {
- for (let s = first_space; s <= last_dept; ++s) {
- if (is_selected_op_space(s))
- continue
- if (can_rally_in_space(s))
+ if (can_select_op_space(1))
+ for (let s = first_space; s <= last_dept; ++s)
+ if (!is_selected_op_space(s) && can_rally_in_space(s))
gen_action_space(s)
- }
- }
view.actions.end_rally = prompt_end_op(1)
},
space(s) {
push_undo()
- log(`S${s}.`)
-
select_op_space(s, 1)
- game.state = "rally_space"
- game.op.where = s
- game.op.count = 0
+ goto_rally_space()
},
end_rally: end_operation,
}
+function resume_rally() {
+ if (game.op.elite_backing)
+ end_elite_backing()
+ else if (game.vm)
+ end_operation()
+ else
+ game.state = "rally"
+}
+
+function goto_rally_space() {
+ game.state = "rally_space"
+ game.op.count = 0
+}
+
states.rally_space = {
prompt() {
view.prompt = `Rally: Place up to ${rally_count()} Guerrillas, build Base, or Move.`
@@ -3584,13 +3565,11 @@ states.rally_space = {
},
base() {
push_undo()
- log("Base.")
game.state = "rally_base_remove"
game.op.count = 2
},
move() {
push_undo()
- log("Move.")
game.state = "rally_move"
game.op.count = 0
},
@@ -3614,15 +3593,6 @@ states.rally_guerrillas = {
},
}
-function resume_rally() {
- if (game.op.elite_backing)
- end_elite_backing()
- else if (game.vm)
- end_operation()
- else
- game.state = "rally"
-}
-
states.rally_base_remove = {
prompt() {
view.prompt = `Rally: Replace 2 Guerrillas with a Base in ${space_name[game.op.where]}.`
@@ -3671,7 +3641,6 @@ states.rally_move = {
},
next() {
push_undo()
- log("Moved " + game.op.count + ".")
if (has_active_guerrilla(game.op.where, game.current))
game.state = "rally_flip"
else
@@ -3699,18 +3668,15 @@ states.rally_flip = {
function goto_march() {
init_operation("March")
- game.state = "march"
game.op.pieces = []
+ game.state = "march"
}
function vm_free_march() {
- init_free_operation("March")
- game.state = "march"
- game.op.limited = 0
- game.op.spaces = []
+ init_free_operation("March", -1)
game.op.pieces = []
- // remember destinations
- game.vm.march = []
+ game.state = "march"
+ game.vm.march = [] // remember destinations
}
function can_march() {
@@ -3742,45 +3708,39 @@ states.march = {
gen_special(CARTELS, "bribe", can_bribe)
}
- if (can_select_op_space(1)) {
- for (let s = first_space; s <= last_dept; ++s) {
- if (is_selected_op_space(s))
- continue
- if (can_march_to(s))
+ // Cities & Depts
+ if (can_select_op_space(1))
+ for (let s = first_space; s <= last_dept; ++s)
+ if (!is_selected_op_space(s) && can_march_to(s))
gen_action_space(s)
- }
- }
- if (can_select_op_space(0)) {
- for (let s = first_loc; s <= last_loc; ++s) {
- if (is_selected_op_space(s))
- continue
- if (can_march_to(s))
+ // LoCs
+ if (can_select_op_space(0))
+ for (let s = first_loc; s <= last_loc; ++s)
+ if (!is_selected_op_space(s) && can_march_to(s))
gen_action_space(s)
- }
- }
view.actions.end_march = prompt_end_op(1)
},
space(s) {
push_undo()
- log(`S${s}.`)
-
- // remember destinations
- if (game.vm)
- set_add(game.vm.march, s)
-
if (is_loc(s))
select_op_space(s, 0)
else
select_op_space(s, 1)
- game.state = "march_move"
- game.op.where = s
+ // track groups moving from the same space
game.op.march = []
+
+ game.state = "march_move"
+ },
+ end_march() {
+ // save destinations for event
+ if (game.vm)
+ game.vm.march = game.op.spaces
+ end_operation()
},
- end_march: end_operation,
}
function may_activate_marching_guerrillas() {
@@ -3802,7 +3762,8 @@ function activate_marching_guerrillas(group) {
count += count_pieces(game.op.where, FARC, GUERRILLA)
if (count > 3)
for (let p of group)
- set_active(p)
+ if (is_underground(p))
+ set_active(p)
}
}
@@ -3840,7 +3801,7 @@ states.march_move = {
},
next() {
push_undo()
- game.op.march = 0
+ game.op.march = null
game.state = "march"
},
}
@@ -3849,20 +3810,20 @@ states.march_move = {
function goto_attack() {
init_operation("Attack")
+ game.op.faction = 0
game.state = "attack"
}
function vm_free_attack() {
- init_free_operation("Attack")
- game.op.spaces = []
- do_attack_space(game.vm.s)
+ init_free_operation("Attack", game.vm.s)
+ game.op.faction = 0
+ goto_attack_space()
}
function vm_free_attack_farc() {
- init_free_operation("Attack")
- game.op.spaces = []
+ init_free_operation("Attack", game.vm.s)
game.op.faction = FARC
- do_attack_space(game.vm.s)
+ goto_attack_space()
}
function can_attack() {
@@ -3892,29 +3853,30 @@ states.attack = {
gen_special(CARTELS, "bribe", can_bribe)
}
- if (can_select_op_space(1)) {
- for (let s = first_space; s <= last_space; ++s) {
- if (is_selected_op_space(s))
- continue
- if (can_attack_in_space(s))
+ if (can_select_op_space(1))
+ for (let s = first_space; s <= last_space; ++s)
+ if (!is_selected_op_space(s) && can_attack_in_space(s))
gen_action_space(s)
- }
- }
view.actions.end_attack = prompt_end_op(1)
},
space(s) {
push_undo()
- do_attack_space(s)
+ select_op_space(s, 1)
+ goto_attack_space()
},
end_attack: end_operation,
}
-function do_attack_space(s) {
- log(`Attack in S${s}.`)
- select_op_space(s, 1)
+function resume_attack() {
+ if (game.vm)
+ vm_next()
+ else
+ game.state = "attack"
+}
+
+function goto_attack_space() {
game.state = "attack_space"
- game.op.where = s
}
states.attack_space = {
@@ -3949,19 +3911,12 @@ states.attack_space = {
} else if (die <= count_pieces(game.op.where, game.current, GUERRILLA)) {
goto_attack_remove()
} else {
- do_attack_next()
+ resume_attack()
}
},
ambush: goto_ambush,
}
-function do_attack_next() {
- if (game.vm)
- vm_next()
- else
- game.state = "attack"
-}
-
function goto_attack_place() {
if (can_stack_any(game.op.where, game.current)) {
if (auto_place_piece(game.op.where, game.current, GUERRILLA))
@@ -3991,7 +3946,7 @@ function goto_attack_remove() {
game.op.count = 2
game.op.targeted = 0
} else {
- do_attack_next()
+ resume_attack()
}
}
@@ -4021,12 +3976,12 @@ states.attack_remove = {
remove_piece(p)
if (--game.op.count === 0 || !has_attack_target(game.op.where)) {
- do_attack_next()
+ resume_attack()
transfer_or_remove_shipments()
}
},
skip() {
- do_attack_next()
+ resume_attack()
game.op.count = 0
transfer_or_remove_shipments()
}
@@ -4040,20 +3995,17 @@ function goto_terror() {
}
function vm_free_terror() {
- init_free_operation("Terror")
+ init_free_operation("Terror", game.vm.s)
if (game.current === AUC)
game.vm.auc_terror = 0
- game.op.spaces = []
- do_terror_space(game.vm.s)
- do_terror_piece(game.vm.p)
+ game.state = "terror_space"
}
-function vm_free_terror_space() {
- init_free_operation("Terror")
+function vm_free_terror_with_piece() {
+ init_free_operation("Terror", game.vm.s)
if (game.current === AUC)
game.vm.auc_terror = 0
- game.op.spaces = []
- do_terror_space(game.vm.s)
+ do_terror_piece(game.vm.p)
}
function can_terror() {
@@ -4079,23 +4031,15 @@ states.terror = {
gen_special(CARTELS, "bribe", can_bribe)
}
- if (can_select_op_space(1)) {
- for (let s = first_space; s <= last_dept; ++s) {
- if (is_selected_op_space(s))
- continue
- if (has_underground_guerrilla(s, game.current))
+ if (can_select_op_space(1))
+ for (let s = first_space; s <= last_dept; ++s)
+ if (!is_selected_op_space(s) && can_terror_in_space(s))
gen_action_space(s)
- }
- }
- if (can_select_op_space(0)) {
- for (let s = first_loc; s <= last_loc; ++s) {
- if (is_selected_op_space(s))
- continue
- if (can_terror_in_space(s))
+ if (can_select_op_space(0))
+ for (let s = first_loc; s <= last_loc; ++s)
+ if (!is_selected_op_space(s) && can_terror_in_space(s))
gen_action_space(s)
- }
- }
view.actions.end_terror = prompt_end_op(1)
},
@@ -4114,13 +4058,12 @@ states.terror = {
}
function do_terror_space(s) {
- if (is_loc(s)) {
+ // Note: can come here from both "terror" and "kidnap" states
+ if (is_loc(s))
select_op_space(s, 0)
- } else {
+ else
select_op_space(s, 1)
- }
game.state = "terror_space"
- game.op.where = s
}
states.terror_space = {
@@ -4312,7 +4255,6 @@ states.air_lift_to = {
push_undo()
game.sa.to = s
game.state = "air_lift_move"
- log(`Air Lift from S${game.sa.from} to S${game.sa.to}.`)
}
}
@@ -4326,7 +4268,7 @@ states.air_lift_move = {
piece(p) {
push_undo()
move_piece(p, game.sa.to)
- if (--game.sa.count === 0 || count_cubes(game.sa.from) === 0 || !can_stack_any(game.sa.to, GOVT))
+ if (--game.sa.count === 0 || count_pieces(game.sa.from, GOVT, TROOPS) === 0 || !can_stack_any(game.sa.to, GOVT))
end_special_activity()
},
end_air_lift() {
@@ -4379,8 +4321,6 @@ states.air_strike = {
}
},
piece(p) {
- let s = piece_space(p)
- log(`Air Strike in S${s}.`)
remove_piece(p)
end_special_activity()
}
@@ -4445,7 +4385,6 @@ states.eradicate = {
},
space(s) {
push_undo()
- log(`Eradicate in S${s}.`)
game.sa.where = s
if (has_piece(s, CARTELS, BASE))
game.state = "eradicate_base"
@@ -4517,15 +4456,13 @@ states.eradicate_place = {
// SPECIAL ACTIVITY: AMBUSH
function vm_free_ambush() {
- init_free_operation("Attack")
+ init_free_operation("Attack", piece_space(game.vm.p))
set_active(game.vm.p)
- game.op.where = piece_space(game.vm.p)
goto_attack_place()
}
function vm_free_ambush_without_activating() {
- init_free_operation("Attack")
- game.op.where = piece_space(game.vm.p)
+ init_free_operation("Attack", piece_space(game.vm.p))
goto_attack_place()
}
@@ -4727,7 +4664,6 @@ states.kidnap_space = {
let g = is_city_or_loc(s) && game.resources[GOVT] > 0
let c = has_piece(s, CARTELS, BASE) && game.resources[CARTELS] > 0
-
if (g)
gen_action_resources(GOVT)
if (c) {
@@ -5678,6 +5614,7 @@ states.remove_farc_zones = {
gen_action_space(s)
},
space(s) {
+ log(`Removed Farc Zone from S${s}.`)
remove_farc_zone(s)
if (!has_any_farc_zones())
goto_elite_backing()
@@ -5708,7 +5645,7 @@ states.elite_backing = {
},
space(s) {
push_undo()
- free_rally_elite_backing(s)
+ goto_free_rally_elite_backing(s)
},
skip() {
end_elite_backing()
@@ -5885,6 +5822,8 @@ states.farc_zone_place = {
},
space(s) {
push_undo()
+
+ log(`FARC Zone in S${s}.`)
add_farc_zone(s)
if (game.vm)
@@ -5965,10 +5904,13 @@ function goto_event(shaded) {
if (shaded) {
log_h2(faction_name[game.current] + " - Shaded Event")
+ log("C" + c)
log(".i " + data.card_flavor_shaded[c] + ".")
goto_vm(c * 2 + 1)
} else {
log_h2(faction_name[game.current] + " - Event")
+ log("C" + c)
+ log(".i " + data.card_flavor_shaded[c] + ".")
if (data.card_flavor[c])
log(".i " + data.card_flavor[c] + ".")
goto_vm(c * 2 + 0)
@@ -6203,6 +6145,7 @@ function vm_remove() {
}
function vm_remove_farc_zone() {
+ log(`Removed Farc Zone from S${s}.`)
remove_farc_zone(game.vm.s)
vm_next()
}
@@ -6259,7 +6202,6 @@ function vm_set_passive_opposition() {
}
function vm_shift_support() {
- log("S" + game.vm.s + " to Passive Opposition.")
if (game.support[game.vm.s] < 2) {
game.support[game.vm.s] ++
log_support_shift(game.vm.s)
@@ -7025,7 +6967,7 @@ states.vm_free_rally_attack_terror = {
},
rally: vm_free_rally,
attack: vm_free_attack,
- terror: vm_free_terror_space,
+ terror: vm_free_terror,
}
states.vm_free_attack_terror = {
@@ -7039,7 +6981,7 @@ states.vm_free_attack_terror = {
view.actions.terror = 1
},
attack: vm_free_attack,
- terror: vm_free_terror_space,
+ terror: vm_free_terror,
}
// === GAME END ===
@@ -7065,6 +7007,18 @@ function log(msg) {
game.log.push(msg)
}
+function log_space(s, action) {
+ log_br()
+ if (action)
+ log("S" + s + " - " + action)
+ else
+ log("S" + s)
+}
+
+function logi(msg) {
+ log(">" + msg)
+}
+
function log_h1(msg) {
log_br()
log(".h1 " + msg)
@@ -8385,7 +8339,7 @@ CODE[46 * 2 + 0] = [
[ vm_prompt, "Execute free Terror with any Guerrilla." ],
[ vm_space, true, 1, 1, (s)=>has_piece(s, game.current, GUERRILLA) ],
[ vm_piece, false, 1, 1, (p,s)=>is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA) ],
- [ vm_free_terror ],
+ [ vm_free_terror_with_piece ],
[ vm_terror ],
[ vm_terror_aid_cut ],
[ vm_endpiece ],
@@ -8422,7 +8376,7 @@ CODE[47 * 2 + 1] = [
[ vm_auto_place, false, 0, AUC, GUERRILLA ],
[ vm_prompt, "Execute free Terror in CĂșcuta." ],
[ vm_piece, false, 1, 1, (p,s)=>is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_underground(p) ],
- [ vm_free_terror ],
+ [ vm_free_terror_with_piece ],
[ vm_terror_aid_cut ],
[ vm_endpiece ],
[ vm_endspace ],
@@ -8823,7 +8777,7 @@ CODE[63 * 2 + 0] = [
[ vm_endpiece ],
[ vm_prompt, "Free Terror with remaining Cartels Guerrilla." ],
[ vm_piece, false, 1, 1, (p,s)=>is_piece_in_event_space(p) && is_cartels_guerrilla(p) ],
- [ vm_free_terror ],
+ [ vm_free_terror_with_piece ],
[ vm_endpiece ],
[ vm_endspace ],
[ vm_terror_aid_cut ],
@@ -8986,7 +8940,7 @@ CODE[70 * 2 + 1] = [
[ vm_space, true, 999, 999, (s)=>is_forest(s) && has_piece(s, game.current, GUERRILLA) ],
[ vm_prompt, "Free Terror with any 1 Guerrilla." ],
[ vm_piece, false, 1, 1, (p,s)=>is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA) ],
- [ vm_free_terror ],
+ [ vm_free_terror_with_piece ],
[ vm_auto_resources, ()=>(game.current), 3 ],
[ vm_endpiece ],
[ vm_endspace ],