From 9656eff54c730205032a0a857f15ac08c6a578f8 Mon Sep 17 00:00:00 2001
From: Tor Andersson <tor@ccxvii.net>
Date: Tue, 21 Mar 2023 19:52:40 +0100
Subject: More events, cleanups, and if/else/endif.

---
 events.txt       | 135 ++++++-----
 rules.js         | 701 ++++++++++++++++++++++++++++++++++---------------------
 tools/gencode.js |  29 ++-
 tools/gendata.js | 152 ++++++------
 4 files changed, 608 insertions(+), 409 deletions(-)

diff --git a/events.txt b/events.txt
index 4a32ddf..8dc75c5 100644
--- a/events.txt
+++ b/events.txt
@@ -1,4 +1,7 @@
-# remove piece - transfer or remove shipments
+# TODO: has_available_piece and can_stack_piece helpers for place/replace/move space/piece loops
+# TODO: can_place_available(s, faction, type)
+
+# TODO: disallow picking spaces with no effect (must remove if able)
 
 EVENT 1
 	log "1 Civic Action space each Support Phase requires Govt Control and any cube."
@@ -63,7 +66,7 @@ EVENT 5
 		mark_space
 	endspace
 	prompt "Flip N Guerrillas there or adjacent to Active."
-	piece 3 is_guerrilla(p) && is_underground(p) && is_with_or_adjacent_to_mark(s, game.vm.m)
+	piece 3 is_any_guerrilla(p) && is_underground(p) && is_with_or_adjacent_to_mark(s, game.vm.m)
 		activate
 	endpiece
 
@@ -203,11 +206,12 @@ SHADED 18
 
 EVENT 19
 	if game.current === GOVT
+		# TODO: can_sweep || can_assault
 		space 0 has_cube(s) && has_enemy_piece(s)
 			free_sweep_assault
 		endspace
-	endif
-	if game.current !== GOVT
+	else
+		# TODO: can_attack || can_terror
 		space 0 has_piece(s, game.current, GUERRILLA)
 			free_attack_terror
 		endspace
@@ -215,8 +219,8 @@ EVENT 19
 
 EVENT 20
 	current GOVT
-	piece 6 is_farc_guerrilla(p)
-		space 1 is_adjacent(s, game.pieces[game.vm.p])
+	piece_undo_opt 6 is_farc_guerrilla(p)
+		space_no_undo 1 is_adjacent(s, game.pieces[game.vm.p])
 			move
 		endspace
 	endpiece
@@ -224,13 +228,13 @@ EVENT 20
 SHADED 20
 	current FARC
 	free_march
-	piece 3 is_farc_guerrilla(p) && is_active(p)
+	piece_undo_opt 3 is_farc_guerrilla(p) && is_active(p)
 		underground
 	endpiece
 
 EVENT 21
 	resources FARC -6
-	piece 1 is_farc_base(p)
+	piece_undo 1 is_farc_base(p)
 		remove
 	endpiece
 
@@ -251,7 +255,7 @@ SHADED 22
 
 EVENT 23
 	space 1 is_dept(s)
-		piece 0 is_piece_in_event_space(p) && is_guerrilla(p) && is_underground(p)
+		piece 0 is_piece_in_event_space(p) && is_any_guerrilla(p) && is_underground(p)
 			activate
 		endpiece
 		piece 0 is_piece_in_event_space(p) && is_cartels_base(p)
@@ -261,7 +265,7 @@ EVENT 23
 
 SHADED 23
 	current GOVT
-	piece 3 is_troops(p)
+	piece_undo 3 is_troops(p)
 		remove
 	endpiece
 	ineligible GOVT
@@ -320,8 +324,8 @@ SHADED 27
 	momentum
 
 EVENT 28
-	space_opt 1 is_next_to_venezuela(s)
-		piece 3 is_piece_in_event_space(p) && is_insurgent_piece(p)
+	space 1 is_next_to_venezuela(s)
+		piece_opt 3 is_piece_in_event_space(p) && is_insurgent_piece(p)
 			remove
 		endpiece
 	endspace
@@ -345,7 +349,7 @@ EVENT 29
 
 SHADED 29
 	current [FARC,AUC]
-	piece 2 is_faction_guerrilla(p, game.current) && has_enemy_piece(s)
+	piece_undo 2 is_piece(p, game.current, GUERRILLA) && has_enemy_piece(s)
 		free_ambush
 		underground
 	endpiece
@@ -384,8 +388,8 @@ SHADED 32
 	resources FARC 12
 
 EVENT 33
-	space_opt 1 is_next_to_ecuador(s)
-		piece 3 is_piece_in_event_space(p) && is_insurgent_piece(p)
+	space 1 is_next_to_ecuador(s)
+		piece_opt 3 is_piece_in_event_space(p) && is_insurgent_piece(p)
 			remove
 		endpiece
 	endspace
@@ -451,27 +455,29 @@ SHADED 37
 	endspace
 
 EVENT 38
-	space 3 has_cube(s) || is_support(s)
-		piece 0 is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_active(p)
+	space_opt 3 (has_cube(s) || is_support(s)) && has_active_guerrilla(s, AUC)
+		piece 0 is_piece_in_event_space(p) && is_active_guerrilla(p, AUC)
 			remove
 		endpiece
 	endspace
 
 SHADED 38
 	space 0 has_cube(s) || is_support(s)
-		piece 0 is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_active(p)
+		piece 0 is_piece_in_event_space(p) && is_active_guerrilla(p, AUC)
 			underground
 		endpiece
 	endspace
 
 EVENT 39
+	prompt "Place Police into each of 6 Departments."
+	# TODO: can_place
 	space 6 is_dept(s) && !is_farc_zone(s)
 		place GOVT POLICE
 	endspace
 
 SHADED 39
-	prompt "Replace Police with AUC Guerrillas."
-	# FIXME: space 3 is_dept(s)
+	# UPTO
+	prompt "In up to 3 Depts, replace 1 Police with AUC Guerrilla."
 	space_opt 3 is_dept(s) && has_police(s)
 		piece 1 is_piece_in_event_space(p) && is_police(p)
 			remove
@@ -480,8 +486,8 @@ SHADED 39
 	endspace
 
 EVENT 40
-	prompt "Replace AUC Guerrillas with Police."
-	piece 3 is_auc_guerrilla(p)
+	prompt "Replace 3 AUC Guerrillas with Police."
+	piece_undo 3 is_auc_guerrilla(p)
 		set_piece_space
 		remove
 		place GOVT POLICE
@@ -490,9 +496,9 @@ EVENT 40
 SHADED 40
 	space 1 is_dept(s) && has_auc_piece(s) && has_cube(s)
 		prompt "Move all cubes to any Cities."
-		piece 0 is_piece_in_event_space(p) && (is_troops(p) || is_police(p))
+		piece_no_undo 0 is_piece_in_event_space(p) && is_cube(p)
 			save_space
-			space 1 is_city(s)
+			space_no_undo 1 is_city(s)
 				move
 			endspace
 			restore_space
@@ -505,7 +511,6 @@ SHADED 40
 
 EVENT 41
 	resources AUC -6
-	# FIXME: space 1 is_space(s)
 	space 1 has_auc_piece(s)
 		piece 0 is_piece_in_event_space(p) && is_auc_piece(p)
 			remove
@@ -574,7 +579,7 @@ EVENT 46
 	current [FARC,AUC,CARTELS]
 	prompt "Execute free Terror with any Guerrilla."
 	space 1 has_piece(s, game.current, GUERRILLA)
-		piece 1 is_piece_in_event_space(p) && is_faction_guerrilla(p, game.current)
+		piece 1 is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA)
 			free_terror
 			terror
 			terror_aid_cut
@@ -614,6 +619,15 @@ SHADED 47
 		underground
 	endpiece
 
+EVENT 48
+	prompt "Remove Opposition or FARC Base adjacent to 3-Econ pipeline."
+	select_space_or_piece (s)=>(is_opposition(s)&&is_adjacent_to_3econ_pipeline(s)) (p,s)=>(is_farc_base(p)&&is_adjacent_to_3econ_pipeline(s))
+	if game.vm.p >= 0
+		remove
+	else
+		shift_support
+	endif
+
 SHADED 48
 	space 2 s !== BOGOTA && is_city(s)
 		shift_opposition
@@ -631,6 +645,7 @@ SHADED 49
 	endspace
 
 EVENT 50
+	# UPTO
 	current GOVT
 	space 1 is_dept(s) && !is_farc_zone(s)
 		place GOVT POLICE
@@ -686,11 +701,10 @@ EVENT 53
 		mark_space
 	endspace
 	prompt "Move Guerrillas between Departments."
-	piece 2 is_guerrilla(p) && (game.pieces[p] === game.vm.m[0] || game.pieces[p] === game.vm.m[1])
+	piece 2 is_any_guerrilla(p) && (s === game.vm.m[0] || s === game.vm.m[1])
 		if game.pieces[game.vm.p] === game.vm.m[0]
 			set_space (game.vm.m[1])
-		endif
-		if game.pieces[game.vm.p] === game.vm.m[1]
+		else
 			set_space (game.vm.m[0])
 		endif
 		move
@@ -698,7 +712,8 @@ EVENT 53
 	endpiece
 
 EVENT 54
-	piece 2 is_guerrilla(p)
+	# UPTO
+	piece_opt 2 is_any_guerrilla(p)
 		set_piece_space
 		remove
 		if piece_faction(game.vm.p) === FARC
@@ -713,8 +728,9 @@ EVENT 54
 	endpiece
 
 EVENT 55
-	remove_shipment
-	remove_shipment
+	shipment 2 true
+		remove_shipment
+	endpiece
 	prompt "Remove N Cartels Guerrillas."
 	piece 5 is_cartels_guerrilla(p)
 		remove
@@ -747,7 +763,7 @@ EVENT 57
 	endpiece
 
 SHADED 57
-	prompt "Replace Police with any Cartels pieces."
+	prompt "In 2 spaces replace 1 Police with any Cartels piece."
 	space 2 has_police(s)
 		piece 1 is_piece_in_event_space(p) && is_police(p)
 			remove
@@ -763,7 +779,7 @@ EVENT 58
 
 SHADED 58
 	current CARTELS
-	prompt "Relocate Police to any spaces."
+	prompt "Relocate up to 4 Police to any spaces."
 	piece_opt 4 is_police(p)
 		space 1 is_space(s)
 			move
@@ -805,6 +821,7 @@ SHADED 60
 	space 2 is_city(s) && can_stack_base(s)
 		place CARTELS BASE
 	endspace
+	# TODO: can_bribe
 	space 1 is_space(s)
 		free_bribe
 	endspace
@@ -884,6 +901,21 @@ SHADED 67
 	log "This Resources phase, Cartels add Resources equal to 4 x Bases."
 	momentum
 
+EVENT 68
+	prompt "Remove 2 Cartels pieces or up to 2 Shipments in coastal spaces."
+	select_shipment_or_cartels_piece_in_coastal_space
+	if game.vm.p >= 0
+		remove
+		piece 1 is_coastal_space(s) && is_cartels_piece(p)
+			remove
+		endpiece
+	else
+		remove_shipment
+		shipment_opt 1 is_coastal_space(s)
+			remove_shipment
+		endshipment
+	endif
+
 SHADED 68
 	prompt "Select each Cartels piece in coastal spaces."
 	piece 0 is_cartels_piece(p) && is_coastal_space(s)
@@ -896,8 +928,7 @@ EVENT 69
 		space 1 has_cube(s)
 			mark_space
 		endspace
-	endif
-	if game.current !== GOVT
+	else
 		space 1 has_piece(s, game.current, GUERRILLA)
 			mark_space
 		endspace
