make character short function take the id of the character instead of adding it later

This commit is contained in:
Rusty Striker 2025-06-18 19:46:30 +03:00
parent 731f22a2c2
commit 3da8c9d5c0
Signed by: RustyStriker
GPG key ID: 87E4D691632DFF15
3 changed files with 68 additions and 67 deletions

View file

@ -2,9 +2,12 @@ use std::fmt::Debug;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::{entry::{ActionDefinition, ActionResult, GameEntry}, chat_message::ChatMessage}; use super::{
chat_message::ChatMessage,
entry::{ActionDefinition, ActionResult, GameEntry},
};
pub trait Character<E: GameEntry> : CharacterSheet { pub trait Character<E: GameEntry>: CharacterSheet {
/// types of actions that can be done on the specified entry (e.g. cast for spells and wear for armor) /// types of actions that can be done on the specified entry (e.g. cast for spells and wear for armor)
fn actions(&self, entry: &E) -> Vec<ActionDefinition>; fn actions(&self, entry: &E) -> Vec<ActionDefinition>;
/// uses an action for a specific character, some actions should be split into multiple /// uses an action for a specific character, some actions should be split into multiple
@ -16,10 +19,10 @@ pub trait Character<E: GameEntry> : CharacterSheet {
/// - `damage` will be used on the target character (which could apply reductions as well) /// - `damage` will be used on the target character (which could apply reductions as well)
fn use_action(&mut self, entry: &E, action: &ActionResult) -> ChatMessage; fn use_action(&mut self, entry: &E, action: &ActionResult) -> ChatMessage;
/// character short display, containing basic info like name(title) level and health /// character short display, containing basic info like name(title) level and health
fn short(&self) -> CharacterShort; fn short(&self, id: usize) -> CharacterShort;
} }
pub trait CharacterSheet : Default { pub trait CharacterSheet: Default {
/// Character sheet inputs (stuff that are not calculated from different items), such as Name, Age, Strength /// Character sheet inputs (stuff that are not calculated from different items), such as Name, Age, Strength
fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>; fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>;
/// All fields in the character sheet, maybe change it to only a vec of strings? /// All fields in the character sheet, maybe change it to only a vec of strings?
@ -34,7 +37,10 @@ pub trait CharacterSheet : Default {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum AccessLevel { pub enum AccessLevel {
Admin = 0, Owner = 1, PartyMember = 2, World = 3, Admin = 0,
Owner = 1,
PartyMember = 2,
World = 3,
} }
impl AccessLevel { impl AccessLevel {
pub fn has_access(self, other: Self) -> bool { pub fn has_access(self, other: Self) -> bool {
@ -66,12 +72,6 @@ pub struct CharacterShort {
pub health: Option<String>, pub health: Option<String>,
pub level: Option<i32>, pub level: Option<i32>,
} }
impl CharacterShort {
pub fn with_id(mut self, id: usize) -> Self {
self.id = id;
self
}
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum EntryType { pub enum EntryType {
@ -87,28 +87,17 @@ impl Default for EntryType {
} }
impl EntryType { impl EntryType {
pub fn as_num(&self) -> i32 { pub fn as_num(&self) -> i32 {
if let EntryType::Number(n) = *self { if let EntryType::Number(n) = *self { n } else { 0 }
n
}
else {
0
}
} }
pub fn as_text(&self) -> String { pub fn as_text(&self) -> String {
if let EntryType::Text(t) = self { if let EntryType::Text(t) = self {
t.clone() t.clone()
} } else {
else {
String::new() String::new()
} }
} }
pub fn as_bool(&self) -> bool { pub fn as_bool(&self) -> bool {
if let EntryType::Bool(b) = *self { if let EntryType::Bool(b) = *self { b } else { false }
b
}
else {
false
}
} }
} }
impl std::fmt::Display for EntryType { impl std::fmt::Display for EntryType {
@ -122,11 +111,11 @@ impl std::fmt::Display for EntryType {
if v.len() > 0 { if v.len() > 0 {
for i in v.iter().take(v.len() - 1) { for i in v.iter().take(v.len() - 1) {
write!(f, "{}, ", i)?; write!(f, "{}, ", i)?;
}; }
write!(f, "{} ", v.iter().last().unwrap())?; write!(f, "{} ", v.iter().last().unwrap())?;
}; };
write!(f, "]") write!(f, "]")
}, }
} }
} }
} }

View file

@ -164,9 +164,7 @@ impl<'a, C: Character<A> + Serialize + Deserialize<'a>, A: entry::GameEntry + Se
} }
fn character_short(&self, character_id: usize) -> Option<CharacterShort> { fn character_short(&self, character_id: usize) -> Option<CharacterShort> {
self.characters self.characters.get(character_id).map(|c| c.0.short(character_id))
.get(character_id)
.map(|c| c.0.short().with_id(character_id))
} }
fn scenes(&self) -> Vec<usize> { fn scenes(&self) -> Vec<usize> {
@ -179,7 +177,7 @@ impl<'a, C: Character<A> + Serialize + Deserialize<'a>, A: entry::GameEntry + Se
s.characters s.characters
.iter() .iter()
.filter(|c| party.can_see(c.1)) .filter(|c| party.can_see(c.1))
.map(|c| self.characters.get(c.0).map(|e| e.0.short().with_id(c.0))) .map(|c| self.characters.get(c.0).map(|e| e.0.short(c.0)))
.flatten() .flatten()
.collect() .collect()
}) })

