#[allow(unused)] use pretty_assertions::{assert_eq, assert_ne, assert_str_eq}; use crate::{ character::CharacterId, game::{Game, GameSettings, SetupRole}, game_test::{ ActionPromptTitleExt, ActionResultExt, GameExt, ServerToHostMessageExt, SettingsExt, gen_players, init_log, }, message::{ host::{HostDayMessage, HostGameMessage, HostNightMessage, ServerToHostMessage}, night::{ActionPrompt, ActionPromptTitle, ActionResponse, ActionResult}, }, role::RoleTitle, }; #[test] fn protect_stops_shapeshift() { init_log(); let players = gen_players(1..10); let mut settings = GameSettings::default(); settings.new_slot(RoleTitle::Shapeshifter); settings.new_slot(RoleTitle::Protector); for _ in 0..7 { settings.new_slot(RoleTitle::Villager); } if let Some(slot) = settings .slots() .iter() .find(|s| matches!(s.role, SetupRole::Werewolf)) { settings.remove_slot(slot.slot_id); } let mut game = Game::new(&players, settings).unwrap(); assert_eq!( game.process(HostGameMessage::Night(HostNightMessage::ActionResponse( ActionResponse::Continue, ))) .unwrap(), ServerToHostMessage::ActionResult(None, ActionResult::Continue) ); assert!(matches!( game.process(HostGameMessage::Night(HostNightMessage::Next)) .unwrap(), ServerToHostMessage::ActionPrompt(ActionPrompt::WolvesIntro { wolves: _ }) )); assert_eq!( game.process(HostGameMessage::Night(HostNightMessage::ActionResponse( ActionResponse::Continue ))) .unwrap(), ServerToHostMessage::ActionResult(None, ActionResult::GoBackToSleep), ); assert!(matches!( game.process(HostGameMessage::Night(HostNightMessage::Next)) .unwrap(), ServerToHostMessage::Daytime { characters: _, marked: _, day: _, } )); let execution_target = game .village() .characters() .into_iter() .find(|v| v.is_village() && !matches!(v.role().title(), RoleTitle::Protector)) .unwrap() .character_id(); match game .process(HostGameMessage::Day(HostDayMessage::MarkForExecution( execution_target, ))) .unwrap() { ServerToHostMessage::Daytime { characters: _, marked, day: _, } => assert_eq!(marked.to_vec(), vec![execution_target]), resp => panic!("unexpected server message: {resp:#?}"), } assert_eq!( game.process(HostGameMessage::Day(HostDayMessage::Execute)) .unwrap() .prompt() .title(), ActionPromptTitle::CoverOfDarkness ); game.r#continue().r#continue(); let (prot_and_wolf_target, prot_char_id) = match game .process(HostGameMessage::Night(HostNightMessage::Next)) .unwrap() { ServerToHostMessage::ActionPrompt(ActionPrompt::Protector { character_id: prot_char_id, targets, marked: None, }) => ( targets .into_iter() .map(|c| game.village().character_by_id(c.character_id).unwrap()) .find(|c| c.is_village()) .unwrap() .character_id(), prot_char_id, ), _ => panic!("first n2 prompt isn't protector"), }; let target = game .village() .character_by_id(prot_and_wolf_target) .unwrap() .clone(); log::info!("target: {target:#?}"); match game .process(HostGameMessage::Night(HostNightMessage::ActionResponse( ActionResponse::MarkTarget(prot_and_wolf_target), ))) .unwrap() { ServerToHostMessage::ActionPrompt(ActionPrompt::Protector { marked: Some(mark), .. }) => assert_eq!(mark, prot_and_wolf_target, "marked target"), resp => panic!("unexpected response: {resp:?}"), } game.r#continue().sleep(); assert_eq!(game.next().title(), ActionPromptTitle::WolfPackKill); game.mark_and_check(prot_and_wolf_target); game.r#continue().r#continue(); assert_eq!(game.next().title(), ActionPromptTitle::Shapeshifter,); game.response(ActionResponse::Shapeshift); game.next_expect_day(); let target = game .village() .character_by_id(target.character_id()) .unwrap(); assert!(target.is_village()); assert!(target.alive()); let prot = game .village() .character_by_id(prot_char_id.character_id) .unwrap(); assert!(prot.is_village()); assert!(prot.alive()); assert_eq!(prot.role().title(), RoleTitle::Protector); } #[test] fn only_1_shapeshift_prompt_if_first_shifts() { let players = gen_players(1..10); let mut settings = GameSettings::default(); settings.new_slot(RoleTitle::Shapeshifter); settings.new_slot(RoleTitle::Shapeshifter); for _ in 0..7 { settings.new_slot(RoleTitle::Villager); } if let Some(slot) = settings .slots() .iter() .find(|s| matches!(s.role, SetupRole::Werewolf)) { settings.remove_slot(slot.slot_id); } let mut game = Game::new(&players, settings).unwrap(); game.r#continue().r#continue(); assert_eq!(game.next().title(), ActionPromptTitle::WolvesIntro); game.r#continue().sleep(); game.next_expect_day(); let target = game .village() .characters() .into_iter() .find_map(|c| c.is_village().then_some(c.character_id())) .unwrap(); let (_, marked, _) = game.mark_for_execution(target); let (marked, target_list): (&[CharacterId], &[CharacterId]) = (&marked, &[target]); assert_eq!(target_list, marked); assert_eq!(game.execute().title(), ActionPromptTitle::WolfPackKill); let target = game .village() .characters() .into_iter() .find_map(|c| (c.is_village() && c.alive()).then_some(c.character_id())) .unwrap(); game.mark_and_check(target); game.r#continue().r#continue(); assert_eq!(game.next().title(), ActionPromptTitle::Shapeshifter); game.response(ActionResponse::Shapeshift).r#continue(); assert_eq!(game.next().title(), ActionPromptTitle::RoleChange); game.r#continue().sleep(); game.next_expect_day(); } #[test] fn i_would_simply_refuse() { let players = gen_players(1..21); let shapeshifter_player_id = players[0].player_id; let wolf_player_id = players[1].player_id; let mut settings = GameSettings::empty(); settings.add_and_assign(SetupRole::Shapeshifter, shapeshifter_player_id); settings.add_and_assign(SetupRole::Werewolf, wolf_player_id); settings.fill_remaining_slots_with_villagers(20); let mut game = Game::new(&players, settings).unwrap(); game.r#continue().r#continue(); assert_eq!(game.next().title(), ActionPromptTitle::WolvesIntro); game.r#continue().sleep(); game.next_expect_day(); game.execute().title().wolf_pack_kill(); let ss_target = game.living_villager(); game.mark(ss_target.character_id()); game.r#continue().r#continue(); game.next().title().shapeshifter(); game.r#continue().sleep(); game.next_expect_day(); }