diff --git a/client/src/city_ui.rs b/client/src/city_ui.rs index ec7724a4..e0a5f99e 100644 --- a/client/src/city_ui.rs +++ b/client/src/city_ui.rs @@ -213,7 +213,7 @@ pub fn city_labels(game: &Game, city: &City) -> Vec { [ vec![format!( "City: {}, {}, {} {}", - game.get_player(city.player_index).get_name(), + game.player_name(city.player_index), city.size(), match city.mood_state { MoodState::Happy => "Happy", @@ -234,7 +234,7 @@ pub fn city_labels(game: &Game, city: &City) -> Vec { if city.player_index == *o { b.name().to_string() } else { - format!("{} (owned by {})", b.name(), game.get_player(*o).get_name()) + format!("{} (owned by {})", b.name(), game.player_name(*o)) } }) }) diff --git a/server/src/ability_initializer.rs b/server/src/ability_initializer.rs index 7f5895c6..4652bf2a 100644 --- a/server/src/ability_initializer.rs +++ b/server/src/ability_initializer.rs @@ -150,7 +150,7 @@ pub(crate) trait AbilityInitializerSetup: Sized { self } - fn add_player_event_listener(self, event: E, listener: F, priority: i32) -> Self + fn add_player_event_listener(self, event: E, priority: i32, listener: F) -> Self where T: Clone + PartialEq, E: Fn(&mut PlayerEvents) -> &mut Event + 'static + Clone, @@ -190,16 +190,12 @@ pub(crate) trait AbilityInitializerSetup: Sized { F: Fn(&mut T, &U, &V) + 'static + Clone, { let id = self.get_key().id(); - self.add_player_event_listener( - event, - move |value, u, v| { - if !get_info(value).contains_key(&id) { - listener(value, u, v); - get_info(value).insert(id.clone(), "used".to_string()); - } - }, - priority, - ) + self.add_player_event_listener(event, priority, move |value, u, v| { + if !get_info(value).contains_key(&id) { + listener(value, u, v); + get_info(value).insert(id.clone(), "used".to_string()); + } + }) } fn add_current_event_listener( @@ -217,72 +213,89 @@ pub(crate) trait AbilityInitializerSetup: Sized { E: Fn(&mut PlayerEvents) -> &mut CurrentEvent + 'static + Clone, { let origin = self.get_key(); - self.add_player_event_listener( - event, - move |game, i, details| { - let player_index = i.player; - let player_name = game.players[player_index].get_name(); - - if let Some(mut phase) = game.current_events.pop() { - if let Some(ref c) = phase.player.handler { - if let Some(ref action) = c.response { - if c.priority == priority { - let mut current = phase.clone(); - current - .player - .handler - .as_mut() - .expect("current missing") - .response = None; - if can_undo(¤t.event_type) { - game.undo_context_stack - .push(UndoContext::Event(Box::new(current))); - } - let r = c.request.clone(); - let a = action.clone(); - phase.player.handler = None; - game.current_events.push(phase); - end_custom_phase.clone()( - game, - player_index, - &player_name, - a, - r, - details, - ); - return; + self.add_player_event_listener(event, priority, move |game, i, details| { + let player_index = i.player; + let player_name = game.player_name(player_index); + + if let Some(mut phase) = game.current_events.pop() { + if let Some(ref c) = phase.player.handler { + if let Some(ref action) = c.response { + if c.priority == priority { + let mut current = phase.clone(); + current + .player + .handler + .as_mut() + .expect("current missing") + .response = None; + if can_undo(¤t.event_type) { + game.undo_context_stack + .push(UndoContext::Event(Box::new(current))); } + let r = c.request.clone(); + let a = action.clone(); + phase.player.handler = None; + game.current_events.push(phase); + end_custom_phase.clone()( + game, + player_index, + &player_name, + a, + r, + details, + ); + return; } } - let is_current = phase.player.handler.is_some(); - game.current_events.push(phase); - if is_current { - return; - } } - - if game - .current_event_player() - .last_priority_used - .is_some_and(|last| last < priority) - { - // already handled before + let is_current = phase.player.handler.is_some(); + game.current_events.push(phase); + if is_current { return; } + } + + if game + .current_event_player() + .last_priority_used + .is_some_and(|last| last < priority) + { + // already handled before + return; + } + + if let Some(request) = start_custom_phase(game, player_index, &player_name, details) { + let s = game.current_event_mut(); + s.player.last_priority_used = Some(priority); + s.player.handler = Some(CurrentEventHandler { + priority, + request: request.clone(), + response: None, + origin: origin.clone(), + }); + }; + }) + } - if let Some(request) = start_custom_phase(game, player_index, &player_name, details) - { - let s = game.current_event_mut(); - s.player.last_priority_used = Some(priority); - s.player.handler = Some(CurrentEventHandler { - priority, - request: request.clone(), - response: None, - origin: origin.clone(), - }); - }; - }, + fn add_simple_current_event_listener( + self, + event: E, + priority: i32, + listener: F, + ) -> Self + where + E: Fn(&mut PlayerEvents) -> &mut CurrentEvent + 'static + Clone, + F: Fn(&mut Game, usize, &str, &V) + 'static + Clone, + { + self.add_current_event_listener( + event, priority, + move |game, player_index, player_name, details| { + // only for the listener + listener(game, player_index, player_name, details); + None + }, + |_, _, _, _, _, _| {}, ) } @@ -300,7 +313,12 @@ pub(crate) trait AbilityInitializerSetup: Sized { event, priority, move |game, player_index, _player_name, details| { - request(game, player_index, details).map(CurrentEventRequest::Payment) + request(game, player_index, details) + .filter(|r| { + r.iter() + .any(|r| game.get_player(player_index).can_afford(&r.cost)) + }) + .map(CurrentEventRequest::Payment) }, move |game, player_index, player_name, action, request, details| { if let CurrentEventRequest::Payment(requests) = &request { @@ -350,7 +368,7 @@ pub(crate) trait AbilityInitializerSetup: Sized { let req = request(game, player_index, details); if let Some(r) = &req { if r.reward.possible_resource_types().len() == 1 { - let player_name = game.players[player_index].get_name(); + let player_name = game.player_name(player_index); let r = r.reward.default_payment(); for log in g( game, @@ -689,7 +707,7 @@ pub(crate) trait AbilityInitializerSetup: Sized { game, &SelectedChoice::new( player_index, - &game.get_player(player_index).get_name(), + &game.player_name(player_index), false, m.choices.clone(), details, diff --git a/server/src/action.rs b/server/src/action.rs index 2fcc352b..5a540674 100644 --- a/server/src/action.rs +++ b/server/src/action.rs @@ -22,6 +22,7 @@ use crate::status_phase::play_status_phase; use crate::undo::{redo, undo, DisembarkUndoContext, UndoContext}; use crate::unit::MovementAction::{Move, Stop}; use crate::unit::{get_current_move, MovementAction}; +use crate::wonder::draw_wonder_card; use itertools::Itertools; use serde::{Deserialize, Serialize}; @@ -124,6 +125,9 @@ pub(crate) fn execute_custom_phase_action( ) { use CurrentEventType::*; match details { + DrawWonderCard => { + draw_wonder_card(game, player_index); + } ExploreResolution(r) => { ask_explore_resolution(game, player_index, r); } diff --git a/server/src/advance.rs b/server/src/advance.rs index 182a2b6b..eb4b6535 100644 --- a/server/src/advance.rs +++ b/server/src/advance.rs @@ -139,7 +139,6 @@ impl Bonus { /// /// Panics if advance does not exist pub fn do_advance(game: &mut Game, advance: &Advance, player_index: usize) { - game.trigger_command_event(player_index, |e| &mut e.on_advance, &advance.name); (advance.listeners.initializer)(game, player_index); (advance.listeners.one_time_initializer)(game, player_index); let name = advance.name.clone(); @@ -190,7 +189,7 @@ pub(crate) fn advance_with_incident_token( pub(crate) fn gain_advance(game: &mut Game, player_index: usize, info: &AdvanceInfo) { if game.trigger_current_event( &[player_index], - |e| &mut e.on_advance_custom_phase, + |e| &mut e.on_advance, info, CurrentEventType::Advance, None, diff --git a/server/src/barbarians.rs b/server/src/barbarians.rs index 49544190..8d0889ad 100644 --- a/server/src/barbarians.rs +++ b/server/src/barbarians.rs @@ -101,8 +101,12 @@ pub(crate) fn barbarians_spawn(mut builder: IncidentBuilder) -> IncidentBuilder IncidentTarget::ActivePlayer, BASE_EFFECT_PRIORITY + 1, |game, _player_index, _i| { + let r = possible_barbarians_reinforcements(game); + if r.is_empty() { + game.add_info_log_item("Barbarians cannot reinforce"); + } Some(new_position_request( - possible_barbarians_reinforcements(game), + r, 1..=1, "Select a position for the additional Barbarian unit", )) @@ -140,7 +144,9 @@ pub(crate) fn barbarians_spawn(mut builder: IncidentBuilder) -> IncidentBuilder pub(crate) fn barbarians_move(mut builder: IncidentBuilder) -> IncidentBuilder { builder = set_info(builder, "Barbarians move", |state, game, human| { - if !get_movable_units(game, human, state).is_empty() { + if get_movable_units(game, human, state).is_empty() { + game.add_info_log_item("Barbarians cannot move - will try to spawn a new city instead"); + } else { state.move_units = true; } }); @@ -221,10 +227,10 @@ pub(crate) fn barbarians_move(mut builder: IncidentBuilder) -> IncidentBuilder { }, ); } - builder.add_incident_listener( + builder.add_simple_incident_listener( IncidentTarget::ActivePlayer, BASE_EFFECT_PRIORITY, - |game, player| { + |game, player, _| { let s = get_barbarian_state(game); if s.move_units && get_movable_units(game, player, &s).is_empty() { // after all moves are done @@ -301,18 +307,18 @@ fn barbarian_march_steps( pub(crate) fn set_info( builder: IncidentBuilder, event_name: &str, - init: impl Fn(&mut BarbariansEventState, &Game, usize) + 'static + Clone, + init: impl Fn(&mut BarbariansEventState, &mut Game, usize) + 'static + Clone, ) -> IncidentBuilder { let name = event_name.to_string(); - builder.add_incident_listener( + builder.add_simple_incident_listener( IncidentTarget::ActivePlayer, BASE_EFFECT_PRIORITY + 200, - move |game, player| { + move |game, player, _| { if game.current_event().barbarians.is_none() { + game.add_info_log_item(&format!("Base effect: {name}")); let mut state = BarbariansEventState::new(); init(&mut state, game, player); game.current_event_mut().barbarians = Some(state); - game.add_info_log_item(&format!("Base effect: {name}")); } }, ) @@ -323,8 +329,16 @@ fn add_barbarians_city(builder: IncidentBuilder) -> IncidentBuilder { IncidentTarget::ActivePlayer, BASE_EFFECT_PRIORITY + 100, move |game, player_index, _i| { - (!get_barbarian_state(game).move_units).then_some(new_position_request( - possible_barbarians_spawns(game, game.get_player(player_index)), + if get_barbarian_state(game).move_units { + return None; + } + + let choices = possible_barbarians_spawns(game, game.get_player(player_index)); + if choices.is_empty() { + game.add_info_log_item("Barbarians cannot spawn a new city"); + } + Some(new_position_request( + choices, 1..=1, "Select a position for the new city and infantry unit", )) diff --git a/server/src/combat.rs b/server/src/combat.rs index 1d8c144c..c2bf4f31 100644 --- a/server/src/combat.rs +++ b/server/src/combat.rs @@ -1,3 +1,4 @@ +use crate::city::City; use crate::city::MoodState::Angry; use crate::city_pieces::Building; use crate::combat_listeners::{ @@ -20,13 +21,14 @@ pub enum CombatModifier { CancelFortressIgnoreHit, SteelWeaponsAttacker, SteelWeaponsDefender, + TrojanHorse, } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug, Copy)] pub enum CombatRetreatState { CanRetreat, CannotRetreat, - Retreated, + EndAfterCurrentRound, } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] @@ -109,15 +111,18 @@ impl Combat { #[must_use] pub fn defender_fortress(&self, game: &Game) -> bool { - game.players[self.defender] - .try_get_city(self.defender_position) + self.defender_city(game) .is_some_and(|city| city.pieces.fortress.is_some()) } + #[must_use] + pub fn defender_city<'a>(&self, game: &'a Game) -> Option<&'a City> { + game.players[self.defender].try_get_city(self.defender_position) + } + #[must_use] pub fn defender_temple(&self, game: &Game) -> bool { - game.players[self.defender] - .try_get_city(self.defender_position) + self.defender_city(game) .is_some_and(|city| city.pieces.temple.is_some()) } @@ -213,7 +218,7 @@ pub(crate) fn combat_loop(game: &mut Game, mut c: Combat) { game.add_info_log_group(format!("Combat round {}", c.round)); //todo: go into tactics phase if either player has tactics card (also if they can not play it unless otherwise specified via setting) - let attacker_name = game.players[c.attacker].get_name(); + let attacker_name = game.player_name(c.attacker); let active_attackers = c.active_attackers(game); let mut attacker_strength = CombatStrength::new(c.attacker, true); let _ = game.players[c.attacker] @@ -233,7 +238,7 @@ pub(crate) fn combat_loop(game: &mut Game, mut c: Combat) { let attacker_log_str = roll_log_str(&attacker_log); let active_defenders = c.active_defenders(game); - let defender_name = game.players[c.defender].get_name(); + let defender_name = game.player_name(c.defender); let mut defender_log = vec![]; let mut defender_strength = CombatStrength::new(c.defender, false); let _ = game.players[c.defender] @@ -283,6 +288,8 @@ pub(crate) fn combat_loop(game: &mut Game, mut c: Combat) { Casualties::new(defender_hits, game, &c, c.attacker), Casualties::new(attacker_hits, game, &c, c.defender), can_retreat, + &c, + game, ); game.push_state(GameState::Combat(c)); @@ -323,15 +330,13 @@ pub(crate) fn combat_round_end(game: &mut Game, r: &CombatRoundResult) -> Option } let mut c = take_combat(game); - let active_attackers = c.active_attackers(game); - let defenders_left = c.active_defenders(game); - if active_attackers.is_empty() && defenders_left.is_empty() { - draw(game, c) - } else if active_attackers.is_empty() { - defender_wins(game, c) - } else if defenders_left.is_empty() { - attacker_wins(game, c) - } else if matches!(c.retreat, CombatRetreatState::Retreated) { + if let Some(f) = &r.final_result { + match f { + CombatResult::AttackerWins => attacker_wins(game, c), + CombatResult::DefenderWins => defender_wins(game, c), + CombatResult::Draw => draw(game, c), + } + } else if matches!(c.retreat, CombatRetreatState::EndAfterCurrentRound) { None } else { c.round += 1; @@ -355,7 +360,7 @@ pub(crate) fn draw(game: &mut Game, c: Combat) -> Option { if c.defender_fortress(game) && c.round == 1 { game.add_info_log_item(&format!( "{} wins the battle because he has a defending fortress", - game.players[c.defender].get_name() + game.player_name(c.defender) )); return end_combat(game, c, CombatResult::DefenderWins); } @@ -532,7 +537,7 @@ pub(crate) fn conquer_city( game.lock_undo(); game.add_to_last_log_item(&format!( " and captured {}'s city at {position}", - game.players[old_player_index].get_name() + game.player_name(old_player_index) )); let attacker_is_human = game.get_player(new_player_index).is_human(); let size = city.mood_modified_size(&game.players[new_player_index]); @@ -585,7 +590,7 @@ pub fn capture_position(game: &mut Game, old_player: usize, position: Position, game.add_to_last_log_item(&format!( " and killed {} settlers of {}", captured_settlers.len(), - game.players[old_player].get_name() + game.player_name(old_player) )); } for id in captured_settlers { diff --git a/server/src/combat_listeners.rs b/server/src/combat_listeners.rs index 6747e2ce..4b5b7fff 100644 --- a/server/src/combat_listeners.rs +++ b/server/src/combat_listeners.rs @@ -17,6 +17,7 @@ pub struct CombatStrength { pub extra_dies: u8, pub extra_combat_value: u8, pub hit_cancels: u8, + pub deny_tactics: Vec, // todo use effect when tactics cards are added pub roll_log: Vec, } @@ -30,6 +31,7 @@ impl CombatStrength { extra_combat_value: 0, hit_cancels: 0, roll_log: vec![], + deny_tactics: vec![], } } } @@ -39,7 +41,6 @@ pub enum CombatResult { AttackerWins, DefenderWins, Draw, - Retreat, } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] @@ -136,6 +137,9 @@ pub struct CombatRoundResult { pub defender_casualties: Casualties, #[serde(default)] pub can_retreat: bool, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub final_result: Option, } impl CombatRoundResult { @@ -144,11 +148,29 @@ impl CombatRoundResult { attacker_casualties: Casualties, defender_casualties: Casualties, can_retreat: bool, + c: &Combat, + game: &Game, ) -> Self { + let attackers_dead = + c.active_attackers(game).len() - attacker_casualties.fighters as usize == 0; + let defenders_dead = + c.active_defenders(game).len() - defender_casualties.fighters as usize == 0; + + let final_result = if attackers_dead && defenders_dead { + Some(CombatResult::Draw) + } else if attackers_dead { + Some(CombatResult::DefenderWins) + } else if defenders_dead { + Some(CombatResult::AttackerWins) + } else { + None + }; + Self { attacker_casualties, defender_casualties, can_retreat, + final_result, } } } @@ -209,8 +231,7 @@ pub(crate) fn offer_retreat() -> Builtin { |game, player, r| { let c = get_combat(game); if c.attacker == player && r.can_retreat { - let p = game.get_player(player); - let name = p.get_name(); + let name = game.player_name(player); game.add_info_log_item(&format!("{name} can retreat",)); Some("Do you want to retreat?".to_string()) } else { @@ -226,7 +247,7 @@ pub(crate) fn offer_retreat() -> Builtin { } if retreat.choice { let mut c = take_combat(game); - c.retreat = CombatRetreatState::Retreated; + c.retreat = CombatRetreatState::EndAfterCurrentRound; game.push_state(GameState::Combat(c)); } }, diff --git a/server/src/content.rs b/server/src/content.rs index f0bbc93a..95ef5d25 100644 --- a/server/src/content.rs +++ b/server/src/content.rs @@ -22,5 +22,6 @@ mod incidents_earthquake; mod incidents_famine; mod incidents_good_year; mod incidents_population_boom; +mod incidents_trojan; pub mod trade_routes; pub mod wonders; diff --git a/server/src/content/advances_agriculture.rs b/server/src/content/advances_agriculture.rs index b4061e21..7bd58fd0 100644 --- a/server/src/content/advances_agriculture.rs +++ b/server/src/content/advances_agriculture.rs @@ -43,10 +43,10 @@ fn irrigation() -> AdvanceBuilder { ) .add_player_event_listener( |event| &mut event.terrain_collect_options, + 0, |m, (), ()| { m.insert(Barren, HashSet::from([ResourcePile::food(1)])); }, - 0, ) .with_advance_bonus(MoodToken) } diff --git a/server/src/content/advances_autocracy.rs b/server/src/content/advances_autocracy.rs index f90ff4d2..1f9c63b9 100644 --- a/server/src/content/advances_autocracy.rs +++ b/server/src/content/advances_autocracy.rs @@ -61,6 +61,7 @@ fn totalitarianism() -> AdvanceBuilder { ) .add_player_event_listener( |event| &mut event.on_influence_culture_attempt, + 0, |info, city, game| { if info.is_defender && game @@ -72,7 +73,6 @@ fn totalitarianism() -> AdvanceBuilder { info.set_no_boost(); } }, - 0, ) } diff --git a/server/src/content/advances_construction.rs b/server/src/content/advances_construction.rs index 153a2e3b..c46fa8c7 100644 --- a/server/src/content/advances_construction.rs +++ b/server/src/content/advances_construction.rs @@ -3,10 +3,10 @@ use crate::advance::Bonus::{CultureToken, MoodToken}; use crate::advance::{Advance, AdvanceBuilder}; use crate::content::advances::{advance_group_builder, AdvanceGroup, ROADS}; use crate::content::custom_actions::CustomActionType::ConstructWonder; -use crate::game::Game; use crate::payment::PaymentConversion; use crate::resource_pile::ResourcePile; use crate::unit::UnitType; +use crate::wonder::draw_wonder_card; pub(crate) fn construction() -> AdvanceGroup { advance_group_builder( @@ -24,7 +24,7 @@ fn engineering() -> AdvanceBuilder { "Engineering", "Immediately draw 1 wonder card. May Construct wonders in happy cities", ) - .add_one_time_ability_initializer(Game::draw_wonder_card) + .add_one_time_ability_initializer(draw_wonder_card) .add_custom_action(ConstructWonder) } @@ -36,6 +36,7 @@ fn sanitation() -> AdvanceBuilder { .with_advance_bonus(MoodToken) .add_player_event_listener( |event| &mut event.recruit_cost, + 1, |cost, units, _| { if units.settlers > 0 { // insert at beginning so that it's preferred over gold @@ -53,7 +54,6 @@ fn sanitation() -> AdvanceBuilder { ); } }, - 1, ) } diff --git a/server/src/content/advances_culture.rs b/server/src/content/advances_culture.rs index 5a53b089..06749e16 100644 --- a/server/src/content/advances_culture.rs +++ b/server/src/content/advances_culture.rs @@ -11,6 +11,7 @@ use crate::playing_actions::{increase_happiness, undo_increase_happiness}; use crate::position::Position; use crate::resource::ResourceType; use crate::resource_pile::ResourcePile; +use crate::wonder::draw_wonder_card; use std::vec; pub(crate) fn culture() -> AdvanceGroup { @@ -32,16 +33,16 @@ fn sports() -> AdvanceBuilder { fn monuments() -> AdvanceBuilder { Advance::builder("Monuments", "Immediately draw 1 wonder card. Your cities with wonders may not be the target of influence culture attempts") - .add_one_time_ability_initializer(Game::draw_wonder_card) + .add_one_time_ability_initializer(draw_wonder_card) .with_advance_bonus(CultureToken) .add_player_event_listener( |event| &mut event.on_influence_culture_attempt, + 1, |info, city, _| { if info.is_defender && !city.pieces.wonders.is_empty() { info.set_impossible(); } }, - 1, ) } diff --git a/server/src/content/advances_democracy.rs b/server/src/content/advances_democracy.rs index dbd77ab6..29522527 100644 --- a/server/src/content/advances_democracy.rs +++ b/server/src/content/advances_democracy.rs @@ -34,12 +34,12 @@ fn separation_of_power() -> AdvanceBuilder { ) .add_player_event_listener( |event| &mut event.on_influence_culture_attempt, + 2, |info, city, _| { if matches!(city.mood_state, MoodState::Happy) { info.set_no_boost(); } }, - 2, ) } @@ -56,12 +56,12 @@ fn free_economy() -> AdvanceBuilder { .add_custom_action(FreeEconomyCollect) .add_player_event_listener( |event| &mut event.is_playing_action_available, + 0, |available, game, i| { let p = game.get_player(i.player); if matches!(i.action_type, PlayingActionType::Collect) && p.played_once_per_turn_actions.contains(&FreeEconomyCollect) { *available = false; } }, - 0, ) } diff --git a/server/src/content/advances_economy.rs b/server/src/content/advances_economy.rs index 78701a4e..b520e2b7 100644 --- a/server/src/content/advances_economy.rs +++ b/server/src/content/advances_economy.rs @@ -97,7 +97,7 @@ fn gain_market_bonus(game: &mut Game, routes: &[TradeRoute]) { .unique() .collect_vec(); for p in players { - let name = game.get_player(p).get_name(); + let name = game.player_name(p); game.add_info_log_item(&format!( "{name} gains 1 gold for using a Market in a trade route", )); diff --git a/server/src/content/advances_education.rs b/server/src/content/advances_education.rs index 4376d04b..387e804d 100644 --- a/server/src/content/advances_education.rs +++ b/server/src/content/advances_education.rs @@ -52,7 +52,7 @@ fn free_education() -> AdvanceBuilder { ) .with_advance_bonus(MoodToken) .add_payment_request_listener( - |e| &mut e.on_advance_custom_phase, + |e| &mut e.on_advance, 1, |_game, _player_index, i| { if i.name == "Free Education" { @@ -71,9 +71,14 @@ fn free_education() -> AdvanceBuilder { }, |game, payment| { payment.to_commands(game, |c, _game, payment| { + let pile = &payment[0]; + if pile.is_empty() { + c.add_info_log_item(&format!("{} declined to pay for free education", c.name)); + return; + } c.add_info_log_item(&format!( "{} paid {} for free education to gain 1 mood token", - c.name, payment[0] + c.name, pile )); c.gain_resources(ResourcePile::mood_tokens(1)); }); @@ -92,19 +97,22 @@ fn philosophy() -> AdvanceBuilder { .add_ability_undo_deinitializer(|game, player_index| { game.players[player_index].lose_resources(ResourcePile::ideas(1)); }) - .add_player_event_listener( + .add_simple_current_event_listener( |event| &mut event.on_advance, - |player, _, advance| { + 0, + |game, player_index, player_name, advance| { if get_group("Science") .advances .iter() - .any(|a| &a.name == advance) + .any(|a| a.name == advance.name) { - player.gain_resources(ResourcePile::ideas(1)); - player.add_info_log_item("Philosophy gained 1 idea"); + game.with_commands(player_index, |player, _game| { + player.gain_resources(ResourcePile::ideas(1)); + player + .add_info_log_item(&format!("{player_name} gained 1 idea from Philosophy")); + }); } }, - 0, ) .with_advance_bonus(MoodToken) } diff --git a/server/src/content/advances_science.rs b/server/src/content/advances_science.rs index c95a2d4f..1b92595f 100644 --- a/server/src/content/advances_science.rs +++ b/server/src/content/advances_science.rs @@ -21,13 +21,13 @@ fn math() -> AdvanceBuilder { ) .add_player_event_listener( |event| &mut event.advance_cost, + 1, |i, a, ()| { if a.name == "Engineering" || a.name == "Roads" { i.info.log.push("Math reduced the cost to 0".to_string()); i.set_zero(); } }, - 1, ) .with_advance_bonus(CultureToken) .with_unlocked_building(Observatory) @@ -40,6 +40,7 @@ fn astronomy() -> AdvanceBuilder { ) .add_player_event_listener( |event| &mut event.advance_cost, + 0, |i, a, ()| { if a.name == "Navigation" || a.name == "Cartography" { i.set_zero(); @@ -48,7 +49,6 @@ fn astronomy() -> AdvanceBuilder { .push("Astronomy reduced the cost to 0".to_string()); } }, - 0, ) .with_advance_bonus(CultureToken) } @@ -98,6 +98,7 @@ fn metallurgy() -> AdvanceBuilder { .with_advance_bonus(CultureToken) .add_player_event_listener( |event| &mut event.collect_total, + 0, |i, (),()| { if i.total.ore >= 2 { i.total.ore -= 1; @@ -105,6 +106,5 @@ fn metallurgy() -> AdvanceBuilder { i.info.log.push("Metallurgy converted 1 ore to 1 gold".to_string()); } }, - 0, ) } diff --git a/server/src/content/advances_seafearing.rs b/server/src/content/advances_seafearing.rs index fe1d6992..7852a28e 100644 --- a/server/src/content/advances_seafearing.rs +++ b/server/src/content/advances_seafearing.rs @@ -18,7 +18,7 @@ pub(crate) fn seafaring() -> AdvanceGroup { fn fishing() -> AdvanceBuilder { Advance::builder("Fishing", "Your cities may Collect food from one Sea space") - .add_player_event_listener(|event| &mut event.collect_options, fishing_collect, 1) + .add_player_event_listener(|event| &mut event.collect_options, 1, fishing_collect) .with_advance_bonus(MoodToken) .with_unlocked_building(Port) } @@ -37,6 +37,7 @@ fn war_ships() -> AdvanceBuilder { "Ignore the first hit it the first round of combat when attacking with Ships or disembarking from Ships") .add_player_event_listener( |event| &mut event.on_combat_round, + 0, |s, c, g| { let attacker = s.attacker && g.map.is_sea(c.attacker_position); let defender = !s.attacker && g.map.is_sea(c.defender_position); @@ -45,7 +46,6 @@ fn war_ships() -> AdvanceBuilder { s.roll_log.push("War Ships ignore the first hit in the first round of combat".to_string()); } }, - 0, ) } @@ -56,6 +56,7 @@ fn cartography() -> AdvanceBuilder { .with_advance_bonus(CultureToken) .add_player_event_listener( |event| &mut event.before_move, + 0, |player, g, i| { // info is the action that we last used this ability for let key = g.actions_left.to_string(); @@ -83,7 +84,6 @@ fn cartography() -> AdvanceBuilder { } } }, - 0, ) } diff --git a/server/src/content/advances_spirituality.rs b/server/src/content/advances_spirituality.rs index f358da0e..7e9dd8ef 100644 --- a/server/src/content/advances_spirituality.rs +++ b/server/src/content/advances_spirituality.rs @@ -46,6 +46,7 @@ fn rituals() -> AdvanceBuilder { .with_advance_bonus(CultureToken) .add_player_event_listener( |event| &mut event.happiness_cost, + 0, |cost, (), ()| { for r in &[ ResourceType::Food, @@ -58,7 +59,6 @@ fn rituals() -> AdvanceBuilder { cost.cost.conversions.push(PaymentConversion::unlimited(ResourcePile::mood_tokens(1), ResourcePile::of(*r, 1))); } }, - 0, ) } diff --git a/server/src/content/advances_theocracy.rs b/server/src/content/advances_theocracy.rs index b0eb26b3..678496df 100644 --- a/server/src/content/advances_theocracy.rs +++ b/server/src/content/advances_theocracy.rs @@ -71,12 +71,12 @@ fn devotion() -> AdvanceBuilder { ) .add_player_event_listener( |event| &mut event.on_influence_culture_attempt, + 4, |info, city, _| { if info.is_defender && city.pieces.temple.is_some() { info.set_no_boost(); } }, - 4, ) } @@ -84,21 +84,21 @@ fn conversion() -> AdvanceBuilder { Advance::builder("Conversion", "You add +1 to your Influence Culture roll and gain 1 culture token when you make a successful Influence Culture attempt.") .add_player_event_listener( |event| &mut event.on_influence_culture_attempt, + 3, |info, _, _| { if !info.is_defender { info.roll_boost += 1; info.info.log.push("Player gets +1 to Influence Culture roll for Conversion Advance".to_string()); } }, - 3, ) .add_player_event_listener( |event| &mut event.on_influence_culture_success, + 0, |c, _, ()| { c.gain_resources(ResourcePile::culture_tokens(1)); c.add_info_log_item("Player gained 1 culture token for a successful Influence Culture attempt for Conversion Advance"); }, - 0, ) } @@ -106,13 +106,13 @@ fn fanaticism() -> AdvanceBuilder { Advance::builder("Fanaticism", "During a battle in a city with a Temple, whether you are the attacker or defender, you add +2 combat value to your first combat roll. If you lose the battle, you get 1 free Infantry Unit after the battle and place it in one of your cities.") .add_player_event_listener( |event| &mut event.on_combat_round, + 1, |s, c, game| { if c.round == 1 && c.defender_temple(game) { s.extra_combat_value += 2; s.roll_log.push("Player gets +2 combat value for Fanaticism Advance".to_string()); } }, - 1, ) .add_position_request( |event| &mut event.on_combat_end, diff --git a/server/src/content/advances_warfare.rs b/server/src/content/advances_warfare.rs index f35065ee..be173b8c 100644 --- a/server/src/content/advances_warfare.rs +++ b/server/src/content/advances_warfare.rs @@ -31,7 +31,7 @@ fn tactics() -> AdvanceBuilder { ) .with_advance_bonus(CultureToken) .with_unlocked_building(Fortress) - .add_player_event_listener(|event| &mut event.on_combat_round, fortress, 3) + .add_player_event_listener(|event| &mut event.on_combat_round, 3, fortress) } fn siegecraft() -> AdvanceBuilder { @@ -128,16 +128,20 @@ fn steel_weapons() -> AdvanceBuilder { } }, |game, s| { + let pile = &s.choice[0]; + game.add_info_log_item( + &format!("{} paid for steel weapons: {}", s.player_name, pile)); let Some(GameState::Combat(c)) = &mut game.state_stack.last_mut() else { panic!("Invalid state") }; + if pile.is_empty() { + return; + } add_steel_weapons(s.player_index, c); - game.add_info_log_item( - &format!("{} paid for steel weapons: {}", s.player_name, s.choice[0])); }, ) .add_player_event_listener( |event| &mut event.on_combat_round, - use_steel_weapons, 2, + use_steel_weapons, ) } @@ -149,6 +153,7 @@ fn draft() -> AdvanceBuilder { .with_advance_bonus(CultureToken) .add_player_event_listener( |event| &mut event.recruit_cost, + 0, |cost, units, player| { if units.infantry > 0 { // insert at beginning so that it's preferred over gold @@ -167,7 +172,6 @@ fn draft() -> AdvanceBuilder { ); } }, - 0, ) } diff --git a/server/src/content/builtin.rs b/server/src/content/builtin.rs index 65f42de3..665c1dd5 100644 --- a/server/src/content/builtin.rs +++ b/server/src/content/builtin.rs @@ -5,6 +5,9 @@ use crate::combat_listeners::{ choose_carried_units_casualties, choose_fighter_casualties, offer_retreat, place_settler, }; use crate::content::incidents_famine::pestilence_permanent_effect; +use crate::content::incidents_trojan::{ + activate_trojan_horse, anarchy_advance, decide_trojan_horse, solar_eclipse_end_combat, +}; use crate::cultural_influence::cultural_influence_resolution; use crate::events::EventOrigin; use crate::explore::explore_resolution; @@ -14,6 +17,7 @@ use crate::status_phase::{ complete_objectives, determine_first_player, draw_cards, free_advance, may_change_government, raze_city, StatusPhaseState, }; +use crate::wonder::on_draw_wonder_card; pub struct Builtin { pub name: String, @@ -68,14 +72,21 @@ pub fn get_all() -> Vec { vec![ cultural_influence_resolution(), explore_resolution(), + on_draw_wonder_card(), + // combat related place_settler(), choose_fighter_casualties(), choose_carried_units_casualties(), offer_retreat(), + // incident related barbarians_bonus(), pirates_bonus(), pirates_round_bonus(), pestilence_permanent_effect(), + decide_trojan_horse(), + activate_trojan_horse(), + solar_eclipse_end_combat(), + anarchy_advance(), ] } @@ -111,3 +122,9 @@ pub(crate) fn status_phase_handler(phase: &StatusPhaseState) -> Builtin { DetermineFirstPlayer(_) => determine_first_player(), } } + +pub(crate) fn init_player(game: &mut Game, player_index: usize) { + for b in get_all() { + (b.listeners.initializer)(game, player_index); + } +} diff --git a/server/src/content/civilizations.rs b/server/src/content/civilizations.rs index 0b669099..62238135 100644 --- a/server/src/content/civilizations.rs +++ b/server/src/content/civilizations.rs @@ -29,6 +29,7 @@ pub fn get_all() -> Vec { SpecialAdvance::builder("Terrace", IRRIGATION) .add_player_event_listener( |events| &mut events.terrain_collect_options, + 2, |m, (), ()| { m.insert( Terrain::Mountain, @@ -39,7 +40,6 @@ pub fn get_all() -> Vec { ]), ); }, - 2, ) .build(), ], @@ -48,13 +48,13 @@ pub fn get_all() -> Vec { "ignore the first hit in a battle with an Obelisk", "", "") .add_player_event_listener( |events| &mut events.on_combat_round, + 4, |s, c, game| { if c.round == 1 && game.try_get_any_city(c.defender_position).is_some_and(|city| city.pieces.obelisk.is_some()) { s.roll_log.push("Kʼinich Janaab Pakal I ignores the first hit in a battle with an Obelisk".to_string()); s.hit_cancels += 1; } }, - 4, ) .build()], ), diff --git a/server/src/content/custom_phase_actions.rs b/server/src/content/custom_phase_actions.rs index 0291c475..0265ea5a 100644 --- a/server/src/content/custom_phase_actions.rs +++ b/server/src/content/custom_phase_actions.rs @@ -31,10 +31,10 @@ pub struct PaymentRequest { impl PaymentRequest { #[must_use] - pub fn new(cost: PaymentOptions, name: String, optional: bool) -> Self { + pub fn new(cost: PaymentOptions, name: &str, optional: bool) -> Self { Self { cost, - name, + name: name.to_string(), optional, } } @@ -173,6 +173,7 @@ pub enum CurrentEventType { Construct(Building), Recruit(Recruit), Incident(IncidentInfo), + DrawWonderCard, } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] diff --git a/server/src/content/incidects_civil_war.rs b/server/src/content/incidects_civil_war.rs index d49a5537..a0cdc8db 100644 --- a/server/src/content/incidects_civil_war.rs +++ b/server/src/content/incidects_civil_war.rs @@ -1,24 +1,29 @@ use crate::city::MoodState; -use crate::content::custom_phase_actions::{new_position_request, UnitsRequest}; +use crate::content::custom_phase_actions::{new_position_request, PaymentRequest, UnitsRequest}; use crate::content::incidents_famine::{decrease_mod_and_log, decrease_mood_incident_city}; use crate::content::incidents_population_boom::select_player_to_gain_settler; use crate::game::{Game, GameState}; use crate::incident::{Incident, IncidentBaseEffect, IncidentBuilder, PermanentIncidentEffect}; +use crate::payment::{PaymentConversion, PaymentConversionType, PaymentOptions}; use crate::player::Player; use crate::player_events::IncidentTarget; use crate::position::Position; +use crate::resource::ResourceType; use crate::resource_pile::ResourcePile; use crate::status_phase::{add_change_government, can_change_government_for_free}; use crate::unit::UnitType; +use crate::wonder::draw_wonder_from_pile; use itertools::Itertools; -pub(crate) fn migrations() -> Vec { +pub(crate) fn civil_wars() -> Vec { vec![ migration(34), migration(35), civil_war(36), civil_war(37), revolution(), + uprising(), + envoy(), ] } @@ -135,7 +140,7 @@ fn revolution() -> Incident { "Kill a unit to avoid losing an action", |game, _player| can_loose_action(game), ); - b = b.add_incident_listener(IncidentTarget::ActivePlayer, 2, |game, player| { + b = b.add_simple_incident_listener(IncidentTarget::ActivePlayer, 2, |game, player, _| { if can_loose_action(game) && game.current_event_player().sacrifice == 0 { loose_action(game, player); } @@ -205,7 +210,7 @@ fn can_loose_action(game: &Game) -> bool { } fn loose_action(game: &mut Game, player: usize) { - let name = game.get_player(player).get_name(); + let name = game.player_name(player); if let GameState::StatusPhase(_) = game.state() { game.add_info_log_item(&format!("{name} lost an action for the next turn")); game.permanent_incident_effects @@ -215,3 +220,67 @@ fn loose_action(game: &mut Game, player: usize) { game.actions_left -= 1; }; } + +#[allow(clippy::float_cmp)] +fn uprising() -> Incident { + Incident::builder(39, "Uprising", "Pay 1-4 mood or culture tokens if possible. Each token is worth half a point at the end of the game.", IncidentBaseEffect::None) + .add_incident_payment_request( + IncidentTarget::ActivePlayer, + 0, + |game, player_index, _incident| { + let player = game.get_player(player_index); + let mut cost = PaymentOptions::sum(4, &[ResourceType::MoodTokens, ResourceType::CultureTokens]); + cost.conversions.push(PaymentConversion::new( + vec![ResourcePile::mood_tokens(1), ResourcePile::culture_tokens(1)], + ResourcePile::empty(), + PaymentConversionType::MayOverpay(3), + )); + player.can_afford(&cost).then_some( + vec![PaymentRequest::new(cost, "Pay 1-4 mood or culture tokens", false)]) + }, + |game, s| { + let player = game.get_player_mut(s.player_index); + let pile = &s.choice[0]; + let v = pile.resource_amount() as f32 / 2_f32; + player.event_victory_points += v; + game.add_info_log_item(&format!("{} paid {} to gain {} victory point{}", s.player_name, pile, v, + if v == 1.0 { "" } else { "s" })); + }, + ) + .build() +} + +fn envoy() -> Incident { + Incident::builder(40, + "Envoy", + "Gain 1 idea and 1 culture token. Select another player to gain 1 culture token. Draw the top card from the wonder deck. This card can be taken by anyone instead of drawing from the wonder pile.", + IncidentBaseEffect::BarbariansMove) + .add_simple_incident_listener( + IncidentTarget::ActivePlayer, + 1, + |game, player, player_name | { + game.add_info_log_item(&format!("{player_name} gained 1 idea and 1 culture token")); + game.get_player_mut(player).gain_resources( + ResourcePile::culture_tokens(1) + ResourcePile::ideas(1)); + + let wonder_from_pile = draw_wonder_from_pile(game); + if let Some(wonder) = wonder_from_pile { + game.add_info_log_item(&format!("{} is now available to be taken by anyone", + wonder.name)); + game.permanent_incident_effects.push( + PermanentIncidentEffect::PublicWonderCard(wonder.name)); + } + }, + ) + .add_incident_player_request( + "Select a player to gain 1 culture token", + |_p| true, + 0, + |game, s| { + let p = s.choice; + game.add_info_log_item(&format!("{} was selected to gain 1 culture token.", + game.player_name(p))); + game.get_player_mut(p).gain_resources(ResourcePile::culture_tokens(1)); + }) + .build() +} diff --git a/server/src/content/incidents.rs b/server/src/content/incidents.rs index b52288b4..8e499592 100644 --- a/server/src/content/incidents.rs +++ b/server/src/content/incidents.rs @@ -1,9 +1,10 @@ -use crate::content::incidects_civil_war::migrations; +use crate::content::incidects_civil_war::civil_wars; use crate::content::incidents_5::successful_year; use crate::content::incidents_earthquake::earthquakes; use crate::content::incidents_famine::{epidemics, famines, pestilence}; use crate::content::incidents_good_year::{awesome_years, fantastic_years, good_years}; use crate::content::incidents_population_boom::population_booms; +use crate::content::incidents_trojan::trojan_incidents; use crate::incident::Incident; use itertools::Itertools; use std::vec; @@ -26,7 +27,9 @@ pub(crate) fn get_all() -> Vec { // 29+ earthquakes(), // 34+ - migrations(), + civil_wars(), + // 41+ + trojan_incidents(), // 51+ successful_year(), ] diff --git a/server/src/content/incidents_earthquake.rs b/server/src/content/incidents_earthquake.rs index 21770462..5ead9c0c 100644 --- a/server/src/content/incidents_earthquake.rs +++ b/server/src/content/incidents_earthquake.rs @@ -167,7 +167,7 @@ fn destroy_city_center(game: &mut Game, position: Position) { p.destroyed_structures.cities += 1; game.add_info_log_item(&format!( "{} gained 2 points for the city center at {}", - game.get_player(owner).get_name(), + game.player_name(owner), position )); } @@ -188,7 +188,7 @@ fn destroy_building(game: &mut Game, b: Building, position: Position) { .remove_building(b); game.add_info_log_item(&format!( "{} gained 2 points for the {:?} at {}", - game.get_player(owner).get_name(), + game.player_name(owner), b, position )); @@ -208,7 +208,7 @@ fn destroy_wonder(game: &mut Game, position: Position, name: &str) { p.event_victory_points += a; game.add_info_log_item(&format!( "{} gained {} points for the {} at {}", - game.get_player(owner).get_name(), + game.player_name(owner), a, name, position diff --git a/server/src/content/incidents_famine.rs b/server/src/content/incidents_famine.rs index 300652ab..c53ef89a 100644 --- a/server/src/content/incidents_famine.rs +++ b/server/src/content/incidents_famine.rs @@ -31,10 +31,11 @@ pub(crate) fn pestilence() -> Vec { } }); builder = pestilence_city(builder, 1); - builder = builder.add_incident_listener(IncidentTarget::ActivePlayer, 0, |game, _p| { - game.permanent_incident_effects - .push(PermanentIncidentEffect::Pestilence); - }); + builder = + builder.add_simple_incident_listener(IncidentTarget::ActivePlayer, 0, |game, _, _| { + game.permanent_incident_effects + .push(PermanentIncidentEffect::Pestilence); + }); vec![builder.build()] } @@ -53,6 +54,7 @@ pub(crate) fn pestilence_permanent_effect() -> Builtin { ) .add_player_event_listener( |event| &mut event.is_playing_action_available, + 1, |available, game, i| { let player = game.get_player(i.player); if game @@ -64,7 +66,6 @@ pub(crate) fn pestilence_permanent_effect() -> Builtin { *available = false; } }, - 1, ) .build() } @@ -229,7 +230,7 @@ pub(crate) fn famine(id: u8, severe: bool) -> Incident { game.add_info_log_item(&format!( "{} lost {} food to Famine", - game.get_player(player_index).get_name(), + game.player_name(player_index), lost )); diff --git a/server/src/content/incidents_good_year.rs b/server/src/content/incidents_good_year.rs index 87d9f072..8bf9a73e 100644 --- a/server/src/content/incidents_good_year.rs +++ b/server/src/content/incidents_good_year.rs @@ -146,7 +146,7 @@ fn good_year(mut builder: IncidentBuilder, amount: u32, good_year_type: &GoodYea move |game, c| { game.add_info_log_item(&format!( "{} gained 1 food from {}", - game.get_player(c.choice).get_name(), + game.player_name(c.choice), n.clone(), )); game.get_player_mut(c.choice) diff --git a/server/src/content/incidents_population_boom.rs b/server/src/content/incidents_population_boom.rs index bd61c844..be6c683d 100644 --- a/server/src/content/incidents_population_boom.rs +++ b/server/src/content/incidents_population_boom.rs @@ -27,7 +27,7 @@ pub(crate) fn select_player_to_gain_settler(mut b: IncidentBuilder) -> IncidentB |game, c| { game.add_info_log_item(&format!( "{} was selected to gain 1 settler.", - game.get_player(c.choice).get_name() + game.player_name(c.choice) )); game.current_event_mut().selected_player = Some(c.choice); }, diff --git a/server/src/content/incidents_trojan.rs b/server/src/content/incidents_trojan.rs new file mode 100644 index 00000000..ce0a3fcf --- /dev/null +++ b/server/src/content/incidents_trojan.rs @@ -0,0 +1,228 @@ +use crate::ability_initializer::AbilityInitializerSetup; +use crate::combat::{get_combat, take_combat, CombatModifier, CombatRetreatState}; +use crate::combat_listeners::CombatResult; +use crate::content::advances::get_advance; +use crate::content::builtin::Builtin; +use crate::content::custom_phase_actions::PaymentRequest; +use crate::game::{Game, GameState}; +use crate::incident::{Anarchy, Incident, IncidentBaseEffect, PermanentIncidentEffect}; +use crate::payment::PaymentOptions; +use crate::player_events::IncidentTarget; +use crate::resource_pile::ResourcePile; +use crate::utils::remove_element_by; + +pub(crate) fn trojan_incidents() -> Vec { + vec![trojan_horse(), solar_eclipse(), anarchy()] +} + +const TROJAN_DESCRIPTION: &str = "In a land battle against a defended city (Army unit or Fortress), the attacker may pay 1 wood and 1 culture token to get 1 victory point and to deny the defender tactics cards in the first round of combat."; + +fn trojan_horse() -> Incident { + Incident::builder( + 42, + "Trojan Horse", + &format!("The following is available to all players: {TROJAN_DESCRIPTION}"), + IncidentBaseEffect::BarbariansMove, + ) + .add_simple_incident_listener(IncidentTarget::ActivePlayer, 0, |game, _, _| { + game.permanent_incident_effects + .push(PermanentIncidentEffect::TrojanHorse); + }) + .build() +} + +fn trojan_cost() -> PaymentOptions { + PaymentOptions::resources(ResourcePile::wood(1) + ResourcePile::culture_tokens(1)) +} + +pub(crate) fn decide_trojan_horse() -> Builtin { + Builtin::builder("Trojan Horse", TROJAN_DESCRIPTION) + .add_payment_request_listener( + |event| &mut event.on_combat_start, + 10, + |game, player_index, ()| { + if is_land_battle_against_defended_city(game, player_index) { + game.permanent_incident_effects.iter().find_map(|e| { + matches!(e, PermanentIncidentEffect::TrojanHorse).then_some(vec![ + PaymentRequest::new(trojan_cost(), "Activate the Trojan Horse?", true), + ]) + }) + } else { + None + } + }, + |game, s| { + if s.choice[0].is_empty() { + game.add_info_log_item(&format!( + "{} declined to activate the Trojan Horse", + s.player_name + )); + } else { + let player = game.get_player_mut(s.player_index); + player.event_victory_points += 1_f32; + game.add_info_log_item(&format!( + "{} activated the Trojan Horse and gained 1 victory point", + s.player_name + )); + game.permanent_incident_effects + .retain(|e| !matches!(e, PermanentIncidentEffect::TrojanHorse)); + let Some(GameState::Combat(c)) = &mut game.state_stack.last_mut() else { + panic!("Invalid state") + }; + c.modifiers.push(CombatModifier::TrojanHorse); + } + }, + ) + .build() +} + +fn is_land_battle_against_defended_city(game: &Game, player_index: usize) -> bool { + let combat = get_combat(game); + !combat.is_sea_battle(game) + && combat.attacker == player_index + && combat.defender_city(game).is_some() +} + +pub(crate) fn activate_trojan_horse() -> Builtin { + Builtin::builder("Trojan Horse", "-") + .add_player_event_listener( + |event| &mut event.on_combat_round, + 10, + |s, c, _game| { + if s.attacker && c.round == 1 && c.modifiers.contains(&CombatModifier::TrojanHorse) { + s.deny_tactics.push(c.defender); + s.roll_log.push( + "Trojan Horse denies the defender tactics cards in the first round of combat" + .to_string(), + ); + } + }, + ) + .build() +} + +fn solar_eclipse() -> Incident { + Incident::builder( + 41, + "Solar Eclipse", + "The next land battle will end after the first round (retreat if not finished). The winner gains 1 victory point (defender if draw).", + IncidentBaseEffect::PiratesSpawnAndRaid, + ) + .add_simple_incident_listener(IncidentTarget::ActivePlayer, 0, |game, _, _| { + game.permanent_incident_effects + .push(PermanentIncidentEffect::SolarEclipse); + }) + .build() +} + +pub(crate) fn solar_eclipse_end_combat() -> Builtin { + Builtin::builder("Solar Eclipse", "-") + .add_player_event_listener( + |event| &mut event.on_combat_round_end, + 10, + |game, _c, r| { + if let Some(p) = game + .permanent_incident_effects + .iter() + .position(|e| matches!(e, PermanentIncidentEffect::SolarEclipse)) + { + let mut c = take_combat(game); + if c.round == 1 && !c.is_sea_battle(game) { + game.permanent_incident_effects.remove(p); + c.retreat = CombatRetreatState::EndAfterCurrentRound; + + let p = match &r.final_result { + Some(CombatResult::AttackerWins) => c.attacker, + _ => c.defender, + }; + let p = game.get_player_mut(p); + p.event_victory_points += 1_f32; + let name = p.get_name().clone(); + game.add_info_log_item(&format!( + "{name} gained 1 victory point for the Solar Eclipse", + )); + } + game.push_state(GameState::Combat(c)); + } + }, + ) + .build() +} + +// fn guillotine() -> Incident { + +// Incident::builder( +// todo implement when leaders are implemented +// +// 43, +// "Guillotine", +// "Kill your leader if you have one. Then, choose one of the following: A) Choose a new leader in one of your cities or armies. B) Gain 2 victory points. You cannot play leaders for the remainder of the game." +// IncidentBaseEffect::BarbariansSpawn, +// ) +// .add_incident_listener(IncidentTarget::ActivePlayer, 0, |game, _player_index| { +// game.permanent_incident_effects +// .push(PermanentIncidentEffect::Guillotine); +// }) +// .build() +// } + +fn anarchy() -> Incident { + Incident::builder( + 44, + "Anarchy", + "Set aside all government advances. Whenever you research a new government advance, take a game event token from there instead of the supply (thereby not triggering game events). Each advance left in the government advances area at the end of the game is worth 1 victory point.", + IncidentBaseEffect::None, + ) + .add_simple_incident_listener(IncidentTarget::ActivePlayer, 0, |game, player_index, player_name| { + let p = game.get_player_mut(player_index); + let old = p.advances.len(); + p.advances.retain(|a| a.government.is_none()); + let lost = old - p.advances.len(); + p.event_victory_points += lost as f32; + if lost > 0 { + game.add_info_log_item(&format!( + "{player_name} lost {lost} government advances due to Anarchy - adding {lost} victory points", + )); + } + + game.permanent_incident_effects + .push(PermanentIncidentEffect::Anarchy(Anarchy { + player: player_index, + advances_lost: lost, + })); + }) + .build() +} + +pub(crate) fn anarchy_advance() -> Builtin { + Builtin::builder("Anarchy", "-") + .add_simple_current_event_listener( + |event| &mut event.on_advance, + 10, + |game, player_index, player_name, i| { + if get_advance(&i.name).government.is_none() { + return; + } + + if let Some(PermanentIncidentEffect::Anarchy(mut a)) = remove_element_by(&mut game + .permanent_incident_effects, + |e| matches!(e, PermanentIncidentEffect::Anarchy(_))) + { + if player_index == a.player { + game.lock_undo(); // until generic undo is implemented + game.add_info_log_item(&format!( + "{player_name} gained a government advance, taking a game event token instead of triggering a game event (and losing 1 victory point)", + )); + let p = game.get_player_mut(player_index); + p.incident_tokens += 1; + p.event_victory_points -= 1_f32; + a.advances_lost -= 1; + if a.advances_lost > 0 { + game.permanent_incident_effects.push(PermanentIncidentEffect::Anarchy(a)); + } + } + } + }, + ) + .build() +} diff --git a/server/src/content/trade_routes.rs b/server/src/content/trade_routes.rs index 8a3f5b41..574044ce 100644 --- a/server/src/content/trade_routes.rs +++ b/server/src/content/trade_routes.rs @@ -47,7 +47,7 @@ pub(crate) fn trade_route_log( if selected { log.push(format!( "{} selected trade routes", - game.players[player_index].get_name(), + game.player_name(player_index), )); } for t in trade_routes { diff --git a/server/src/content/wonders.rs b/server/src/content/wonders.rs index bf3f05aa..5fd79307 100644 --- a/server/src/content/wonders.rs +++ b/server/src/content/wonders.rs @@ -27,6 +27,7 @@ pub fn get_all() -> Vec { ) .add_player_event_listener( |events| &mut events.terrain_collect_options, + 1, |m,(),()| { m.insert(Fertile, HashSet::from([ ResourcePile::food(1), @@ -35,8 +36,7 @@ pub fn get_all() -> Vec { ResourcePile::ideas(1), ResourcePile::gold(1), ])); - }, - 1 + } ) .build(), ] diff --git a/server/src/cultural_influence.rs b/server/src/cultural_influence.rs index cb98850c..5d07c0c7 100644 --- a/server/src/cultural_influence.rs +++ b/server/src/cultural_influence.rs @@ -60,7 +60,7 @@ pub(crate) fn influence_culture_attempt( { game.add_to_last_log_item(&format!(" and rolled a {roll}")); info.info.execute(game); - game.add_info_log_item(&format!("{} now has the option to pay {roll_boost_cost} to increase the dice roll and proceed with the cultural influence", game.players[player_index].get_name())); + game.add_info_log_item(&format!("{} now has the option to pay {roll_boost_cost} to increase the dice roll and proceed with the cultural influence", game.player_name(player_index))); ask_for_cultural_influence_payment(game, player_index, &roll_boost_cost); } else { game.add_to_last_log_item(&format!( @@ -95,12 +95,18 @@ pub(crate) fn cultural_influence_resolution() -> Builtin { |_game, _player_index, cost| { Some(vec![PaymentRequest::new( PaymentOptions::resources(cost.clone()), - format!("Pay {cost} to increase the dice roll"), + &format!("Pay {cost} to increase the dice roll"), true, )]) }, |game, s| { let roll_boost_cost = s.choice[0].clone(); + if roll_boost_cost.is_empty() { + game.add_info_log_item(&format!( + "{} declined to pay to increase the dice roll and failed the cultural influence", s.player_name + )); + return; + } game.add_info_log_item(&format!( "{} paid {roll_boost_cost} to increase the dice roll and proceed with the cultural influence", s.player_name diff --git a/server/src/events.rs b/server/src/events.rs index 4286ca96..f8e0cd20 100644 --- a/server/src/events.rs +++ b/server/src/events.rs @@ -51,6 +51,13 @@ impl EventMut where T: Clone + PartialEq, { + fn new() -> Self { + Self { + listeners: Vec::new(), + next_id: 0, + } + } + //return the id of the listener witch can be used to remove the listener later pub(crate) fn add_listener_mut( &mut self, @@ -146,28 +153,19 @@ where } } -impl Default for EventMut { +impl Default for Event { fn default() -> Self { Self { - listeners: Vec::new(), - next_id: 0, + inner: Some(EventMut::new()), } } } pub struct Event { pub inner: Option>, - pub name: String, } impl Event { - pub(crate) fn new(name: &str) -> Self { - Self { - inner: Some(EventMut::default()), - name: name.to_string(), - } - } - pub(crate) fn get(&self) -> &EventMut { self.inner.as_ref().expect("Event should be initialized") } @@ -187,7 +185,7 @@ mod tests { #[test] fn mutable_event() { - let mut event = EventMut::default(); + let mut event = EventMut::new(); event.add_listener_mut( |item, constant, _| *item += constant, 0, @@ -239,7 +237,7 @@ mod tests { pub modifiers: Vec, } - let mut event = EventMut::default(); + let mut event = EventMut::new(); event.add_listener_mut( |value: &mut Info, (), ()| value.value += 1, 0, diff --git a/server/src/game.rs b/server/src/game.rs index d1d1b5d2..b96fbd4c 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -6,6 +6,7 @@ use std::vec; use crate::ability_initializer::AbilityListeners; use crate::combat::{Combat, CombatDieRoll, COMBAT_DIE_SIDES}; use crate::consts::{ACTIONS, NON_HUMAN_PLAYERS}; +use crate::content::builtin; use crate::content::civilizations::{BARBARIANS, PIRATES}; use crate::content::custom_phase_actions::{ CurrentEventHandler, CurrentEventPlayer, CurrentEventState, CurrentEventType, @@ -56,7 +57,7 @@ pub struct Game { pub dice_roll_log: Vec, pub dropped_players: Vec, pub wonders_left: Vec, - pub wonder_amount_left: usize, + pub wonder_amount_left: usize, // todo is this redundant? pub incidents_left: Vec, pub permanent_incident_effects: Vec, pub undo_context_stack: Vec, // transient @@ -126,7 +127,7 @@ impl Game { Map::new(HashMap::new()) }; - Self { + let mut game = Self { state_stack: vec![GameState::Playing], current_events: Vec::new(), players, @@ -158,7 +159,12 @@ impl Game { incidents_left: Vec::new(), permanent_incident_effects: Vec::new(), undo_context_stack: Vec::new(), + }; + for i in 0..game.players.len() { + builtin::init_player(&mut game, i); } + + game } /// @@ -275,6 +281,11 @@ impl Game { &self.players[player_index] } + #[must_use] + pub fn player_name(&self, player_index: usize) -> String { + self.get_player(player_index).get_name() + } + #[must_use] pub fn get_player_mut(&mut self, player_index: usize) -> &mut Player { &mut self.players[player_index] @@ -387,13 +398,13 @@ impl Game { players: &[usize], event: fn(&mut PlayerEvents) -> &mut CurrentEvent, details: &V, - store_details: impl Fn(V) -> CurrentEventType, + to_event_type: impl Fn(V) -> CurrentEventType, log: Option<&str>, ) -> bool where V: Clone, { - let current_event_details = store_details(details.clone()); + let current_event_details = to_event_type(details.clone()); if self .current_events .last() @@ -580,7 +591,7 @@ impl Game { self.increment_player_index(); self.add_info_log_group(format!( "It's {}'s turn", - self.players[self.current_player_index].get_name() + self.player_name(self.current_player_index) )); self.actions_left = ACTIONS; let lost_action = self.permanent_incident_effects.iter().position( @@ -705,7 +716,7 @@ impl Game { .max_by(|(_, player), (_, other)| player.compare_score(other, self)) .expect("there should be at least one player in the game") .0; - let winner_name = self.players[winner_player_index].get_name(); + let winner_name = self.player_name(winner_player_index); self.add_info_log_group(format!("The game has ended. {winner_name} has won")); self.add_message("The game has ended"); } @@ -732,7 +743,7 @@ impl Game { self.dropped_players.push(player_index); self.add_message(&format!( "{} has left the game", - self.players[player_index].get_name() + self.player_name(player_index) )); if self.current_player_index != player_index { return; @@ -773,16 +784,6 @@ impl Game { .any(|(a, _)| a == action) } - pub fn draw_wonder_card(&mut self, player_index: usize) { - let Some(wonder) = self.wonders_left.pop() else { - return; - }; - - self.wonder_amount_left -= 1; - self.players[player_index].wonder_cards.push(wonder); - self.lock_undo(); - } - /// /// /// # Panics diff --git a/server/src/incident.rs b/server/src/incident.rs index ebd47d65..e1949fa8 100644 --- a/server/src/incident.rs +++ b/server/src/incident.rs @@ -84,10 +84,20 @@ impl std::fmt::Display for IncidentBaseEffect { } } +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +pub struct Anarchy { + pub player: usize, + pub advances_lost: usize, +} + #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub enum PermanentIncidentEffect { Pestilence, LooseAction(usize), + PublicWonderCard(String), + TrojanHorse, + SolarEclipse, + Anarchy(Anarchy), } #[derive(Clone)] @@ -170,18 +180,23 @@ impl IncidentBuilder { } #[must_use] - pub fn add_incident_listener(self, role: IncidentTarget, priority: i32, listener: F) -> Self + pub fn add_simple_incident_listener( + self, + role: IncidentTarget, + priority: i32, + listener: F, + ) -> Self where - F: Fn(&mut Game, usize) + 'static + Clone, + F: Fn(&mut Game, usize, &str) + 'static + Clone, { - self.add_incident_resource_request( - role, + self.add_simple_current_event_listener( + |event| &mut event.on_incident, priority, - move |game, player_index, _incident| { - listener(game, player_index); - None // only to call the listener + move |game, player_index, player_name, i| { + if i.is_active(role, player_index) { + listener(game, player_index, player_name); + } }, - |_game, _s| vec![], // only to call the listener ) } @@ -398,8 +413,7 @@ impl IncidentBuilder { Some(vec![PaymentRequest::new( options, - "You may pay 1 mood token for each city to avoid reducing its mood" - .to_string(), + "You may pay 1 mood token for each city to avoid reducing its mood", false, )]) } else { diff --git a/server/src/log.rs b/server/src/log.rs index 52597994..1a708c49 100644 --- a/server/src/log.rs +++ b/server/src/log.rs @@ -90,7 +90,7 @@ pub(crate) fn format_cultural_influence_attempt_log_item( let player = if target_player_index == game.active_player() { String::from("themselves") } else { - game.players[target_player_index].get_name() + game.player_name(target_player_index) }; let city = if starting_city_position != target_city_position { format!(" with the city at {starting_city_position}") diff --git a/server/src/pirates.rs b/server/src/pirates.rs index e83ed936..7ca035c6 100644 --- a/server/src/pirates.rs +++ b/server/src/pirates.rs @@ -103,7 +103,7 @@ pub(crate) fn pirates_spawn_and_raid(mut builder: IncidentBuilder) -> IncidentBu )); Some(vec![PaymentRequest::new( PaymentOptions::sum(1, &ResourceType::all()), - "Pay 1 Resource or token to bribe the pirates".to_string(), + "Pay 1 Resource or token to bribe the pirates", false, )]) } else { @@ -128,7 +128,7 @@ pub(crate) fn pirates_spawn_and_raid(mut builder: IncidentBuilder) -> IncidentBu } let player = game.get_player(player_index); - let choices = cities_with_adjacent_pirates(game.get_player(player_index), game) + let choices = cities_with_adjacent_pirates(player, game) .into_iter() .filter(|&pos| !matches!(player.get_city(pos).mood_state, MoodState::Angry)) .collect_vec(); @@ -233,6 +233,12 @@ fn place_pirate_ship(builder: IncidentBuilder, priority: i32, blockade: bool) -> sea_spaces = blocking; } } + + if sea_spaces.is_empty() && blockade { + // don't log this twice (blockade is only for first call) + game.add_info_log_item("No valid positions for Pirate Ship"); + } + Some(new_position_request( sea_spaces, 1..=1, diff --git a/server/src/player.rs b/server/src/player.rs index 13a3cfa8..2abdf9f3 100644 --- a/server/src/player.rs +++ b/server/src/player.rs @@ -125,10 +125,7 @@ impl Player { let player = Self::from_data(data); let player_index = player.index; game.players.push(player); - let builtin = builtin::get_all(); - for b in builtin { - (b.listeners.initializer)(game, player_index); - } + builtin::init_player(game, player_index); let advances = mem::take(&mut game.players[player_index].advances); for advance in &advances { (advance.listeners.initializer)(game, player_index); diff --git a/server/src/player_events.rs b/server/src/player_events.rs index 372b86db..7b2e9f85 100644 --- a/server/src/player_events.rs +++ b/server/src/player_events.rs @@ -22,12 +22,13 @@ pub(crate) type CurrentEvent = Event; pub(crate) type PlayerCommandEvent = Event; +#[derive(Default)] pub(crate) struct PlayerEvents { pub on_construct: CurrentEvent, pub on_construct_wonder: Event, + pub on_draw_wonder_card: CurrentEvent, pub on_collect: PlayerCommandEvent, - pub on_advance: PlayerCommandEvent, - pub on_advance_custom_phase: CurrentEvent, + pub on_advance: CurrentEvent, pub on_recruit: CurrentEvent, pub on_influence_culture_attempt: Event, pub on_influence_culture_success: PlayerCommandEvent, @@ -58,39 +59,7 @@ pub(crate) struct PlayerEvents { impl PlayerEvents { pub fn new() -> PlayerEvents { - Self { - on_construct: Event::new("on_construct"), - on_construct_wonder: Event::new("on_construct_wonder"), - on_collect: Event::new("on_collect"), - on_advance: Event::new("on_advance"), - on_advance_custom_phase: Event::new("on_advance_custom_phase"), - on_recruit: Event::new("on_recruit"), - on_influence_culture_attempt: Event::new("on_influence_culture_attempt"), - on_influence_culture_success: Event::new("on_influence_culture_success"), - on_influence_culture_resolution: Event::new("on_influence_culture_resolution"), - before_move: Event::new("before_move"), - on_explore_resolution: Event::new("on_explore_resolution"), - - construct_cost: Event::new("construct_cost"), - wonder_cost: Event::new("wonder_cost"), - advance_cost: Event::new("advance_cost"), - happiness_cost: Event::new("happiness_cost"), - recruit_cost: Event::new("recruit_cost"), - - is_playing_action_available: Event::new("is_playing_action_available"), - - terrain_collect_options: Event::new("terrain_collect_options"), - collect_options: Event::new("collect_options"), - collect_total: Event::new("collect_total"), - - on_status_phase: Event::new("on_status_phase"), - on_turn_start: Event::new("on_turn_start"), - on_incident: Event::new("on_incident"), - on_combat_start: Event::new("on_combat_start"), - on_combat_round: Event::new("on_combat_round"), - on_combat_round_end: Event::new("on_combat_round_end"), - on_combat_end: Event::new("on_combat_end"), - } + Self::default() } } @@ -183,7 +152,7 @@ pub struct AdvanceInfo { #[derive(Clone, PartialEq)] pub struct CurrentEventInfo { - pub player: usize, + pub player: usize, // player currently handling the event } pub struct MoveInfo { @@ -283,7 +252,7 @@ impl PlayerCommands { self.content.gained_resources += resources; } - pub fn add_info_log_item(&mut self, edit: &str) { - self.log.push(edit.to_string()); + pub fn add_info_log_item(&mut self, log: &str) { + self.log.push(log.to_string()); } } diff --git a/server/src/resource.rs b/server/src/resource.rs index ed05777a..7689720e 100644 --- a/server/src/resource.rs +++ b/server/src/resource.rs @@ -59,7 +59,7 @@ pub(crate) fn check_for_waste(game: &mut Game) { if !wasted_resources.is_empty() { game.add_info_log_item(&format!( "{} could not store {wasted_resources}", - game.players[p].get_name() + game.player_name(p) )); game.push_undo_context(UndoContext::WastedResources { resources: wasted_resources, diff --git a/server/src/status_phase.rs b/server/src/status_phase.rs index 147c3dc9..3c0ffa45 100644 --- a/server/src/status_phase.rs +++ b/server/src/status_phase.rs @@ -143,10 +143,10 @@ pub(crate) fn draw_cards() -> Builtin { Builtin::builder("Draw Cards", "-") .add_player_event_listener( |event| &mut event.on_status_phase, + 0, |_game, _p, ()| { // every player draws 1 action card and 1 objective card }, - 0, ) .build() } @@ -335,14 +335,14 @@ pub(crate) fn determine_first_player() -> Builtin { |game, s| { game.add_info_log_item(&format!( "{} choose {}", - game.players[s.player_index].get_name(), + game.player_name(s.player_index), if s.choice == game.starting_player_index { format!( "{} to remain the staring player", if s.choice == game.active_player() { String::new() } else { - game.players[s.choice].get_name() + game.player_name(s.choice) } ) } else { @@ -351,7 +351,7 @@ pub(crate) fn determine_first_player() -> Builtin { if s.choice == game.active_player() { String::from("themselves") } else { - game.players[s.choice].get_name() + game.player_name(s.choice) } ) } diff --git a/server/src/utils.rs b/server/src/utils.rs index 86b9848b..2ce750b4 100644 --- a/server/src/utils.rs +++ b/server/src/utils.rs @@ -26,6 +26,17 @@ where None } +pub fn remove_element_by(list: &mut Vec, f: F) -> Option +where + F: Fn(&T) -> bool, +{ + let index = list.iter().position(f); + if let Some(index) = index { + return Some(list.remove(index)); + } + None +} + pub fn ordinal_number(value: u32) -> String { format!( "{value}{}", diff --git a/server/src/wonder.rs b/server/src/wonder.rs index 14f7144e..79284b12 100644 --- a/server/src/wonder.rs +++ b/server/src/wonder.rs @@ -1,5 +1,9 @@ use crate::ability_initializer::{AbilityInitializerBuilder, AbilityListeners}; +use crate::content::builtin::Builtin; +use crate::content::custom_phase_actions::CurrentEventType; +use crate::content::wonders::get_wonder; use crate::events::EventOrigin; +use crate::incident::PermanentIncidentEffect; use crate::payment::PaymentOptions; use crate::{ability_initializer::AbilityInitializerSetup, game::Game, position::Position}; @@ -85,3 +89,84 @@ impl AbilityInitializerSetup for WonderBuilder { EventOrigin::Wonder(self.name.clone()) } } + +pub(crate) fn draw_wonder_card(game: &mut Game, player_index: usize) { + game.lock_undo(); + game.trigger_current_event( + &[player_index], + |e| &mut e.on_draw_wonder_card, + &(), + |()| CurrentEventType::DrawWonderCard, + None, + ); +} + +pub(crate) fn draw_wonder_from_pile(game: &mut Game) -> Option { + if game.wonder_amount_left == 0 { + return None; + } + game.wonder_amount_left -= 1; + game.wonders_left.pop() +} + +fn gain_wonder(game: &mut Game, player_index: usize, wonder: Wonder) { + game.players[player_index].wonder_cards.push(wonder); + game.lock_undo(); +} + +pub(crate) fn on_draw_wonder_card() -> Builtin { + Builtin::builder("Draw Wonder Card", "Draw a wonder card") + .add_bool_request( + |e| &mut e.on_draw_wonder_card, + 0, + |game, player_index, ()| { + let public_wonder = find_public_wonder(game); + if let Some(public_wonder) = public_wonder { + Some(format!( + "Do you want to draw the public wonder card {public_wonder}?" + )) + } else { + gain_wonder_from_pile(game, player_index); + None + } + }, + |game, s| { + if s.choice { + let name = find_public_wonder(game) + .expect("public wonder card not found") + .clone(); + game.add_info_log_item(&format!( + "{} drew the public wonder card {}", + s.player_name, name + )); + gain_wonder(game, s.player_index, get_wonder(&name)); + game.permanent_incident_effects + .retain(|e| !matches!(e, PermanentIncidentEffect::PublicWonderCard(_))); + } else { + gain_wonder_from_pile(game, s.player_index); + } + }, + ) + .build() +} + +fn gain_wonder_from_pile(game: &mut Game, player: usize) { + if let Some(w) = draw_wonder_from_pile(game) { + game.add_info_log_item(&format!( + "{} drew a wonder card from the pile", + game.player_name(player) + )); + gain_wonder(game, player, w); + } else { + game.add_info_log_item("No wonders left to draw"); + } +} + +fn find_public_wonder(game: &Game) -> Option<&String> { + game.permanent_incident_effects + .iter() + .find_map(|e| match e { + PermanentIncidentEffect::PublicWonderCard(name) => Some(name), + _ => None, + }) +} diff --git a/server/tests/advances_tests.rs b/server/tests/advances_tests.rs index febde873..211d2014 100644 --- a/server/tests/advances_tests.rs +++ b/server/tests/advances_tests.rs @@ -1,12 +1,10 @@ -use crate::common::{ - illegal_action_test, influence_action, load_game, test_action, test_actions, TestAction, -}; +use crate::common::{illegal_action_test, influence_action, load_game, JsonTest, TestAction}; use server::action::{execute_action, Action}; -use server::city_pieces::Building::Temple; +use server::city_pieces::Building::{Fortress, Temple}; use server::content::custom_actions::CustomAction; use server::content::custom_actions::CustomAction::{ - AbsolutePower, CivilRights, ConstructWonder, ForcedLabor, Sports, Taxes, Theaters, - VotingIncreaseHappiness, + AbsolutePower, ArtsInfluenceCultureAttempt, CivilRights, ConstructWonder, ForcedLabor, Sports, + Taxes, Theaters, VotingIncreaseHappiness, }; use server::content::custom_phase_actions::CurrentEventResponse; use server::content::trade_routes::find_trade_routes; @@ -25,12 +23,14 @@ use server::unit::{MoveUnits, Units}; mod common; +const JSON: JsonTest = JsonTest::new("advances"); + #[test] fn test_sanitation_and_draft() { // we should figure out that sanitation or draft are used, but not both let units = Units::new(1, 1, 0, 0, 0, 0); let city_position = Position::from_offset("A1"); - test_actions( + JSON.test( "sanitation_and_draft", vec![TestAction::undoable( 0, @@ -64,7 +64,7 @@ fn test_sanitation_and_draft() { #[test] fn test_separation_of_power() { illegal_action_test(|test| { - let mut game = load_game("cultural_influence"); + let mut game = load_culture(); execute_action(&mut game, Action::Playing(EndTurn), 1); if test.fail { execute_action( @@ -85,7 +85,7 @@ fn test_separation_of_power() { #[test] fn test_devotion() { illegal_action_test(|test| { - let mut game = load_game("cultural_influence"); + let mut game = load_culture(); execute_action(&mut game, Action::Playing(EndTurn), 1); if test.fail { execute_action( @@ -103,10 +103,14 @@ fn test_devotion() { }); } +fn load_culture() -> Game { + load_game("base/cultural_influence") +} + #[test] fn test_totalitarianism() { illegal_action_test(|test| { - let mut game = load_game("cultural_influence"); + let mut game = load_culture(); execute_action(&mut game, Action::Playing(EndTurn), 1); if test.fail { execute_action( @@ -127,7 +131,7 @@ fn test_totalitarianism() { #[test] fn test_monuments() { illegal_action_test(|test| { - let mut game = load_game("cultural_influence"); + let mut game = load_culture(); execute_action(&mut game, Action::Playing(EndTurn), 1); if test.fail { execute_action( @@ -156,84 +160,84 @@ fn test_monuments() { #[test] fn test_increase_happiness_sports() { - test_action( + JSON.test( "increase_happiness_sports", - Action::Playing(Custom(Sports { - payment: ResourcePile::culture_tokens(1), - city_position: Position::from_offset("C2"), - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(Sports { + payment: ResourcePile::culture_tokens(1), + city_position: Position::from_offset("C2"), + })), + )], ); } #[test] fn test_increase_happiness_sports2() { - test_action( + JSON.test( "increase_happiness_sports2", - Action::Playing(Custom(Sports { - payment: ResourcePile::culture_tokens(2), - city_position: Position::from_offset("C2"), - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(Sports { + payment: ResourcePile::culture_tokens(2), + city_position: Position::from_offset("C2"), + })), + )], ); } #[test] fn test_increase_happiness_voting() { - test_action( + JSON.test( "increase_happiness_voting", - Action::Playing(Custom(VotingIncreaseHappiness( - playing_actions::IncreaseHappiness { - happiness_increases: vec![ - (Position::from_offset("C2"), 1), - (Position::from_offset("B3"), 2), - ], - payment: ResourcePile::mood_tokens(5), - }, - ))), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(VotingIncreaseHappiness( + playing_actions::IncreaseHappiness { + happiness_increases: vec![ + (Position::from_offset("C2"), 1), + (Position::from_offset("B3"), 2), + ], + payment: ResourcePile::mood_tokens(5), + }, + ))), + )], ); } #[test] fn test_increase_happiness_voting_rituals() { - test_action( + JSON.test( "increase_happiness_voting_rituals", - Action::Playing(Custom(VotingIncreaseHappiness( - playing_actions::IncreaseHappiness { - happiness_increases: vec![ - (Position::from_offset("C2"), 1), - (Position::from_offset("B3"), 2), - ], - payment: ResourcePile::new(1, 0, 1, 1, 1, 1, 0), - }, - ))), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(VotingIncreaseHappiness( + playing_actions::IncreaseHappiness { + happiness_increases: vec![ + (Position::from_offset("C2"), 1), + (Position::from_offset("B3"), 2), + ], + payment: ResourcePile::new(1, 0, 1, 1, 1, 1, 0), + }, + ))), + )], ); } #[test] fn test_absolute_power() { - test_action( + JSON.test( "absolute_power", - Action::Playing(Custom(AbsolutePower)), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(AbsolutePower)), + )], ); } #[test] fn test_forced_labor() { - test_actions( + JSON.test( "forced_labor", vec![ TestAction::undoable(0, Action::Playing(Custom(ForcedLabor))), @@ -253,7 +257,7 @@ fn test_forced_labor() { #[test] fn test_civil_liberties() { - test_actions( + JSON.test( "civil_liberties", vec![ TestAction::undoable(0, Action::Playing(Custom(CivilRights))), @@ -275,17 +279,17 @@ fn test_civil_liberties() { fn test_movement_on_roads_from_city() { let units = vec![0]; let destination = Position::from_offset("F7"); - test_action( + JSON.test( "movement_on_roads_from_city", - Action::Movement(Move(MoveUnits { - units, - destination, - embark_carrier_id: None, - payment: ResourcePile::food(1) + ResourcePile::ore(1), - })), - 1, - true, - false, + vec![TestAction::undoable( + 1, + Action::Movement(Move(MoveUnits { + units, + destination, + embark_carrier_id: None, + payment: ResourcePile::food(1) + ResourcePile::ore(1), + })), + )], ); } @@ -293,23 +297,23 @@ fn test_movement_on_roads_from_city() { fn test_movement_on_roads_to_city() { let units = vec![0]; let destination = Position::from_offset("D8"); - test_action( + JSON.test( "movement_on_roads_to_city", - Action::Movement(Move(MoveUnits { - units, - destination, - embark_carrier_id: None, - payment: ResourcePile::food(1) + ResourcePile::ore(1), - })), - 1, - true, - false, + vec![TestAction::undoable( + 1, + Action::Movement(Move(MoveUnits { + units, + destination, + embark_carrier_id: None, + payment: ResourcePile::food(1) + ResourcePile::ore(1), + })), + )], ); } #[test] fn test_road_coordinates() { - let game = &load_game("roads_unit_test"); + let game = &JSON.load_game("roads_unit_test"); // city units at D8 are 0, 1, 2 // 3 and 4 are on mountain C8 and can move to the city at D8 (ignoring movement restrictions), @@ -345,29 +349,29 @@ fn get_destinations(game: &Game, units: &[u32], position: &str) -> Vec { #[test] fn test_theaters() { - test_action( + JSON.test( "theaters", - Action::Playing(Custom(Theaters(ResourcePile::culture_tokens(1)))), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(Theaters(ResourcePile::culture_tokens(1)))), + )], ); } #[test] fn test_taxes() { - test_action( + JSON.test( "taxes", - Action::Playing(Custom(Taxes(ResourcePile::new(1, 1, 1, 0, 1, 0, 0)))), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(Taxes(ResourcePile::new(1, 1, 1, 0, 1, 0, 0)))), + )], ); } #[test] fn test_trade_route_coordinates() { - let game = &load_game("trade_routes_unit_test"); + let game = &JSON.load_game("trade_routes_unit_test"); // trading cities are C6, D6, E6, B6 // 1 ships and 1 settler on E7 can trade with C6, D6, E6 @@ -382,12 +386,15 @@ fn test_trade_route_coordinates() { #[test] fn test_trade_routes() { - test_action("trade_routes", Action::Playing(EndTurn), 0, false, false); + JSON.test( + "trade_routes", + vec![TestAction::not_undoable(0, Action::Playing(EndTurn))], + ); } #[test] fn test_trade_routes_with_currency() { - test_actions( + JSON.test( "trade_routes_with_currency", vec![ TestAction::not_undoable(0, Action::Playing(EndTurn)), @@ -403,7 +410,7 @@ fn test_trade_routes_with_currency() { #[test] fn test_dogma() { - test_actions( + JSON.test( "dogma", vec![ TestAction::undoable( @@ -440,7 +447,7 @@ fn test_dogma() { #[test] fn test_priesthood() { - test_actions( + JSON.test( "priesthood", vec![ TestAction::undoable( @@ -470,7 +477,7 @@ fn test_priesthood() { #[test] fn test_free_education() { - test_actions( + JSON.test( "free_education", vec![ TestAction::undoable( @@ -494,7 +501,7 @@ fn test_collect_husbandry() { city_position: Position::from_offset("B3"), collections: vec![(Position::from_offset("B5"), ResourcePile::food(1))], })); - test_actions( + JSON.test( "collect_husbandry", vec![ TestAction::undoable(0, action.clone()), @@ -505,19 +512,70 @@ fn test_collect_husbandry() { #[test] fn test_collect_free_economy() { - test_action( + JSON.test( "collect_free_economy", - Action::Playing(Custom(CustomAction::FreeEconomyCollect( - playing_actions::Collect { - city_position: Position::from_offset("C2"), - collections: vec![ - (Position::from_offset("B1"), ResourcePile::ore(1)), - (Position::from_offset("B2"), ResourcePile::ore(1)), - ], - }, - ))), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(CustomAction::FreeEconomyCollect( + playing_actions::Collect { + city_position: Position::from_offset("C2"), + collections: vec![ + (Position::from_offset("B1"), ResourcePile::ore(1)), + (Position::from_offset("B2"), ResourcePile::ore(1)), + ], + }, + ))), + )], + ); +} + +#[test] +fn test_cultural_influence_instant_with_arts() { + JSON.test( + "cultural_influence_instant_with_arts", + vec![TestAction::not_undoable( + 1, + Action::Playing(Custom(ArtsInfluenceCultureAttempt( + playing_actions::InfluenceCultureAttempt { + starting_city_position: Position::from_offset("C1"), + target_player_index: 0, + target_city_position: Position::from_offset("C2"), + city_piece: Fortress, + }, + ))), + )], + ) +} + +#[test] +fn test_cultural_influence_with_conversion() { + JSON.test( + "cultural_influence_with_conversion", + vec![ + TestAction::not_undoable(1, influence_action()), + TestAction::undoable( + 1, + Action::Response(CurrentEventResponse::Payment(vec![ + ResourcePile::culture_tokens(3), + ])), + ), + ], + ); +} + +#[test] +fn test_overpay() { + JSON.test( + "sanitation_and_draft", + vec![TestAction::illegal( + 0, + Action::Playing(Recruit(server::playing_actions::Recruit { + units: Units::new(0, 1, 0, 0, 0, 0), + city_position: Position::from_offset("A1"), + payment: ResourcePile::mood_tokens(1) + ResourcePile::gold(2), //paid too much + leader_name: None, + replaced_units: vec![], + })), + )], ); } diff --git a/server/tests/civ_tests.rs b/server/tests/civ_tests.rs index 2bb4ffc1..905d64fd 100644 --- a/server/tests/civ_tests.rs +++ b/server/tests/civ_tests.rs @@ -1,13 +1,15 @@ -use crate::common::{move_action, test_actions, TestAction}; +use crate::common::{move_action, JsonTest, TestAction}; use server::action::Action; use server::content::custom_phase_actions::CurrentEventResponse; use server::position::Position; mod common; +const JSON: JsonTest = JsonTest::new("civ"); + #[test] fn test_civ_maya_leader_pakal_and_place_settler() { - test_actions( + JSON.test( "civ_maya_leader_pakal", vec![ TestAction::not_undoable(0, move_action(vec![10], Position::from_offset("B1"))), diff --git a/server/tests/combat_tests.rs b/server/tests/combat_tests.rs index fac6a824..3fc86433 100644 --- a/server/tests/combat_tests.rs +++ b/server/tests/combat_tests.rs @@ -1,6 +1,7 @@ // combat -use crate::common::{move_action, test_action, test_actions, TestAction}; +use crate::common::{move_action, TestAction}; +use common::JsonTest; use server::action::Action; use server::content::custom_phase_actions::CurrentEventResponse; use server::playing_actions::PlayingAction::Recruit; @@ -10,9 +11,11 @@ use server::unit::Units; mod common; +const JSON: JsonTest = JsonTest::new("combat"); + #[test] fn test_remove_casualties_attacker() { - test_actions( + JSON.test( "remove_casualties_attacker", vec![ TestAction::not_undoable( @@ -29,7 +32,7 @@ fn test_remove_casualties_attacker() { #[test] fn test_remove_casualties_defender() { - test_actions( + JSON.test( "remove_casualties_defender", vec![TestAction::not_undoable( 0, @@ -40,40 +43,40 @@ fn test_remove_casualties_defender() { #[test] fn test_direct_capture_city_metallurgy() { - test_action( + JSON.test( "direct_capture_city_metallurgy", - move_action(vec![0, 1, 2, 3], Position::from_offset("C1")), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + move_action(vec![0, 1, 2, 3], Position::from_offset("C1")), + )], ); } #[test] fn test_direct_capture_city_fortress() { - test_action( + JSON.test( "direct_capture_city_fortress", - move_action(vec![0, 1, 2, 3], Position::from_offset("C1")), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + move_action(vec![0, 1, 2, 3], Position::from_offset("C1")), + )], ); } #[test] fn test_direct_capture_city_only_fortress() { - test_action( + JSON.test( "direct_capture_city_only_fortress", - move_action(vec![0, 1, 2, 3], Position::from_offset("C1")), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + move_action(vec![0, 1, 2, 3], Position::from_offset("C1")), + )], ); } #[test] fn test_combat_all_modifiers() { - test_actions( + JSON.test( "combat_all_modifiers", vec![ TestAction::not_undoable( @@ -101,7 +104,7 @@ fn test_combat_all_modifiers() { #[test] fn test_combat_fanaticism() { - test_actions( + JSON.test( "combat_fanaticism", vec![TestAction::not_undoable( 0, @@ -112,7 +115,7 @@ fn test_combat_fanaticism() { #[test] fn test_retreat() { - test_actions( + JSON.test( "retreat", vec![ TestAction::not_undoable(0, move_action(vec![0], Position::from_offset("C1"))), @@ -123,7 +126,7 @@ fn test_retreat() { #[test] fn test_do_not_retreat() { - test_actions( + JSON.test( "retreat_no", vec![ TestAction::not_undoable(0, move_action(vec![0], Position::from_offset("C1"))), @@ -134,7 +137,7 @@ fn test_do_not_retreat() { #[test] fn test_ship_combat() { - test_actions( + JSON.test( "ship_combat", vec![ TestAction::not_undoable(0, move_action(vec![7, 8], Position::from_offset("D2"))), @@ -148,18 +151,18 @@ fn test_ship_combat() { #[test] fn test_ship_combat_war_ships() { - test_action( + JSON.test( "ship_combat_war_ships", - move_action(vec![7, 8], Position::from_offset("D2")), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + move_action(vec![7, 8], Position::from_offset("D2")), + )], ); } #[test] fn test_recruit_combat() { - test_actions( + JSON.test( "recruit_combat", vec![ TestAction::undoable( diff --git a/server/tests/common/mod.rs b/server/tests/common/mod.rs index fa79e8ee..9f2ae595 100644 --- a/server/tests/common/mod.rs +++ b/server/tests/common/mod.rs @@ -18,6 +18,28 @@ use std::{ vec, }; +pub struct JsonTest { + pub directory: &'static str, +} + +impl JsonTest { + pub const fn new(directory: &'static str) -> Self { + Self { directory } + } + + pub fn test(&self, name: &str, actions: Vec) { + test_actions(&self.full_path(name), actions); + } + + pub fn load_game(&self, name: &str) -> Game { + load_game(&self.full_path(name)) + } + + fn full_path(&self, name: &str) -> String { + format!("{}{}{name}", self.directory, SEPARATOR) + } +} + fn assert_eq_game_json( expected: &str, actual: &str, @@ -144,22 +166,6 @@ pub(crate) fn test_actions(name: &str, actions: Vec) { } } -pub fn test_action( - name: &str, - action: Action, - player_index: usize, - undoable: bool, - illegal_action_test: bool, -) { - let outcome = format!("{name}.outcome"); - test_action_internal( - load_game(name), - name, - &outcome, - TestAction::new(action, undoable, illegal_action_test, player_index), - ); -} - fn test_action_internal(game: Game, name: &str, outcome: &str, test: TestAction) -> Game { let action = test.action; let a = serde_json::to_string(&action).expect("action should be serializable"); diff --git a/server/tests/game_api_tests.rs b/server/tests/game_api_tests.rs index 71c55163..cb1f389e 100644 --- a/server/tests/game_api_tests.rs +++ b/server/tests/game_api_tests.rs @@ -19,6 +19,8 @@ use std::{collections::HashMap, vec}; mod common; +const JSON: JsonTest = JsonTest::new("base"); + #[test] fn basic_actions() { let seed = String::new(); @@ -241,59 +243,25 @@ fn undo() { #[test] fn test_cultural_influence_instant() { - test_action( + JSON.test( "cultural_influence_instant", - Action::Playing(InfluenceCultureAttempt( - playing_actions::InfluenceCultureAttempt { - starting_city_position: Position::from_offset("C1"), - target_player_index: 0, - target_city_position: Position::from_offset("C2"), - city_piece: Fortress, - }, - )), - 1, - false, - false, - ); -} - -#[test] -fn test_cultural_influence_instant_with_arts() { - test_action( - "cultural_influence_instant_with_arts", - Action::Playing(Custom(ArtsInfluenceCultureAttempt( - playing_actions::InfluenceCultureAttempt { - starting_city_position: Position::from_offset("C1"), - target_player_index: 0, - target_city_position: Position::from_offset("C2"), - city_piece: Fortress, - }, - ))), - 1, - false, - false, - ); -} - -#[test] -fn test_cultural_influence_with_conversion() { - test_actions( - "cultural_influence_with_conversion", - vec![ - TestAction::not_undoable(1, influence_action()), - TestAction::undoable( - 1, - Action::Response(CurrentEventResponse::Payment(vec![ - ResourcePile::culture_tokens(3), - ])), - ), - ], + vec![TestAction::not_undoable( + 1, + Action::Playing(InfluenceCultureAttempt( + playing_actions::InfluenceCultureAttempt { + starting_city_position: Position::from_offset("C1"), + target_player_index: 0, + target_city_position: Position::from_offset("C2"), + city_piece: Fortress, + }, + )), + )], ); } #[test] fn test_cultural_influence() { - test_actions( + JSON.test( "cultural_influence", vec![ TestAction::not_undoable(1, influence_action()), @@ -309,160 +277,143 @@ fn test_cultural_influence() { #[test] fn test_found_city() { - test_action( + JSON.test( "found_city", - Action::Playing(FoundCity { settler: 4 }), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(FoundCity { settler: 4 }), + )], ); } #[test] fn test_wonder() { - test_action( + JSON.test( "wonder", - Action::Playing(Custom(ConstructWonder { - city_position: Position::from_offset("A1"), - wonder: String::from("Pyramids"), - payment: ResourcePile::new(2, 3, 3, 0, 0, 0, 4), - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Custom(ConstructWonder { + city_position: Position::from_offset("A1"), + wonder: String::from("Pyramids"), + payment: ResourcePile::new(2, 3, 3, 0, 0, 0, 4), + })), + )], ); } #[test] fn test_increase_happiness() { - test_action( + JSON.test( "increase_happiness", - Action::Playing(IncreaseHappiness(playing_actions::IncreaseHappiness { - happiness_increases: vec![ - (Position::from_offset("C2"), 1), - (Position::from_offset("B3"), 2), - ], - payment: ResourcePile::mood_tokens(5), - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(IncreaseHappiness(playing_actions::IncreaseHappiness { + happiness_increases: vec![ + (Position::from_offset("C2"), 1), + (Position::from_offset("B3"), 2), + ], + payment: ResourcePile::mood_tokens(5), + })), + )], ); } #[test] fn test_recruit() { - test_action( + JSON.test( "recruit", - Action::Playing(Recruit(server::playing_actions::Recruit { - units: Units::new(1, 1, 0, 0, 0, 0), - city_position: Position::from_offset("A1"), - payment: ResourcePile::food(1) + ResourcePile::ore(1) + ResourcePile::gold(2), - leader_name: None, - replaced_units: vec![4], - })), - 0, - true, - false, - ); -} - -#[test] -fn test_overpay() { - test_action( - "sanitation_and_draft", - Action::Playing(Recruit(server::playing_actions::Recruit { - units: Units::new(0, 1, 0, 0, 0, 0), - city_position: Position::from_offset("A1"), - payment: ResourcePile::mood_tokens(1) + ResourcePile::gold(2), //paid too much - leader_name: None, - replaced_units: vec![], - })), - 0, - true, - true, + vec![TestAction::undoable( + 0, + Action::Playing(Recruit(server::playing_actions::Recruit { + units: Units::new(1, 1, 0, 0, 0, 0), + city_position: Position::from_offset("A1"), + payment: ResourcePile::food(1) + ResourcePile::ore(1) + ResourcePile::gold(2), + leader_name: None, + replaced_units: vec![4], + })), + )], ); } #[test] fn test_recruit_leader() { - test_action( + JSON.test( "recruit_leader", - Action::Playing(Recruit(server::playing_actions::Recruit { - units: Units::new(0, 0, 0, 0, 0, 1), - city_position: Position::from_offset("A1"), - payment: ResourcePile::mood_tokens(1) + ResourcePile::culture_tokens(1), - leader_name: Some("Alexander".to_string()), - replaced_units: vec![], - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Recruit(server::playing_actions::Recruit { + units: Units::new(0, 0, 0, 0, 0, 1), + city_position: Position::from_offset("A1"), + payment: ResourcePile::mood_tokens(1) + ResourcePile::culture_tokens(1), + leader_name: Some("Alexander".to_string()), + replaced_units: vec![], + })), + )], ); } #[test] fn test_replace_leader() { - test_action( + JSON.test( "replace_leader", - Action::Playing(Recruit(server::playing_actions::Recruit { - units: Units::new(0, 0, 0, 0, 0, 1), - city_position: Position::from_offset("A1"), - payment: ResourcePile::mood_tokens(1) + ResourcePile::culture_tokens(1), - leader_name: Some("Kleopatra".to_string()), - replaced_units: vec![10], - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Recruit(server::playing_actions::Recruit { + units: Units::new(0, 0, 0, 0, 0, 1), + city_position: Position::from_offset("A1"), + payment: ResourcePile::mood_tokens(1) + ResourcePile::culture_tokens(1), + leader_name: Some("Kleopatra".to_string()), + replaced_units: vec![10], + })), + )], ); } #[test] fn test_collect() { - test_action( + JSON.test( "collect", - Action::Playing(Collect(playing_actions::Collect { - city_position: Position::from_offset("C2"), - collections: vec![ - (Position::from_offset("B1"), ResourcePile::ore(1)), - (Position::from_offset("B2"), ResourcePile::wood(1)), - ], - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Collect(playing_actions::Collect { + city_position: Position::from_offset("C2"), + collections: vec![ + (Position::from_offset("B1"), ResourcePile::ore(1)), + (Position::from_offset("B2"), ResourcePile::wood(1)), + ], + })), + )], ); } #[test] fn test_construct() { - test_action( + JSON.test( "construct", - Action::Playing(Construct(playing_actions::Construct { - city_position: Position::from_offset("C2"), - city_piece: Observatory, - payment: ResourcePile::new(1, 1, 1, 0, 0, 0, 0), - port_position: None, - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Construct(playing_actions::Construct { + city_position: Position::from_offset("C2"), + city_piece: Observatory, + payment: ResourcePile::new(1, 1, 1, 0, 0, 0, 0), + port_position: None, + })), + )], ); } #[test] fn test_construct_port() { - test_action( + JSON.test( "construct_port", - Action::Playing(Construct(playing_actions::Construct { - city_position: Position::from_offset("A1"), - city_piece: Port, - payment: ResourcePile::new(1, 1, 1, 0, 0, 0, 0), - port_position: Some(Position::from_offset("A2")), - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Playing(Construct(playing_actions::Construct { + city_position: Position::from_offset("A1"), + city_piece: Port, + payment: ResourcePile::new(1, 1, 1, 0, 0, 0, 0), + port_position: Some(Position::from_offset("A2")), + })), + )], ); } diff --git a/server/tests/incident_tests.rs b/server/tests/incident_tests.rs index 5f99c776..b4845e8e 100644 --- a/server/tests/incident_tests.rs +++ b/server/tests/incident_tests.rs @@ -1,4 +1,4 @@ -use crate::common::{move_action, test_actions, TestAction}; +use crate::common::{move_action, JsonTest, TestAction}; use server::action::Action; use server::city_pieces::Building::Fortress; use server::content::custom_phase_actions::{CurrentEventResponse, Structure}; @@ -12,9 +12,11 @@ use std::vec; mod common; +const JSON: JsonTest = JsonTest::new("incidents"); + #[test] fn test_barbarians_spawn() { - test_actions( + JSON.test( "barbarians_spawn", vec![ TestAction::not_undoable( @@ -37,7 +39,7 @@ fn test_barbarians_spawn() { #[test] fn test_barbarians_move() { - test_actions( + JSON.test( "barbarians_move", vec![ TestAction::not_undoable( @@ -56,7 +58,7 @@ fn test_barbarians_move() { #[test] fn test_pirates_spawn() { - test_actions( + JSON.test( "pirates_spawn", vec![ TestAction::not_undoable( @@ -89,7 +91,7 @@ fn test_pirates_spawn() { #[test] fn test_barbarians_attack() { - test_actions( + JSON.test( "barbarians_attack", vec![TestAction::not_undoable( 0, @@ -100,7 +102,7 @@ fn test_barbarians_attack() { #[test] fn test_barbarians_recapture_city() { - test_actions( + JSON.test( "barbarians_recapture_city", vec![TestAction::not_undoable( 0, @@ -117,7 +119,7 @@ fn test_pestilence() { payment: ResourcePile::new(1, 1, 1, 0, 0, 0, 0), port_position: None, })); - test_actions( + JSON.test( "pestilence", vec![ TestAction::not_undoable( @@ -156,7 +158,7 @@ fn test_pestilence() { #[test] fn test_famine() { - test_actions( + JSON.test( "famine", vec![TestAction::not_undoable( 0, @@ -170,7 +172,7 @@ fn test_famine() { #[test] fn test_epidemics() { - test_actions( + JSON.test( "epidemics", vec![ TestAction::not_undoable( @@ -190,7 +192,7 @@ fn test_epidemics() { #[test] fn test_good_year_with_player_select() { - test_actions( + JSON.test( "good_year", vec![ TestAction::not_undoable( @@ -207,7 +209,7 @@ fn test_good_year_with_player_select() { #[test] fn test_exhausted_land() { - test_actions( + JSON.test( "exhausted_land", vec![ TestAction::not_undoable( @@ -226,7 +228,7 @@ fn test_exhausted_land() { #[test] fn test_volcano() { - test_actions( + JSON.test( "volcano", vec![ TestAction::not_undoable( @@ -248,7 +250,7 @@ fn test_volcano() { #[test] fn test_flood() { - test_actions( + JSON.test( "flood", vec![ TestAction::not_undoable( @@ -276,7 +278,7 @@ fn test_flood() { #[test] fn test_earthquake() { - test_actions( + JSON.test( "earthquake", vec![ TestAction::not_undoable( @@ -317,7 +319,7 @@ fn test_earthquake() { #[test] fn test_migration() { - test_actions( + JSON.test( "migration", vec![TestAction::not_undoable( 0, @@ -331,7 +333,7 @@ fn test_migration() { #[test] fn test_civil_war() { - test_actions( + JSON.test( "civil_war", vec![TestAction::not_undoable( 0, @@ -345,7 +347,7 @@ fn test_civil_war() { #[test] fn test_revolution() { - test_actions( + JSON.test( "revolution", vec![ TestAction::not_undoable( @@ -375,3 +377,118 @@ fn test_revolution() { ], ); } + +#[test] +fn test_uprising() { + JSON.test( + "uprising", + vec![ + TestAction::not_undoable( + 0, + Action::Playing(Advance { + advance: String::from("Storage"), + payment: ResourcePile::gold(2), + }), + ), + TestAction::not_undoable( + 0, + Action::Response(CurrentEventResponse::Payment(vec![ + ResourcePile::mood_tokens(1) + ResourcePile::culture_tokens(1), + ])), + ), + ], + ); +} + +#[test] +fn test_envoy() { + JSON.test( + "envoy", + vec![ + TestAction::not_undoable( + 0, + Action::Playing(Advance { + advance: String::from("Storage"), + payment: ResourcePile::gold(2), + }), + ), + TestAction::not_undoable( + 0, + Action::Playing(Advance { + advance: String::from("Monuments"), + payment: ResourcePile::gold(2), + }), + ), + TestAction::not_undoable(0, Action::Response(CurrentEventResponse::Bool(true))), + ], + ); +} + +#[test] +fn test_trojan_horse() { + JSON.test( + "trojan_horse", + vec![ + TestAction::not_undoable( + 0, + Action::Playing(Advance { + advance: String::from("Storage"), + payment: ResourcePile::gold(2), + }), + ), + TestAction::not_undoable( + 0, + move_action(vec![0, 1, 2, 3, 4, 5], Position::from_offset("C1")), + ), + TestAction::not_undoable( + 0, + Action::Response(CurrentEventResponse::Payment(vec![ + ResourcePile::culture_tokens(1) + ResourcePile::gold(1), + ])), + ), + ], + ); +} + +#[test] +fn test_solar_eclipse() { + JSON.test( + "solar_eclipse", + vec![ + TestAction::not_undoable( + 0, + Action::Playing(Advance { + advance: String::from("Storage"), + payment: ResourcePile::gold(2), + }), + ), + TestAction::not_undoable( + 0, + move_action(vec![0, 1, 2, 3, 4, 5], Position::from_offset("C1")), + ), + ], + ); +} + +#[test] +fn test_anarchy() { + JSON.test( + "anarchy", + vec![ + TestAction::not_undoable( + 0, + Action::Playing(Advance { + advance: String::from("Storage"), + payment: ResourcePile::gold(2), + }), + ), + TestAction::not_undoable( + 0, + Action::Playing(Advance { + advance: String::from("Dogma"), + payment: ResourcePile::gold(2), + }), + ), + ], + ); +} diff --git a/server/tests/movement_tests.rs b/server/tests/movement_tests.rs index 8faef6a6..e733145b 100644 --- a/server/tests/movement_tests.rs +++ b/server/tests/movement_tests.rs @@ -1,4 +1,4 @@ -use crate::common::{load_game, move_action, test_action, test_actions, TestAction}; +use crate::common::{move_action, JsonTest, TestAction}; use server::action::Action; use server::content::custom_phase_actions::CurrentEventResponse; use server::game::Game; @@ -10,64 +10,66 @@ use server::unit::MovementAction::Move; mod common; +const JSON: JsonTest = JsonTest::new("movement"); + #[test] fn test_movement() { - test_action( + JSON.test( "movement", - move_action(vec![4], Position::from_offset("B3")), - 0, - true, - false, + vec![TestAction::undoable( + 0, + move_action(vec![4], Position::from_offset("B3")), + )], ); } #[test] fn test_explore_choose() { - test_action( + JSON.test( "explore_choose", - move_action(vec![0], Position::from_offset("C7")), - 1, - false, - false, + vec![TestAction::not_undoable( + 1, + move_action(vec![0], Position::from_offset("C7")), + )], ); } #[test] fn test_explore_auto_no_walk_on_water() { - test_action( + JSON.test( "explore_auto_no_walk_on_water", - move_action(vec![0], Position::from_offset("B2")), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + move_action(vec![0], Position::from_offset("B2")), + )], ); } #[test] fn test_explore_auto_adjacent_water() { - test_action( + JSON.test( "explore_auto_adjacent_water", - move_action(vec![0], Position::from_offset("C7")), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + move_action(vec![0], Position::from_offset("C7")), + )], ); } #[test] fn test_explore_auto_water_outside() { - test_action( + JSON.test( "explore_auto_water_outside", - move_action(vec![1], Position::from_offset("F5")), - 1, - false, - false, + vec![TestAction::not_undoable( + 1, + move_action(vec![1], Position::from_offset("F5")), + )], ); } #[test] fn test_explore_resolution() { - test_actions( + JSON.test( "explore_resolution", vec![ TestAction::not_undoable(1, move_action(vec![0], Position::from_offset("D6"))), @@ -81,130 +83,127 @@ fn test_explore_resolution() { #[test] fn test_ship_transport() { - // undo capture empty city is broken - test_action( + JSON.test( "ship_transport", - move_action(vec![7], Position::from_offset("D2")), - 0, - true, - false, + vec![TestAction::undoable( + 0, + move_action(vec![7], Position::from_offset("D2")), + )], ); } #[test] fn test_ship_transport_same_sea() { - // undo capture empty city is broken - test_action( + JSON.test( "ship_transport_same_sea", - move_action(vec![7], Position::from_offset("C3")), - 0, - true, - false, + vec![TestAction::undoable( + 0, + move_action(vec![7], Position::from_offset("C3")), + )], ); } #[test] fn test_ship_embark() { - test_action( + JSON.test( "ship_embark", - Action::Movement(Move(MoveUnits { - units: vec![3, 4], - destination: Position::from_offset("C3"), - embark_carrier_id: Some(8), - payment: ResourcePile::empty(), - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Movement(Move(MoveUnits { + units: vec![3, 4], + destination: Position::from_offset("C3"), + embark_carrier_id: Some(8), + payment: ResourcePile::empty(), + })), + )], ); } #[test] fn test_ship_embark_continue() { - test_action( + JSON.test( "ship_embark_continue", - Action::Movement(Move(MoveUnits { - units: vec![5, 6], - destination: Position::from_offset("C3"), - embark_carrier_id: Some(9), - payment: ResourcePile::empty(), - })), - 0, - true, - false, + vec![TestAction::undoable( + 0, + Action::Movement(Move(MoveUnits { + units: vec![5, 6], + destination: Position::from_offset("C3"), + embark_carrier_id: Some(9), + payment: ResourcePile::empty(), + })), + )], ); } #[test] fn test_ship_disembark() { - // undo capture empty city is broken - test_action( + JSON.test( "ship_disembark", - move_action(vec![1, 2], Position::from_offset("B3")), - 0, - true, - false, + vec![TestAction::undoable( + 0, + move_action(vec![1, 2], Position::from_offset("B3")), + )], ); } #[test] fn test_ship_disembark_capture_empty_city() { - test_action( + JSON.test( "ship_disembark_capture_empty_city", - move_action(vec![1, 2], Position::from_offset("B2")), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + move_action(vec![1, 2], Position::from_offset("B2")), + )], ); } #[test] fn test_ship_explore() { - test_action( + JSON.test( "ship_explore", - move_action(vec![1], Position::from_offset("C5")), - 1, - false, - false, + vec![TestAction::not_undoable( + 1, + move_action(vec![1], Position::from_offset("C5")), + )], ); } #[test] fn test_ship_explore_teleport() { - test_action( + JSON.test( "ship_explore_teleport", - move_action(vec![1], Position::from_offset("C4")), - 1, - false, - false, + vec![TestAction::not_undoable( + 1, + move_action(vec![1], Position::from_offset("C4")), + )], ); } #[test] fn test_ship_explore_move_not_possible() { - test_action( + JSON.test( "ship_explore_move_not_possible", - Action::Response(CurrentEventResponse::ExploreResolution(3)), - 1, - true, - false, + vec![TestAction::undoable( + 1, + Action::Response(CurrentEventResponse::ExploreResolution(3)), + )], ); } #[test] fn test_ship_navigate() { - test_action( + JSON.test( "ship_navigate", - move_action(vec![1], Position::from_offset("A7")), - 1, - true, - false, + vec![TestAction::undoable( + 1, + move_action(vec![1], Position::from_offset("A7")), + )], ); } #[test] fn test_ship_navigate_coordinates() { - let mut game = load_game("ship_navigation_unit_test"); + let mut game = JSON.load_game("ship_navigation_unit_test"); let pairs = [ ("B3", "B5"), @@ -235,22 +234,22 @@ fn assert_navigate(game: &mut Game, from: Position, to: Position) { #[test] fn test_ship_navigate_explore_move() { - test_action( + JSON.test( "ship_navigate_explore_move", - move_action(vec![1], Position::from_offset("F2")), - 1, - false, - false, + vec![TestAction::not_undoable( + 1, + move_action(vec![1], Position::from_offset("F2")), + )], ); } #[test] fn test_ship_navigate_explore_not_move() { - test_action( + JSON.test( "ship_navigate_explore_not_move", - move_action(vec![1], Position::from_offset("F2")), - 1, - false, - false, + vec![TestAction::not_undoable( + 1, + move_action(vec![1], Position::from_offset("F2")), + )], ); } diff --git a/server/tests/status_phase_tests.rs b/server/tests/status_phase_tests.rs index 56b8538a..3314b277 100644 --- a/server/tests/status_phase_tests.rs +++ b/server/tests/status_phase_tests.rs @@ -1,4 +1,5 @@ -use crate::common::{test_action, test_actions, TestAction}; +use crate::common::TestAction; +use common::JsonTest; use server::action::Action; use server::content::custom_phase_actions::CurrentEventResponse; use server::playing_actions::PlayingAction; @@ -7,9 +8,11 @@ use server::status_phase::{ChangeGovernment, ChangeGovernmentType}; mod common; +const JSON: JsonTest = JsonTest::new("status_phase"); + #[test] fn test_end_game() { - test_actions( + JSON.test( "end_game", vec![TestAction::not_undoable( 0, @@ -20,7 +23,7 @@ fn test_end_game() { #[test] fn test_free_advance() { - test_actions( + JSON.test( "free_advance", vec![ TestAction::not_undoable(0, Action::Playing(PlayingAction::EndTurn)), @@ -34,62 +37,62 @@ fn test_free_advance() { #[test] fn test_wrong_status_phase_action() { - test_action( + JSON.test( "illegal_free_advance", - Action::Response(CurrentEventResponse::SelectPositions(vec![])), - 0, - false, - true, + vec![TestAction::illegal( + 0, + Action::Response(CurrentEventResponse::SelectPositions(vec![])), + )], ); } #[test] fn test_raze_city() { - test_action( + JSON.test( "raze_city", - Action::Response(CurrentEventResponse::SelectPositions(vec![ - Position::from_offset("A1"), - ])), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + Action::Response(CurrentEventResponse::SelectPositions(vec![ + Position::from_offset("A1"), + ])), + )], ); } #[test] fn test_raze_city_decline() { - test_action( + JSON.test( "raze_city_decline", - Action::Response(CurrentEventResponse::SelectPositions(vec![])), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + Action::Response(CurrentEventResponse::SelectPositions(vec![])), + )], ); } #[test] fn test_determine_first_player() { - test_action( + JSON.test( "determine_first_player", - Action::Response(CurrentEventResponse::SelectPlayer(1)), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + Action::Response(CurrentEventResponse::SelectPlayer(1)), + )], ); } #[test] fn test_change_government() { - test_action( + JSON.test( "change_government", - Action::Response(CurrentEventResponse::ChangeGovernmentType( - ChangeGovernmentType::ChangeGovernment(ChangeGovernment { - new_government: String::from("Theocracy"), - additional_advances: vec![String::from("Devotion")], - }), - )), - 0, - false, - false, + vec![TestAction::not_undoable( + 0, + Action::Response(CurrentEventResponse::ChangeGovernmentType( + ChangeGovernmentType::ChangeGovernment(ChangeGovernment { + new_government: String::from("Theocracy"), + additional_advances: vec![String::from("Devotion")], + }), + )), + )], ); } diff --git a/server/tests/test_games/absolute_power.json b/server/tests/test_games/advances/absolute_power.json similarity index 100% rename from server/tests/test_games/absolute_power.json rename to server/tests/test_games/advances/absolute_power.json diff --git a/server/tests/test_games/absolute_power.outcome.json b/server/tests/test_games/advances/absolute_power.outcome.json similarity index 100% rename from server/tests/test_games/absolute_power.outcome.json rename to server/tests/test_games/advances/absolute_power.outcome.json diff --git a/server/tests/test_games/civil_liberties.json b/server/tests/test_games/advances/civil_liberties.json similarity index 100% rename from server/tests/test_games/civil_liberties.json rename to server/tests/test_games/advances/civil_liberties.json diff --git a/server/tests/test_games/civil_liberties.outcome.json b/server/tests/test_games/advances/civil_liberties.outcome.json similarity index 100% rename from server/tests/test_games/civil_liberties.outcome.json rename to server/tests/test_games/advances/civil_liberties.outcome.json diff --git a/server/tests/test_games/civil_liberties.outcome1.json b/server/tests/test_games/advances/civil_liberties.outcome1.json similarity index 100% rename from server/tests/test_games/civil_liberties.outcome1.json rename to server/tests/test_games/advances/civil_liberties.outcome1.json diff --git a/server/tests/test_games/collect_free_economy.json b/server/tests/test_games/advances/collect_free_economy.json similarity index 100% rename from server/tests/test_games/collect_free_economy.json rename to server/tests/test_games/advances/collect_free_economy.json diff --git a/server/tests/test_games/collect_free_economy.outcome.json b/server/tests/test_games/advances/collect_free_economy.outcome.json similarity index 100% rename from server/tests/test_games/collect_free_economy.outcome.json rename to server/tests/test_games/advances/collect_free_economy.outcome.json diff --git a/server/tests/test_games/collect_husbandry.json b/server/tests/test_games/advances/collect_husbandry.json similarity index 100% rename from server/tests/test_games/collect_husbandry.json rename to server/tests/test_games/advances/collect_husbandry.json diff --git a/server/tests/test_games/collect_husbandry.outcome.json b/server/tests/test_games/advances/collect_husbandry.outcome.json similarity index 100% rename from server/tests/test_games/collect_husbandry.outcome.json rename to server/tests/test_games/advances/collect_husbandry.outcome.json diff --git a/server/tests/test_games/cultural_influence_instant_with_arts.json b/server/tests/test_games/advances/cultural_influence_instant_with_arts.json similarity index 100% rename from server/tests/test_games/cultural_influence_instant_with_arts.json rename to server/tests/test_games/advances/cultural_influence_instant_with_arts.json diff --git a/server/tests/test_games/cultural_influence_instant_with_arts.outcome.json b/server/tests/test_games/advances/cultural_influence_instant_with_arts.outcome.json similarity index 100% rename from server/tests/test_games/cultural_influence_instant_with_arts.outcome.json rename to server/tests/test_games/advances/cultural_influence_instant_with_arts.outcome.json diff --git a/server/tests/test_games/cultural_influence_with_conversion.json b/server/tests/test_games/advances/cultural_influence_with_conversion.json similarity index 100% rename from server/tests/test_games/cultural_influence_with_conversion.json rename to server/tests/test_games/advances/cultural_influence_with_conversion.json diff --git a/server/tests/test_games/cultural_influence_with_conversion.outcome.json b/server/tests/test_games/advances/cultural_influence_with_conversion.outcome.json similarity index 100% rename from server/tests/test_games/cultural_influence_with_conversion.outcome.json rename to server/tests/test_games/advances/cultural_influence_with_conversion.outcome.json diff --git a/server/tests/test_games/cultural_influence_with_conversion.outcome1.json b/server/tests/test_games/advances/cultural_influence_with_conversion.outcome1.json similarity index 100% rename from server/tests/test_games/cultural_influence_with_conversion.outcome1.json rename to server/tests/test_games/advances/cultural_influence_with_conversion.outcome1.json diff --git a/server/tests/test_games/dogma.json b/server/tests/test_games/advances/dogma.json similarity index 100% rename from server/tests/test_games/dogma.json rename to server/tests/test_games/advances/dogma.json diff --git a/server/tests/test_games/dogma.outcome.json b/server/tests/test_games/advances/dogma.outcome.json similarity index 100% rename from server/tests/test_games/dogma.outcome.json rename to server/tests/test_games/advances/dogma.outcome.json diff --git a/server/tests/test_games/dogma.outcome1.json b/server/tests/test_games/advances/dogma.outcome1.json similarity index 100% rename from server/tests/test_games/dogma.outcome1.json rename to server/tests/test_games/advances/dogma.outcome1.json diff --git a/server/tests/test_games/dogma.outcome2.json b/server/tests/test_games/advances/dogma.outcome2.json similarity index 100% rename from server/tests/test_games/dogma.outcome2.json rename to server/tests/test_games/advances/dogma.outcome2.json diff --git a/server/tests/test_games/dogma.outcome3.json b/server/tests/test_games/advances/dogma.outcome3.json similarity index 100% rename from server/tests/test_games/dogma.outcome3.json rename to server/tests/test_games/advances/dogma.outcome3.json diff --git a/server/tests/test_games/forced_labor.json b/server/tests/test_games/advances/forced_labor.json similarity index 100% rename from server/tests/test_games/forced_labor.json rename to server/tests/test_games/advances/forced_labor.json diff --git a/server/tests/test_games/forced_labor.outcome.json b/server/tests/test_games/advances/forced_labor.outcome.json similarity index 100% rename from server/tests/test_games/forced_labor.outcome.json rename to server/tests/test_games/advances/forced_labor.outcome.json diff --git a/server/tests/test_games/forced_labor.outcome1.json b/server/tests/test_games/advances/forced_labor.outcome1.json similarity index 100% rename from server/tests/test_games/forced_labor.outcome1.json rename to server/tests/test_games/advances/forced_labor.outcome1.json diff --git a/server/tests/test_games/free_education.json b/server/tests/test_games/advances/free_education.json similarity index 100% rename from server/tests/test_games/free_education.json rename to server/tests/test_games/advances/free_education.json diff --git a/server/tests/test_games/free_education.outcome.json b/server/tests/test_games/advances/free_education.outcome.json similarity index 100% rename from server/tests/test_games/free_education.outcome.json rename to server/tests/test_games/advances/free_education.outcome.json diff --git a/server/tests/test_games/free_education.outcome1.json b/server/tests/test_games/advances/free_education.outcome1.json similarity index 100% rename from server/tests/test_games/free_education.outcome1.json rename to server/tests/test_games/advances/free_education.outcome1.json diff --git a/server/tests/test_games/increase_happiness_sports.json b/server/tests/test_games/advances/increase_happiness_sports.json similarity index 100% rename from server/tests/test_games/increase_happiness_sports.json rename to server/tests/test_games/advances/increase_happiness_sports.json diff --git a/server/tests/test_games/increase_happiness_sports.outcome.json b/server/tests/test_games/advances/increase_happiness_sports.outcome.json similarity index 100% rename from server/tests/test_games/increase_happiness_sports.outcome.json rename to server/tests/test_games/advances/increase_happiness_sports.outcome.json diff --git a/server/tests/test_games/increase_happiness_sports2.json b/server/tests/test_games/advances/increase_happiness_sports2.json similarity index 100% rename from server/tests/test_games/increase_happiness_sports2.json rename to server/tests/test_games/advances/increase_happiness_sports2.json diff --git a/server/tests/test_games/increase_happiness_sports2.outcome.json b/server/tests/test_games/advances/increase_happiness_sports2.outcome.json similarity index 100% rename from server/tests/test_games/increase_happiness_sports2.outcome.json rename to server/tests/test_games/advances/increase_happiness_sports2.outcome.json diff --git a/server/tests/test_games/increase_happiness_voting.json b/server/tests/test_games/advances/increase_happiness_voting.json similarity index 100% rename from server/tests/test_games/increase_happiness_voting.json rename to server/tests/test_games/advances/increase_happiness_voting.json diff --git a/server/tests/test_games/increase_happiness_voting.outcome.json b/server/tests/test_games/advances/increase_happiness_voting.outcome.json similarity index 100% rename from server/tests/test_games/increase_happiness_voting.outcome.json rename to server/tests/test_games/advances/increase_happiness_voting.outcome.json diff --git a/server/tests/test_games/increase_happiness_voting_rituals.json b/server/tests/test_games/advances/increase_happiness_voting_rituals.json similarity index 100% rename from server/tests/test_games/increase_happiness_voting_rituals.json rename to server/tests/test_games/advances/increase_happiness_voting_rituals.json diff --git a/server/tests/test_games/increase_happiness_voting_rituals.outcome.json b/server/tests/test_games/advances/increase_happiness_voting_rituals.outcome.json similarity index 100% rename from server/tests/test_games/increase_happiness_voting_rituals.outcome.json rename to server/tests/test_games/advances/increase_happiness_voting_rituals.outcome.json diff --git a/server/tests/test_games/movement_on_roads_from_city.json b/server/tests/test_games/advances/movement_on_roads_from_city.json similarity index 100% rename from server/tests/test_games/movement_on_roads_from_city.json rename to server/tests/test_games/advances/movement_on_roads_from_city.json diff --git a/server/tests/test_games/movement_on_roads_from_city.outcome.json b/server/tests/test_games/advances/movement_on_roads_from_city.outcome.json similarity index 100% rename from server/tests/test_games/movement_on_roads_from_city.outcome.json rename to server/tests/test_games/advances/movement_on_roads_from_city.outcome.json diff --git a/server/tests/test_games/movement_on_roads_to_city.json b/server/tests/test_games/advances/movement_on_roads_to_city.json similarity index 100% rename from server/tests/test_games/movement_on_roads_to_city.json rename to server/tests/test_games/advances/movement_on_roads_to_city.json diff --git a/server/tests/test_games/movement_on_roads_to_city.outcome.json b/server/tests/test_games/advances/movement_on_roads_to_city.outcome.json similarity index 100% rename from server/tests/test_games/movement_on_roads_to_city.outcome.json rename to server/tests/test_games/advances/movement_on_roads_to_city.outcome.json diff --git a/server/tests/test_games/priesthood.json b/server/tests/test_games/advances/priesthood.json similarity index 99% rename from server/tests/test_games/priesthood.json rename to server/tests/test_games/advances/priesthood.json index 7b321a87..b07ca7fa 100644 --- a/server/tests/test_games/priesthood.json +++ b/server/tests/test_games/advances/priesthood.json @@ -202,6 +202,7 @@ "Fishing", "Mining", "Myths", + "Philosophy", "Priesthood" ], "unlocked_special_advance": [], diff --git a/server/tests/test_games/priesthood.outcome.json b/server/tests/test_games/advances/priesthood.outcome.json similarity index 94% rename from server/tests/test_games/priesthood.outcome.json rename to server/tests/test_games/advances/priesthood.outcome.json index d7e0735f..a87209fa 100644 --- a/server/tests/test_games/priesthood.outcome.json +++ b/server/tests/test_games/advances/priesthood.outcome.json @@ -1,5 +1,7 @@ { - "state": ["Playing"], + "state": [ + "Playing" + ], "players": [ { "name": null, @@ -146,6 +148,7 @@ "food": 1, "wood": 5, "ore": 5, + "ideas": 1, "gold": 5, "mood_tokens": 9, "culture_tokens": 10 @@ -201,6 +204,7 @@ "Math", "Mining", "Myths", + "Philosophy", "Priesthood" ], "unlocked_special_advance": [], @@ -309,6 +313,16 @@ "undo": [ { "Command": {} + }, + { + "Command": { + "info": { + "Priesthood": "used" + }, + "gained_resources": { + "ideas": 1 + } + } } ] } @@ -318,7 +332,8 @@ [ "Player2 paid nothing to get the Math advance", "Priesthood reduced the cost to 0", - "Player gained 1 culture token as advance bonus" + "Player gained 1 culture token as advance bonus", + "Player2 gained 1 idea from Philosophy" ] ], "undo_limit": 0, @@ -350,4 +365,4 @@ "Pyramids" ], "wonder_amount_left": 2 -} +} \ No newline at end of file diff --git a/server/tests/test_games/priesthood.outcome1.json b/server/tests/test_games/advances/priesthood.outcome1.json similarity index 90% rename from server/tests/test_games/priesthood.outcome1.json rename to server/tests/test_games/advances/priesthood.outcome1.json index 1aae2050..eeca195b 100644 --- a/server/tests/test_games/priesthood.outcome1.json +++ b/server/tests/test_games/advances/priesthood.outcome1.json @@ -1,5 +1,7 @@ { - "state": ["Playing"], + "state": [ + "Playing" + ], "players": [ { "name": null, @@ -146,6 +148,7 @@ "food": 1, "wood": 5, "ore": 5, + "ideas": 2, "gold": 3, "mood_tokens": 9, "culture_tokens": 11 @@ -202,6 +205,7 @@ "Math", "Mining", "Myths", + "Philosophy", "Priesthood" ], "unlocked_special_advance": [], @@ -310,6 +314,16 @@ "undo": [ { "Command": {} + }, + { + "Command": { + "info": { + "Priesthood": "used" + }, + "gained_resources": { + "ideas": 1 + } + } } ] }, @@ -323,7 +337,19 @@ } } } - } + }, + "undo": [ + { + "Command": { + "info": { + "Priesthood": "used" + }, + "gained_resources": { + "ideas": 1 + } + } + } + ] } ], "action_log_index": 2, @@ -331,11 +357,13 @@ [ "Player2 paid nothing to get the Math advance", "Priesthood reduced the cost to 0", - "Player gained 1 culture token as advance bonus" + "Player gained 1 culture token as advance bonus", + "Player2 gained 1 idea from Philosophy" ], [ "Player2 paid 2 gold to get the Astronomy advance", - "Player gained 1 culture token as advance bonus" + "Player gained 1 culture token as advance bonus", + "Player2 gained 1 idea from Philosophy" ] ], "undo_limit": 0, @@ -367,4 +395,4 @@ "Pyramids" ], "wonder_amount_left": 2 -} +} \ No newline at end of file diff --git a/server/tests/test_games/roads_unit_test.json b/server/tests/test_games/advances/roads_unit_test.json similarity index 100% rename from server/tests/test_games/roads_unit_test.json rename to server/tests/test_games/advances/roads_unit_test.json diff --git a/server/tests/test_games/sanitation_and_draft.json b/server/tests/test_games/advances/sanitation_and_draft.json similarity index 100% rename from server/tests/test_games/sanitation_and_draft.json rename to server/tests/test_games/advances/sanitation_and_draft.json diff --git a/server/tests/test_games/sanitation_and_draft.outcome.json b/server/tests/test_games/advances/sanitation_and_draft.outcome.json similarity index 100% rename from server/tests/test_games/sanitation_and_draft.outcome.json rename to server/tests/test_games/advances/sanitation_and_draft.outcome.json diff --git a/server/tests/test_games/taxes.json b/server/tests/test_games/advances/taxes.json similarity index 100% rename from server/tests/test_games/taxes.json rename to server/tests/test_games/advances/taxes.json diff --git a/server/tests/test_games/taxes.outcome.json b/server/tests/test_games/advances/taxes.outcome.json similarity index 100% rename from server/tests/test_games/taxes.outcome.json rename to server/tests/test_games/advances/taxes.outcome.json diff --git a/server/tests/test_games/theaters.json b/server/tests/test_games/advances/theaters.json similarity index 100% rename from server/tests/test_games/theaters.json rename to server/tests/test_games/advances/theaters.json diff --git a/server/tests/test_games/theaters.outcome.json b/server/tests/test_games/advances/theaters.outcome.json similarity index 100% rename from server/tests/test_games/theaters.outcome.json rename to server/tests/test_games/advances/theaters.outcome.json diff --git a/server/tests/test_games/trade_routes.json b/server/tests/test_games/advances/trade_routes.json similarity index 100% rename from server/tests/test_games/trade_routes.json rename to server/tests/test_games/advances/trade_routes.json diff --git a/server/tests/test_games/trade_routes.outcome.json b/server/tests/test_games/advances/trade_routes.outcome.json similarity index 100% rename from server/tests/test_games/trade_routes.outcome.json rename to server/tests/test_games/advances/trade_routes.outcome.json diff --git a/server/tests/test_games/trade_routes_unit_test.json b/server/tests/test_games/advances/trade_routes_unit_test.json similarity index 100% rename from server/tests/test_games/trade_routes_unit_test.json rename to server/tests/test_games/advances/trade_routes_unit_test.json diff --git a/server/tests/test_games/trade_routes_with_currency.json b/server/tests/test_games/advances/trade_routes_with_currency.json similarity index 100% rename from server/tests/test_games/trade_routes_with_currency.json rename to server/tests/test_games/advances/trade_routes_with_currency.json diff --git a/server/tests/test_games/trade_routes_with_currency.outcome.json b/server/tests/test_games/advances/trade_routes_with_currency.outcome.json similarity index 100% rename from server/tests/test_games/trade_routes_with_currency.outcome.json rename to server/tests/test_games/advances/trade_routes_with_currency.outcome.json diff --git a/server/tests/test_games/trade_routes_with_currency.outcome1.json b/server/tests/test_games/advances/trade_routes_with_currency.outcome1.json similarity index 100% rename from server/tests/test_games/trade_routes_with_currency.outcome1.json rename to server/tests/test_games/advances/trade_routes_with_currency.outcome1.json diff --git a/server/tests/test_games/collect.json b/server/tests/test_games/base/collect.json similarity index 100% rename from server/tests/test_games/collect.json rename to server/tests/test_games/base/collect.json diff --git a/server/tests/test_games/collect.outcome.json b/server/tests/test_games/base/collect.outcome.json similarity index 100% rename from server/tests/test_games/collect.outcome.json rename to server/tests/test_games/base/collect.outcome.json diff --git a/server/tests/test_games/construct.json b/server/tests/test_games/base/construct.json similarity index 100% rename from server/tests/test_games/construct.json rename to server/tests/test_games/base/construct.json diff --git a/server/tests/test_games/construct.outcome.json b/server/tests/test_games/base/construct.outcome.json similarity index 100% rename from server/tests/test_games/construct.outcome.json rename to server/tests/test_games/base/construct.outcome.json diff --git a/server/tests/test_games/construct_port.json b/server/tests/test_games/base/construct_port.json similarity index 100% rename from server/tests/test_games/construct_port.json rename to server/tests/test_games/base/construct_port.json diff --git a/server/tests/test_games/construct_port.outcome.json b/server/tests/test_games/base/construct_port.outcome.json similarity index 100% rename from server/tests/test_games/construct_port.outcome.json rename to server/tests/test_games/base/construct_port.outcome.json diff --git a/server/tests/test_games/cultural_influence.json b/server/tests/test_games/base/cultural_influence.json similarity index 100% rename from server/tests/test_games/cultural_influence.json rename to server/tests/test_games/base/cultural_influence.json diff --git a/server/tests/test_games/cultural_influence.outcome.json b/server/tests/test_games/base/cultural_influence.outcome.json similarity index 100% rename from server/tests/test_games/cultural_influence.outcome.json rename to server/tests/test_games/base/cultural_influence.outcome.json diff --git a/server/tests/test_games/cultural_influence.outcome1.json b/server/tests/test_games/base/cultural_influence.outcome1.json similarity index 100% rename from server/tests/test_games/cultural_influence.outcome1.json rename to server/tests/test_games/base/cultural_influence.outcome1.json diff --git a/server/tests/test_games/cultural_influence_instant.json b/server/tests/test_games/base/cultural_influence_instant.json similarity index 100% rename from server/tests/test_games/cultural_influence_instant.json rename to server/tests/test_games/base/cultural_influence_instant.json diff --git a/server/tests/test_games/cultural_influence_instant.outcome.json b/server/tests/test_games/base/cultural_influence_instant.outcome.json similarity index 100% rename from server/tests/test_games/cultural_influence_instant.outcome.json rename to server/tests/test_games/base/cultural_influence_instant.outcome.json diff --git a/server/tests/test_games/found_city.json b/server/tests/test_games/base/found_city.json similarity index 100% rename from server/tests/test_games/found_city.json rename to server/tests/test_games/base/found_city.json diff --git a/server/tests/test_games/found_city.outcome.json b/server/tests/test_games/base/found_city.outcome.json similarity index 100% rename from server/tests/test_games/found_city.outcome.json rename to server/tests/test_games/base/found_city.outcome.json diff --git a/server/tests/test_games/increase_happiness.json b/server/tests/test_games/base/increase_happiness.json similarity index 100% rename from server/tests/test_games/increase_happiness.json rename to server/tests/test_games/base/increase_happiness.json diff --git a/server/tests/test_games/increase_happiness.outcome.json b/server/tests/test_games/base/increase_happiness.outcome.json similarity index 100% rename from server/tests/test_games/increase_happiness.outcome.json rename to server/tests/test_games/base/increase_happiness.outcome.json diff --git a/server/tests/test_games/recruit.json b/server/tests/test_games/base/recruit.json similarity index 100% rename from server/tests/test_games/recruit.json rename to server/tests/test_games/base/recruit.json diff --git a/server/tests/test_games/recruit.outcome.json b/server/tests/test_games/base/recruit.outcome.json similarity index 100% rename from server/tests/test_games/recruit.outcome.json rename to server/tests/test_games/base/recruit.outcome.json diff --git a/server/tests/test_games/recruit_leader.json b/server/tests/test_games/base/recruit_leader.json similarity index 100% rename from server/tests/test_games/recruit_leader.json rename to server/tests/test_games/base/recruit_leader.json diff --git a/server/tests/test_games/recruit_leader.outcome.json b/server/tests/test_games/base/recruit_leader.outcome.json similarity index 100% rename from server/tests/test_games/recruit_leader.outcome.json rename to server/tests/test_games/base/recruit_leader.outcome.json diff --git a/server/tests/test_games/replace_leader.json b/server/tests/test_games/base/replace_leader.json similarity index 100% rename from server/tests/test_games/replace_leader.json rename to server/tests/test_games/base/replace_leader.json diff --git a/server/tests/test_games/replace_leader.outcome.json b/server/tests/test_games/base/replace_leader.outcome.json similarity index 100% rename from server/tests/test_games/replace_leader.outcome.json rename to server/tests/test_games/base/replace_leader.outcome.json diff --git a/server/tests/test_games/wonder.json b/server/tests/test_games/base/wonder.json similarity index 100% rename from server/tests/test_games/wonder.json rename to server/tests/test_games/base/wonder.json diff --git a/server/tests/test_games/wonder.outcome.json b/server/tests/test_games/base/wonder.outcome.json similarity index 100% rename from server/tests/test_games/wonder.outcome.json rename to server/tests/test_games/base/wonder.outcome.json diff --git a/server/tests/test_games/civ_maya_leader_pakal.json b/server/tests/test_games/civ/civ_maya_leader_pakal.json similarity index 100% rename from server/tests/test_games/civ_maya_leader_pakal.json rename to server/tests/test_games/civ/civ_maya_leader_pakal.json diff --git a/server/tests/test_games/civ_maya_leader_pakal.outcome.json b/server/tests/test_games/civ/civ_maya_leader_pakal.outcome.json similarity index 100% rename from server/tests/test_games/civ_maya_leader_pakal.outcome.json rename to server/tests/test_games/civ/civ_maya_leader_pakal.outcome.json diff --git a/server/tests/test_games/civ_maya_leader_pakal.outcome1.json b/server/tests/test_games/civ/civ_maya_leader_pakal.outcome1.json similarity index 100% rename from server/tests/test_games/civ_maya_leader_pakal.outcome1.json rename to server/tests/test_games/civ/civ_maya_leader_pakal.outcome1.json diff --git a/server/tests/test_games/combat_all_modifiers.json b/server/tests/test_games/combat/combat_all_modifiers.json similarity index 100% rename from server/tests/test_games/combat_all_modifiers.json rename to server/tests/test_games/combat/combat_all_modifiers.json diff --git a/server/tests/test_games/combat_all_modifiers.outcome.json b/server/tests/test_games/combat/combat_all_modifiers.outcome.json similarity index 100% rename from server/tests/test_games/combat_all_modifiers.outcome.json rename to server/tests/test_games/combat/combat_all_modifiers.outcome.json diff --git a/server/tests/test_games/combat_all_modifiers.outcome1.json b/server/tests/test_games/combat/combat_all_modifiers.outcome1.json similarity index 100% rename from server/tests/test_games/combat_all_modifiers.outcome1.json rename to server/tests/test_games/combat/combat_all_modifiers.outcome1.json diff --git a/server/tests/test_games/combat_all_modifiers.outcome2.json b/server/tests/test_games/combat/combat_all_modifiers.outcome2.json similarity index 100% rename from server/tests/test_games/combat_all_modifiers.outcome2.json rename to server/tests/test_games/combat/combat_all_modifiers.outcome2.json diff --git a/server/tests/test_games/combat_all_modifiers.outcome3.json b/server/tests/test_games/combat/combat_all_modifiers.outcome3.json similarity index 100% rename from server/tests/test_games/combat_all_modifiers.outcome3.json rename to server/tests/test_games/combat/combat_all_modifiers.outcome3.json diff --git a/server/tests/test_games/combat_fanaticism.json b/server/tests/test_games/combat/combat_fanaticism.json similarity index 100% rename from server/tests/test_games/combat_fanaticism.json rename to server/tests/test_games/combat/combat_fanaticism.json diff --git a/server/tests/test_games/combat_fanaticism.outcome.json b/server/tests/test_games/combat/combat_fanaticism.outcome.json similarity index 100% rename from server/tests/test_games/combat_fanaticism.outcome.json rename to server/tests/test_games/combat/combat_fanaticism.outcome.json diff --git a/server/tests/test_games/direct_capture_city_fortress.json b/server/tests/test_games/combat/direct_capture_city_fortress.json similarity index 100% rename from server/tests/test_games/direct_capture_city_fortress.json rename to server/tests/test_games/combat/direct_capture_city_fortress.json diff --git a/server/tests/test_games/direct_capture_city_fortress.outcome.json b/server/tests/test_games/combat/direct_capture_city_fortress.outcome.json similarity index 100% rename from server/tests/test_games/direct_capture_city_fortress.outcome.json rename to server/tests/test_games/combat/direct_capture_city_fortress.outcome.json diff --git a/server/tests/test_games/direct_capture_city_metallurgy.json b/server/tests/test_games/combat/direct_capture_city_metallurgy.json similarity index 100% rename from server/tests/test_games/direct_capture_city_metallurgy.json rename to server/tests/test_games/combat/direct_capture_city_metallurgy.json diff --git a/server/tests/test_games/direct_capture_city_metallurgy.outcome.json b/server/tests/test_games/combat/direct_capture_city_metallurgy.outcome.json similarity index 100% rename from server/tests/test_games/direct_capture_city_metallurgy.outcome.json rename to server/tests/test_games/combat/direct_capture_city_metallurgy.outcome.json diff --git a/server/tests/test_games/direct_capture_city_only_fortress.json b/server/tests/test_games/combat/direct_capture_city_only_fortress.json similarity index 100% rename from server/tests/test_games/direct_capture_city_only_fortress.json rename to server/tests/test_games/combat/direct_capture_city_only_fortress.json diff --git a/server/tests/test_games/direct_capture_city_only_fortress.outcome.json b/server/tests/test_games/combat/direct_capture_city_only_fortress.outcome.json similarity index 100% rename from server/tests/test_games/direct_capture_city_only_fortress.outcome.json rename to server/tests/test_games/combat/direct_capture_city_only_fortress.outcome.json diff --git a/server/tests/test_games/recruit_combat.json b/server/tests/test_games/combat/recruit_combat.json similarity index 100% rename from server/tests/test_games/recruit_combat.json rename to server/tests/test_games/combat/recruit_combat.json diff --git a/server/tests/test_games/recruit_combat.outcome.json b/server/tests/test_games/combat/recruit_combat.outcome.json similarity index 100% rename from server/tests/test_games/recruit_combat.outcome.json rename to server/tests/test_games/combat/recruit_combat.outcome.json diff --git a/server/tests/test_games/recruit_combat.outcome1.json b/server/tests/test_games/combat/recruit_combat.outcome1.json similarity index 100% rename from server/tests/test_games/recruit_combat.outcome1.json rename to server/tests/test_games/combat/recruit_combat.outcome1.json diff --git a/server/tests/test_games/recruit_combat.outcome2.json b/server/tests/test_games/combat/recruit_combat.outcome2.json similarity index 100% rename from server/tests/test_games/recruit_combat.outcome2.json rename to server/tests/test_games/combat/recruit_combat.outcome2.json diff --git a/server/tests/test_games/recruit_combat.outcome3.json b/server/tests/test_games/combat/recruit_combat.outcome3.json similarity index 100% rename from server/tests/test_games/recruit_combat.outcome3.json rename to server/tests/test_games/combat/recruit_combat.outcome3.json diff --git a/server/tests/test_games/remove_casualties_attacker.json b/server/tests/test_games/combat/remove_casualties_attacker.json similarity index 100% rename from server/tests/test_games/remove_casualties_attacker.json rename to server/tests/test_games/combat/remove_casualties_attacker.json diff --git a/server/tests/test_games/remove_casualties_attacker.outcome.json b/server/tests/test_games/combat/remove_casualties_attacker.outcome.json similarity index 98% rename from server/tests/test_games/remove_casualties_attacker.outcome.json rename to server/tests/test_games/combat/remove_casualties_attacker.outcome.json index 62b4c610..71ae7af8 100644 --- a/server/tests/test_games/remove_casualties_attacker.outcome.json +++ b/server/tests/test_games/combat/remove_casualties_attacker.outcome.json @@ -39,7 +39,8 @@ "defender_casualties": { "fighters": 2 }, - "can_retreat": false + "can_retreat": false, + "final_result": "AttackerWins" } }, "player": 0, diff --git a/server/tests/test_games/remove_casualties_attacker.outcome1.json b/server/tests/test_games/combat/remove_casualties_attacker.outcome1.json similarity index 100% rename from server/tests/test_games/remove_casualties_attacker.outcome1.json rename to server/tests/test_games/combat/remove_casualties_attacker.outcome1.json diff --git a/server/tests/test_games/remove_casualties_defender.json b/server/tests/test_games/combat/remove_casualties_defender.json similarity index 100% rename from server/tests/test_games/remove_casualties_defender.json rename to server/tests/test_games/combat/remove_casualties_defender.json diff --git a/server/tests/test_games/remove_casualties_defender.outcome.json b/server/tests/test_games/combat/remove_casualties_defender.outcome.json similarity index 100% rename from server/tests/test_games/remove_casualties_defender.outcome.json rename to server/tests/test_games/combat/remove_casualties_defender.outcome.json diff --git a/server/tests/test_games/retreat.json b/server/tests/test_games/combat/retreat.json similarity index 100% rename from server/tests/test_games/retreat.json rename to server/tests/test_games/combat/retreat.json diff --git a/server/tests/test_games/retreat.outcome.json b/server/tests/test_games/combat/retreat.outcome.json similarity index 100% rename from server/tests/test_games/retreat.outcome.json rename to server/tests/test_games/combat/retreat.outcome.json diff --git a/server/tests/test_games/retreat.outcome1.json b/server/tests/test_games/combat/retreat.outcome1.json similarity index 100% rename from server/tests/test_games/retreat.outcome1.json rename to server/tests/test_games/combat/retreat.outcome1.json diff --git a/server/tests/test_games/retreat_no.json b/server/tests/test_games/combat/retreat_no.json similarity index 100% rename from server/tests/test_games/retreat_no.json rename to server/tests/test_games/combat/retreat_no.json diff --git a/server/tests/test_games/retreat_no.outcome.json b/server/tests/test_games/combat/retreat_no.outcome.json similarity index 100% rename from server/tests/test_games/retreat_no.outcome.json rename to server/tests/test_games/combat/retreat_no.outcome.json diff --git a/server/tests/test_games/retreat_no.outcome1.json b/server/tests/test_games/combat/retreat_no.outcome1.json similarity index 100% rename from server/tests/test_games/retreat_no.outcome1.json rename to server/tests/test_games/combat/retreat_no.outcome1.json diff --git a/server/tests/test_games/ship_combat.json b/server/tests/test_games/combat/ship_combat.json similarity index 100% rename from server/tests/test_games/ship_combat.json rename to server/tests/test_games/combat/ship_combat.json diff --git a/server/tests/test_games/ship_combat.outcome.json b/server/tests/test_games/combat/ship_combat.outcome.json similarity index 99% rename from server/tests/test_games/ship_combat.outcome.json rename to server/tests/test_games/combat/ship_combat.outcome.json index b9ddc9e0..44ea0c76 100644 --- a/server/tests/test_games/ship_combat.outcome.json +++ b/server/tests/test_games/combat/ship_combat.outcome.json @@ -44,7 +44,8 @@ "defender_casualties": { "fighters": 1 }, - "can_retreat": false + "can_retreat": false, + "final_result": "AttackerWins" } }, "player": 0, diff --git a/server/tests/test_games/ship_combat.outcome1.json b/server/tests/test_games/combat/ship_combat.outcome1.json similarity index 100% rename from server/tests/test_games/ship_combat.outcome1.json rename to server/tests/test_games/combat/ship_combat.outcome1.json diff --git a/server/tests/test_games/ship_combat_war_ships.json b/server/tests/test_games/combat/ship_combat_war_ships.json similarity index 100% rename from server/tests/test_games/ship_combat_war_ships.json rename to server/tests/test_games/combat/ship_combat_war_ships.json diff --git a/server/tests/test_games/ship_combat_war_ships.outcome.json b/server/tests/test_games/combat/ship_combat_war_ships.outcome.json similarity index 100% rename from server/tests/test_games/ship_combat_war_ships.outcome.json rename to server/tests/test_games/combat/ship_combat_war_ships.outcome.json diff --git a/server/tests/test_games/incidents/anarchy.json b/server/tests/test_games/incidents/anarchy.json new file mode 100644 index 00000000..0fa6f803 --- /dev/null +++ b/server/tests/test_games/incidents/anarchy.json @@ -0,0 +1,260 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "State Religion", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 1, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Pirates", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [], + "action_log_index": 0, + "log": [], + "undo_limit": 0, + "actions_left": 3, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "incidents_left": [ + 44 + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/anarchy.outcome.json b/server/tests/test_games/incidents/anarchy.outcome.json new file mode 100644 index 00000000..65c562c7 --- /dev/null +++ b/server/tests/test_games/incidents/anarchy.outcome.json @@ -0,0 +1,287 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 5, + "mood_tokens": 8, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "State Religion", + "Storage", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 1.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Pirates", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + } + ], + "action_log_index": 1, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Anarchy", + "Player1 lost 1 government advances due to Anarchy - adding 1 victory points" + ] + ], + "undo_limit": 1, + "actions_left": 2, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "permanent_incident_effects": [ + { + "Anarchy": { + "player": 0, + "advances_lost": 1 + } + } + ] +} diff --git a/server/tests/test_games/incidents/anarchy.outcome1.json b/server/tests/test_games/incidents/anarchy.outcome1.json new file mode 100644 index 00000000..4f4dc268 --- /dev/null +++ b/server/tests/test_games/incidents/anarchy.outcome1.json @@ -0,0 +1,308 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 2, + "gold": 3, + "mood_tokens": 8, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 2, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Dogma", + "Farming", + "Mining", + "State Religion", + "Storage", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Pirates", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Playing": { + "Advance": { + "advance": "Dogma", + "payment": { + "gold": 2 + } + } + } + }, + "undo": [ + { + "WastedResources": { + "resources": { + "ideas": 1 + }, + "player_index": 0 + } + } + ] + } + ], + "action_log_index": 2, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Anarchy", + "Player1 lost 1 government advances due to Anarchy - adding 1 victory points" + ], + [ + "Player1 paid 2 gold to get the Dogma advance", + "Player1 is now limited to a maximum of 2 ideas for Dogma Advance", + "Player1 gained a government advance, taking a game event token instead of triggering a game event (and losing 1 victory point)", + "Player1 could not store 1 idea" + ] + ], + "undo_limit": 2, + "actions_left": 1, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1 +} \ No newline at end of file diff --git a/server/tests/test_games/barbarians_attack.json b/server/tests/test_games/incidents/barbarians_attack.json similarity index 100% rename from server/tests/test_games/barbarians_attack.json rename to server/tests/test_games/incidents/barbarians_attack.json diff --git a/server/tests/test_games/barbarians_attack.outcome.json b/server/tests/test_games/incidents/barbarians_attack.outcome.json similarity index 99% rename from server/tests/test_games/barbarians_attack.outcome.json rename to server/tests/test_games/incidents/barbarians_attack.outcome.json index de8b6835..a4938856 100644 --- a/server/tests/test_games/barbarians_attack.outcome.json +++ b/server/tests/test_games/incidents/barbarians_attack.outcome.json @@ -344,4 +344,4 @@ "incidents_left": [ 28 ] -} +} \ No newline at end of file diff --git a/server/tests/test_games/barbarians_move.json b/server/tests/test_games/incidents/barbarians_move.json similarity index 100% rename from server/tests/test_games/barbarians_move.json rename to server/tests/test_games/incidents/barbarians_move.json diff --git a/server/tests/test_games/barbarians_move.outcome.json b/server/tests/test_games/incidents/barbarians_move.outcome.json similarity index 100% rename from server/tests/test_games/barbarians_move.outcome.json rename to server/tests/test_games/incidents/barbarians_move.outcome.json diff --git a/server/tests/test_games/barbarians_move.outcome1.json b/server/tests/test_games/incidents/barbarians_move.outcome1.json similarity index 99% rename from server/tests/test_games/barbarians_move.outcome1.json rename to server/tests/test_games/incidents/barbarians_move.outcome1.json index c423d39d..4c8e2136 100644 --- a/server/tests/test_games/barbarians_move.outcome1.json +++ b/server/tests/test_games/incidents/barbarians_move.outcome1.json @@ -351,4 +351,4 @@ "incidents_left": [ 28 ] -} +} \ No newline at end of file diff --git a/server/tests/test_games/barbarians_recapture_city.json b/server/tests/test_games/incidents/barbarians_recapture_city.json similarity index 100% rename from server/tests/test_games/barbarians_recapture_city.json rename to server/tests/test_games/incidents/barbarians_recapture_city.json diff --git a/server/tests/test_games/barbarians_recapture_city.outcome.json b/server/tests/test_games/incidents/barbarians_recapture_city.outcome.json similarity index 100% rename from server/tests/test_games/barbarians_recapture_city.outcome.json rename to server/tests/test_games/incidents/barbarians_recapture_city.outcome.json diff --git a/server/tests/test_games/barbarians_spawn.json b/server/tests/test_games/incidents/barbarians_spawn.json similarity index 100% rename from server/tests/test_games/barbarians_spawn.json rename to server/tests/test_games/incidents/barbarians_spawn.json diff --git a/server/tests/test_games/barbarians_spawn.outcome.json b/server/tests/test_games/incidents/barbarians_spawn.outcome.json similarity index 100% rename from server/tests/test_games/barbarians_spawn.outcome.json rename to server/tests/test_games/incidents/barbarians_spawn.outcome.json diff --git a/server/tests/test_games/barbarians_spawn.outcome1.json b/server/tests/test_games/incidents/barbarians_spawn.outcome1.json similarity index 100% rename from server/tests/test_games/barbarians_spawn.outcome1.json rename to server/tests/test_games/incidents/barbarians_spawn.outcome1.json diff --git a/server/tests/test_games/barbarians_spawn.outcome2.json b/server/tests/test_games/incidents/barbarians_spawn.outcome2.json similarity index 100% rename from server/tests/test_games/barbarians_spawn.outcome2.json rename to server/tests/test_games/incidents/barbarians_spawn.outcome2.json diff --git a/server/tests/test_games/civil_war.json b/server/tests/test_games/incidents/civil_war.json similarity index 100% rename from server/tests/test_games/civil_war.json rename to server/tests/test_games/incidents/civil_war.json diff --git a/server/tests/test_games/civil_war.outcome.json b/server/tests/test_games/incidents/civil_war.outcome.json similarity index 100% rename from server/tests/test_games/civil_war.outcome.json rename to server/tests/test_games/incidents/civil_war.outcome.json diff --git a/server/tests/test_games/earthquake.json b/server/tests/test_games/incidents/earthquake.json similarity index 100% rename from server/tests/test_games/earthquake.json rename to server/tests/test_games/incidents/earthquake.json diff --git a/server/tests/test_games/earthquake.outcome.json b/server/tests/test_games/incidents/earthquake.outcome.json similarity index 100% rename from server/tests/test_games/earthquake.outcome.json rename to server/tests/test_games/incidents/earthquake.outcome.json diff --git a/server/tests/test_games/earthquake.outcome1.json b/server/tests/test_games/incidents/earthquake.outcome1.json similarity index 100% rename from server/tests/test_games/earthquake.outcome1.json rename to server/tests/test_games/incidents/earthquake.outcome1.json diff --git a/server/tests/test_games/earthquake.outcome2.json b/server/tests/test_games/incidents/earthquake.outcome2.json similarity index 100% rename from server/tests/test_games/earthquake.outcome2.json rename to server/tests/test_games/incidents/earthquake.outcome2.json diff --git a/server/tests/test_games/earthquake.outcome3.json b/server/tests/test_games/incidents/earthquake.outcome3.json similarity index 100% rename from server/tests/test_games/earthquake.outcome3.json rename to server/tests/test_games/incidents/earthquake.outcome3.json diff --git a/server/tests/test_games/incidents/envoy.json b/server/tests/test_games/incidents/envoy.json new file mode 100644 index 00000000..1d65a710 --- /dev/null +++ b/server/tests/test_games/incidents/envoy.json @@ -0,0 +1,295 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 1, + "wood": 6, + "ore": 6, + "ideas": 5, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0, + "temple": 1 + }, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B3" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Arts", + "Farming", + "Mining", + "State Religion", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 1, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A3" + }, + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A4" + } + ], + "units": [], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + "Mountain" + ], + [ + "A4", + "Mountain" + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [], + "action_log_index": 0, + "log": [], + "undo_limit": 0, + "actions_left": 3, + "successful_cultural_influence": false, + "round": 1, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + "dice_roll_log": [ + 10 + ], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "incidents_left": [ + 40 + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/envoy.outcome.json b/server/tests/test_games/incidents/envoy.outcome.json new file mode 100644 index 00000000..a34e8fbb --- /dev/null +++ b/server/tests/test_games/incidents/envoy.outcome.json @@ -0,0 +1,323 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 1, + "wood": 6, + "ore": 6, + "ideas": 6, + "gold": 5, + "mood_tokens": 8, + "culture_tokens": 8 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0, + "temple": 1 + }, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B3" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Arts", + "Farming", + "Mining", + "State Religion", + "Storage", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 8 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A3" + }, + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A4" + } + ], + "units": [], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + "Mountain" + ], + [ + "A4", + "Mountain" + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + } + ], + "action_log_index": 1, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Envoy", + "Base effect: Barbarians move", + "Barbarians cannot move - will try to spawn a new city instead", + "Barbarians cannot spawn a new city", + "Player1 gained 1 idea and 1 culture token", + "Pyramids is now available to be taken by anyone", + "Player2 was selected to gain 1 culture token." + ] + ], + "undo_limit": 1, + "actions_left": 2, + "successful_cultural_influence": false, + "round": 1, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + "dice_roll_log": [ + 10 + ], + "dropped_players": [], + "wonders_left": [], + "wonder_amount_left": 0, + "permanent_incident_effects": [ + { + "PublicWonderCard": "Pyramids" + } + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/envoy.outcome1.json b/server/tests/test_games/incidents/envoy.outcome1.json new file mode 100644 index 00000000..06d07a1e --- /dev/null +++ b/server/tests/test_games/incidents/envoy.outcome1.json @@ -0,0 +1,356 @@ +{ + "state": [ + "Playing" + ], + "current_events": [ + { + "event_type": "DrawWonderCard", + "player": 0, + "last_priority_used": 0, + "handler": { + "priority": 0, + "request": { + "BoolRequest": "Do you want to draw the public wonder card Pyramids?" + }, + "origin": { + "Builtin": "Draw Wonder Card" + } + } + } + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 1, + "wood": 6, + "ore": 6, + "ideas": 6, + "gold": 3, + "mood_tokens": 8, + "culture_tokens": 9 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0, + "temple": 1 + }, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B3" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Arts", + "Farming", + "Mining", + "Monuments", + "State Religion", + "Storage", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 2, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 8 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A3" + }, + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A4" + } + ], + "units": [], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + "Mountain" + ], + [ + "A4", + "Mountain" + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Playing": { + "Advance": { + "advance": "Monuments", + "payment": { + "gold": 2 + } + } + } + } + } + ], + "action_log_index": 2, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Envoy", + "Base effect: Barbarians move", + "Barbarians cannot move - will try to spawn a new city instead", + "Barbarians cannot spawn a new city", + "Player1 gained 1 idea and 1 culture token", + "Pyramids is now available to be taken by anyone", + "Player2 was selected to gain 1 culture token." + ], + [ + "Player1 paid 2 gold to get the Monuments advance", + "Player gained 1 culture token as advance bonus" + ] + ], + "undo_limit": 2, + "actions_left": 1, + "successful_cultural_influence": false, + "round": 1, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + "dice_roll_log": [ + 10 + ], + "dropped_players": [], + "wonders_left": [], + "wonder_amount_left": 0, + "permanent_incident_effects": [ + { + "PublicWonderCard": "Pyramids" + } + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/envoy.outcome2.json b/server/tests/test_games/incidents/envoy.outcome2.json new file mode 100644 index 00000000..7b0c2ea1 --- /dev/null +++ b/server/tests/test_games/incidents/envoy.outcome2.json @@ -0,0 +1,347 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 1, + "wood": 6, + "ore": 6, + "ideas": 6, + "gold": 3, + "mood_tokens": 8, + "culture_tokens": 9 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0, + "temple": 1 + }, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B3" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Arts", + "Farming", + "Mining", + "Monuments", + "State Religion", + "Storage", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 2, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [ + "Pyramids" + ], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 8 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A3" + }, + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A4" + } + ], + "units": [], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + "Mountain" + ], + [ + "A4", + "Mountain" + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Playing": { + "Advance": { + "advance": "Monuments", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Response": { + "Bool": true + } + } + } + ], + "action_log_index": 3, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Envoy", + "Base effect: Barbarians move", + "Barbarians cannot move - will try to spawn a new city instead", + "Barbarians cannot spawn a new city", + "Player1 gained 1 idea and 1 culture token", + "Pyramids is now available to be taken by anyone", + "Player2 was selected to gain 1 culture token." + ], + [ + "Player1 paid 2 gold to get the Monuments advance", + "Player gained 1 culture token as advance bonus" + ], + [ + "Player1 drew the public wonder card Pyramids" + ] + ], + "undo_limit": 3, + "actions_left": 1, + "successful_cultural_influence": false, + "round": 1, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + "dice_roll_log": [ + 10 + ], + "dropped_players": [], + "wonders_left": [], + "wonder_amount_left": 0 +} \ No newline at end of file diff --git a/server/tests/test_games/epidemics.json b/server/tests/test_games/incidents/epidemics.json similarity index 100% rename from server/tests/test_games/epidemics.json rename to server/tests/test_games/incidents/epidemics.json diff --git a/server/tests/test_games/epidemics.outcome.json b/server/tests/test_games/incidents/epidemics.outcome.json similarity index 100% rename from server/tests/test_games/epidemics.outcome.json rename to server/tests/test_games/incidents/epidemics.outcome.json diff --git a/server/tests/test_games/epidemics.outcome1.json b/server/tests/test_games/incidents/epidemics.outcome1.json similarity index 100% rename from server/tests/test_games/epidemics.outcome1.json rename to server/tests/test_games/incidents/epidemics.outcome1.json diff --git a/server/tests/test_games/exhausted_land.json b/server/tests/test_games/incidents/exhausted_land.json similarity index 100% rename from server/tests/test_games/exhausted_land.json rename to server/tests/test_games/incidents/exhausted_land.json diff --git a/server/tests/test_games/exhausted_land.outcome.json b/server/tests/test_games/incidents/exhausted_land.outcome.json similarity index 100% rename from server/tests/test_games/exhausted_land.outcome.json rename to server/tests/test_games/incidents/exhausted_land.outcome.json diff --git a/server/tests/test_games/exhausted_land.outcome1.json b/server/tests/test_games/incidents/exhausted_land.outcome1.json similarity index 100% rename from server/tests/test_games/exhausted_land.outcome1.json rename to server/tests/test_games/incidents/exhausted_land.outcome1.json diff --git a/server/tests/test_games/famine.json b/server/tests/test_games/incidents/famine.json similarity index 100% rename from server/tests/test_games/famine.json rename to server/tests/test_games/incidents/famine.json diff --git a/server/tests/test_games/famine.outcome.json b/server/tests/test_games/incidents/famine.outcome.json similarity index 97% rename from server/tests/test_games/famine.outcome.json rename to server/tests/test_games/incidents/famine.outcome.json index 0fd49e50..641e4200 100644 --- a/server/tests/test_games/famine.outcome.json +++ b/server/tests/test_games/incidents/famine.outcome.json @@ -1,5 +1,7 @@ { - "state": ["Playing"], + "state": [ + "Playing" + ], "players": [ { "name": null, @@ -259,6 +261,8 @@ [ "A new game event has been triggered: Severe famine", "Base effect: Barbarians move", + "Barbarians cannot move - will try to spawn a new city instead", + "Barbarians cannot spawn a new city", "Player1 lost 1 food to Famine", "Player1 made city A1 Angry" ] @@ -290,4 +294,4 @@ "Pyramids" ], "wonder_amount_left": 1 -} +} \ No newline at end of file diff --git a/server/tests/test_games/flood.json b/server/tests/test_games/incidents/flood.json similarity index 100% rename from server/tests/test_games/flood.json rename to server/tests/test_games/incidents/flood.json diff --git a/server/tests/test_games/flood.outcome.json b/server/tests/test_games/incidents/flood.outcome.json similarity index 100% rename from server/tests/test_games/flood.outcome.json rename to server/tests/test_games/incidents/flood.outcome.json diff --git a/server/tests/test_games/flood.outcome1.json b/server/tests/test_games/incidents/flood.outcome1.json similarity index 100% rename from server/tests/test_games/flood.outcome1.json rename to server/tests/test_games/incidents/flood.outcome1.json diff --git a/server/tests/test_games/flood.outcome2.json b/server/tests/test_games/incidents/flood.outcome2.json similarity index 100% rename from server/tests/test_games/flood.outcome2.json rename to server/tests/test_games/incidents/flood.outcome2.json diff --git a/server/tests/test_games/good_year.json b/server/tests/test_games/incidents/good_year.json similarity index 100% rename from server/tests/test_games/good_year.json rename to server/tests/test_games/incidents/good_year.json diff --git a/server/tests/test_games/good_year.outcome.json b/server/tests/test_games/incidents/good_year.outcome.json similarity index 100% rename from server/tests/test_games/good_year.outcome.json rename to server/tests/test_games/incidents/good_year.outcome.json diff --git a/server/tests/test_games/good_year.outcome1.json b/server/tests/test_games/incidents/good_year.outcome1.json similarity index 100% rename from server/tests/test_games/good_year.outcome1.json rename to server/tests/test_games/incidents/good_year.outcome1.json diff --git a/server/tests/test_games/migration.json b/server/tests/test_games/incidents/migration.json similarity index 100% rename from server/tests/test_games/migration.json rename to server/tests/test_games/incidents/migration.json diff --git a/server/tests/test_games/migration.outcome.json b/server/tests/test_games/incidents/migration.outcome.json similarity index 100% rename from server/tests/test_games/migration.outcome.json rename to server/tests/test_games/incidents/migration.outcome.json diff --git a/server/tests/test_games/pestilence.json b/server/tests/test_games/incidents/pestilence.json similarity index 100% rename from server/tests/test_games/pestilence.json rename to server/tests/test_games/incidents/pestilence.json diff --git a/server/tests/test_games/pestilence.outcome.json b/server/tests/test_games/incidents/pestilence.outcome.json similarity index 100% rename from server/tests/test_games/pestilence.outcome.json rename to server/tests/test_games/incidents/pestilence.outcome.json diff --git a/server/tests/test_games/pestilence.outcome1.json b/server/tests/test_games/incidents/pestilence.outcome1.json similarity index 100% rename from server/tests/test_games/pestilence.outcome1.json rename to server/tests/test_games/incidents/pestilence.outcome1.json diff --git a/server/tests/test_games/pestilence.outcome2.json b/server/tests/test_games/incidents/pestilence.outcome2.json similarity index 100% rename from server/tests/test_games/pestilence.outcome2.json rename to server/tests/test_games/incidents/pestilence.outcome2.json diff --git a/server/tests/test_games/pirates_spawn.json b/server/tests/test_games/incidents/pirates_spawn.json similarity index 100% rename from server/tests/test_games/pirates_spawn.json rename to server/tests/test_games/incidents/pirates_spawn.json diff --git a/server/tests/test_games/pirates_spawn.outcome.json b/server/tests/test_games/incidents/pirates_spawn.outcome.json similarity index 100% rename from server/tests/test_games/pirates_spawn.outcome.json rename to server/tests/test_games/incidents/pirates_spawn.outcome.json diff --git a/server/tests/test_games/pirates_spawn.outcome1.json b/server/tests/test_games/incidents/pirates_spawn.outcome1.json similarity index 100% rename from server/tests/test_games/pirates_spawn.outcome1.json rename to server/tests/test_games/incidents/pirates_spawn.outcome1.json diff --git a/server/tests/test_games/pirates_spawn.outcome2.json b/server/tests/test_games/incidents/pirates_spawn.outcome2.json similarity index 100% rename from server/tests/test_games/pirates_spawn.outcome2.json rename to server/tests/test_games/incidents/pirates_spawn.outcome2.json diff --git a/server/tests/test_games/pirates_spawn.outcome3.json b/server/tests/test_games/incidents/pirates_spawn.outcome3.json similarity index 100% rename from server/tests/test_games/pirates_spawn.outcome3.json rename to server/tests/test_games/incidents/pirates_spawn.outcome3.json diff --git a/server/tests/test_games/pirates_spawn.outcome4.json b/server/tests/test_games/incidents/pirates_spawn.outcome4.json similarity index 100% rename from server/tests/test_games/pirates_spawn.outcome4.json rename to server/tests/test_games/incidents/pirates_spawn.outcome4.json diff --git a/server/tests/test_games/revolution.json b/server/tests/test_games/incidents/revolution.json similarity index 100% rename from server/tests/test_games/revolution.json rename to server/tests/test_games/incidents/revolution.json diff --git a/server/tests/test_games/revolution.outcome.json b/server/tests/test_games/incidents/revolution.outcome.json similarity index 100% rename from server/tests/test_games/revolution.outcome.json rename to server/tests/test_games/incidents/revolution.outcome.json diff --git a/server/tests/test_games/revolution.outcome1.json b/server/tests/test_games/incidents/revolution.outcome1.json similarity index 100% rename from server/tests/test_games/revolution.outcome1.json rename to server/tests/test_games/incidents/revolution.outcome1.json diff --git a/server/tests/test_games/revolution.outcome2.json b/server/tests/test_games/incidents/revolution.outcome2.json similarity index 100% rename from server/tests/test_games/revolution.outcome2.json rename to server/tests/test_games/incidents/revolution.outcome2.json diff --git a/server/tests/test_games/revolution.outcome3.json b/server/tests/test_games/incidents/revolution.outcome3.json similarity index 100% rename from server/tests/test_games/revolution.outcome3.json rename to server/tests/test_games/incidents/revolution.outcome3.json diff --git a/server/tests/test_games/incidents/solar_eclipse.json b/server/tests/test_games/incidents/solar_eclipse.json new file mode 100644 index 00000000..28336d39 --- /dev/null +++ b/server/tests/test_games/incidents/solar_eclipse.json @@ -0,0 +1,258 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 1, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Pirates", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [], + "action_log_index": 0, + "log": [], + "undo_limit": 0, + "actions_left": 3, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "incidents_left": [ + 41 + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/solar_eclipse.outcome.json b/server/tests/test_games/incidents/solar_eclipse.outcome.json new file mode 100644 index 00000000..f1c2f219 --- /dev/null +++ b/server/tests/test_games/incidents/solar_eclipse.outcome.json @@ -0,0 +1,282 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 5, + "mood_tokens": 8, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "Storage", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Pirates", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + } + ], + "action_log_index": 1, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Solar Eclipse", + "Base effect: Pirates spawn", + "No valid positions for Pirate Ship" + ] + ], + "undo_limit": 1, + "actions_left": 2, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "permanent_incident_effects": [ + "SolarEclipse" + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/solar_eclipse.outcome1.json b/server/tests/test_games/incidents/solar_eclipse.outcome1.json new file mode 100644 index 00000000..eb67ce46 --- /dev/null +++ b/server/tests/test_games/incidents/solar_eclipse.outcome1.json @@ -0,0 +1,337 @@ +{ + "state": [ + "Playing", + { + "Movement": { + "movement_actions_left": 2, + "moved_units": [ + 0, + 1, + 2, + 3, + 4, + 5 + ] + } + } + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 6, + "mood_tokens": 8, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": { + "temple": 0 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 0 + }, + { + "position": "C1", + "unit_type": "Cavalry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C1", + "unit_type": "Leader", + "movement_restrictions": [ + "Battle" + ], + "id": 2 + }, + { + "position": "C1", + "unit_type": "Elephant", + "movement_restrictions": [ + "Battle" + ], + "id": 3 + }, + { + "position": "C1", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C1", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "Storage", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 1.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 3 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 4 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Pirates", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Movement": { + "Move": { + "units": [ + 0, + 1, + 2, + 3, + 4, + 5 + ], + "destination": "C1" + } + } + } + } + ], + "action_log_index": 2, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Solar Eclipse", + "Base effect: Pirates spawn", + "No valid positions for Pirate Ship" + ], + [ + "Player1 marched 2 settlers, 1 infantry, 1 cavalry, 1 elephant and a leader from C2 to C1" + ], + [ + "Combat round 1", + "Player1 rolled 6 (Infantry, +1 combat value), 6 (Infantry, no bonus), 6 (Infantry, no bonus), 6 (Infantry, no bonus) for combined combat value of 25 and gets 2 hits against defending units.", + "Player2 rolled 1 (Leader, no bonus), 1 (Leader, no bonus) for combined combat value of 4 and gets 0 hits against attacking units.", + "Player2 used the following combat modifiers: Player gets +2 combat value for Fanaticism Advance", + "Player1 gained 1 victory point for the Solar Eclipse", + "Player2 has to remove all of their defending units", + "Player2 removed 2 infantry", + "Attacker wins and captured Player2's city at C1", + "Player2 gained 1 free Infantry Unit at C2 for Fanaticism Advance", + "Player2 gained 1 free Settler Unit at C2 for losing a city" + ] + ], + "undo_limit": 2, + "actions_left": 1, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1 + ], + "dice_roll_log": [ + 11, + 11, + 11, + 11, + 1, + 1 + ], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1 +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/trojan_horse.json b/server/tests/test_games/incidents/trojan_horse.json new file mode 100644 index 00000000..2b23ea57 --- /dev/null +++ b/server/tests/test_games/incidents/trojan_horse.json @@ -0,0 +1,270 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 1, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [], + "action_log_index": 0, + "log": [], + "undo_limit": 0, + "actions_left": 3, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "incidents_left": [ + 42 + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/trojan_horse.outcome.json b/server/tests/test_games/incidents/trojan_horse.outcome.json new file mode 100644 index 00000000..7e253822 --- /dev/null +++ b/server/tests/test_games/incidents/trojan_horse.outcome.json @@ -0,0 +1,295 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 5, + "mood_tokens": 8, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "Storage", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + } + ], + "action_log_index": 1, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Trojan Horse", + "Base effect: Barbarians move", + "Barbarians cannot move - will try to spawn a new city instead", + "Barbarians cannot spawn a new city" + ] + ], + "undo_limit": 1, + "actions_left": 2, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "permanent_incident_effects": [ + "TrojanHorse" + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/trojan_horse.outcome1.json b/server/tests/test_games/incidents/trojan_horse.outcome1.json new file mode 100644 index 00000000..cdd61c97 --- /dev/null +++ b/server/tests/test_games/incidents/trojan_horse.outcome1.json @@ -0,0 +1,407 @@ +{ + "state": [ + "Playing", + { + "Movement": { + "movement_actions_left": 2, + "moved_units": [ + 0, + 1, + 2, + 3, + 4, + 5 + ] + } + }, + { + "Combat": { + "round": 1, + "defender": 1, + "defender_position": "C1", + "attacker": 0, + "attacker_position": "C2", + "attackers": [ + 0, + 1, + 2, + 3, + 4, + 5 + ], + "retreat": "CanRetreat" + } + } + ], + "current_events": [ + { + "event_type": "CombatStart", + "player": 0, + "last_priority_used": 10, + "handler": { + "priority": 10, + "request": { + "Payment": [ + { + "cost": { + "default": { + "wood": 1, + "culture_tokens": 1 + }, + "conversions": [ + { + "from": [ + { + "food": 1 + }, + { + "wood": 1 + }, + { + "ore": 1 + }, + { + "ideas": 1 + } + ], + "to": { + "gold": 1 + }, + "type": "Unlimited" + } + ] + }, + "name": "Activate the Trojan Horse?", + "optional": true + } + ] + }, + "origin": { + "Builtin": "Trojan Horse" + } + } + } + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 5, + "mood_tokens": 8, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 0 + }, + { + "position": "C2", + "unit_type": "Cavalry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Leader", + "movement_restrictions": [ + "Battle" + ], + "id": 2 + }, + { + "position": "C2", + "unit_type": "Elephant", + "movement_restrictions": [ + "Battle" + ], + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "Storage", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "temple": 1 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C1", + "unit_type": "Infantry", + "id": 1 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Movement": { + "Move": { + "units": [ + 0, + 1, + 2, + 3, + 4, + 5 + ], + "destination": "C1" + } + } + } + } + ], + "action_log_index": 2, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Trojan Horse", + "Base effect: Barbarians move", + "Barbarians cannot move - will try to spawn a new city instead", + "Barbarians cannot spawn a new city" + ], + [ + "Player1 marched 2 settlers, 1 infantry, 1 cavalry, 1 elephant and a leader from C2 to C1" + ] + ], + "undo_limit": 2, + "actions_left": 1, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1, + 1, + 1, + 11, + 11, + 11, + 11 + ], + "dice_roll_log": [], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1, + "permanent_incident_effects": [ + "TrojanHorse" + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/trojan_horse.outcome2.json b/server/tests/test_games/incidents/trojan_horse.outcome2.json new file mode 100644 index 00000000..8d470347 --- /dev/null +++ b/server/tests/test_games/incidents/trojan_horse.outcome2.json @@ -0,0 +1,365 @@ +{ + "state": [ + "Playing", + { + "Movement": { + "movement_actions_left": 2, + "moved_units": [ + 0, + 1, + 2, + 3, + 4, + 5 + ] + } + } + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 3, + "gold": 5, + "mood_tokens": 8, + "culture_tokens": 6 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": { + "temple": 0 + }, + "mood_state": "Angry", + "activations": 0, + "angry_activation": false, + "position": "C1" + } + ], + "units": [ + { + "position": "C1", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 0 + }, + { + "position": "C1", + "unit_type": "Cavalry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C1", + "unit_type": "Leader", + "movement_restrictions": [ + "Battle" + ], + "id": 2 + }, + { + "position": "C1", + "unit_type": "Elephant", + "movement_restrictions": [ + "Battle" + ], + "id": 3 + }, + { + "position": "C1", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C1", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "Storage", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 1.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": {}, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 2 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 3 + } + ], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Fanaticism", + "Farming", + "Mining", + "Tactics" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 4 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + { + "Exhausted": "Forest" + } + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Movement": { + "Move": { + "units": [ + 0, + 1, + 2, + 3, + 4, + 5 + ], + "destination": "C1" + } + } + } + }, + { + "action": { + "Response": { + "Payment": [ + { + "gold": 1, + "culture_tokens": 1 + } + ] + } + } + } + ], + "action_log_index": 3, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Trojan Horse", + "Base effect: Barbarians move", + "Barbarians cannot move - will try to spawn a new city instead", + "Barbarians cannot spawn a new city" + ], + [ + "Player1 marched 2 settlers, 1 infantry, 1 cavalry, 1 elephant and a leader from C2 to C1" + ], + [ + "Player1 activated the Trojan Horse and gained 1 victory point" + ], + [ + "Combat round 1", + "Player1 rolled 6 (Infantry, +1 combat value), 6 (Infantry, no bonus), 6 (Infantry, no bonus), 6 (Infantry, no bonus) for combined combat value of 25 and gets 2 hits against defending units.", + "Player2 rolled 1 (Leader, no bonus), 1 (Leader, no bonus) for combined combat value of 4 and gets 0 hits against attacking units.", + "Player1 used the following combat modifiers: Trojan Horse denies the defender tactics cards in the first round of combat", + "Player2 used the following combat modifiers: Player gets +2 combat value for Fanaticism Advance", + "Player2 has to remove all of their defending units", + "Player2 removed 2 infantry", + "Attacker wins and captured Player2's city at C1", + "Player2 gained 1 free Infantry Unit at C2 for Fanaticism Advance", + "Player2 gained 1 free Settler Unit at C2 for losing a city" + ] + ], + "undo_limit": 3, + "actions_left": 1, + "successful_cultural_influence": false, + "round": 2, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 1 + ], + "dice_roll_log": [ + 11, + 11, + 11, + 11, + 1, + 1 + ], + "dropped_players": [], + "wonders_left": [ + "Pyramids" + ], + "wonder_amount_left": 1 +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/uprising.json b/server/tests/test_games/incidents/uprising.json new file mode 100644 index 00000000..d77f723c --- /dev/null +++ b/server/tests/test_games/incidents/uprising.json @@ -0,0 +1,297 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 1, + "wood": 6, + "ore": 6, + "ideas": 5, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0, + "temple": 1, + "wonders": [ + "Pyramids" + ] + }, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B3" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "State Religion", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [ + "Pyramids" + ], + "incident_tokens": 1, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A3" + }, + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A4" + } + ], + "units": [], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + "Mountain" + ], + [ + "A4", + "Mountain" + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [], + "action_log_index": 0, + "log": [], + "undo_limit": 0, + "actions_left": 3, + "successful_cultural_influence": false, + "round": 1, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + "dice_roll_log": [ + 10 + ], + "dropped_players": [], + "wonders_left": [], + "wonder_amount_left": 1, + "incidents_left": [ + 39 + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/uprising.outcome.json b/server/tests/test_games/incidents/uprising.outcome.json new file mode 100644 index 00000000..51b6c7ee --- /dev/null +++ b/server/tests/test_games/incidents/uprising.outcome.json @@ -0,0 +1,376 @@ +{ + "state": [ + "Playing" + ], + "current_events": [ + { + "event_type": { + "Incident": { + "active_player": 0 + } + }, + "player": 0, + "last_priority_used": 0, + "handler": { + "priority": 0, + "request": { + "Payment": [ + { + "cost": { + "default": { + "mood_tokens": 4 + }, + "conversions": [ + { + "from": [ + { + "mood_tokens": 1 + } + ], + "to": { + "culture_tokens": 1 + }, + "type": "Unlimited" + }, + { + "from": [ + { + "mood_tokens": 1 + }, + { + "culture_tokens": 1 + } + ], + "to": {}, + "type": { + "MayOverpay": 3 + } + } + ] + }, + "name": "Pay 1-4 mood or culture tokens", + "optional": false + } + ] + }, + "origin": { + "Incident": 39 + } + } + } + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 1, + "wood": 6, + "ore": 6, + "ideas": 5, + "gold": 5, + "mood_tokens": 8, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0, + "temple": 1, + "wonders": [ + "Pyramids" + ] + }, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B3" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "State Religion", + "Storage", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [ + "Pyramids" + ], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A3" + }, + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A4" + } + ], + "units": [], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + "Mountain" + ], + [ + "A4", + "Mountain" + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + } + ], + "action_log_index": 1, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Uprising" + ] + ], + "undo_limit": 1, + "actions_left": 2, + "successful_cultural_influence": false, + "round": 1, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + "dice_roll_log": [ + 10 + ], + "dropped_players": [], + "wonders_left": [], + "wonder_amount_left": 1, + "incidents_left": [ + 39 + ] +} \ No newline at end of file diff --git a/server/tests/test_games/incidents/uprising.outcome1.json b/server/tests/test_games/incidents/uprising.outcome1.json new file mode 100644 index 00000000..1306f79a --- /dev/null +++ b/server/tests/test_games/incidents/uprising.outcome1.json @@ -0,0 +1,331 @@ +{ + "state": [ + "Playing" + ], + "players": [ + { + "name": null, + "id": 0, + "resources": { + "food": 1, + "wood": 6, + "ore": 6, + "ideas": 5, + "gold": 5, + "mood_tokens": 7, + "culture_tokens": 6 + }, + "resource_limit": { + "food": 7, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0, + "temple": 1, + "wonders": [ + "Pyramids" + ] + }, + "mood_state": "Neutral", + "activations": 0, + "angry_activation": false, + "position": "C2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "C1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B2" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "B3" + } + ], + "units": [ + { + "position": "C2", + "unit_type": "Infantry", + "id": 0 + }, + { + "position": "C2", + "unit_type": "Infantry", + "movement_restrictions": [ + "Battle" + ], + "id": 1 + }, + { + "position": "C2", + "unit_type": "Elephant", + "id": 3 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 4 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 5 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 6 + }, + { + "position": "C2", + "unit_type": "Settler", + "id": 7 + } + ], + "civilization": "test0", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining", + "State Religion", + "Storage", + "Tactics", + "Voting" + ], + "unlocked_special_advance": [], + "wonders_build": [ + "Pyramids" + ], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 1.0, + "wonder_cards": [], + "next_unit_id": 8 + }, + { + "name": null, + "id": 1, + "resources": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7, + "mood_tokens": 7, + "culture_tokens": 7 + }, + "cities": [ + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A1" + }, + { + "city_pieces": {}, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A3" + }, + { + "city_pieces": { + "fortress": 0 + }, + "mood_state": "Happy", + "activations": 0, + "angry_activation": false, + "position": "A4" + } + ], + "units": [], + "civilization": "test1", + "active_leader": null, + "available_leaders": [], + "advances": [ + "Farming", + "Mining" + ], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 2 + }, + { + "name": null, + "id": 2, + "resources": {}, + "resource_limit": { + "food": 2, + "wood": 7, + "ore": 7, + "ideas": 7, + "gold": 7 + }, + "cities": [], + "units": [], + "civilization": "Barbarians", + "active_leader": null, + "available_leaders": [], + "advances": [], + "unlocked_special_advance": [], + "wonders_build": [], + "incident_tokens": 3, + "completed_objectives": [], + "captured_leaders": [], + "event_victory_points": 0.0, + "wonder_cards": [], + "next_unit_id": 0 + } + ], + "map": { + "tiles": [ + [ + "A1", + "Fertile" + ], + [ + "A2", + "Water" + ], + [ + "A3", + "Mountain" + ], + [ + "A4", + "Mountain" + ], + [ + "B1", + "Mountain" + ], + [ + "B2", + "Forest" + ], + [ + "B3", + "Fertile" + ], + [ + "C1", + "Barren" + ], + [ + "C2", + "Forest" + ], + [ + "C3", + "Water" + ], + [ + "D2", + "Water" + ] + ] + }, + "starting_player_index": 0, + "current_player_index": 0, + "action_log": [ + { + "action": { + "Playing": { + "Advance": { + "advance": "Storage", + "payment": { + "gold": 2 + } + } + } + } + }, + { + "action": { + "Response": { + "Payment": [ + { + "mood_tokens": 1, + "culture_tokens": 1 + } + ] + } + } + } + ], + "action_log_index": 2, + "log": [ + [ + "Player1 paid 2 gold to get the Storage advance", + "Player gained 1 mood token as advance bonus" + ], + [ + "A new game event has been triggered: Uprising" + ], + [ + "Player1 paid 1 mood token and 1 culture token to gain 1 victory point" + ] + ], + "undo_limit": 2, + "actions_left": 2, + "successful_cultural_influence": false, + "round": 1, + "age": 1, + "messages": [ + "The game has started" + ], + "dice_roll_outcomes": [ + 1, + 1, + 10, + 10, + 10, + 10, + 10, + 10, + 10 + ], + "dice_roll_log": [ + 10 + ], + "dropped_players": [], + "wonders_left": [], + "wonder_amount_left": 1 +} \ No newline at end of file diff --git a/server/tests/test_games/volcano.json b/server/tests/test_games/incidents/volcano.json similarity index 100% rename from server/tests/test_games/volcano.json rename to server/tests/test_games/incidents/volcano.json diff --git a/server/tests/test_games/volcano.outcome.json b/server/tests/test_games/incidents/volcano.outcome.json similarity index 100% rename from server/tests/test_games/volcano.outcome.json rename to server/tests/test_games/incidents/volcano.outcome.json diff --git a/server/tests/test_games/volcano.outcome1.json b/server/tests/test_games/incidents/volcano.outcome1.json similarity index 100% rename from server/tests/test_games/volcano.outcome1.json rename to server/tests/test_games/incidents/volcano.outcome1.json diff --git a/server/tests/test_games/explore_auto_adjacent_water.json b/server/tests/test_games/movement/explore_auto_adjacent_water.json similarity index 100% rename from server/tests/test_games/explore_auto_adjacent_water.json rename to server/tests/test_games/movement/explore_auto_adjacent_water.json diff --git a/server/tests/test_games/explore_auto_adjacent_water.outcome.json b/server/tests/test_games/movement/explore_auto_adjacent_water.outcome.json similarity index 100% rename from server/tests/test_games/explore_auto_adjacent_water.outcome.json rename to server/tests/test_games/movement/explore_auto_adjacent_water.outcome.json diff --git a/server/tests/test_games/explore_auto_no_walk_on_water.json b/server/tests/test_games/movement/explore_auto_no_walk_on_water.json similarity index 100% rename from server/tests/test_games/explore_auto_no_walk_on_water.json rename to server/tests/test_games/movement/explore_auto_no_walk_on_water.json diff --git a/server/tests/test_games/explore_auto_no_walk_on_water.outcome.json b/server/tests/test_games/movement/explore_auto_no_walk_on_water.outcome.json similarity index 100% rename from server/tests/test_games/explore_auto_no_walk_on_water.outcome.json rename to server/tests/test_games/movement/explore_auto_no_walk_on_water.outcome.json diff --git a/server/tests/test_games/explore_auto_water_outside.json b/server/tests/test_games/movement/explore_auto_water_outside.json similarity index 100% rename from server/tests/test_games/explore_auto_water_outside.json rename to server/tests/test_games/movement/explore_auto_water_outside.json diff --git a/server/tests/test_games/explore_auto_water_outside.outcome.json b/server/tests/test_games/movement/explore_auto_water_outside.outcome.json similarity index 100% rename from server/tests/test_games/explore_auto_water_outside.outcome.json rename to server/tests/test_games/movement/explore_auto_water_outside.outcome.json diff --git a/server/tests/test_games/explore_choose.json b/server/tests/test_games/movement/explore_choose.json similarity index 100% rename from server/tests/test_games/explore_choose.json rename to server/tests/test_games/movement/explore_choose.json diff --git a/server/tests/test_games/explore_choose.outcome.json b/server/tests/test_games/movement/explore_choose.outcome.json similarity index 100% rename from server/tests/test_games/explore_choose.outcome.json rename to server/tests/test_games/movement/explore_choose.outcome.json diff --git a/server/tests/test_games/explore_resolution.json b/server/tests/test_games/movement/explore_resolution.json similarity index 100% rename from server/tests/test_games/explore_resolution.json rename to server/tests/test_games/movement/explore_resolution.json diff --git a/server/tests/test_games/explore_resolution.outcome.json b/server/tests/test_games/movement/explore_resolution.outcome.json similarity index 100% rename from server/tests/test_games/explore_resolution.outcome.json rename to server/tests/test_games/movement/explore_resolution.outcome.json diff --git a/server/tests/test_games/explore_resolution.outcome1.json b/server/tests/test_games/movement/explore_resolution.outcome1.json similarity index 100% rename from server/tests/test_games/explore_resolution.outcome1.json rename to server/tests/test_games/movement/explore_resolution.outcome1.json diff --git a/server/tests/test_games/movement.json b/server/tests/test_games/movement/movement.json similarity index 100% rename from server/tests/test_games/movement.json rename to server/tests/test_games/movement/movement.json diff --git a/server/tests/test_games/movement.outcome.json b/server/tests/test_games/movement/movement.outcome.json similarity index 100% rename from server/tests/test_games/movement.outcome.json rename to server/tests/test_games/movement/movement.outcome.json diff --git a/server/tests/test_games/ship_disembark.json b/server/tests/test_games/movement/ship_disembark.json similarity index 100% rename from server/tests/test_games/ship_disembark.json rename to server/tests/test_games/movement/ship_disembark.json diff --git a/server/tests/test_games/ship_disembark.outcome.json b/server/tests/test_games/movement/ship_disembark.outcome.json similarity index 100% rename from server/tests/test_games/ship_disembark.outcome.json rename to server/tests/test_games/movement/ship_disembark.outcome.json diff --git a/server/tests/test_games/ship_disembark_capture_empty_city.json b/server/tests/test_games/movement/ship_disembark_capture_empty_city.json similarity index 100% rename from server/tests/test_games/ship_disembark_capture_empty_city.json rename to server/tests/test_games/movement/ship_disembark_capture_empty_city.json diff --git a/server/tests/test_games/ship_disembark_capture_empty_city.outcome.json b/server/tests/test_games/movement/ship_disembark_capture_empty_city.outcome.json similarity index 100% rename from server/tests/test_games/ship_disembark_capture_empty_city.outcome.json rename to server/tests/test_games/movement/ship_disembark_capture_empty_city.outcome.json diff --git a/server/tests/test_games/ship_embark.json b/server/tests/test_games/movement/ship_embark.json similarity index 100% rename from server/tests/test_games/ship_embark.json rename to server/tests/test_games/movement/ship_embark.json diff --git a/server/tests/test_games/ship_embark.outcome.json b/server/tests/test_games/movement/ship_embark.outcome.json similarity index 100% rename from server/tests/test_games/ship_embark.outcome.json rename to server/tests/test_games/movement/ship_embark.outcome.json diff --git a/server/tests/test_games/ship_embark_continue.json b/server/tests/test_games/movement/ship_embark_continue.json similarity index 100% rename from server/tests/test_games/ship_embark_continue.json rename to server/tests/test_games/movement/ship_embark_continue.json diff --git a/server/tests/test_games/ship_embark_continue.outcome.json b/server/tests/test_games/movement/ship_embark_continue.outcome.json similarity index 100% rename from server/tests/test_games/ship_embark_continue.outcome.json rename to server/tests/test_games/movement/ship_embark_continue.outcome.json diff --git a/server/tests/test_games/ship_explore.json b/server/tests/test_games/movement/ship_explore.json similarity index 100% rename from server/tests/test_games/ship_explore.json rename to server/tests/test_games/movement/ship_explore.json diff --git a/server/tests/test_games/ship_explore.outcome.json b/server/tests/test_games/movement/ship_explore.outcome.json similarity index 100% rename from server/tests/test_games/ship_explore.outcome.json rename to server/tests/test_games/movement/ship_explore.outcome.json diff --git a/server/tests/test_games/ship_explore_move_not_possible.json b/server/tests/test_games/movement/ship_explore_move_not_possible.json similarity index 100% rename from server/tests/test_games/ship_explore_move_not_possible.json rename to server/tests/test_games/movement/ship_explore_move_not_possible.json diff --git a/server/tests/test_games/ship_explore_move_not_possible.outcome.json b/server/tests/test_games/movement/ship_explore_move_not_possible.outcome.json similarity index 100% rename from server/tests/test_games/ship_explore_move_not_possible.outcome.json rename to server/tests/test_games/movement/ship_explore_move_not_possible.outcome.json diff --git a/server/tests/test_games/ship_explore_teleport.json b/server/tests/test_games/movement/ship_explore_teleport.json similarity index 100% rename from server/tests/test_games/ship_explore_teleport.json rename to server/tests/test_games/movement/ship_explore_teleport.json diff --git a/server/tests/test_games/ship_explore_teleport.outcome.json b/server/tests/test_games/movement/ship_explore_teleport.outcome.json similarity index 100% rename from server/tests/test_games/ship_explore_teleport.outcome.json rename to server/tests/test_games/movement/ship_explore_teleport.outcome.json diff --git a/server/tests/test_games/ship_navigate.json b/server/tests/test_games/movement/ship_navigate.json similarity index 100% rename from server/tests/test_games/ship_navigate.json rename to server/tests/test_games/movement/ship_navigate.json diff --git a/server/tests/test_games/ship_navigate.outcome.json b/server/tests/test_games/movement/ship_navigate.outcome.json similarity index 100% rename from server/tests/test_games/ship_navigate.outcome.json rename to server/tests/test_games/movement/ship_navigate.outcome.json diff --git a/server/tests/test_games/ship_navigate_explore_move.json b/server/tests/test_games/movement/ship_navigate_explore_move.json similarity index 100% rename from server/tests/test_games/ship_navigate_explore_move.json rename to server/tests/test_games/movement/ship_navigate_explore_move.json diff --git a/server/tests/test_games/ship_navigate_explore_move.outcome.json b/server/tests/test_games/movement/ship_navigate_explore_move.outcome.json similarity index 100% rename from server/tests/test_games/ship_navigate_explore_move.outcome.json rename to server/tests/test_games/movement/ship_navigate_explore_move.outcome.json diff --git a/server/tests/test_games/ship_navigate_explore_not_move.json b/server/tests/test_games/movement/ship_navigate_explore_not_move.json similarity index 100% rename from server/tests/test_games/ship_navigate_explore_not_move.json rename to server/tests/test_games/movement/ship_navigate_explore_not_move.json diff --git a/server/tests/test_games/ship_navigate_explore_not_move.outcome.json b/server/tests/test_games/movement/ship_navigate_explore_not_move.outcome.json similarity index 100% rename from server/tests/test_games/ship_navigate_explore_not_move.outcome.json rename to server/tests/test_games/movement/ship_navigate_explore_not_move.outcome.json diff --git a/server/tests/test_games/ship_navigation_unit_test.json b/server/tests/test_games/movement/ship_navigation_unit_test.json similarity index 100% rename from server/tests/test_games/ship_navigation_unit_test.json rename to server/tests/test_games/movement/ship_navigation_unit_test.json diff --git a/server/tests/test_games/ship_transport.json b/server/tests/test_games/movement/ship_transport.json similarity index 100% rename from server/tests/test_games/ship_transport.json rename to server/tests/test_games/movement/ship_transport.json diff --git a/server/tests/test_games/ship_transport.outcome.json b/server/tests/test_games/movement/ship_transport.outcome.json similarity index 100% rename from server/tests/test_games/ship_transport.outcome.json rename to server/tests/test_games/movement/ship_transport.outcome.json diff --git a/server/tests/test_games/ship_transport_same_sea.json b/server/tests/test_games/movement/ship_transport_same_sea.json similarity index 100% rename from server/tests/test_games/ship_transport_same_sea.json rename to server/tests/test_games/movement/ship_transport_same_sea.json diff --git a/server/tests/test_games/ship_transport_same_sea.outcome.json b/server/tests/test_games/movement/ship_transport_same_sea.outcome.json similarity index 100% rename from server/tests/test_games/ship_transport_same_sea.outcome.json rename to server/tests/test_games/movement/ship_transport_same_sea.outcome.json diff --git a/server/tests/test_games/change_government.json b/server/tests/test_games/status_phase/change_government.json similarity index 100% rename from server/tests/test_games/change_government.json rename to server/tests/test_games/status_phase/change_government.json diff --git a/server/tests/test_games/change_government.outcome.json b/server/tests/test_games/status_phase/change_government.outcome.json similarity index 100% rename from server/tests/test_games/change_government.outcome.json rename to server/tests/test_games/status_phase/change_government.outcome.json diff --git a/server/tests/test_games/determine_first_player.json b/server/tests/test_games/status_phase/determine_first_player.json similarity index 100% rename from server/tests/test_games/determine_first_player.json rename to server/tests/test_games/status_phase/determine_first_player.json diff --git a/server/tests/test_games/determine_first_player.outcome.json b/server/tests/test_games/status_phase/determine_first_player.outcome.json similarity index 100% rename from server/tests/test_games/determine_first_player.outcome.json rename to server/tests/test_games/status_phase/determine_first_player.outcome.json diff --git a/server/tests/test_games/end_game.json b/server/tests/test_games/status_phase/end_game.json similarity index 100% rename from server/tests/test_games/end_game.json rename to server/tests/test_games/status_phase/end_game.json diff --git a/server/tests/test_games/end_game.outcome.json b/server/tests/test_games/status_phase/end_game.outcome.json similarity index 100% rename from server/tests/test_games/end_game.outcome.json rename to server/tests/test_games/status_phase/end_game.outcome.json diff --git a/server/tests/test_games/free_advance.json b/server/tests/test_games/status_phase/free_advance.json similarity index 100% rename from server/tests/test_games/free_advance.json rename to server/tests/test_games/status_phase/free_advance.json diff --git a/server/tests/test_games/free_advance.outcome.json b/server/tests/test_games/status_phase/free_advance.outcome.json similarity index 100% rename from server/tests/test_games/free_advance.outcome.json rename to server/tests/test_games/status_phase/free_advance.outcome.json diff --git a/server/tests/test_games/free_advance.outcome1.json b/server/tests/test_games/status_phase/free_advance.outcome1.json similarity index 100% rename from server/tests/test_games/free_advance.outcome1.json rename to server/tests/test_games/status_phase/free_advance.outcome1.json diff --git a/server/tests/test_games/illegal_free_advance.json b/server/tests/test_games/status_phase/illegal_free_advance.json similarity index 100% rename from server/tests/test_games/illegal_free_advance.json rename to server/tests/test_games/status_phase/illegal_free_advance.json diff --git a/server/tests/test_games/raze_city.json b/server/tests/test_games/status_phase/raze_city.json similarity index 100% rename from server/tests/test_games/raze_city.json rename to server/tests/test_games/status_phase/raze_city.json diff --git a/server/tests/test_games/raze_city.outcome.json b/server/tests/test_games/status_phase/raze_city.outcome.json similarity index 100% rename from server/tests/test_games/raze_city.outcome.json rename to server/tests/test_games/status_phase/raze_city.outcome.json diff --git a/server/tests/test_games/raze_city_decline.json b/server/tests/test_games/status_phase/raze_city_decline.json similarity index 100% rename from server/tests/test_games/raze_city_decline.json rename to server/tests/test_games/status_phase/raze_city_decline.json diff --git a/server/tests/test_games/raze_city_decline.outcome.json b/server/tests/test_games/status_phase/raze_city_decline.outcome.json similarity index 100% rename from server/tests/test_games/raze_city_decline.outcome.json rename to server/tests/test_games/status_phase/raze_city_decline.outcome.json