faction table, applying factions to mobs, and querying reactions

This commit is contained in:
Llywelwyn 2023-08-15 15:56:00 +01:00
parent 0375c31acf
commit 76d835021b
11 changed files with 108 additions and 13 deletions

26
raws/factions.json Normal file
View file

@ -0,0 +1,26 @@
[
{
"id": "player",
"responses": {}
},
{
"id": "mindless",
"responses": { "default": "attack" }
},
{
"id": "neutral",
"responses": { "default": "ignore" }
},
{
"id": "hostile",
"responses": { "default": "attack", "hostile": "ignore" }
},
{
"id": "herbivore",
"responses": { "default": "flee", "herbivores": "ignore" }
},
{
"id": "carnivore",
"responses": { "default": "attack", "carnivores": "ignore" }
}
]

View file

@ -1,4 +1,4 @@
use super::{Bystander, EntityMoved, Map, Position, TakingTurn, Viewshed};
use crate::{Bystander, EntityMoved, Map, Position, TakingTurn, Viewshed};
use specs::prelude::*;
pub struct BystanderAI {}

View file

@ -8,3 +8,7 @@ mod regen_system;
pub use regen_system::RegenSystem;
mod encumbrance_system;
pub use encumbrance_system::{EncumbranceSystem, CARRY_CAPACITY_PER_STRENGTH};
mod bystander_ai_system;
pub use bystander_ai_system::BystanderAI;
mod monster_ai_system;
pub use monster_ai_system::MonsterAI;

View file

