overlord_event_system/mechanics/
content_lookups.rs

1//! engine init. Holds fields that the Rust schemas don't carry (`q`, `eff`,
2//! `fixed_power`, `is_boss`, `is_dungeon`, `is_bossfight`, attribute
3//! `base_value`, effect `on_apply`/`on_change` callbacks, ...).
4
5use std::collections::HashMap;
6use std::sync::Arc;
7
8use essences::abilities::{AbilityId, AbilityRarityId};
9use essences::fighting::FightTemplateId;
10use essences::game::EntityTemplate;
11use essences::game::EntityTemplateId;
12use essences::items::{AttributeId, ItemRarityId};
13use uuid::Uuid;
14
15#[derive(Debug, Default, Clone)]
16pub struct ContentLookups {
17    // --- Balance ---
18    pub item_rarity_q: HashMap<ItemRarityId, f64>,
19    /// `ItemRarity::sell_q` — the Gold multiplier on sale, deliberately separate
20    /// from `item_rarity_q`. `q` sets power and grows smoothly; the sale value has
21    /// to follow the chest price ladder so sales keep funding 78-82% of the next
22    /// upgrade. Read only by `behaviors::items::item_price`.
23    pub item_rarity_sell_q: HashMap<ItemRarityId, f64>,
24    pub ability_rarity_eff: HashMap<AbilityRarityId, f64>,
25    /// Rarities that belong to a class kit. Class abilities rank on their own
26    /// authored ladder (BAL-034) rather than on the shard-level curve every
27    /// other ability uses, and the rarity is what tells the two apart.
28    pub class_ability_rarities: std::collections::HashSet<AbilityRarityId>,
29    pub item_fixed_power: HashMap<Uuid, f64>,
30    /// `ItemTemplate::next_mimic_item_code` (an `i64`) → item template id, for
31    /// `content::get_item_by_code`. Codes are unique across items in the
32    /// shipped content.
33    pub item_id_by_mimic_code: HashMap<i64, Uuid>,
34
35    // --- Fight / AI ---
36    /// Effect templates keyed by their `code`. The effect reactions
37    /// (`on_apply` / `on_change`) are native, dispatched by
38    /// [`crate::mechanics::effect_cb::OverlordEffectCb`] keyed by `code`.
39    pub effects_by_code: HashMap<String, Arc<EffectTpl>>,
40    pub fight_template_is_dungeon: HashMap<FightTemplateId, bool>,
41    pub fight_template_is_bossfight: HashMap<FightTemplateId, bool>,
42    pub entity_template_is_boss: HashMap<EntityTemplateId, bool>,
43    /// `fight_settings.ally_run_speed_mult` — ally-team run speed multiplier used by
44    /// `entity_run` (docs/combat-feel-porting-plan.md [3.4]). Cached here because `entity_run`
45    /// receives lookups, not the GameConfig. `Default` (0.0) is treated as 1.0 by the consumer.
46    pub ally_run_speed_mult: f64,
47
48    /// `attribute.code` → AttributeId, for `get_attribute_by_code` / stat lookups.
49    pub attribute_by_code: HashMap<String, AttributeId>,
50    /// `attribute.base_value` extracted from content_raw (not on Rust schema).
51    pub attribute_base_value: HashMap<AttributeId, f64>,
52
53    // --- Loop tasks / quests ---
54    /// Quest `code` → quest UUID, for `loop_tasks::get_quest_by_code`.
55    pub quest_by_code: HashMap<String, Uuid>,
56
57    // --- Abilities (content_raw extras) ---
58    /// Per-ability `range` (cells), from `content_raw::abilities[id].range`.
59    pub ability_range: HashMap<AbilityId, i64>,
60    /// Per-ability `target_type` string ("Enemy", "Ally", "Self"),
61    /// from `content_raw::abilities[id].target_type`.
62    pub ability_target_type: HashMap<AbilityId, String>,
63}
64
65#[derive(Debug, Clone)]
66pub struct EffectTpl {
67    pub id: Uuid,
68    pub code: String,
69    pub max_duration_ticks: Option<i64>,
70}
71
72/// Pre-cached entity-template wrapper for fast lookup of `width`, `cast_time`.
73#[derive(Debug, Clone)]
74pub struct CachedEntityTemplate {
75    pub width: i64,
76    pub cast_time: i64,
77    pub is_boss: bool,
78}
79
80impl ContentLookups {
81    pub fn entity_template_cache(&self, tpl: &EntityTemplate) -> CachedEntityTemplate {
82        CachedEntityTemplate {
83            width: tpl.width as i64,
84            cast_time: tpl.cast_time as i64,
85            is_boss: self
86                .entity_template_is_boss
87                .get(&tpl.id)
88                .copied()
89                .unwrap_or(false),
90        }
91    }
92}