@@ -906,17 +937,16 @@ EVENT 69
 	if game.current === GOVT
 		space 1 (s !== game.vm.m[0]) && !is_farc_zone(s) && is_within_adjacent_depts(s, game.vm.m[0], 3)
 			prompt "Move cubes to destination."
-			piece_opt 0 (game.pieces[p] === game.vm.m[0]) && is_cube(p)
+			piece_opt 0 (s === game.vm.m[0]) && is_cube(p)
 				move
 			endpiece
 			# TODO: free sweep move or only flip?
 			free_train_sweep_assault
 		endspace
-	endif
-	if game.current !== GOVT
+	else
 		space 1 (s !== game.vm.m[0]) && is_within_adjacent_depts(s, game.vm.m[0], 3)
 			prompt "Move Guerrillas to destination."
-			piece_opt 0 (game.pieces[p] === game.vm.m[0]) && is_piece(p, game.current, GUERRILLA)
+			piece_opt 0 console.log("CHECK",p,s) || ((s === game.vm.m[0]) && is_piece(p, game.current, GUERRILLA))
 				move
 			endpiece
 			free_rally_attack_terror
@@ -932,7 +962,7 @@ EVENT 70
 SHADED 70
 	current [FARC,AUC,CARTELS]
 	space 0 is_forest(s) && has_piece(s, game.current, GUERRILLA)
-		piece 1 is_piece_in_event_space(p) && is_faction_guerrilla(p, game.current)
+		piece 1 is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA)
 			free_terror
 			resources (game.current) 3
 		endpiece
@@ -941,7 +971,8 @@ SHADED 70
 
 EVENT 71
 	prompt "Remove a Guerrilla from Chocó."
-	piece 1 is_guerrilla(p) && game.pieces[p] === CHOCO
+	set_space CHOCO
+	piece 1 is_any_guerrilla(p) && s === CHOCO
 		remove
 		resources (piece_faction(game.vm.p)) -5
 	endpiece
@@ -969,23 +1000,3 @@ SHADED 72
 			place CARTELS GUERRILLA
 		endspace
 	endwhile
-
-# --- --- --- --- ---
-
-EOF
-
-EVENT 68
-	remove 2 cartels pieces from coastal spaces
-	OR
-	remove 2 shipments from coastal spaces
-
-EVENT 48
-	space 1 is_adjacent_to_3econ_pipeline(s)
-		piece 1 is_piece_in_event_space(p) && is_farc_base(p)
-			remove
-		endpiece
-		TODO: OR
-		if has_opposition(game.vm.s)
-			shift_neutral
-		endif
-	endspace
diff --git a/rules.js b/rules.js
index 69f5403..2270e82 100644
--- a/rules.js
+++ b/rules.js
@@ -6,10 +6,9 @@
 // TODO: auto-next at end of Special Activity / operation space ?
 // TODO: resume_...activity - end automatically when no more possible
 // TODO: clean up init_free_operation and transitions
-// OP in a space -> next handler to cope with events/elite backing
+// OP in a space -> next() transition handler to deal with ops/events/elite-backing in a common way
 
 // TODO: All - Ecuador and Panama stacking for place/move
-// TODO: Free Train
 
 let states = {}
 let game = null
@@ -281,7 +280,7 @@ exports.setup = function (seed, scenario, options) {
 			setup_deck(4, 0, 15)
 	}
 
-	game.deck[0] = 69
+	game.deck[0] = 48
 	log("DECK " + game.deck.join(", "))
 
 	update_control()
@@ -489,23 +488,23 @@ function is_farc_base(p) { return is_piece(p, FARC, BASE) }
 function is_farc_guerrilla(p) { return is_piece(p, FARC, GUERRILLA) }
 function is_farc_piece(p) { return is_farc_base(p) || is_farc_guerrilla(p) }
 
-function is_auc_base(p) { is_piece(p, AUC, BASE) }
-function is_auc_guerrilla(p) { is_piece(p, AUC, GUERRILLA) }
+function is_auc_base(p) { return is_piece(p, AUC, BASE) }
+function is_auc_guerrilla(p) { return is_piece(p, AUC, GUERRILLA) }
 function is_auc_piece(p) { return is_auc_base(p) || is_auc_guerrilla(p) }
 
-function is_cartels_base(p) { is_piece(p, CARTELS, BASE) }
-function is_cartels_guerrilla(p) { is_piece(p, CARTELS, GUERRILLA) }
+function is_cartels_base(p) { return is_piece(p, CARTELS, BASE) }
+function is_cartels_guerrilla(p) { return is_piece(p, CARTELS, GUERRILLA) }
 function is_cartels_piece(p) { return is_cartels_base(p) || is_cartels_guerrilla(p) }
 
 function is_faction_guerrilla(p, faction) {
 	return is_piece(p, faction, GUERRILLA)
 }
 
