From 5b91837ae8c298ca0110854c48a1bf2fb6bea69a Mon Sep 17 00:00:00 2001
From: Tor Andersson <tor@ccxvii.net>
Date: Thu, 22 Jun 2023 12:29:34 +0200
Subject: Gain Legacy.

---
 rules.js | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 210 insertions(+), 34 deletions(-)

diff --git a/rules.js b/rules.js
index 410cb39..bdac983 100644
--- a/rules.js
+++ b/rules.js
@@ -33,19 +33,15 @@ game.battle -> game.battle / game.count + game.where
 	[x] remove at start
 	[x] remove when replaced
 
-[ ] castra
+[x] castra
 	[x] place
 	[x] remove at start
 	[x] remove when move/attack
-	[ ] move militia to general at end of turn
+	[x] move militia to general at end of turn
 	[x] remove when retreat
 
 [x] support check
-
-[ ] gain legacy
-	[ ] emperor
-	[ ] provinces
-	[ ] improvements
+[x] gain legacy
 
 [x] end turn
 	[x] grow mobs
@@ -765,7 +761,7 @@ function is_own_province(where) {
 	return is_own_governor(get_province_governor(where))
 }
 
-function is_emperor(governor) {
+function is_emperor_governor(governor) {
 	let emperor = get_province_governor(ITALIA)
 	if (emperor >= 0 && governor >= 0)
 		return (emperor / 6 | 0) === (governor / 6 | 0)
@@ -879,6 +875,45 @@ function count_units_in_army(id) {
 	return n
 }
 
+function is_emperor_player() {
+	return is_own_province(ITALIA)
+}
+
+function is_pretender_player() {
+	for (let where = 1; where < 12; ++where)
+		if (is_seat_of_power(where) || is_breakaway(where))
+			if (is_own_province(where))
+				return true
+	return false
+}
+
+function is_only_pretender_player() {
+	let result = false
+	for (let where = 1; where < 12; ++where)
+		if (is_seat_of_power(where))
+			if (is_own_province(where))
+				result = true
+			else
+				return false
+	return result
+}
+
+function count_pretender_provinces() {
+	let n = 0
+	for (let where = 1; where < 12; ++where)
+		if (is_seat_of_power(where) || is_breakaway(where))
+			++n
+	return n
+}
+
+function count_own_breakaway_provinces() {
+	let n = 0
+	for (let where = 0; where < 12; ++where)
+		if (is_own_province(where) && (is_seat_of_power(where) || is_breakaway(where)))
+			++n
+	return n
+}
+
 function count_own_provinces() {
 	let n = 0
 	for (let where = 0; where < 12; ++where)
@@ -887,6 +922,21 @@ function count_own_provinces() {
 	return n
 }
 
+function count_own_improvements() {
+	let n = 0
+	for (let where = 0; where < 12; ++where) {
+		if (is_own_province(where)) {
+			if (has_amphitheater(where))
+				++n
+			if (has_basilica(where))
+				++n
+			if (has_limes(where))
+				++n
+		}
+	}
+	return n
+}
+
 function count_own_basilicas() {
 	let n = 0
 	for (let where = 0; where < 12; ++where)
@@ -1639,7 +1689,7 @@ function remove_governor(where) {
 	let old_governor = get_province_governor(where)
 	if (old_governor >= 0) {
 		set_governor_location(old_governor, AVAILABLE)
-		if (where !== ITALIA && is_emperor(old_governor))
+		if (where !== ITALIA && is_emperor_governor(old_governor))
 			reduce_support(ITALIA)
 	}
 
@@ -1657,7 +1707,7 @@ function place_governor(where, new_governor) {
 	let old_governor = get_province_governor(where)
 	if (old_governor >= 0) {
 		set_governor_location(old_governor, AVAILABLE)
-		if (where !== ITALIA && is_emperor(old_governor))
+		if (where !== ITALIA && is_emperor_governor(old_governor))
 			reduce_support(ITALIA)
 	}
 
@@ -1667,7 +1717,7 @@ function place_governor(where, new_governor) {
 	else
 		game.support[where] = Math.max(1, game.support[where] - 1)
 
-	if (where !== ITALIA && is_emperor(new_governor))
+	if (where !== ITALIA && is_emperor_governor(new_governor))
 		increase_support(ITALIA)
 
 	update_neutral_italia()
@@ -1780,7 +1830,7 @@ function roll_to_place_governor(pg) {
 // ACTION: PRAETORIAN GUARD
 
 function has_unused_praetorian_guard() {
-	return game.ip[MILITARY] >= 1 && !is_own_province(ITALIA) && !has_placed_governor(ITALIA) && has_praetorian_guard_card()
+	return game.ip[MILITARY] >= 1 && !is_emperor_player() && !has_placed_governor(ITALIA) && has_praetorian_guard_card()
 }
 
 function has_praetorian_guard_card() {
@@ -1797,7 +1847,7 @@ function has_praetorian_guard_card() {
 
 function can_play_praetorian_guard() {
 	if (game.selected_governor >= 0 && get_governor_location(game.selected_governor) === AVAILABLE)
-		return game.ip[MILITARY] >= 1 && !is_own_province(ITALIA) && !has_placed_governor(ITALIA)
+		return game.ip[MILITARY] >= 1 && !is_emperor_player() && !has_placed_governor(ITALIA)
 	return false
 }
 
@@ -2454,30 +2504,31 @@ function goto_combat_victory() {
 		goto_combat_victory_defender()
 }
 
-function award_legacy(p, n) {
-	log(PLAYER_NAMES[p] + " gained " + n + " VP.")
+function award_legacy(p, reason, n) {
+	log(PLAYER_NAMES[p] + " gained " + n + " Legacy for " + reason + ".")
 	game.legacy[p] += n
 }
 
 function goto_combat_victory_defender() {
 	if (game.battle.type === "general")
-		award_legacy(game.battle.target / 6 | 0, 2)
+		award_legacy(game.battle.target / 6 | 0, "Victory", 2)
 	if (game.battle.type === "militia")
-		award_legacy(get_province_governor(game.where) / 6 | 0, 2)
+		award_legacy(get_province_governor(game.where) / 6 | 0, "Victory", 2)
 	end_battle()
 }
 
 function goto_combat_victory_attacker() {
-	award_legacy(game.current, 2)
 
 	if (game.battle.type === "barbarians") {
-		award_legacy(game.current, game.battle.dtaken)
+		award_legacy(game.current, "Victory", 2 + game.battle.dtaken)
 
 		// Surviving Barbarians go home (to active)
 		let tribe = get_barbarian_tribe(game.battle.target)
 		for (let id = first_barbarian[tribe]; id <= last_barbarian[tribe]; ++id)
 			if (get_barbarian_location(id) === game.battle)
 				set_barbarian_location(id, BARBARIAN_HOMELAND[tribe])
+	} else {
+		award_legacy(game.current, "Victory", 2)
 	}
 
 	// Defending Romans must retreat into province
@@ -2569,7 +2620,7 @@ states.support_check = {
 }
 
 function goto_support_check_emperor() {
-	if (is_own_province(ITALIA) && is_any_rival_emperor_or_pretender()) {
+	if (is_emperor_player() && is_any_rival_emperor_or_pretender()) {
 		game.state = "support_check_emperor"
 		return
 	}
@@ -2627,6 +2678,57 @@ function goto_expand_pretender_empire() {
 // === GAIN LEGACY ===
 
 function goto_gain_legacy() {
+	log_h3("Gain Legacy")
+
+	if (is_only_pretender())
+		award_legacy(game.current, "Pretender", count_own_breakaway_provinces())
+
+	if (is_emperor_player())
+		goto_legitimize_claim()
+	else
+		goto_gain_legacy_provinces()
+}
+
+function goto_legitimize_claim() {
+	if (is_pretender_player())
+		game.state = "legitimize_claim"
+	else
+		goto_gain_legacy_emperor()
+}
+
+states.legitimize_claim = {
+	prompt() {
+		prompt("Gain Legacy: Remove Seat of Power and Breakaway markers in your provinces.")
+		for (let where = 1; where < 12; ++where) {
+			if (is_own_province(where) && is_seat_of_power(where) || is_breakaway(where)) {
+				gen_action_region(where)
+	},
+	region(where) {
+		push_undo()
+		remove_seat_of_power(where)
+		remove_breakaway(where)
+		goto_legitimize_claim()
+	},
+}
+
+function goto_gain_legacy_emperor() {
+	award_legacy(game.current, "Emperor", Math.max(0, game.support[ITALIA] - count_pretender_provinces()))
+	if (!is_any_rival_emperor_or_pretender()) {
+		log(PLAYER_NAMES[game.current] + " gained Emperor Turn")
+		game.emperor_turns[game.current] += 1
+	}
+	goto_gain_legacy_provinces()
+}
+
+function goto_gain_legacy_provinces() {
+	award_legacy(game.current, "Provinces", count_own_provinces())
+	award_legacy(game.current, "Improvements", count_own_improvements())
+
+	if (is_emperor_player() && game.legacy[game.current] >= 60) {
+		log("Game will end after this round!")
+		game.end = 1
+	}
+
 	goto_buy_trash_cards()
 }
 
@@ -2648,11 +2750,12 @@ function goto_buy_trash_cards() {
 	for (let c of game.played)
 		set_add(discard, c)
 	game.played.length = 0
-	game.battle = {
-		count: 0,
-		pp: count_political_points(),
-	}
-	if (current_hand().length > 0)
+	game.count = 0
+	game.pp = count_political_points()
+
+	if (game.end)
+		goto_end_of_turn()
+	else if (current_hand().length > 0)
 		game.state = "buy_trash_discard"
 	else
 		game.state = "buy_trash"
@@ -2685,9 +2788,9 @@ function find_market_with_card(c) {
 
 states.buy_trash = {
 	prompt() {
-		prompt("Buy/Trash cards: " + game.battle.pp + "PP left.")
+		prompt("Buy/Trash cards: " + game.pp + "PP left.")
 		let nprov = count_own_provinces()
-		if (game.battle.pp >= 3) {
+		if (game.pp >= 3) {
 			for (let c of current_discard())
 				gen_action_card(c)
 		}
@@ -2697,8 +2800,8 @@ states.buy_trash = {
 				let cost = card_cost(c)
 				if (cost > nprov)
 					cost *= 2
-				cost += game.battle.count
-				if (game.battle.pp >= cost)
+				cost += game.count
+				if (game.pp >= cost)
 					gen_action_card(c)
 			}
 		}
@@ -2709,7 +2812,7 @@ states.buy_trash = {
 		if (set_has(current_discard(), c)) {
 			log("Trashed " + card_name(c))
 			set_delete(current_discard(), c)
-			game.battle.pp -= 3
+			game.pp -= 3
 		} else {
 			log("Bought " + card_name(c))
 			set_add(current_discard(), c)
@@ -2717,9 +2820,9 @@ states.buy_trash = {
 			let cost = card_cost(c)
 			if (cost > count_own_provinces())
 				cost *= 2
-			cost += game.battle.count
-			game.battle.pp -= cost
-			game.battle.count += 1
+			cost += game.count
+			game.pp -= cost
+			game.count += 1
 		}
 	},
 	done() {
@@ -2834,7 +2937,79 @@ states.refill_hand = {
 
 function end_refill_hand() {
 	game.current = next_player()
-	goto_start_turn()
+	if (game.current === game.first && game.end)
+		goto_game_end()
+	else
+		goto_start_turn()
+}
+
+// === GAME END ===
+
+function max_emperor_turns(cutoff) {
+	let n = 0
+	for (let x of game.emperor_turns)
+		if (x > n && x < cutoff)
+			n = x
+	return n
+}
+
+function award_emperor_turns(amount, cutoff) {
+	let x = max_emperor_turns(cutoff)
+	if (x > 0) {
+		for (let p = 0; p < game.legacy.length; ++p)
+			if (game.emperor_turns[p] === x)
+				award_legacy(p, "Emperor Turns", amount)
+	}
+	return x
+}
+
+function vp_tie(p) {
+	let vp = game.legacy[p] * 100000
+
+	game.current = p
+	if (is_emperor_player())
+		vp += 10000
+	if (is_pretender_player())
+		vp += 1000
+	vp += count_own_provinces() * 100
+	vp += count_own_legions() * 10
+	vp += random(10)
+
+	return vp
+}
+
+function goto_game_end() {
+	let cutoff = 1000
+
+	log_h2("Game End")
+
+	cutoff = award_emperor_turns(10, cutoff)
+	cutoff = award_emperor_turns(6, cutoff)
+	cutoff = award_emperor_turns(3, cutoff)
+	cutoff = award_emperor_turns(0, cutoff)
+
+	let victor = game.legacy.map((legacy,p) => [vp_tie(p),p]).sort((a,b) => b[0] - a[0])[0][1]
+
+	goto_game_over(PLAYER_NAMES[victor], PLAYER_NAMES[victor] + " won!")
+}
+
+function goto_game_over(result, victory) {
+	game.state = "game_over"
+	game.active = "None"
+	game.result = result
+	game.victory = victory
+	log_h1("Game Over")
+	log(game.victory)
+	return true
+}
+
+states.game_over = {
+	get inactive() {
+		return game.victory
+	},
+	prompt() {
+		view.prompt = game.victory
+	},
 }
 
 // === SETUP ===
@@ -2893,6 +3068,7 @@ exports.setup = function (seed, scenario, options) {
 		active_events: [],
 
 		ip: [],
+		pp: 0,
 		selected_governor: -1,
 		selected_general: -1,
 		played: [],
-- 
cgit v1.2.3