@ -1,4 +1,5 @@
use super::{bystander_ai_system, EntityMoved, Map, Monster, Position, TakingTurn, Viewshed, WantsToMelee};
use super::bystander_ai_system::try_move_randomly;
use crate::{EntityMoved, Map, Monster, Position, TakingTurn, Viewshed, WantsToMelee};
use rltk::Point;
use specs::prelude::*;
@ -60,7 +61,7 @@ impl<'a> System<'a> for MonsterAI {
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert marker");
}
} else {
if bystander_ai_system::try_move_randomly(&mut pos, &mut rng, &mut map, &mut viewshed) {
if try_move_randomly(&mut pos, &mut rng, &mut map, &mut viewshed) {
entity_moved.insert(entity, EntityMoved {}).expect("Unable to insert marker");
}
}

View file

@ -46,6 +46,11 @@ pub struct Renderable {
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Player {}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Faction {
pub name: String,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Prop {}

View file

@ -20,9 +20,6 @@ mod saveload_system;
mod spawner;
mod visibility_system;
use visibility_system::VisibilitySystem;
mod monster_ai_system;
use monster_ai_system::MonsterAI;
pub mod bystander_ai_system;
mod map_indexing_system;
use map_indexing_system::MapIndexingSystem;
mod damage_system;
@ -99,8 +96,8 @@ impl State {
let mut encumbrance_system = ai::EncumbranceSystem {};
let mut turn_status_system = ai::TurnStatusSystem {};
let mut quip_system = ai::QuipSystem {};
let mut mob = MonsterAI {};
let mut bystanders = bystander_ai_system::BystanderAI {};
let mut mob = ai::MonsterAI {};
let mut bystanders = ai::BystanderAI {};
let mut trigger_system = trigger_system::TriggerSystem {};
let mut melee_system = MeleeCombatSystem {};
let mut damage_system = DamageSystem {};
@ -520,6 +517,7 @@ fn main() -> rltk::BError {
gs.ecs.register::<Burden>();
gs.ecs.register::<Prop>();
gs.ecs.register::<Player>();
gs.ecs.register::<Faction>();
gs.ecs.register::<Clock>();
gs.ecs.register::<Monster>();
gs.ecs.register::<Bystander>();

View file

@ -0,0 +1,15 @@
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Deserialize, Debug)]
pub struct FactionData {
pub id: String,
pub responses: HashMap<String, String>,
}
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
pub enum Reaction {
Ignore,
Attack,
Flee,
}

View file

@ -11,6 +11,8 @@ mod spawn_table_structs;
use spawn_table_structs::*;
mod loot_table_structs;
use loot_table_structs::*;
mod faction_structs;
use faction_structs::{FactionData, Reaction};
use std::sync::Mutex;
lazy_static! {
@ -24,6 +26,7 @@ pub struct Raws {
pub props: Vec<Prop>,
pub spawn_tables: Vec<SpawnTable>,
pub loot_tables: Vec<LootTable>,
pub factions: Vec<FactionData>,
}
rltk::embedded_resource!(RAW_ITEMS, "../../raws/items.json");
@ -31,6 +34,7 @@ rltk::embedded_resource!(RAW_MOBS, "../../raws/mobs.json");
rltk::embedded_resource!(RAW_PROPS, "../../raws/props.json");
rltk::embedded_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
rltk::embedded_resource!(RAW_LOOT_TABLES, "../../raws/loot_tables.json");
rltk::embedded_resource!(RAW_FACTIONS, "../../raws/factions.json");
pub fn load_raws() {
rltk::link_resource!(RAW_ITEMS, "../../raws/items.json");
@ -38,6 +42,7 @@ pub fn load_raws() {
rltk::link_resource!(RAW_PROPS, "../../raws/props.json");
rltk::link_resource!(RAW_SPAWN_TABLES, "../../raws/spawn_tables.json");
rltk::link_resource!(RAW_LOOT_TABLES, "../../raws/loot_tables.json");
rltk::link_resource!(RAW_FACTIONS, "../../raws/factions.json");
let decoded_raws = get_decoded_raws();
RAWS.lock().unwrap().load(decoded_raws);
@ -49,8 +54,9 @@ pub fn get_decoded_raws() -> Raws {
let props: Vec<Prop> = ParseJson::parse_raws_into_vector("../../raws/props.json".to_string());
let spawn_tables: Vec<SpawnTable> = ParseJson::parse_raws_into_vector("../../raws/spawn_tables.json".to_string());
let loot_tables: Vec<LootTable> = ParseJson::parse_raws_into_vector("../../raws/loot_tables.json".to_string());
let factions: Vec<FactionData> = ParseJson::parse_raws_into_vector("../../raws/factions.json".to_string());
return Raws { items, mobs, props, spawn_tables, loot_tables };
return Raws { items, mobs, props, spawn_tables, loot_tables, factions };
}
trait ParseJson {
@ -67,4 +73,4 @@ macro_rules! impl_ParseJson {
})*
}
}
impl_ParseJson!(for Vec<Item>, Vec<Mob>, Vec<Prop>, Vec<SpawnTable>, Vec<LootTable>);
impl_ParseJson!(for Vec<Item>, Vec<Mob>, Vec<Prop>, Vec<SpawnTable>, Vec<LootTable>, Vec<FactionData>);

View file

@ -1,4 +1,4 @@
use super::Raws;
use super::{Raws, Reaction};
use crate::components::*;
use crate::gamesystem::*;
use crate::random_table::RandomTable;
@ -22,6 +22,7 @@ pub struct RawMaster {
prop_index: HashMap<String, usize>,
table_index: HashMap<String, usize>,
loot_index: HashMap<String, usize>,
faction_index: HashMap<String, HashMap<String, Reaction>>,
}
impl RawMaster {
@ -33,12 +34,14 @@ impl RawMaster {
props: Vec::new(),
spawn_tables: Vec::new(),
loot_tables: Vec::new(),
factions: Vec::new(),
},
item_index: HashMap::new(),
mob_index: HashMap::new(),
prop_index: HashMap::new(),
table_index: HashMap::new(),
loot_index: HashMap::new(),
faction_index: HashMap::new(),
}
}
@ -75,6 +78,20 @@ impl RawMaster {
check_for_unspecified_entity(&used_names, &entry.id)
}
}
for faction in self.raws.factions.iter() {
let mut reactions: HashMap<String, Reaction> = HashMap::new();
for other in faction.responses.iter() {
reactions.insert(
other.0.clone(),
match other.1.as_str() {
"flee" => Reaction::Flee,
"attack" => Reaction::Attack,
_ => Reaction::Ignore,
},
);
}
self.faction_index.insert(faction.id.clone(), reactions);
}
}
}
@ -279,7 +296,14 @@ pub fn spawn_named_mob(
"BLOCKS_TILE" => eb = eb.with(BlocksTile {}),
"BYSTANDER" => eb = eb.with(Bystander {}),
"MONSTER" => eb = eb.with(Monster {}),
"MINDLESS" => has_mind = false,
"MINDLESS" => {
eb = eb.with(Faction { name: "mindless".to_string() });
has_mind = false;
}
"NEUTRAL" => eb = eb.with(Faction { name: "neutral".to_string() }),
"HOSTILE" => eb = eb.with(Faction { name: "hostile".to_string() }),
"HERBIVORE" => eb = eb.with(Faction { name: "herbivore".to_string() }),
"CARNIVORE" => eb = eb.with(Faction { name: "carnivore".to_string() }),
"SMALL_GROUP" => {} // These flags are for region spawning,
"LARGE_GROUP" => {} // and don't matter here (yet)?
"MULTIATTACK" => {
@ -738,3 +762,16 @@ pub fn is_tag_magic(tag: &str) -> bool {
return false;
}
}
/// Queries the faction index to obtain one faction's reaction to another faction.
pub fn faction_reaction(this_faction: &str, other_faction: &str, raws: &RawMaster) -> Reaction {
if raws.faction_index.contains_key(this_faction) {
let mine = &raws.faction_index[this_faction];
if mine.contains_key(other_faction) {
return mine[other_faction];
} else if mine.contains_key("default") {
return mine["default"];
}
}
return Reaction::Ignore;
}

View file

@ -70,6 +70,7 @@ pub fn save_game(ecs: &mut World) {
EquipmentChanged,
Equippable,
Equipped,
Faction,
GrantsXP,
Hidden,
HungerClock,
@ -185,6 +186,7 @@ pub fn load_game(ecs: &mut World) {
EquipmentChanged,
Equippable,
Equipped,
Faction,
GrantsXP,
Hidden,
HungerClock,

View file

@ -1,6 +1,6 @@
use super::{
ai::NORMAL_SPEED, gamesystem, gamesystem::attr_bonus, random_table::RandomTable, raws, Attribute, Attributes,
Clock, Energy, EquipmentChanged, HungerClock, HungerState, Map, Name, Player, Pool, Pools, Position, Rect,
Clock, Energy, EquipmentChanged, Faction, HungerClock, HungerState, Map, Name, Player, Pool, Pools, Position, Rect,
Renderable, SerializeMe, Skill, Skills, TileType, Viewshed,
};
use rltk::{RandomNumberGenerator, RGB};
@ -36,6 +36,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
render_order: 0,
})
.with(Player {})
.with(Faction { name: "player".to_string() })
.with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true })
.with(Name { name: "you".to_string(), plural: "you".to_string() })
.with(HungerClock { state: HungerState::Satiated, duration: 200 })