-function is_base(p) {
+function is_any_base(p) {
 	return is_govt_base(p) || is_farc_base(p) || is_auc_base(p) || is_cartels_base(p)
 }
 
-function is_guerrilla(p) {
+function is_any_guerrilla(p) {
 	return is_farc_guerrilla(p) || is_auc_guerrilla(p) || is_cartels_guerrilla(p)
 }
 
@@ -513,6 +512,14 @@ function is_insurgent_piece(p) {
 	return is_farc_piece(p) || is_auc_piece(p) || is_cartels_piece(p)
 }
 
+function is_active_guerrilla(p, faction) {
+	return is_piece(p, faction, GUERRILLA) && is_active(p)
+}
+
+function is_underground_guerrilla(p, faction) {
+	return is_piece(p, faction, GUERRILLA) && is_underground(p)
+}
+
 // === MISC SPACE + PIECE QUERIES ===
 
 function count_pieces(s, faction, type) {
@@ -876,7 +883,7 @@ function is_possible_farc_zone(s) {
 function is_highest_value_pipeline_without_cubes(s) {
 	let max = 0
 	for (let x = first_loc; x <= last_loc; ++x) {
-		if (is_pipeline(x) && !has_cube(x)) {
+		if (is_unsabotaged_pipeline(x) && !has_cube(x)) {
 			let e = data.spaces[x].econ
 			if (e > max)
 				max = e
@@ -1039,7 +1046,7 @@ function place_piece(p, s) {
 }
 
 function remove_piece(p) {
-	if (is_guerrilla(p)) {
+	if (is_any_guerrilla(p)) {
 		// let s = game.pieces[p]
 		drop_held_shipments(p)
 		// TODO: auto_transfer_dropped_shipments(s) - immediate or wait?
@@ -2002,25 +2009,6 @@ states.eligible2 = {
 	},
 }
 
-function goto_pass() {
-	log_h2(faction_name[game.current] + " - Pass")
-	game.state = "pass"
-}
-
-states.pass = {
-	prompt() {
-		view.prompt = `Pass: ${faction_name[game.current]} +${game.current === GOVT ? 3 : 1} Resources.`
-		gen_action_resources(game.current)
-	},
-	resources(_) {
-		if (game.current === GOVT)
-			add_resources(game.current, 3)
-		else
-			add_resources(game.current, 1)
-		resume_event_card()
-	},
-}
-
 function goto_limop_or_event() {
 	game.state = "limop_or_event"
 }
@@ -2039,14 +2027,46 @@ states.limop_or_event = {
 	}
 }
 
-function goto_event() {
-	log_h2(faction_name[game.current] + " - Event")
-	if (set_has(single_events, this_card()))
-		execute_event(0)
-	else
-		game.state = "event"
+function can_ship() {
+	return game.op.ship && is_any_shipment_held()
+}
+
+function end_operation() {
+	if (can_ship()) {
+		push_undo()
+		game.state = "ship"
+	} else {
+		game.op = null
+		if (game.vm)
+			vm_next()
+		else
+			resume_event_card()
+	}
+}
+
+// === PASS ===
+
+function goto_pass() {
+	log_h2(faction_name[game.current] + " - Pass")
+	game.state = "pass"
+}
+
+states.pass = {
+	prompt() {
+		view.prompt = `Pass: ${faction_name[game.current]} +${game.current === GOVT ? 3 : 1} Resources.`
+		gen_action_resources(game.current)
+	},
+	resources(_) {
+		if (game.current === GOVT)
+			add_resources(game.current, 3)
+		else
+			add_resources(game.current, 1)
+		resume_event_card()
+	},
 }
 
+// === OPERATIONS ===
+
 function goto_op_only() {
 	log_h2(faction_name[game.current] + " - Op Only")
 	goto_operation(0, 0, 0, 1)
@@ -2086,25 +2106,6 @@ function init_free_operation(state) {
 	game.state = state
 }
 
-function can_ship() {
-	return game.op.ship && is_any_shipment_held()
-}
-
-function end_operation() {
-	if (can_ship()) {
-		push_undo()
-		game.state = "ship"
-	} else {
-		game.op = null
-		if (game.vm)
-			vm_next()
-		else
-			resume_event_card()
-	}
-}
-
-// === OPERATIONS ===
-
 states.op = {
 	prompt() {
 		view.prompt = "Choose an Operation."
@@ -2202,10 +2203,16 @@ function select_op_space(s, cost) {
 
 // OPERATION: TRAIN
 
-// REDO: place/base/civic for free action
-
 function vm_free_train() {
-	throw "TODO"
+	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
+	if (can_govt_train_place(game.op.where))
+		game.state = "train_place"
+	else
+		game.state = "train_base_or_civic"
 }
 
 function can_govt_train_place(s) {
@@ -2278,10 +2285,17 @@ states.train_place = {
 		place_piece(p, game.op.where)
 		update_control()
 		if (--game.op.count == 0)
-			game.state = "train"
+			this.next()
 	},
 	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 = "train_base_or_civic"
+			else
+				end_operation()
+			return
+		}
 		game.state = "train"
 	},
 }
@@ -3660,7 +3674,7 @@ function do_terror_piece(p) {
 		place_terror(s)
 		if (is_pop(s)) {
 			if (game.current === FARC) {
-				if (game.support[s] !== 0)
+				if (game.support[s] > -2)
 					game.support[s] --
 			} else {
 				if (game.support[s] > 0)
@@ -4449,7 +4463,7 @@ states.process_space = {
 		view.actions.next = 1
 	},
 	piece(p) {
-		if (is_base(p)) {
+		if (is_any_base(p)) {
 			log("Removed Base.")
 			add_resources(CARTELS, 3)
 			remove_piece(p)
@@ -4571,7 +4585,7 @@ states.bribe_space = {
 	piece(p) {
 		remove_piece(p)
 		update_control()
-		if (game.sa.targeted || is_base(p)) {
+		if (game.sa.targeted || is_any_base(p)) {
 			resume_bribe()
 			transfer_or_remove_shipments()
 		} else {
@@ -5283,12 +5297,20 @@ function end_farc_zone_place() {
 
 // === EVENTS ===
 
+function goto_event() {
+	log_h2(faction_name[game.current] + " - Event")
+	if (set_has(single_events, this_card()))
+		execute_event(0)
+	else
+		game.state = "event_effect"
+}
+
 function end_event() {
 	game.vm = null
 	resume_event_card()
 }
 
-states.event = {
+states.event_effect = {
 	prompt() {
 		let c = this_card()
 		view.prompt = `${data.card_title[c]}: Choose effect.`
@@ -5296,11 +5318,9 @@ states.event = {
 		view.actions.shaded = 1
 	},
 	unshaded() {
-		push_undo()
 		execute_event(0)
 	},
 	shaded() {
-		push_undo()
 		execute_event(1)
 	},
 }
@@ -5320,7 +5340,7 @@ function execute_event(shaded) {
 	}
 }
 
-// === EVENT VM ===
+// EVENT VM
 
 function is_piece_in_event_space(p) {
 	return game.pieces[p] === game.vm.s
@@ -5393,10 +5413,32 @@ function vm_asm() {
 }
 
 function vm_if() {
-	if (vm_operand(1))
-		vm_next()
-	else
-		vm_goto(vm_endif, vm_if, 1, 1)
+	if (!vm_operand(1)) {
+		let balance = 1
+		while (balance > 0) {
+			++game.vm.pc
+			console.log("scan else:", CODE[game.vm.pc][0].name)
+			switch (CODE[game.vm.pc][0]) {
+				case vm_if:
+					++balance
+					break
+				case vm_endif:
+					--balance
+					break
+				case vm_else:
+					if (balance === 1)
+						--balance
+					break
+			}
+			if (game.vm.pc < 0 || game.vm.pc > CODE.length)
+				throw "ERROR"
+		}
+	}
+	vm_next()
+}
+
+function vm_else() {
+	vm_goto(vm_endif, vm_if, 1, 1)
 }
 
 function vm_endif() {
@@ -5502,6 +5544,7 @@ function vm_move() {
 function vm_remove() {
 	remove_piece(game.vm.p)
 	update_control()
+	transfer_or_remove_shipments()
 	vm_next()
 }
 
@@ -5516,6 +5559,11 @@ function vm_place_shipment() {
 	vm_next()
 }
 
+function vm_remove_shipment() {
+	remove_shipment(game.vm.sh)
+	vm_next()
+}
+
 function vm_activate() {
 	set_active(game.vm.p)
 	vm_next()
@@ -5709,26 +5757,7 @@ states.vm_remove_permanently = {
 		place_piece(p, OUT_OF_PLAY)
 		update_control()
 		vm_next()
-	},
-}
-
-function vm_remove_shipment() {
-	if (is_any_shipment_held())
-		game.state = "vm_remove_shipment"
-	else
-		vm_next()
-}
-
-states.vm_remove_shipment = {
-	prompt() {
-		event_prompt("Remove Shipment.")
-		for (let sh = 0; sh < 4; ++sh)
-			if (is_shipment_held(sh))
-				gen_action_shipment(sh)
-	},
-	shipment(sh) {
-		remove_shipment(sh)
-		vm_next()
+		transfer_or_remove_shipments()
 	},
 }
 
@@ -5789,9 +5818,9 @@ states.vm_space = {
 		let n = CODE[game.vm.pc][3]
 		let f = CODE[game.vm.pc][4]
 		if (game.vm.prompt)
-			event_prompt(CODE[game.vm.prompt][1], n, n - game.vm.ss.length)
+			event_prompt(CODE[game.vm.prompt][1])
 		else
-			event_prompt("Select N space(s).", n, n - game.vm.ss.length)
+			event_prompt("Select space.")
 		for (let s = first_space; s <= last_space; ++s)
 			if (!set_has(game.vm.ss, s) && f(s))
 				gen_action_space(s)
@@ -5844,9 +5873,9 @@ states.vm_piece = {
 		let f = CODE[game.vm.pc][4]
 		view.where = game.vm.s
 		if (game.vm.prompt)
-			event_prompt(CODE[game.vm.prompt][1], n, n - game.vm.pp.length)
+			event_prompt(CODE[game.vm.prompt][1])
 		else
-			event_prompt("Select N piece(s).", n, n - game.vm.pp.length)
+			event_prompt("Select piece.")
 		for (let p = all_first_piece; p <= all_last_piece; ++p)
 			if (game.pieces[p] >= 0 && !set_has(game.vm.pp, p) && f(p, game.pieces[p]))
 				gen_action_piece(p)
@@ -5867,7 +5896,66 @@ states.vm_piece = {
 	},
 }
 
-// VM: PLACE
+// VM: SHIPMENT ITERATOR
+
+function vm_shipment() {
+	if (can_vm_shipment())
+		game.state = "vm_shipment"
+	else
+		vm_goto(vm_endshipment, vm_shipment, 1, 1)
+}
+
+function vm_endshipment() {
+	vm_goto(vm_shipment, vm_endshipment, -1, 0)
+}
+
+function can_vm_shipment() {
+	let n = CODE[game.vm.pc][3]
+	let f = CODE[game.vm.pc][4]
+	if (n > 0 && game.vm.m >= n)
+		return false
+	for (let sh = 0; sh < 4; ++sh) {
+		if (is_shipment_held(sh)) {
+			let p = get_held_shipment_piece(sh)
+			if (f(p, game.pieces[p]))
+				return true
+		}
+	}
+	return false
+}
+
+states.vm_shipment = {
+	prompt() {
+		let n = CODE[game.vm.pc][3]
+		let f = CODE[game.vm.pc][4]
+		if (game.vm.prompt)
+			event_prompt(CODE[game.vm.prompt][1])
+		else
+			event_prompt("Select shipment.")
+		for (let sh = 0; sh < 4; ++sh) {
+			if (is_shipment_held(sh)) {
+				let p = get_held_shipment_piece(sh)
+				if (f(p, game.pieces[p]))
+					gen_action_shipment(sh)
+			}
+		}
+		if (CODE[game.vm.pc][2])
+			view.actions.skip = 1
+	},
+	shipment(sh) {
+		if (CODE[game.vm.pc][1])
+			push_undo()
+		game.vm.sh = sh
+		vm_next()
+	},
+	skip() {
+		if (CODE[game.vm.pc][1])
+			push_undo()
+		vm_goto(vm_endshipment, vm_shipment, 1, 1)
+	},
+}
+
+// VM: PLACE PIECE
 
 function vm_place() {
 	if (can_vm_place())
@@ -5988,7 +6076,7 @@ function vm_place_or_remove_shipment() {
 
 states.vm_place_or_remove_shipment = {
 	prompt() {
-		event_prompt(`Place or Remove Shipment in ${space_name[game.vm.s]}.`)
+		event_prompt(`Place or remove Shipment in ${space_name[game.vm.s]}.`)
 		for (let sh = 0; sh < 4; ++sh)
 			if (is_shipment_held_in_space(sh, game.vm.s))
 				gen_action_shipment(sh)
@@ -6021,7 +6109,7 @@ function vm_place_or_remove_insurgent_base() {
 
 states.vm_place_or_remove_insurgent_base = {
 	prompt() {
-		event_prompt(`Place or Remove Insurgent Base in ${space_name[game.vm.s]}.`)
+		event_prompt(`Place or remove Insurgent Base in ${space_name[game.vm.s]}.`)
 		gen_piece_in_space(game.vm.s, FARC, BASE)
 		gen_piece_in_space(game.vm.s, AUC, BASE)
 		gen_piece_in_space(game.vm.s, CARTELS, BASE)
@@ -6038,6 +6126,64 @@ states.vm_place_or_remove_insurgent_base = {
 			remove_piece(p)
 		update_control()
 		vm_next()
+		transfer_or_remove_shipments()
+	},
+}
+
+function vm_select_shipment_or_cartels_piece_in_coastal_space() {
+	game.state = "vm_select_shipment_or_cartels_piece_in_coastal_space"
+}
+
+states.vm_select_shipment_or_cartels_piece_in_coastal_space = {
+	prompt() {
+		event_prompt(CODE[game.vm.prompt][1])
+		for (let s = first_space; s <= last_space; ++s) {
+			if (is_coastal_space(s)) {
+				gen_piece_in_space(s, CARTELS, GUERRILLA)
+				gen_piece_in_space(s, CARTELS, BASE)
+				for (let sh = 0; sh < 4; ++sh)
+					if (is_shipment_held_in_space(sh, s))
+						gen_action_shipment(sh)
+			}
+		}
+	},
+	piece(p) {
+		game.vm.sh = -1
+		game.vm.p = p
+		vm_next()
+	},
+	shipment(sh) {
+		game.vm.p = -1
+		game.vm.sh = sh
+		vm_next()
+	},
+}
+
+function vm_select_space_or_piece() {
+	game.state = "vm_select_space_or_piece"
+}
+
+states.vm_select_space_or_piece = {
+	prompt() {
+		let sf = CODE[game.vm.pc][1]
+		let pf = CODE[game.vm.pc][2]
+		event_prompt(CODE[game.vm.prompt][1])
+		for (let s = first_space; s <= last_space; ++s)
+			if (sf(s))
+				gen_action_space(s)
+		for (let p = all_first_piece; p <= all_last_piece; ++p)
+			if (game.pieces[p] >= 0 && pf(p, game.pieces[p]))
+				gen_action_piece(p)
+	},
+	space(s) {
+		game.vm.p = -1
+		game.vm.s = s
+		vm_next()
+	},
+	piece(p) {
+		game.vm.p = p
+		game.vm.s = -1
+		vm_next()
 	},
 }
 
@@ -6638,67 +6784,67 @@ const CODE = [
 	[ vm_return ],
 // EVENT 4
 	[ vm_prompt, "Select unsabotaged pipelines." ],
-	[ vm_space, 0, 0, 3, (s)=>is_unsabotaged_pipeline(s) ],
+	[ vm_space, 1, 0, 3, (s)=>is_unsabotaged_pipeline(s) ],
 	[ vm_resources, GOVT, ()=>(2*data.spaces[game.vm.s].econ) ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 4
 	[ vm_prompt, "Sabotage the 3 pipelines with highest value and no cubes." ],
-	[ vm_space, 0, 0, 3, (s)=>is_highest_value_pipeline_without_cubes(s) ],
+	[ vm_space, 1, 0, 3, (s)=>is_highest_value_pipeline_without_cubes(s) ],
 	[ vm_sabotage ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 5
 	[ vm_prompt, "Place Police onto Pipelines." ],
-	[ vm_space, 0, 0, 1, (s)=>is_pipeline(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pipeline(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_pipeline(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pipeline(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_pipeline(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pipeline(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_pipeline(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pipeline(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_pipeline(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pipeline(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_pipeline(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pipeline(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
 	[ vm_prompt, "Flip N Guerrillas there or adjacent to Active." ],
-	[ vm_piece, 0, 0, 3, (s,p)=>is_guerrilla(p) && is_underground(p) && is_with_or_adjacent_to_mark(s, game.vm.m) ],
+	[ vm_piece, 0, 0, 3, (p,s)=>is_any_guerrilla(p) && is_underground(p) && is_with_or_adjacent_to_mark(s, game.vm.m) ],
 	[ vm_activate ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 5
 	[ vm_prompt, "Shift space adjacent to a 3-Econ LoC by 2 levels toward Active Opposition." ],
-	[ vm_space, 0, 0, 1, (s)=>is_adjacent_to_3econ_loc(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_adjacent_to_3econ_loc(s) ],
 	[ vm_shift_opposition ],
 	[ vm_shift_opposition ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 6
 	[ vm_prompt, "Select Opposition or Neutral Departments adjacent to Sabotage." ],
-	[ vm_space, 0, 0, 2, (s)=>(!is_support(s) && is_adjacent_to_support(s)) ],
+	[ vm_space, 1, 0, 2, (s)=>(!is_support(s) && is_adjacent_to_support(s)) ],
 	[ vm_set_passive_support ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 6
 	[ vm_prompt, "Sabotage a pipeline." ],
-	[ vm_space, 0, 0, 1, (s)=>is_pipeline(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pipeline(s) ],
 	[ vm_sabotage ],
 	[ vm_endspace ],
 	[ vm_prompt, "Shift an Adjacent Department." ],
-	[ vm_space, 0, 0, 1, (s)=>is_pop(s) && is_dept(s) && is_adjacent(s, game.vm.s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_pop(s) && is_dept(s) && is_adjacent(s, game.vm.s) ],
 	[ vm_shift_opposition ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -6761,7 +6907,7 @@ const CODE = [
 	[ vm_return ],
 // EVENT 14
 	[ vm_current, GOVT ],
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
 	[ vm_place, 0, 0, GOVT, BASE ],
 	[ vm_place, 0, 0, GOVT, TROOPS ],
 	[ vm_place, 0, 0, GOVT, TROOPS ],
@@ -6769,11 +6915,11 @@ const CODE = [
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 14
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_govt_base(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_govt_base(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && (is_troops(p) || is_police(p)) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && (is_troops(p) || is_police(p)) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
@@ -6783,13 +6929,13 @@ const CODE = [
 	[ vm_resources, GOVT, ()=>(game.vm.die*4) ],
 	[ vm_return ],
 // SHADED 15
-	[ vm_space, 0, 0, 1, (s)=>is_city() && (is_neutral(s) || is_passive_support(s)) ],
+	[ vm_space, 1, 0, 1, (s)=>is_city() && (is_neutral(s) || is_passive_support(s)) ],
 	[ vm_set_passive_opposition ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 16
 	[ vm_prompt, "Select each Mountain Department." ],
-	[ vm_space, 0, 0, 0, (s)=>is_mountain(s) ],
+	[ vm_space, 1, 0, 0, (s)=>is_mountain(s) ],
 	[ vm_resources, ()=>(faction_with_most_pieces(game.vm.s)), 5 ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -6815,19 +6961,18 @@ const CODE = [
 	[ vm_return ],
 // EVENT 19
 	[ vm_if, ()=>game.current === GOVT ],
-	[ vm_space, 0, 0, 0, (s)=>has_cube(s) && has_enemy_piece(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_cube(s) && has_enemy_piece(s) ],
 	[ vm_free_sweep_assault ],
 	[ vm_endspace ],
-	[ vm_endif ],
-	[ vm_if, ()=>game.current !== GOVT ],
-	[ vm_space, 0, 0, 0, (s)=>has_piece(s, game.current, GUERRILLA) ],
+	[ vm_else ],
+	[ vm_space, 1, 0, 0, (s)=>has_piece(s, game.current, GUERRILLA) ],
 	[ vm_free_attack_terror ],
 	[ vm_endspace ],
 	[ vm_endif ],
 	[ vm_return ],
 // EVENT 20
 	[ vm_current, GOVT ],
-	[ vm_piece, 0, 0, 6, (s,p)=>is_farc_guerrilla(p) ],
+	[ vm_piece, 1, 1, 6, (p,s)=>is_farc_guerrilla(p) ],
 	[ vm_space, 0, 0, 1, (s)=>is_adjacent(s, game.pieces[game.vm.p]) ],
 	[ vm_move ],
 	[ vm_endspace ],
@@ -6836,24 +6981,24 @@ const CODE = [
 // SHADED 20
 	[ vm_current, FARC ],
 	[ vm_free_march ],
-	[ vm_piece, 0, 0, 3, (s,p)=>is_farc_guerrilla(p) && is_active(p) ],
+	[ vm_piece, 1, 1, 3, (p,s)=>is_farc_guerrilla(p) && is_active(p) ],
 	[ vm_underground ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 21
 	[ vm_resources, FARC, -6 ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_farc_base(p) ],
+	[ vm_piece, 1, 0, 1, (p,s)=>is_farc_base(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 21
 	[ vm_resources, FARC, 6 ],
-	[ vm_space, 0, 0, 1, (s)=>(is_city(s) || is_dept(s)) && can_stack_base(s) ],
+	[ vm_space, 1, 0, 1, (s)=>(is_city(s) || is_dept(s)) && can_stack_base(s) ],
 	[ vm_place, 0, 0, FARC, BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 22
-	[ vm_space, 0, 0, 1, (s)=>is_opposition(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_opposition(s) ],
 	[ vm_set_neutral ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -6862,48 +7007,48 @@ const CODE = [
 	[ vm_momentum ],
 	[ vm_return ],
 // EVENT 23
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_guerrilla(p) && is_underground(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_any_guerrilla(p) && is_underground(p) ],
 	[ vm_activate ],
 	[ vm_endpiece ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_cartels_base(p) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_cartels_base(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 23
 	[ vm_current, GOVT ],
-	[ vm_piece, 0, 0, 3, (s,p)=>is_troops(p) ],
+	[ vm_piece, 1, 0, 3, (p,s)=>is_troops(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_ineligible, GOVT ],
 	[ vm_ineligible, FARC ],
 	[ vm_return ],
 // EVENT 24
-	[ vm_space, 0, 0, 1, (s)=>is_city(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_city(s) ],
 	[ vm_set_active_support ],
 	[ vm_endspace ],
 	[ vm_ineligible, FARC ],
 	[ vm_return ],
 // SHADED 24
-	[ vm_space, 0, 0, 1, (s)=>has_farc_piece(s) ],
-	[ vm_piece, 0, 0, 2, (s,p)=>is_piece_in_event_space(p) && is_troops(p) ],
+	[ vm_space, 1, 0, 1, (s)=>has_farc_piece(s) ],
+	[ vm_piece, 0, 0, 2, (p,s)=>is_piece_in_event_space(p) && is_troops(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_city(s) && is_support(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_city(s) && is_support(s) ],
 	[ vm_set_neutral ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 25
-	[ vm_space, 0, 0, 1, (s)=>is_mountain(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_farc_piece(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_mountain(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_farc_piece(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 25
-	[ vm_space, 0, 0, 1, (s)=>s === ANTIOQUIA || (is_dept(s) && is_adjacent(ANTIOQUIA, s)) ],
+	[ vm_space, 1, 0, 1, (s)=>s === ANTIOQUIA || (is_dept(s) && is_adjacent(ANTIOQUIA, s)) ],
 	[ vm_place, 0, 0, FARC, [BASE,GUERRILLA] ],
 	[ vm_place, 0, 0, FARC, [BASE,GUERRILLA] ],
 	[ vm_place, 0, 0, FARC, [BASE,GUERRILLA] ],
@@ -6911,13 +7056,13 @@ const CODE = [
 	[ vm_return ],
 // EVENT 26
 	[ vm_current, CARTELS ],
-	[ vm_space, 0, 0, 0, (s)=>has_cartels_guerrilla(s) && has_farc_piece(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_cartels_guerrilla(s) && has_farc_piece(s) ],
 	[ vm_free_attack ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 26
 	[ vm_prompt, "Transfer 6 Resources from Cartels to FARC for each space with CB and FG." ],
-	[ vm_space, 0, 0, 0, (s)=>has_cartels_base(s) && has_farc_guerrilla(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_cartels_base(s) && has_farc_guerrilla(s) ],
 	[ vm_transfer, CARTELS, FARC, 6 ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -6932,24 +7077,24 @@ const CODE = [
 	[ vm_momentum ],
 	[ vm_return ],
 // EVENT 28
-	[ vm_space, 0, 1, 1, (s)=>is_next_to_venezuela(s) ],
-	[ vm_piece, 0, 0, 3, (s,p)=>is_piece_in_event_space(p) && is_insurgent_piece(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_next_to_venezuela(s) ],
+	[ vm_piece, 0, 1, 3, (p,s)=>is_piece_in_event_space(p) && is_insurgent_piece(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 28
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && is_next_to_venezuela(s) && can_stack_base(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && is_next_to_venezuela(s) && can_stack_base(s) ],
 	[ vm_place, 0, 0, FARC, BASE ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 0, (s)=>is_loc(s) && is_adjacent(CUCUTA, s) && is_empty(s) ],
+	[ vm_space, 1, 0, 0, (s)=>is_loc(s) && is_adjacent(CUCUTA, s) && is_empty(s) ],
 	[ vm_sabotage ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 29
 	[ vm_current, GOVT ],
-	[ vm_space, 0, 0, 1, (s)=>has_farc_piece(s) && has_govt_piece(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_farc_guerrilla(p) && is_underground(p) ],
+	[ vm_space, 1, 0, 1, (s)=>has_farc_piece(s) && has_govt_piece(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_farc_guerrilla(p) && is_underground(p) ],
 	[ vm_activate ],
 	[ vm_endpiece ],
 	[ vm_free_assault ],
@@ -6957,15 +7102,15 @@ const CODE = [
 	[ vm_return ],
 // SHADED 29
 	[ vm_current, [FARC,AUC] ],
-	[ vm_piece, 0, 0, 2, (s,p)=>is_faction_guerrilla(p, game.current) && has_enemy_piece(s) ],
+	[ vm_piece, 1, 0, 2, (p,s)=>is_piece(p, game.current, GUERRILLA) && has_enemy_piece(s) ],
 	[ vm_free_ambush ],
 	[ vm_underground ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 30
-	[ vm_space, 0, 0, 1, (s)=>is_farc_zone(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_farc_zone(s) ],
 	[ vm_remove_farc_zone ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_farc_base(p) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_farc_base(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
@@ -6975,20 +7120,20 @@ const CODE = [
 	[ vm_place_farc_zone ],
 	[ vm_return ],
 // EVENT 31
-	[ vm_space, 0, 0, 2, (s)=>is_city(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_city(s) ],
 	[ vm_shift_support ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) ],
 	[ vm_shift_support ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 31
-	[ vm_space, 0, 0, 3, (s)=>is_passive_opposition(s) ],
+	[ vm_space, 1, 0, 3, (s)=>is_passive_opposition(s) ],
 	[ vm_set_active_opposition ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 32
-	[ vm_space, 0, 0, 2, (s)=>is_neutral(s) || is_passive_opposition(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_neutral(s) || is_passive_opposition(s) ],
 	[ vm_set_passive_support ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -6996,15 +7141,15 @@ const CODE = [
 	[ vm_resources, FARC, 12 ],
 	[ vm_return ],
 // EVENT 33
-	[ vm_space, 0, 1, 1, (s)=>is_next_to_ecuador(s) ],
-	[ vm_piece, 0, 0, 3, (s,p)=>is_piece_in_event_space(p) && is_insurgent_piece(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_next_to_ecuador(s) ],
+	[ vm_piece, 0, 1, 3, (p,s)=>is_piece_in_event_space(p) && is_insurgent_piece(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 33
 	[ vm_capability ],
-	[ vm_space, 0, 0, 1, (s)=>s === ECUADOR ],
+	[ vm_space, 1, 0, 1, (s)=>s === ECUADOR ],
 	[ vm_place, 0, 0, ()=>(game.current), [BASE,GUERRILLA,TROOPS,POLICE] ],
 	[ vm_place, 0, 0, ()=>(game.current), [BASE,GUERRILLA,TROOPS,POLICE] ],
 	[ vm_endspace ],
@@ -7014,15 +7159,15 @@ const CODE = [
 	[ vm_return ],
 // SHADED 34
 	[ vm_current, [FARC,AUC,CARTELS] ],
-	[ vm_space, 0, 0, 1, (s)=>is_zero_pop_dept(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_zero_pop_dept(s) ],
 	[ vm_place, 0, 0, ()=>(game.current), GUERRILLA ],
 	[ vm_place, 0, 0, ()=>(game.current), GUERRILLA ],
 	[ vm_place, 0, 0, ()=>(game.current), BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 35
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_cartels_base(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_cartels_base(p) ],
 	[ vm_remove ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_endpiece ],
@@ -7030,7 +7175,7 @@ const CODE = [
 	[ vm_aid, 3 ],
 	[ vm_return ],
 // SHADED 35
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && has_cartels_base(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && has_cartels_base(s) ],
 	[ vm_shift_opposition ],
 	[ vm_shift_opposition ],
 	[ vm_endspace ],
@@ -7042,65 +7187,66 @@ const CODE = [
 	[ vm_place_farc_zone ],
 	[ vm_asm, ()=>game.current = game.vm.m ],
 	[ vm_prompt, "Shift adjacent spaces toward Active Support." ],
-	[ vm_space, 0, 0, 2, (s)=>is_pop(s) && !is_active_support(s) && is_adjacent(game.vm.farc_zone, s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_pop(s) && !is_active_support(s) && is_adjacent(game.vm.farc_zone, s) ],
 	[ vm_shift_support ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 37
 	[ vm_current, GOVT ],
-	[ vm_space, 0, 0, 0, (s)=>has_cube(s) && has_farc_piece(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_cube(s) && has_farc_piece(s) ],
 	[ vm_free_sweep_assault_farc ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 37
 	[ vm_current, AUC ],
 	[ vm_free_march ],
-	[ vm_space, 0, 0, 1, (s)=>set_has(game.vm.m, s) && has_underground_guerrilla(s, AUC) ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_underground(p) ],
+	[ vm_space, 1, 0, 1, (s)=>set_has(game.vm.m, s) && has_underground_guerrilla(s, AUC) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_underground(p) ],
 	[ vm_free_ambush ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 38
-	[ vm_space, 0, 0, 3, (s)=>has_cube(s) || is_support(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_active(p) ],
+	[ vm_space, 1, 1, 3, (s)=>(has_cube(s) || is_support(s)) && has_active_guerrilla(s, AUC) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_active_guerrilla(p, AUC) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 38
-	[ vm_space, 0, 0, 0, (s)=>has_cube(s) || is_support(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_active(p) ],
+	[ vm_space, 1, 0, 0, (s)=>has_cube(s) || is_support(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_active_guerrilla(p, AUC) ],
 	[ vm_underground ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 39
-	[ vm_space, 0, 0, 6, (s)=>is_dept(s) && !is_farc_zone(s) ],
+	[ vm_prompt, "Place Police into each of 6 Departments." ],
+	[ vm_space, 1, 0, 6, (s)=>is_dept(s) && !is_farc_zone(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 39
-	[ vm_prompt, "Replace Police with AUC Guerrillas." ],
-	[ vm_space, 0, 1, 3, (s)=>is_dept(s) && has_police(s) ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_police(p) ],
+	[ vm_prompt, "In up to 3 Depts, replace 1 Police with AUC Guerrilla." ],
+	[ vm_space, 1, 1, 3, (s)=>is_dept(s) && has_police(s) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_police(p) ],
 	[ vm_remove ],
 	[ vm_place, 0, 0, AUC, GUERRILLA ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 40
-	[ vm_prompt, "Replace AUC Guerrillas with Police." ],
-	[ vm_piece, 0, 0, 3, (s,p)=>is_auc_guerrilla(p) ],
+	[ vm_prompt, "Replace 3 AUC Guerrillas with Police." ],
+	[ vm_piece, 1, 0, 3, (p,s)=>is_auc_guerrilla(p) ],
 	[ vm_set_piece_space ],
 	[ vm_remove ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 40
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && has_auc_piece(s) && has_cube(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && has_auc_piece(s) && has_cube(s) ],
 	[ vm_prompt, "Move all cubes to any Cities." ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && (is_troops(p) || is_police(p)) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_cube(p) ],
 	[ vm_save_space ],
 	[ vm_space, 0, 0, 1, (s)=>is_city(s) ],
 	[ vm_move ],
@@ -7109,26 +7255,26 @@ const CODE = [
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_prompt, "Place AUC pieces in Cities." ],
-	[ vm_space, 0, 0, 2, (s)=>is_city(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_city(s) ],
 	[ vm_place, 0, 0, AUC, [BASE,GUERRILLA] ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 41
 	[ vm_resources, AUC, -6 ],
-	[ vm_space, 0, 0, 1, (s)=>has_auc_piece(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_auc_piece(p) ],
+	[ vm_space, 1, 0, 1, (s)=>has_auc_piece(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_auc_piece(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 41
 	[ vm_prompt, "Select each space with AUC and Cartels pieces." ],
-	[ vm_space, 0, 0, 0, (s)=>has_auc_piece(s) && has_cartels_piece(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_auc_piece(s) && has_cartels_piece(s) ],
 	[ vm_resources, AUC, 3 ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 42
-	[ vm_space, 0, 0, 2, (s)=>is_neutral(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_neutral(s) ],
 	[ vm_set_passive_support ],
 	[ vm_endspace ],
 	[ vm_resources, GOVT, 3 ],
@@ -7139,41 +7285,41 @@ const CODE = [
 	[ vm_momentum ],
 	[ vm_return ],
 // EVENT 43
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && has_troops(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && has_troops(s) ],
 	[ vm_terror ],
 	[ vm_terror ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_farc_base(p) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_farc_base(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 43
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && has_troops(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && has_troops(s) ],
 	[ vm_terror ],
 	[ vm_terror ],
 	[ vm_endspace ],
 	[ vm_aid, -9 ],
 	[ vm_return ],
 // EVENT 44
-	[ vm_space, 0, 0, 1, (s)=>is_city(s) && !is_opposition(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_city(s) && !is_opposition(s) ],
 	[ vm_set_active_support ],
 	[ vm_endspace ],
 	[ vm_resources, GOVT, 3 ],
 	[ vm_return ],
 // SHADED 44
-	[ vm_space, 0, 0, 1, (s)=>is_city(s) && is_support(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_city(s) && is_support(s) ],
 	[ vm_set_neutral ],
 	[ vm_endspace ],
 	[ vm_resources, GOVT, -3 ],
 	[ vm_return ],
 // EVENT 45
-	[ vm_space, 0, 0, 0, (s)=>has_cube(s) && has_terror(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_cube(s) && has_terror(s) ],
 	[ vm_shift_support ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 45
 	[ vm_prompt, "Select each space with AUC pieces." ],
-	[ vm_space, 0, 0, 0, (s)=>has_auc_piece(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_auc_piece(s) ],
 	[ vm_aid, -1 ],
 	[ vm_endspace ],
 	[ vm_roll ],
@@ -7182,14 +7328,14 @@ const CODE = [
 // EVENT 46
 	[ vm_current, [FARC,AUC,CARTELS] ],
 	[ vm_prompt, "Execute free Terror with any Guerrilla." ],
-	[ vm_space, 0, 0, 1, (s)=>has_piece(s, game.current, GUERRILLA) ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_faction_guerrilla(p, game.current) ],
+	[ vm_space, 1, 0, 1, (s)=>has_piece(s, game.current, GUERRILLA) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA) ],
 	[ vm_free_terror ],
 	[ vm_terror ],
 	[ vm_terror_aid_cut ],
 	[ vm_endpiece ],
 	[ vm_prompt, "Remove enemy pieces." ],
-	[ vm_piece, 0, 0, 2, (s,p)=>is_piece_in_event_space(p) && is_enemy_piece(p) ],
+	[ vm_piece, 0, 0, 2, (p,s)=>is_piece_in_event_space(p) && is_enemy_piece(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_if, ()=>is_pop(game.vm.s) ],
@@ -7198,10 +7344,10 @@ const CODE = [
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 47
-	[ vm_piece, 0, 0, 0, (s,p)=>is_auc_guerrilla(p) && is_underground(p) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_auc_guerrilla(p) && is_underground(p) ],
 	[ vm_activate ],
 	[ vm_endpiece ],
-	[ vm_space, 0, 0, 0, (s)=>has_police(s) && has_auc_piece(s) ],
+	[ vm_space, 1, 0, 0, (s)=>has_police(s) && has_auc_piece(s) ],
 	[ vm_free_assault_auc ],
 	[ vm_endpiece ],
 	[ vm_return ],
@@ -7212,17 +7358,26 @@ const CODE = [
 	[ vm_place, 0, 0, AUC, GUERRILLA ],
 	[ vm_place, 0, 0, AUC, GUERRILLA ],
 	[ vm_prompt, "Execute free Terror in Cúcuta." ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_underground(p) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_auc_guerrilla(p) && is_underground(p) ],
 	[ vm_free_terror ],
 	[ vm_terror_aid_cut ],
 	[ vm_endpiece ],
 	[ vm_prompt, "Flip any AUC Guerrillas Underground." ],
-	[ vm_piece, 0, 0, 2, (s,p)=>is_auc_guerrilla(p) && is_active(p) ],
+	[ vm_piece, 0, 0, 2, (p,s)=>is_auc_guerrilla(p) && is_active(p) ],
 	[ vm_underground ],
 	[ vm_endpiece ],
 	[ vm_return ],
+// EVENT 48
+	[ vm_prompt, "Remove Opposition or FARC Base adjacent to 3-Econ pipeline." ],
+	[ vm_select_space_or_piece, (s)=>(is_opposition(s)&&is_adjacent_to_3econ_pipeline(s)), (p,s)=>(is_farc_base(p)&&is_adjacent_to_3econ_pipeline(s)) ],
+	[ vm_if, ()=>game.vm.p >= 0 ],
+	[ vm_remove ],
+	[ vm_else ],
+	[ vm_shift_support ],
+	[ vm_endif ],
+	[ vm_return ],
 // SHADED 48
-	[ vm_space, 0, 0, 2, (s)=>s !== BOGOTA && is_city(s) ],
+	[ vm_space, 1, 0, 2, (s)=>s !== BOGOTA && is_city(s) ],
 	[ vm_shift_opposition ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -7232,25 +7387,25 @@ const CODE = [
 	[ vm_remove_permanently, AUC, GUERRILLA ],
 	[ vm_return ],
 // SHADED 49
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) ],
 	[ vm_place, 0, 0, AUC, GUERRILLA ],
 	[ vm_place, 0, 0, AUC, BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 50
 	[ vm_current, GOVT ],
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_dept(s) && !is_farc_zone(s) ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 50
-	[ vm_piece, 0, 0, 2, (s,p)=>is_police(p) ],
+	[ vm_piece, 0, 0, 2, (p,s)=>is_police(p) ],
 	[ vm_set_piece_space ],
 	[ vm_remove ],
 	[ vm_place, 0, 1, AUC, GUERRILLA ],
@@ -7259,7 +7414,7 @@ const CODE = [
 // EVENT 51
 	[ vm_if, ()=>is_any_pipeline_sabotaged() ],
 	[ vm_prompt, "Remove all Pipeline Sabotage." ],
-	[ vm_space, 0, 0, 0, (s)=>is_pipeline(s) && has_sabotage(s) ],
+	[ vm_space, 1, 0, 0, (s)=>is_pipeline(s) && has_sabotage(s) ],
 	[ vm_remove_sabotage ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -7268,35 +7423,34 @@ const CODE = [
 	[ vm_return ],
 // SHADED 51
 	[ vm_prompt, "Sabotage Pipelines with or adjacent to FARC Guerrillas." ],
-	[ vm_space, 0, 0, 3, (s)=>is_pipeline(s) && is_with_or_adjacent_to_farc_guerrilla(s) ],
+	[ vm_space, 1, 0, 3, (s)=>is_pipeline(s) && is_with_or_adjacent_to_farc_guerrilla(s) ],
 	[ vm_sabotage ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 52
-	[ vm_space, 0, 0, 2, (s)=>is_city(s) || is_mountain(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_city(s) || is_mountain(s) ],
 	[ vm_shift_support ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 52
-	[ vm_space, 0, 0, 1, (s)=>has_auc_piece(s) && can_stack_base(s) ],
+	[ vm_space, 1, 0, 1, (s)=>has_auc_piece(s) && can_stack_base(s) ],
 	[ vm_place, 0, 0, AUC, BASE ],
 	[ vm_endspace ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_auc_base(p) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_auc_base(p) ],
 	[ vm_resources, AUC, 1 ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 53
 	[ vm_current, [FARC,AUC,CARTELS] ],
 	[ vm_prompt, "Select Departments to move Guerrillas between." ],
-	[ vm_space, 0, 0, 2, (s)=>is_dept(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_dept(s) ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
 	[ vm_prompt, "Move Guerrillas between Departments." ],
-	[ vm_piece, 0, 0, 2, (s,p)=>is_guerrilla(p) && (game.pieces[p] === game.vm.m[0] || game.pieces[p] === game.vm.m[1]) ],
+	[ vm_piece, 0, 0, 2, (p,s)=>is_any_guerrilla(p) && (s === game.vm.m[0] || s === game.vm.m[1]) ],
 	[ vm_if, ()=>game.pieces[game.vm.p] === game.vm.m[0] ],
 	[ vm_set_space, ()=>(game.vm.m[1]) ],
-	[ vm_endif ],
-	[ vm_if, ()=>game.pieces[game.vm.p] === game.vm.m[1] ],
+	[ vm_else ],
 	[ vm_set_space, ()=>(game.vm.m[0]) ],
 	[ vm_endif ],
 	[ vm_move ],
@@ -7304,7 +7458,7 @@ const CODE = [
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 54
-	[ vm_piece, 0, 0, 2, (s,p)=>is_guerrilla(p) ],
+	[ vm_piece, 0, 1, 2, (p,s)=>is_any_guerrilla(p) ],
 	[ vm_set_piece_space ],
 	[ vm_remove ],
 	[ vm_if, ()=>piece_faction(game.vm.p) === FARC ],
@@ -7319,17 +7473,18 @@ const CODE = [
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 55
+	[ vm_shipment, 0, 0, 2, (p,s)=>true ],
 	[ vm_remove_shipment ],
-	[ vm_remove_shipment ],
+	[ vm_endpiece ],
 	[ vm_prompt, "Remove N Cartels Guerrillas." ],
-	[ vm_piece, 0, 0, 5, (s,p)=>is_cartels_guerrilla(p) ],
+	[ vm_piece, 0, 0, 5, (p,s)=>is_cartels_guerrilla(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_aid, 3 ],
 	[ vm_return ],
 // SHADED 55
 	[ vm_prompt, "Shift N spaces with Cartels pieces 1 level toward Active Opposition." ],
-	[ vm_space, 0, 0, 3, (s)=>has_cartels_piece(s) && !is_active_opposition(s) ],
+	[ vm_space, 1, 0, 3, (s)=>has_cartels_piece(s) && !is_active_opposition(s) ],
 	[ vm_shift_opposition ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -7337,25 +7492,25 @@ const CODE = [
 	[ vm_transfer, CARTELS, GOVT, 15 ],
 	[ vm_return ],
 // SHADED 56
-	[ vm_piece, 0, 0, 0, (s,p)=>is_cartels_piece(p) && is_city(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_cartels_piece(p) && is_city(s) ],
 	[ vm_resources, CARTELS, 2 ],
 	[ vm_endpiece ],
-	[ vm_space, 0, 0, 2, (s)=>is_city(s) && can_stack_base(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_city(s) && can_stack_base(s) ],
 	[ vm_place, 0, 0, CARTELS, BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 57
 	[ vm_prompt, "Replace Cartels pieces with Police." ],
-	[ vm_piece, 0, 1, 3, (s,p)=>is_cartels_piece(p) ],
+	[ vm_piece, 0, 1, 3, (p,s)=>is_cartels_piece(p) ],
 	[ vm_set_piece_space ],
 	[ vm_remove ],
 	[ vm_place, 0, 0, GOVT, POLICE ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 57
-	[ vm_prompt, "Replace Police with any Cartels pieces." ],
-	[ vm_space, 0, 0, 2, (s)=>has_police(s) ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_police(p) ],
+	[ vm_prompt, "In 2 spaces replace 1 Police with any Cartels piece." ],
+	[ vm_space, 1, 0, 2, (s)=>has_police(s) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_police(p) ],
 	[ vm_remove ],
 	[ vm_place, 0, 0, CARTELS, [BASE,GUERRILLA] ],
 	[ vm_endpiece ],
@@ -7363,44 +7518,44 @@ const CODE = [
 	[ vm_return ],
 // EVENT 58
 	[ vm_resources, CARTELS, -6 ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_cartels_guerrilla(p) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_cartels_guerrilla(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 58
 	[ vm_current, CARTELS ],
-	[ vm_prompt, "Relocate Police to any spaces." ],
-	[ vm_piece, 0, 1, 4, (s,p)=>is_police(p) ],
-	[ vm_space, 0, 0, 1, (s)=>is_space(s) ],
+	[ vm_prompt, "Relocate up to 4 Police to any spaces." ],
+	[ vm_piece, 0, 1, 4, (p,s)=>is_police(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_space(s) ],
 	[ vm_move ],
 	[ vm_endspace ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 59
 	[ vm_current, GOVT ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_cartels_guerrilla(p) && is_underground(p) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_cartels_guerrilla(p) && is_underground(p) ],
 	[ vm_activate ],
 	[ vm_endpiece ],
-	[ vm_space, 0, 0, 0, (s)=>can_assault(s, CARTELS) ],
+	[ vm_space, 1, 0, 0, (s)=>can_assault(s, CARTELS) ],
 	[ vm_free_assault_cartels ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 59
 	[ vm_current, CARTELS ],
 	[ vm_prompt, "Flip all Cartels Guerrillas underground." ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_cartels_guerrilla(p) && is_active(p) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_cartels_guerrilla(p) && is_active(p) ],
 	[ vm_underground ],
 	[ vm_endpiece ],
 	[ vm_prompt, "Relocate Cartels Guerrillas anywhere." ],
-	[ vm_piece, 0, 1, 3, (s,p)=>is_cartels_guerrilla(p) ],
-	[ vm_space, 0, 0, 1, (s)=>is_space(s) ],
+	[ vm_piece, 0, 1, 3, (p,s)=>is_cartels_guerrilla(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_space(s) ],
 	[ vm_move ],
 	[ vm_endspace ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 60
-	[ vm_space, 0, 0, 2, (s)=>has_cartels_piece(s) && ((is_city(s) && (game.vm.ss.length === 0 || is_city(game.vm.ss[0]))) || (is_dept(s) && game.vm.ss.length === 0)) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_cartels_piece(p) ],
+	[ vm_space, 1, 0, 2, (s)=>has_cartels_piece(s) && ((is_city(s) && (game.vm.ss.length === 0 || is_city(game.vm.ss[0]))) || (is_dept(s) && game.vm.ss.length === 0)) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_cartels_piece(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
@@ -7408,43 +7563,43 @@ const CODE = [
 	[ vm_return ],
 // SHADED 60
 	[ vm_current, CARTELS ],
-	[ vm_space, 0, 0, 2, (s)=>is_city(s) && can_stack_base(s) ],
+	[ vm_space, 1, 0, 2, (s)=>is_city(s) && can_stack_base(s) ],
 	[ vm_place, 0, 0, CARTELS, BASE ],
 	[ vm_endspace ],
-	[ vm_space, 0, 0, 1, (s)=>is_space(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_space(s) ],
 	[ vm_free_bribe ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 61
-	[ vm_space, 0, 0, 1, (s)=>is_city(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_cartels_piece(p) ],
+	[ vm_space, 1, 0, 1, (s)=>is_city(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_cartels_piece(p) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
 	[ vm_resources, CARTELS, -6 ],
 	[ vm_return ],
 // SHADED 61
-	[ vm_space, 0, 0, 3, (s)=>!has_cartels_piece(s) && can_stack_base(s) ],
+	[ vm_space, 1, 0, 3, (s)=>!has_cartels_piece(s) && can_stack_base(s) ],
 	[ vm_place, 0, 0, CARTELS, BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 62
-	[ vm_piece, 0, 1, 3, (s,p)=>is_insurgent_piece(p) && is_zero_pop_forest(s) ],
+	[ vm_piece, 0, 1, 3, (p,s)=>is_insurgent_piece(p) && is_zero_pop_forest(s) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 62
-	[ vm_space, 0, 0, 3, (s)=>s === GUAINIA || s === VAUPES || s === AMAZONAS ],
+	[ vm_space, 1, 0, 3, (s)=>s === GUAINIA || s === VAUPES || s === AMAZONAS ],
 	[ vm_place, 0, 0, CARTELS, BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 63
 	[ vm_current, CARTELS ],
-	[ vm_space, 0, 0, 0, (s)=>has_cartels_guerrilla(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_cartels_guerrilla(p) && count_pieces(s, CARTELS, GUERRILLA) > 1 ],
+	[ vm_space, 1, 0, 0, (s)=>has_cartels_guerrilla(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_cartels_guerrilla(p) && count_pieces(s, CARTELS, GUERRILLA) > 1 ],
 	[ vm_remove ],
 	[ vm_endpiece ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_cartels_guerrilla(p) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_cartels_guerrilla(p) ],
 	[ vm_free_terror ],
 	[ vm_endpiece ],
 	[ vm_endspace ],
@@ -7453,33 +7608,33 @@ const CODE = [
 	[ vm_return ],
 // EVENT 64
 	[ vm_prompt, "Place Shipments with FARC Guerrillas." ],
-	[ vm_piece, 0, 0, 2, (s,p)=>is_farc_guerrilla(p) && has_cartels_base(s) && has_available_shipment() ],
+	[ vm_piece, 0, 0, 2, (p,s)=>is_farc_guerrilla(p) && has_cartels_base(s) && has_available_shipment() ],
 	[ vm_place_shipment ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 64
 	[ vm_prompt, "Select each Cartels Base in a City." ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_cartels_base(p) && is_city(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_cartels_base(p) && is_city(s) ],
 	[ vm_resources, CARTELS, 2 ],
 	[ vm_endpiece ],
 	[ vm_prompt, "Select each Cartels Base in a Dept." ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_cartels_base(p) && is_dept(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_cartels_base(p) && is_dept(s) ],
 	[ vm_resources, CARTELS, 1 ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 65
-	[ vm_space, 0, 0, 1, (s)=>is_mountain(s) ],
+	[ vm_space, 1, 0, 1, (s)=>is_mountain(s) ],
 	[ vm_place_or_remove_shipment ],
 	[ vm_place_or_remove_insurgent_base ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 66
-	[ vm_piece, 0, 0, 3, (s,p)=>is_cartels_base(p) && is_forest(s) ],
+	[ vm_piece, 0, 0, 3, (p,s)=>is_cartels_base(p) && is_forest(s) ],
 	[ vm_remove ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 66
-	[ vm_space, 0, 0, 0, (s)=>is_forest(s) && has_cartels_base(s) && can_stack_base(s) ],
+	[ vm_space, 1, 0, 0, (s)=>is_forest(s) && has_cartels_base(s) && can_stack_base(s) ],
 	[ vm_place, 0, 0, CARTELS, BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
@@ -7490,38 +7645,51 @@ const CODE = [
 	[ vm_log, "This Resources phase, Cartels add Resources equal to 4 x Bases." ],
 	[ vm_momentum ],
 	[ vm_return ],
+// EVENT 68
+	[ vm_prompt, "Remove 2 Cartels pieces or up to 2 Shipments in coastal spaces." ],
+	[ vm_select_shipment_or_cartels_piece_in_coastal_space ],
+	[ vm_if, ()=>game.vm.p >= 0 ],
+	[ vm_remove ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_coastal_space(s) && is_cartels_piece(p) ],
+	[ vm_remove ],
+	[ vm_endpiece ],
+	[ vm_else ],
+	[ vm_remove_shipment ],
+	[ vm_shipment, 0, 1, 1, (p,s)=>is_coastal_space(s) ],
+	[ vm_remove_shipment ],
+	[ vm_endshipment ],
+	[ vm_endif ],
+	[ vm_return ],
 // SHADED 68
 	[ vm_prompt, "Select each Cartels piece in coastal spaces." ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_cartels_piece(p) && is_coastal_space(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_cartels_piece(p) && is_coastal_space(s) ],
 	[ vm_resources, CARTELS, 2 ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // EVENT 69
 	[ vm_prompt, "Select source space." ],
 	[ vm_if, ()=>game.current === GOVT ],
-	[ vm_space, 0, 0, 1, (s)=>has_cube(s) ],
+	[ vm_space, 1, 0, 1, (s)=>has_cube(s) ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
-	[ vm_endif ],
-	[ vm_if, ()=>game.current !== GOVT ],
-	[ vm_space, 0, 0, 1, (s)=>has_piece(s, game.current, GUERRILLA) ],
+	[ vm_else ],
+	[ vm_space, 1, 0, 1, (s)=>has_piece(s, game.current, GUERRILLA) ],
 	[ vm_mark_space ],
 	[ vm_endspace ],
 	[ vm_endif ],
 	[ vm_prompt, "Select destination space." ],
 	[ vm_if, ()=>game.current === GOVT ],
-	[ vm_space, 0, 0, 1, (s)=>(s !== game.vm.m[0]) && !is_farc_zone(s) && is_within_adjacent_depts(s, game.vm.m[0], 3) ],
+	[ vm_space, 1, 0, 1, (s)=>(s !== game.vm.m[0]) && !is_farc_zone(s) && is_within_adjacent_depts(s, game.vm.m[0], 3) ],
 	[ vm_prompt, "Move cubes to destination." ],
-	[ vm_piece, 0, 1, 0, (s,p)=>(game.pieces[p] === game.vm.m[0]) && is_cube(p) ],
+	[ vm_piece, 0, 1, 0, (p,s)=>(s === game.vm.m[0]) && is_cube(p) ],
 	[ vm_move ],
 	[ vm_endpiece ],
 	[ vm_free_train_sweep_assault ],
 	[ vm_endspace ],
-	[ vm_endif ],
-	[ vm_if, ()=>game.current !== GOVT ],
-	[ vm_space, 0, 0, 1, (s)=>(s !== game.vm.m[0]) && is_within_adjacent_depts(s, game.vm.m[0], 3) ],
+	[ vm_else ],
+	[ vm_space, 1, 0, 1, (s)=>(s !== game.vm.m[0]) && is_within_adjacent_depts(s, game.vm.m[0], 3) ],
 	[ vm_prompt, "Move Guerrillas to destination." ],
-	[ vm_piece, 0, 1, 0, (s,p)=>(game.pieces[p] === game.vm.m[0]) && is_piece(p, game.current, GUERRILLA) ],
+	[ vm_piece, 0, 1, 0, (p,s)=>console.log("CHECK",p,s) || ((s === game.vm.m[0]) && is_piece(p, game.current, GUERRILLA)) ],
 	[ vm_move ],
 	[ vm_endpiece ],
 	[ vm_free_rally_attack_terror ],
@@ -7530,14 +7698,14 @@ const CODE = [
 	[ vm_return ],
 // EVENT 70
 	[ vm_prompt, "Select each Forest without Guerrillas." ],
-	[ vm_space, 0, 0, 0, (s)=>is_forest(s) && !has_any_guerrilla(s) ],
+	[ vm_space, 1, 0, 0, (s)=>is_forest(s) && !has_any_guerrilla(s) ],
 	[ vm_resources, GOVT, 6 ],
 	[ vm_endspace ],
 	[ vm_return ],
 // SHADED 70
 	[ vm_current, [FARC,AUC,CARTELS] ],
-	[ vm_space, 0, 0, 0, (s)=>is_forest(s) && has_piece(s, game.current, GUERRILLA) ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_piece_in_event_space(p) && is_faction_guerrilla(p, game.current) ],
+	[ vm_space, 1, 0, 0, (s)=>is_forest(s) && has_piece(s, game.current, GUERRILLA) ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_piece_in_event_space(p) && is_piece(p, game.current, GUERRILLA) ],
 	[ vm_free_terror ],
 	[ vm_resources, ()=>(game.current), 3 ],
 	[ vm_endpiece ],
@@ -7546,21 +7714,22 @@ const CODE = [
 	[ vm_return ],
 // EVENT 71
 	[ vm_prompt, "Remove a Guerrilla from Chocó." ],
-	[ vm_piece, 0, 0, 1, (s,p)=>is_guerrilla(p) && game.pieces[p] === CHOCO ],
+	[ vm_set_space, CHOCO ],
+	[ vm_piece, 0, 0, 1, (p,s)=>is_any_guerrilla(p) && s === CHOCO ],
 	[ vm_remove ],
 	[ vm_resources, ()=>(piece_faction(game.vm.p)), -5 ],
 	[ vm_endpiece ],
 	[ vm_return ],
 // SHADED 71
 	[ vm_capability ],
-	[ vm_space, 0, 0, 1, (s)=>s === PANAMA ],
+	[ vm_space, 1, 0, 1, (s)=>s === PANAMA ],
 	[ vm_place, 0, 0, ()=>(game.current), BASE ],
 	[ vm_place, 0, 0, ()=>(game.current), BASE ],
 	[ vm_endspace ],
 	[ vm_return ],
 // EVENT 72
-	[ vm_space, 0, 0, 2, (s)=>has_cartels_guerrilla(s) ],
-	[ vm_piece, 0, 0, 0, (s,p)=>is_piece_in_event_space(p) && is_cartels_guerrilla(p) ],
+	[ vm_space, 1, 0, 2, (s)=>has_cartels_guerrilla(s) ],
+	[ vm_piece, 0, 0, 0, (p,s)=>is_piece_in_event_space(p) && is_cartels_guerrilla(p) ],
 	[ vm_remove ],
 	[ vm_place, 0, 0, [FARC,AUC], GUERRILLA ],
 	[ vm_endpiece ],
@@ -7569,11 +7738,11 @@ const CODE = [
 // SHADED 72
 	[ vm_prompt, "Place all available Cartels Guerrillas into spaces with Cartels Bases." ],
 	[ vm_while, ()=>has_piece(AVAILABLE, CARTELS, GUERRILLA) && count_pieces(AVAILABLE, CARTELS, BASE) < 15 ],
-	[ vm_space, 0, 0, 1, (s)=>has_cartels_base(s) ],
+	[ vm_space, 1, 0, 1, (s)=>has_cartels_base(s) ],
 	[ vm_place, 0, 0, CARTELS, GUERRILLA ],
 	[ vm_endspace ],
 	[ vm_endwhile ],
 	[ vm_return ],
 ]
-const UCODE = [0,1,7,13,19,29,65,79,85,92,98,104,110,116,122,139,146,153,159,166,177,190,200,207,223,237,249,259,267,280,294,304,315,321,333,342,355,365,378,390,402,424,436,445,459,469,480,497,0,523,532,549,563,574,591,605,618,627,642,655,675,690,701,709,721,735,740,748,0,758,789,803,815]
-const SCODE = [0,4,10,16,24,59,70,82,90,95,101,107,113,119,130,142,151,156,162,0,184,195,204,216,228,243,254,264,273,288,301,311,319,327,335,350,0,370,384,394,409,431,441,453,464,473,0,504,519,527,543,558,567,0,0,613,620,634,647,663,682,697,705,0,726,0,744,750,753,0,794,809,822]
+const UCODE = [0,1,7,13,19,29,65,79,85,92,98,104,110,116,122,139,146,153,159,166,176,189,199,206,222,236,248,258,266,279,293,303,314,320,332,341,354,364,377,389,402,424,436,445,459,469,480,497,519,531,540,557,571,582,598,612,626,635,650,663,683,698,709,717,729,743,748,756,761,780,809,823,836]
+const SCODE = [0,4,10,16,24,59,70,82,90,95,101,107,113,119,130,142,151,156,162,0,183,194,203,215,227,242,253,263,272,287,300,310,318,326,334,349,0,369,383,394,409,431,441,453,464,473,0,504,527,535,551,566,575,0,0,621,628,642,655,671,690,705,713,0,734,0,752,758,775,0,814,830,843]
diff --git a/tools/gencode.js b/tools/gencode.js
index c2071bb..4ac01d1 100644
--- a/tools/gencode.js
+++ b/tools/gencode.js
@@ -38,9 +38,15 @@ for (let line of fs.readFileSync("events.txt", "utf-8").split("\n")) {
 		break
 
 	case "space_opt":
-		emit([ "space", 0, 1, line[1], "(s)=>" + line.slice(2).join(" ") ])
+		emit([ "space", 1, 1, line[1], "(s)=>" + line.slice(2).join(" ") ])
 		break
 	case "space":
+		emit([ "space", 1, 0, line[1], "(s)=>" + line.slice(2).join(" ") ])
+		break
+	case "space_no_undo_opt":
+		emit([ "space", 0, 1, line[1], "(s)=>" + line.slice(2).join(" ") ])
+		break
+	case "space_no_undo":
 		emit([ "space", 0, 0, line[1], "(s)=>" + line.slice(2).join(" ") ])
 		break
 	case "space_undo_opt":
@@ -51,16 +57,29 @@ for (let line of fs.readFileSync("events.txt", "utf-8").split("\n")) {
 		break
 
 	case "piece_opt":
-		emit([ "piece", 0, 1, line[1], "(s,p)=>" + line.slice(2).join(" ") ])
+		emit([ "piece", 0, 1, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
 		break
 	case "piece":
-		emit([ "piece", 0, 0, line[1], "(s,p)=>" + line.slice(2).join(" ") ])
+		emit([ "piece", 0, 0, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
+		break
+	case "piece_no_undo_opt":
+		emit([ "piece", 0, 1, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
+		break
+	case "piece_no_undo":
+		emit([ "piece", 0, 0, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
 		break
 	case "piece_undo_opt":
-		emit([ "piece", 1, 1, line[1], "(s,p)=>" + line.slice(2).join(" ") ])
+		emit([ "piece", 1, 1, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
 		break
 	case "piece_undo":
-		emit([ "piece", 1, 0, line[1], "(s,p)=>" + line.slice(2).join(" ") ])
+		emit([ "piece", 1, 0, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
+		break
+
+	case "shipment_opt":
+		emit([ "shipment", 0, 1, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
+		break
+	case "shipment":
+		emit([ "shipment", 0, 0, line[1], "(p,s)=>" + line.slice(2).join(" ") ])
 		break
 
 	case "place_opt":
diff --git a/tools/gendata.js b/tools/gendata.js
index 5e30f35..01db4b5 100644
--- a/tools/gendata.js
+++ b/tools/gendata.js
@@ -141,82 +141,82 @@ function flavor(id, unshaded, shaded) {
 		card_flavor_shaded[id] = shaded
 }
 
-flavor("1. 1st Division","Jointness","Service parochialism")
-flavor("2. Ospina & Mora","COIN experts take charge","COIN strategy eludes Army")
-flavor("3. Tapias","CO tightens civil-military bonds","Civil-military rivalries fester")
-flavor("4. Caño Limón - Coveñas","Profitable pipeline","Pipeline draws attacks")
-flavor("5. Occidental & Ecopetrol","Oil company security","Industry thought exploitative")
-flavor("6. Oil Spill","Rebels blamed","Multinationals make mess")
-flavor("7. 7th Special Forces","Infrastructure protection training","US training ineffective")
-flavor("8. Fuerza Aérea Colombiana","COIN strike aircraft","Budget diverted to expensive jets")
-flavor("9. High Mountain Battalions","Elites guard high-altitude corridors","Equipment not delivered")
-flavor("10. Blackhawks","US helos delivered","Delivery of US helos delayed")
-flavor("11. National Defense & Security Council","Military-police jointness","Military-police rivalry")
-flavor("12. Plan Colombia","US \"War on Drugs\"","US aid focuses on drug war")
-flavor("13. Plan Meteoro","Transport protection units","Transport security deemphasized")
-flavor("14. Tres Esquinas","Forward base","Base overrun")
-flavor("15. War Tax","Defense budget shot in the arm","Middle class resents cost of war")
-flavor("16. Coffee Prices","They're up","They're down")
-flavor("17. Madrid Donors","Aid conference generous","EU aid focuses on reconstruction")
-flavor("18. NSPD-18","US \"War on Terror\" takes on FARC","US focused on Mid-East and South Asia")
-flavor("19. General Offensive","","")
-flavor("20. Mono Jojoy","KIA puts FARC in disarray","Military strategist")
-flavor("21. Raúl Reyes","FARC Deputy killed","FARC Deputy channels foreign support")
-flavor("22. Alfonso Cano","FARC leader killed in military strike","Ideologue")
-flavor("23. DoD Contractors","US provides aircrew","Plane down - hostage search and evasion")
-flavor("24. Operación Jaque","Dramatic hostage rescue","Hostage rescue goes awry")
-flavor("25. Ejército de Liberación Nacional","ELN and FARC jockey","ELN and FARC coordinate ops")
-flavor("26. Gramaje","FARC protection rejected","Schedule of fees")
-flavor("27. Misil Antiaéreo","FARC MANPADs deemed a myth","MANPADs feared")
-flavor("28. Hugo Chávez","Caracas controls border","Caracas aids rebels")
-flavor("29. Kill Zone","Army sniffs out FARC trap","Tactics lure enemy in")
-flavor("30. Peace Commission","FARC accused in Commissioner's killing","Peace bid")
-flavor("31. Betancourt","Sympathy for famous hostage","Hostage negotiations forum for FARC")
-flavor("32. Secuestrados","Fed up with hostage-taking","Ransoming highly profitable")
-flavor("33. Sucumbíos","Ecuadoran buffer zone","Cross-border war")
-flavor("34. Airdropped AKs","Insurgents scammed by Russian criminals","Covert weapons delivery")
-flavor("35. Crop Substitution","Government initiative","FARC proposals lauded")
-flavor("36. Zona de Convivencia","ELN gets its DMZ","")
-flavor("37. Former Military","Ties that bind","Ex-officers advise paramilitaries")
-flavor("38. National Coordination Center","New command fights paramilitaries","Sympathizers alert AUC")
-flavor("39. Soldados Campesinos","Local forces platoons","Local forces augment autodefensas")
-flavor("40. Demobilization","Negotiated reintegration","Talks a ruse, fighters recycled")
-flavor("41. Mancuso","AUC No.2 extradited","AUC drug lord")
-flavor("42. Senado & Cámara","Unity behind Presidential war policy","Insurgent sympathies")
-flavor("43. Calima Front","Suspect leftists massacred","Brutality blamed on Army")
-flavor("44. Colombia Nueva","Anti-corruption campaign","Political campaign divisive")
-flavor("45. Los Derechos Humanos","Officers disciplined","International human rights cartel")
-flavor("46. Limpieza","Ruthless elimination","")
-flavor("47. Pinto & del Rosario","Human rights investigators","Prosecutors killed")
-flavor("48. Unión Sindical Obrera","AUC targets oil labor organizers","Labor backs FARC")
-flavor("49. Bloques","Militias defy Castaño","Independent militias join AUC")
-flavor("50. Carabineros","National police field forces","National police corruption")
-flavor("51. Pipeline Repairs","Speedy patching","Security concerns hinder maintenance")
-flavor("52. Castaño","AUC leader's memoir a best seller","Charismatic AUC political leader")
-flavor("53. Criminal Air Force","Insurgent access to small aircraft","")
-flavor("54. Deserters & Defectors","","")
-flavor("55. DEA Agents","Law enforcement assistance","Más Yanquis")
-flavor("56. Drogas La Rebaja","Cali cartel's drugstore chain seized","Retail empire")
-flavor("57. Op Millenium","Colombian-US strike at Bernal syndicate","Investigation penetrated")
-flavor("58. General Serrano","National Police hammer cartels","Officials on cartel payroll")
-flavor("59. Salcedo","Cartel informant","Cali cartel security chief")
-flavor("60. The Chess Player","Kingpin strategy scores","Cali's Gilberto Rodríguez Orejuela expands empire")
-flavor("61. Air Bridge","Peruvian coca supply controlled","Colombian coca growers fill Peruvian void")
-flavor("62. Amazonía","Brasília's Op Cobra blocks border","Jungle landing strips")
-flavor("63. Narco-War","Rival syndicates go for the throat","")
-flavor("64. Cocaine Labs","FARC taps suppliers","Well-oiled industry")
-flavor("65. Poppies","Growers and Government eradication focus on heroin source","")
-flavor("66. Tingo María","Coca crop fails","Hearty coca variety")
-flavor("67. Mexican Traffickers","Major shipment busted en route","New routes to US market")
-flavor("68. Narco-Subs","Submersibles seized","Littoral stealth")
-flavor("69. Riverines & Fast Boats","","")
-flavor("70. Ayahuasca Tourism","Eco-tourism helps trade balance","Eco-tourists taken")
-flavor("71. Darién","Arms traffic interdicted","Border sanctuary")
-flavor("72. Sicarios","Hired drug guns unreliable","Unemployed ready to work for syndicates")
-flavor("73. Propaganda!","","")
-flavor("74. Propaganda!","","")
-flavor("75. Propaganda!","","")
-flavor("76. Propaganda!","","")
+flavor("1. 1st Division", "Jointness", "Service parochialism")
+flavor("2. Ospina & Mora", "COIN experts take charge", "COIN strategy eludes Army")
+flavor("3. Tapias", "CO tightens civil-military bonds", "Civil-military rivalries fester")
+flavor("4. Caño Limón - Coveñas", "Profitable pipeline", "Pipeline draws attacks")
+flavor("5. Occidental & Ecopetrol", "Oil company security", "Industry thought exploitative")
+flavor("6. Oil Spill", "Rebels blamed", "Multinationals make mess")
+flavor("7. 7th Special Forces", "Infrastructure protection training", "US training ineffective")
+flavor("8. Fuerza Aérea Colombiana", "COIN strike aircraft", "Budget diverted to expensive jets")
+flavor("9. High Mountain Battalions", "Elites guard high-altitude corridors", "Equipment not delivered")
+flavor("10. Blackhawks", "US helos delivered", "Delivery of US helos delayed")
+flavor("11. National Defense & Security Council", "Military-police jointness", "Military-police rivalry")
+flavor("12. Plan Colombia", "US \"War on Drugs\"", "US aid focuses on drug war")
+flavor("13. Plan Meteoro", "Transport protection units", "Transport security deemphasized")
+flavor("14. Tres Esquinas", "Forward base", "Base overrun")
+flavor("15. War Tax", "Defense budget shot in the arm", "Middle class resents cost of war")
+flavor("16. Coffee Prices", "They're up", "They're down")
+flavor("17. Madrid Donors", "Aid conference generous", "EU aid focuses on reconstruction")
+flavor("18. NSPD-18", "US \"War on Terror\" takes on FARC", "US focused on Mid-East and South Asia")
+flavor("19. General Offensive", "", "")
+flavor("20. Mono Jojoy", "KIA puts FARC in disarray", "Military strategist")
+flavor("21. Raúl Reyes", "FARC Deputy killed", "FARC Deputy channels foreign support")
+flavor("22. Alfonso Cano", "FARC leader killed in military strike", "Ideologue")
+flavor("23. DoD Contractors", "US provides aircrew", "Plane down - hostage search and evasion")
+flavor("24. Operación Jaque", "Dramatic hostage rescue", "Hostage rescue goes awry")
+flavor("25. Ejército de Liberación Nacional", "ELN and FARC jockey", "ELN and FARC coordinate ops")
+flavor("26. Gramaje", "FARC protection rejected", "Schedule of fees")
+flavor("27. Misil Antiaéreo", "FARC MANPADs deemed a myth", "MANPADs feared")
+flavor("28. Hugo Chávez", "Caracas controls border", "Caracas aids rebels")
+flavor("29. Kill Zone", "Army sniffs out FARC trap", "Tactics lure enemy in")
+flavor("30. Peace Commission", "FARC accused in Commissioner's killing", "Peace bid")
+flavor("31. Betancourt", "Sympathy for famous hostage", "Hostage negotiations forum for FARC")
+flavor("32. Secuestrados", "Fed up with hostage-taking", "Ransoming highly profitable")
+flavor("33. Sucumbíos", "Ecuadoran buffer zone", "Cross-border war")
+flavor("34. Airdropped AKs", "Insurgents scammed by Russian criminals", "Covert weapons delivery")
+flavor("35. Crop Substitution", "Government initiative", "FARC proposals lauded")
+flavor("36. Zona de Convivencia", "ELN gets its DMZ", "")
+flavor("37. Former Military", "Ties that bind", "Ex-officers advise paramilitaries")
+flavor("38. National Coordination Center", "New command fights paramilitaries", "Sympathizers alert AUC")
+flavor("39. Soldados Campesinos", "Local forces platoons", "Local forces augment autodefensas")
+flavor("40. Demobilization", "Negotiated reintegration", "Talks a ruse, fighters recycled")
+flavor("41. Mancuso", "AUC No.2 extradited", "AUC drug lord")
+flavor("42. Senado & Cámara", "Unity behind Presidential war policy", "Insurgent sympathies")
+flavor("43. Calima Front", "Suspect leftists massacred", "Brutality blamed on Army")
+flavor("44. Colombia Nueva", "Anti-corruption campaign", "Political campaign divisive")
+flavor("45. Los Derechos Humanos", "Officers disciplined", "International human rights cartel")
+flavor("46. Limpieza", "Ruthless elimination", "")
+flavor("47. Pinto & del Rosario", "Human rights investigators", "Prosecutors killed")
+flavor("48. Unión Sindical Obrera", "AUC targets oil labor organizers", "Labor backs FARC")
+flavor("49. Bloques", "Militias defy Castaño", "Independent militias join AUC")
+flavor("50. Carabineros", "National police field forces", "National police corruption")
+flavor("51. Pipeline Repairs", "Speedy patching", "Security concerns hinder maintenance")
+flavor("52. Castaño", "AUC leader's memoir a best seller", "Charismatic AUC political leader")
+flavor("53. Criminal Air Force", "Insurgent access to small aircraft", "")
+flavor("54. Deserters & Defectors", "", "")
+flavor("55. DEA Agents", "Law enforcement assistance", "Más Yanquis")
+flavor("56. Drogas La Rebaja", "Cali cartel's drugstore chain seized", "Retail empire")
+flavor("57. Op Millenium", "Colombian-US strike at Bernal syndicate", "Investigation penetrated")
+flavor("58. General Serrano", "National Police hammer cartels", "Officials on cartel payroll")
+flavor("59. Salcedo", "Cartel informant", "Cali cartel security chief")
+flavor("60. The Chess Player", "Kingpin strategy scores", "Cali's Gilberto Rodríguez Orejuela expands empire")
+flavor("61. Air Bridge", "Peruvian coca supply controlled", "Colombian coca growers fill Peruvian void")
+flavor("62. Amazonía", "Brasília's Op Cobra blocks border", "Jungle landing strips")
+flavor("63. Narco-War", "Rival syndicates go for the throat", "")
+flavor("64. Cocaine Labs", "FARC taps suppliers", "Well-oiled industry")
+flavor("65. Poppies", "Growers and Government eradication focus on heroin source", "")
+flavor("66. Tingo María", "Coca crop fails", "Hearty coca variety")
+flavor("67. Mexican Traffickers", "Major shipment busted en route", "New routes to US market")
+flavor("68. Narco-Subs", "Submersibles seized", "Littoral stealth")
+flavor("69. Riverines & Fast Boats", "", "")
+flavor("70. Ayahuasca Tourism", "Eco-tourism helps trade balance", "Eco-tourists taken")
+flavor("71. Darién", "Arms traffic interdicted", "Border sanctuary")
+flavor("72. Sicarios", "Hired drug guns unreliable", "Unemployed ready to work for syndicates")
+flavor("73. Propaganda!", "", "")
+flavor("74. Propaganda!", "", "")
+flavor("75. Propaganda!", "", "")
+flavor("76. Propaganda!", "", "")
 
 let spaces = [ ]
 let space_name = [ ]
-- 
cgit v1.2.3