M client/src/game_status/mod.rs => client/src/game_status/mod.rs +30 -0
@@ 68,6 68,8 @@ pub struct PlayerStatus {
/// constructed from a vector of [`Action`]s
#[derive(Clone)]
pub struct GameStatus {
+ /// log entries, filled in one at a time when parsing actions
+ pub log: Vec<LogEntry>,
/// a modifiable Actions Vector, will be modified when parsing actions,
/// used for showing the log
pub actions: Vec<Action>,
@@ 84,3 86,31 @@ impl GameStatus {
}
}
}
+
+#[derive(Clone)]
+pub struct LogEntry {
+ pub sections: Vec<LogSection>,
+}
+
+impl LogEntry {
+ pub fn from_sections(sections: impl IntoIterator<Item = LogSection>) -> Self {
+ Self {
+ sections: sections.into_iter().collect(),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub enum LogSection {
+ Normal(String),
+ Bold(String),
+}
+
+impl LogSection {
+ pub fn normal(value: &str) -> LogSection {
+ LogSection::Normal(value.to_string())
+ }
+ pub fn bold(value: &str) -> LogSection {
+ LogSection::Bold(value.to_string())
+ }
+}
M client/src/game_status/parser.rs => client/src/game_status/parser.rs +4 -1
@@ 12,7 12,7 @@ use fastrand::Rng;
use crate::{
api::game::{Action, Command, Game},
- game_status::SupplyPile,
+ game_status::SupplyPile, util::action_to_log,
};
use super::{GameStatus, PlayerState, PlayerStatus};
@@ 43,6 43,7 @@ where
pub fn parse(game: &Game) -> Result<GameStatus, ()> {
let mut game_status = GameStatus {
+ log: vec![],
actions: game.actions.as_ref().unwrap().to_vec(),
supply_piles: vec![],
players: HashMap::new(),
@@ 94,6 95,8 @@ macro_rules! current_seed {
}
fn parse_action(action: &Action, game: &Game, game_status: &mut GameStatus) {
+ game_status.log.push(action_to_log(action, game_status));
+
// invoker: the one who invoked the action
// target: the one who the action affects, may also be the invoker, e.g. draw
let (invoker, target) =
M client/src/plugins/game/ui/log.rs => client/src/plugins/game/ui/log.rs +24 -4
@@ 8,7 8,7 @@
use bevy::{prelude::*, input::mouse::{MouseScrollUnit, MouseWheel}, a11y::{AccessibilityNode, accesskit::NodeBuilder}};
-use crate::{AppState, plugins::GameData, util::action_to_log};
+use crate::{AppState, plugins::GameData, game_status::LogSection};
pub struct LogPlugin;
@@ 222,7 222,7 @@ fn update_log(
let index_spaces = status.actions.len().to_string().len();
- for (i, action) in status.actions.iter().enumerate() {
+ for (i, _action) in status.actions.iter().enumerate() {
let spaces = " ".repeat(index_spaces - i.to_string().len());
let index_text = TextSection {
value: format!("{}{}. ", spaces, i),
@@ 232,8 232,28 @@ fn update_log(
},
};
- let mut sections = action_to_log(action, (font.clone(), font_bold.clone()), style.clone());
- sections.insert(0, index_text);
+ let mut sections = vec![index_text];
+
+ let log = status.log.get(i).unwrap();
+ for section in &log.sections {
+ match section {
+ LogSection::Normal(value) => {
+ sections.push(TextSection {
+ value: value.to_string(),
+ style: style.clone(),
+ });
+ }
+ LogSection::Bold(value) => {
+ sections.push(TextSection {
+ value: value.to_string(),
+ style: TextStyle {
+ font: font_bold.clone(),
+ ..style.clone()
+ },
+ });
+ }
+ }
+ }
commands.spawn((
TextBundle::from_sections(sections)
M client/src/util/action_to_log.rs => client/src/util/action_to_log.rs +49 -45
@@ 6,58 6,62 @@
* See LICENSE for licensing information.
*/
-use bevy::prelude::*;
-
-use crate::api::game::{Action, Command};
-
-macro_rules! section {
- ($value:expr, $style:ident) => {
- TextSection {
- value: $value,
- style: $style.clone(),
- }
- };
-
- ($value:expr, $style:expr) => {
- TextSection {
- value: $value,
- style: $style,
- }
- };
-}
+use crate::{api::game::{Action, Command}, game_status::{GameStatus, LogEntry, LogSection}};
pub fn action_to_log(
action: &Action,
- (font, font_bold): (Handle<Font>, Handle<Font>),
- style: TextStyle,
-) -> Vec<TextSection> {
+ game_status: &GameStatus,
+) -> LogEntry {
+ let invoker_name = &game_status.players.get(&action.invoker).unwrap().display_name;
+
match &action.command {
Command::InitSupplyPile { card, amount } => {
- vec![
- section!(format!("Created supply pile of "), style),
- section!(format!("{}", card.name), TextStyle {
- font: font_bold.clone(),
- ..style.clone()
- }),
- section!(format!(" with "), style),
- section!(format!("{}", amount), TextStyle {
- font: font_bold.clone(),
- ..style.clone()
- }),
- section!(format!(" cards."), TextStyle {
- ..style.clone()
- }),
- ]
+ LogEntry::from_sections(vec![
+ LogSection::normal("Created supply pile of "),
+ LogSection::bold(&card.name),
+ LogSection::normal(" with "),
+ LogSection::bold(&amount.to_string()),
+ LogSection::normal(" cards"),
+ ])
+ }
+ Command::TakeFromPile { index, for_cost: _ } => {
+ let card_name = &game_status.supply_piles.get(*index).unwrap().card.name;
+ LogEntry::from_sections(vec![
+ LogSection::bold(invoker_name),
+ LogSection::normal(" bought "),
+ LogSection::bold(card_name),
+ ])
+ }
+ Command::PlayCard { index } => {
+ let card_name = &game_status.players.get(&action.invoker).unwrap().hand.get(*index).unwrap().name;
+ LogEntry::from_sections(vec![
+ LogSection::bold(invoker_name),
+ LogSection::normal(" played "),
+ LogSection::bold(card_name),
+ ])
+ }
+ Command::Draw { amount } => {
+ LogEntry::from_sections(vec![
+ LogSection::bold(invoker_name),
+ LogSection::normal(" drew "),
+ LogSection::bold(&amount.to_string()),
+ LogSection::normal(" cards"),
+ ])
+ }
+ Command::Discard { index } => {
+ let card_name = &game_status.players.get(&action.invoker).unwrap().hand.get(*index).unwrap().name;
+ LogEntry::from_sections(vec![
+ LogSection::bold(invoker_name),
+ LogSection::normal(" discarded "),
+ LogSection::bold(card_name),
+ ])
}
_ => {
- vec![
- TextSection {
- value: format!("No log configuration for this command"),
- style: TextStyle {
- ..style
- },
- },
- ]
+ LogEntry {
+ sections: vec![
+ LogSection::normal("No log configuration for this command"),
+ ]
+ }
}
}
}