View file

@ -1,4 +1,8 @@
use crate::game::{character_sheet::*, chat_message::ChatMessage, entry::{ActionDefinition, ActionResult, DiceRoll, GameEntry}}; use crate::game::{
character_sheet::*,
chat_message::ChatMessage,
entry::{ActionDefinition, ActionResult, DiceRoll, GameEntry},
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tavern_macros::CharacterSheet; use tavern_macros::CharacterSheet;
@ -58,11 +62,7 @@ pub struct Pathfinder2rCharacterSheet {
impl Pathfinder2rCharacterSheet { impl Pathfinder2rCharacterSheet {
fn set_items(&mut self, entry: EntryType) { fn set_items(&mut self, entry: EntryType) {
if let EntryType::Array(a) = entry { if let EntryType::Array(a) = entry {
let ws: Vec<Entry> = a let ws: Vec<Entry> = a.iter().map(|e| Entry::load(&e.as_text())).flatten().collect();
.iter()
.map(|e| Entry::load(&e.as_text()))
.flatten()
.collect();
self.weapon = [None, None]; self.weapon = [None, None];
for w in ws { for w in ws {
if let Entry::Weapon(w) = w { if let Entry::Weapon(w) = w {
@ -74,8 +74,7 @@ impl Pathfinder2rCharacterSheet {
} }
} }
} }
} } else {
else {
let s = entry.as_text(); let s = entry.as_text();
if let Some(Entry::Weapon(w)) = Entry::load(&s) { if let Some(Entry::Weapon(w)) = Entry::load(&s) {
self.weapon[0] = Some(w); self.weapon[0] = Some(w);
@ -97,21 +96,26 @@ impl Character<Entry> for Pathfinder2rCharacterSheet {
fn use_action(&mut self, entry: &Entry, action: &ActionResult) -> ChatMessage { fn use_action(&mut self, entry: &Entry, action: &ActionResult) -> ChatMessage {
match entry { match entry {
Entry::Weapon(_) => ChatMessage::new("Attack".to_string()) Entry::Weapon(_) => ChatMessage::new("Attack".to_string())
.with_action( .with_action(ActionDefinition::new("Attack".to_string()).with_roll(DiceRoll::new(
ActionDefinition::new("Attack".to_string()) "Piercing".to_string(),
.with_roll(DiceRoll::new("Piercing".to_string(), 12, 1)) 12,
) 1,
.with_action( )))
ActionDefinition::new("Double".to_string()) .with_action(ActionDefinition::new("Double".to_string()).with_roll(DiceRoll::new(
.with_roll(DiceRoll::new("Piercing".to_string(), 12, 2)) "Piercing".to_string(),
), 12,
Entry::Consumable(_consumable) => if action.name == "consume" { 2,
ChatMessage::new("Heal".to_string()) ))),
.with_action( Entry::Consumable(_consumable) => {
if action.name == "consume" {
ChatMessage::new("Heal".to_string()).with_action(
ActionDefinition::new("Heal".to_string()) ActionDefinition::new("Heal".to_string())
.with_roll(DiceRoll::new("Heal".to_string(), 6, 0).constant(6)) .with_roll(DiceRoll::new("Heal".to_string(), 6, 0).constant(6)),
) )
} else { todo!() }, } else {
todo!()
}
}
Entry::Spell(_spell) => todo!(), Entry::Spell(_spell) => todo!(),
} }
} }
@ -120,23 +124,33 @@ impl Character<Entry> for Pathfinder2rCharacterSheet {
let v; let v;
match entry { match entry {
Entry::Weapon(_) => Entry::Weapon(_) =>
// should technically check if the item is in the user's packpack or something // should technically check if the item is in the user's packpack or something
// but for now just return a constant list // but for now just return a constant list
v = vec![ ("wield", 0), ("attack", 1), ("drop", 0), ("stow", 0) ], {
v = vec![("wield", 0), ("attack", 1), ("drop", 0), ("stow", 0)]
}
Entry::Consumable(_) => v = vec![("consume", 0), ("stow", 0), ("drop", 0)], Entry::Consumable(_) => v = vec![("consume", 0), ("stow", 0), ("drop", 0)],
Entry::Spell(_) => v = vec![("cast", 1)], Entry::Spell(_) => v = vec![("cast", 1)],
}; };
v.iter() v.iter()
.map(|s| ActionDefinition { name: s.0.to_string(), targets: s.1, display_name: None, source: None, rolls: None }) .map(|s| ActionDefinition {
name: s.0.to_string(),
targets: s.1,
display_name: None,
source: None,
rolls: None,
})
.collect() .collect()
} }
fn short(&self) -> CharacterShort { fn short(&self, id: usize) -> CharacterShort {
CharacterShort { CharacterShort {
id: 0, id,
title: self.name.clone(), title: self.name.clone(),
sub_title: Some("A Character!".to_string()), sub_title: Some("A Character!".to_string()),
health: Some([ "Dying", "Hurt", "Harmed", "Unharmed" ][((self.health * 4) / self.max_health) as usize].to_string()), health: Some(
["Dying", "Hurt", "Harmed", "Unharmed"][((self.health * 4) / self.max_health) as usize].to_string(),
),
level: Some(1), level: Some(1),
} }
} }