overlord_event_system/
game_config_helpers.rs

1use anyhow::Context;
2
3use configs::{
4    abilities::{AbilityCasesSettingsByLevel, AbilityLevel, Projectile, ProjectileId},
5    cheats::{CheatScript, CheatScriptId},
6    fighting::ArenaLeague,
7    game_config::GameConfig,
8    pets::{PetCasesSettingsByLevel, PetLevel},
9};
10
11use essences::{
12    abilities::{AbilityId, AbilityRarity, AbilityRarityId, AbilityTemplate},
13    bundles::{BundleId, BundleRaw},
14    class::{Class, ClassId},
15    dungeons::{DungeonTemplate, DungeonTemplateId},
16    effect::{Effect, EffectId},
17    fighting::{FightTemplate, FightTemplateId},
18    game::{Chapter, CharacterLevel, EntityTemplate, EntityTemplateId},
19    gift::GiftTemplate,
20    item_case::ItemCasesSettingsByLevel,
21    items::{Attribute, AttributeId, ItemRarity, ItemRarityId, ItemTemplate, ItemTemplateId},
22    mail::MailTemplate,
23    pets::{PetId, PetRarity, PetRarityId, PetTemplate},
24    quest::QuestTemplate,
25    referrals::ReferralLevelInfo,
26    skins::{ConfigSkin, SkinId},
27    talent_tree::{TalentId, TalentTemplate},
28    vassals::VassalTaskTemplate,
29};
30
31pub trait GameConfigLookup {
32    fn attribute(&self, attribute_id: AttributeId) -> Option<&Attribute>;
33    fn require_attribute(&self, attribute_id: AttributeId) -> anyhow::Result<&Attribute>;
34
35    fn attribute_by_db_code(&self, db_code: u8) -> Option<&Attribute>;
36    fn require_attribute_by_db_code(&self, db_code: u8) -> anyhow::Result<&Attribute>;
37
38    fn ability_template(&self, ability_id: AbilityId) -> Option<&AbilityTemplate>;
39    fn require_ability_template(&self, ability_id: AbilityId) -> anyhow::Result<&AbilityTemplate>;
40
41    fn ability_rarity(&self, rarity_id: AbilityRarityId) -> Option<&AbilityRarity>;
42    fn require_ability_rarity(&self, rarity_id: AbilityRarityId) -> anyhow::Result<&AbilityRarity>;
43
44    fn ability_level(&self, rarity_id: AbilityRarityId, level: i64) -> Option<&AbilityLevel>;
45    fn require_ability_level(
46        &self,
47        rarity_id: AbilityRarityId,
48        level: i64,
49    ) -> anyhow::Result<&AbilityLevel>;
50
51    fn ability_case_settings_by_level(&self, level: i64) -> Option<&AbilityCasesSettingsByLevel>;
52    fn require_ability_case_settings_by_level(
53        &self,
54        level: i64,
55    ) -> anyhow::Result<&AbilityCasesSettingsByLevel>;
56
57    fn bundle(&self, bundle_id: BundleId) -> Option<&BundleRaw>;
58    fn require_bundle(&self, bundle_id: BundleId) -> anyhow::Result<&BundleRaw>;
59
60    fn chapter_by_level(&self, chapter_level: i64) -> Option<&Chapter>;
61    fn require_chapter_by_level(&self, chapter_level: i64) -> anyhow::Result<&Chapter>;
62
63    fn ability_slots_for_chapter_level(&self, chapter_level: i64) -> Option<u64>;
64
65    fn character_level(&self, level: i64) -> Option<&CharacterLevel>;
66    fn require_character_level(&self, level: i64) -> anyhow::Result<&CharacterLevel>;
67
68    fn class(&self, class_id: ClassId) -> Option<&Class>;
69    fn require_class(&self, class_id: ClassId) -> anyhow::Result<&Class>;
70
71    fn dungeon_template(&self, dungeon_id: DungeonTemplateId) -> Option<&DungeonTemplate>;
72    fn require_dungeon_template(
73        &self,
74        dungeon_id: DungeonTemplateId,
75    ) -> anyhow::Result<&DungeonTemplate>;
76
77    fn effect(&self, effect_id: EffectId) -> Option<&Effect>;
78    fn require_effect(&self, effect_id: EffectId) -> anyhow::Result<&Effect>;
79
80    fn fight_template(&self, fight_id: FightTemplateId) -> Option<&FightTemplate>;
81    fn require_fight_template(&self, fight_id: FightTemplateId) -> anyhow::Result<&FightTemplate>;
82
83    fn arena_league_for_rating(&self, rating: i64) -> Option<&ArenaLeague>;
84    fn require_arena_league_for_rating(&self, rating: i64) -> anyhow::Result<&ArenaLeague>;
85
86    fn entity_template(&self, entity_template_id: EntityTemplateId) -> Option<&EntityTemplate>;
87    fn require_entity_template(
88        &self,
89        entity_template_id: EntityTemplateId,
90    ) -> anyhow::Result<&EntityTemplate>;
91
92    fn gift_template(&self, gift_id: uuid::Uuid) -> Option<&GiftTemplate>;
93    fn require_gift_template(&self, gift_id: uuid::Uuid) -> anyhow::Result<&GiftTemplate>;
94
95    fn item_case_settings_by_level(&self, level: i64) -> Option<&ItemCasesSettingsByLevel>;
96    fn require_item_case_settings_by_level(
97        &self,
98        level: i64,
99    ) -> anyhow::Result<&ItemCasesSettingsByLevel>;
100
101    fn item_rarity(&self, rarity_id: ItemRarityId) -> Option<&ItemRarity>;
102    fn require_item_rarity(&self, rarity_id: ItemRarityId) -> anyhow::Result<&ItemRarity>;
103
104    fn item_template(&self, item_id: ItemTemplateId) -> Option<&ItemTemplate>;
105    fn require_item_template(&self, item_id: ItemTemplateId) -> anyhow::Result<&ItemTemplate>;
106
107    fn mail_template(&self, template_id: uuid::Uuid) -> Option<&MailTemplate>;
108    fn require_mail_template(&self, template_id: uuid::Uuid) -> anyhow::Result<&MailTemplate>;
109
110    fn patron_level_info(&self, level: i64) -> Option<&ReferralLevelInfo>;
111    fn require_patron_level_info(&self, level: i64) -> anyhow::Result<&ReferralLevelInfo>;
112
113    fn projectile(&self, projectile_id: ProjectileId) -> Option<&Projectile>;
114    fn require_projectile(&self, projectile_id: ProjectileId) -> anyhow::Result<&Projectile>;
115
116    fn quest(&self, quest_id: uuid::Uuid) -> Option<&QuestTemplate>;
117    fn require_quest(&self, quest_id: uuid::Uuid) -> anyhow::Result<&QuestTemplate>;
118
119    fn quest_by_code(&self, code: &str) -> Option<&QuestTemplate>;
120
121    fn skin(&self, skin_id: SkinId) -> Option<&ConfigSkin>;
122    fn require_skin(&self, skin_id: SkinId) -> anyhow::Result<&ConfigSkin>;
123
124    fn vassal_task_template(&self, task_template_id: uuid::Uuid) -> Option<&VassalTaskTemplate>;
125    fn require_vassal_task_template(
126        &self,
127        task_template_id: uuid::Uuid,
128    ) -> anyhow::Result<&VassalTaskTemplate>;
129
130    fn cheat_script(&self, cheat_script_id: CheatScriptId) -> Option<&CheatScript>;
131
132    fn talent(&self, talent_id: TalentId) -> Option<&TalentTemplate>;
133    fn require_talent(&self, talent_id: TalentId) -> anyhow::Result<&TalentTemplate>;
134
135    fn allowed_wishlist_rarity_ids(
136        &self,
137        ability_case_level: i64,
138    ) -> Vec<essences::abilities::AbilityRarityId>;
139
140    fn pet_template(&self, pet_id: PetId) -> Option<&PetTemplate>;
141    fn require_pet_template(&self, pet_id: PetId) -> anyhow::Result<&PetTemplate>;
142
143    fn pet_rarity(&self, rarity_id: PetRarityId) -> Option<&PetRarity>;
144
145    fn pet_level(&self, rarity_id: PetRarityId, level: i64) -> Option<&PetLevel>;
146
147    fn pet_slots_for_chapter_level(&self, chapter_level: i64) -> Option<u64>;
148
149    fn pet_case_settings_by_level(&self, level: i64) -> Option<&PetCasesSettingsByLevel>;
150    fn require_pet_case_settings_by_level(
151        &self,
152        level: i64,
153    ) -> anyhow::Result<&PetCasesSettingsByLevel>;
154
155    fn allowed_pet_wishlist_rarity_ids(
156        &self,
157        pet_case_level: i64,
158    ) -> Vec<essences::pets::PetRarityId>;
159}
160
161impl GameConfigLookup for GameConfig {
162    fn attribute(&self, attribute_id: AttributeId) -> Option<&Attribute> {
163        self.attributes.iter().find(|a| a.id == attribute_id)
164    }
165
166    fn require_attribute(&self, attribute_id: AttributeId) -> anyhow::Result<&Attribute> {
167        self.attribute(attribute_id)
168            .with_context(|| format!("No attribute in config with id={attribute_id}"))
169    }
170
171    fn attribute_by_db_code(&self, db_code: u8) -> Option<&Attribute> {
172        self.attributes.iter().find(|a| a.db_code == db_code)
173    }
174
175    fn require_attribute_by_db_code(&self, db_code: u8) -> anyhow::Result<&Attribute> {
176        self.attribute_by_db_code(db_code)
177            .with_context(|| format!("No attribute in config with db_code={db_code}"))
178    }
179
180    fn ability_template(&self, ability_id: AbilityId) -> Option<&AbilityTemplate> {
181        self.abilities.iter().find(|a| a.id == ability_id)
182    }
183
184    fn require_ability_template(&self, ability_id: AbilityId) -> anyhow::Result<&AbilityTemplate> {
185        self.ability_template(ability_id)
186            .with_context(|| format!("No ability_template in config with id={ability_id}"))
187    }
188
189    fn ability_rarity(&self, rarity_id: AbilityRarityId) -> Option<&AbilityRarity> {
190        self.ability_rarities.iter().find(|r| r.id == rarity_id)
191    }
192
193    fn require_ability_rarity(&self, rarity_id: AbilityRarityId) -> anyhow::Result<&AbilityRarity> {
194        self.ability_rarity(rarity_id)
195            .with_context(|| format!("No ability_rarity in config with id={rarity_id}"))
196    }
197
198    fn ability_level(&self, rarity_id: AbilityRarityId, level: i64) -> Option<&AbilityLevel> {
199        self.ability_levels
200            .iter()
201            .find(|x| x.rarity_id == rarity_id && x.level == level)
202    }
203
204    fn require_ability_level(
205        &self,
206        rarity_id: AbilityRarityId,
207        level: i64,
208    ) -> anyhow::Result<&AbilityLevel> {
209        self.ability_level(rarity_id, level).with_context(|| {
210            format!("No ability_level in config with rarity_id={rarity_id} and level={level}")
211        })
212    }
213
214    fn ability_case_settings_by_level(&self, level: i64) -> Option<&AbilityCasesSettingsByLevel> {
215        self.ability_cases_settings
216            .iter()
217            .find(|x| x.level == level)
218    }
219
220    fn require_ability_case_settings_by_level(
221        &self,
222        level: i64,
223    ) -> anyhow::Result<&AbilityCasesSettingsByLevel> {
224        self.ability_case_settings_by_level(level)
225            .with_context(|| format!("No ability_case_settings with level={level}"))
226    }
227
228    fn bundle(&self, bundle_id: BundleId) -> Option<&BundleRaw> {
229        self.bundles.iter().find(|b| b.id == bundle_id)
230    }
231
232    fn require_bundle(&self, bundle_id: BundleId) -> anyhow::Result<&BundleRaw> {
233        self.bundle(bundle_id)
234            .with_context(|| format!("No bundle in config with id={bundle_id}"))
235    }
236
237    fn chapter_by_level(&self, chapter_level: i64) -> Option<&Chapter> {
238        self.chapters.iter().find(|c| c.level == chapter_level)
239    }
240
241    fn require_chapter_by_level(&self, chapter_level: i64) -> anyhow::Result<&Chapter> {
242        self.chapter_by_level(chapter_level)
243            .with_context(|| format!("No chapter with level={chapter_level}"))
244    }
245
246    fn ability_slots_for_chapter_level(&self, chapter_level: i64) -> Option<u64> {
247        self.ability_slots_levels
248            .iter()
249            .rev()
250            .find(|level| level.from_chapter_level <= chapter_level)
251            .map(|level| level.ability_slots)
252    }
253
254    fn character_level(&self, level: i64) -> Option<&CharacterLevel> {
255        self.character_levels.iter().find(|x| x.level == level)
256    }
257
258    fn require_character_level(&self, level: i64) -> anyhow::Result<&CharacterLevel> {
259        self.character_level(level)
260            .with_context(|| format!("No character_level with level={level}"))
261    }
262
263    fn class(&self, class_id: ClassId) -> Option<&Class> {
264        self.classes.iter().find(|c| c.id == class_id)
265    }
266
267    fn require_class(&self, class_id: ClassId) -> anyhow::Result<&Class> {
268        self.class(class_id)
269            .with_context(|| format!("No class in config with id={class_id}"))
270    }
271
272    fn dungeon_template(&self, dungeon_id: DungeonTemplateId) -> Option<&DungeonTemplate> {
273        self.dungeon_templates.iter().find(|d| d.id == dungeon_id)
274    }
275
276    fn require_dungeon_template(
277        &self,
278        dungeon_id: DungeonTemplateId,
279    ) -> anyhow::Result<&DungeonTemplate> {
280        self.dungeon_template(dungeon_id)
281            .with_context(|| format!("No dungeon_template in config with id={dungeon_id}"))
282    }
283
284    fn effect(&self, effect_id: EffectId) -> Option<&Effect> {
285        self.effects.iter().find(|e| e.id == effect_id)
286    }
287
288    fn require_effect(&self, effect_id: EffectId) -> anyhow::Result<&Effect> {
289        self.effect(effect_id)
290            .with_context(|| format!("No effect in config with id={effect_id}"))
291    }
292
293    fn fight_template(&self, fight_id: FightTemplateId) -> Option<&FightTemplate> {
294        self.fight_templates.iter().find(|f| f.id == fight_id)
295    }
296
297    fn require_fight_template(&self, fight_id: FightTemplateId) -> anyhow::Result<&FightTemplate> {
298        self.fight_template(fight_id)
299            .with_context(|| format!("No fight_template in config with id={fight_id}"))
300    }
301
302    fn arena_league_for_rating(&self, rating: i64) -> Option<&ArenaLeague> {
303        self.arena_leagues
304            .iter()
305            .find(|league| rating >= league.min_rating && rating <= league.max_rating)
306    }
307
308    fn require_arena_league_for_rating(&self, rating: i64) -> anyhow::Result<&ArenaLeague> {
309        self.arena_league_for_rating(rating)
310            .with_context(|| format!("No arena_league in config for rating={rating}"))
311    }
312
313    fn entity_template(&self, entity_template_id: EntityTemplateId) -> Option<&EntityTemplate> {
314        self.entities.iter().find(|e| e.id == entity_template_id)
315    }
316
317    fn require_entity_template(
318        &self,
319        entity_template_id: EntityTemplateId,
320    ) -> anyhow::Result<&EntityTemplate> {
321        self.entity_template(entity_template_id)
322            .with_context(|| format!("No entity_template in config with id={entity_template_id}"))
323    }
324
325    fn gift_template(&self, gift_id: uuid::Uuid) -> Option<&GiftTemplate> {
326        self.gifts.iter().find(|g| g.id == gift_id)
327    }
328
329    fn require_gift_template(&self, gift_id: uuid::Uuid) -> anyhow::Result<&GiftTemplate> {
330        self.gift_template(gift_id)
331            .with_context(|| format!("No gift_template in config with id={gift_id}"))
332    }
333
334    fn item_case_settings_by_level(&self, level: i64) -> Option<&ItemCasesSettingsByLevel> {
335        self.item_cases_settings.iter().find(|s| s.level == level)
336    }
337
338    fn require_item_case_settings_by_level(
339        &self,
340        level: i64,
341    ) -> anyhow::Result<&ItemCasesSettingsByLevel> {
342        self.item_case_settings_by_level(level)
343            .with_context(|| format!("No item_case_settings with level={level}"))
344    }
345
346    fn item_rarity(&self, rarity_id: ItemRarityId) -> Option<&ItemRarity> {
347        self.item_rarities.iter().find(|r| r.id == rarity_id)
348    }
349
350    fn require_item_rarity(&self, rarity_id: ItemRarityId) -> anyhow::Result<&ItemRarity> {
351        self.item_rarity(rarity_id)
352            .with_context(|| format!("No item_rarity in config with id={rarity_id}"))
353    }
354
355    fn item_template(&self, item_id: ItemTemplateId) -> Option<&ItemTemplate> {
356        self.items.iter().find(|i| i.id == item_id)
357    }
358
359    fn require_item_template(&self, item_id: ItemTemplateId) -> anyhow::Result<&ItemTemplate> {
360        self.item_template(item_id)
361            .with_context(|| format!("No item_template in config with id={item_id}"))
362    }
363
364    fn mail_template(&self, template_id: uuid::Uuid) -> Option<&MailTemplate> {
365        self.mail_templates.iter().find(|t| t.id == template_id)
366    }
367
368    fn require_mail_template(&self, template_id: uuid::Uuid) -> anyhow::Result<&MailTemplate> {
369        self.mail_template(template_id)
370            .with_context(|| format!("No mail_template in config with id={template_id}"))
371    }
372
373    fn patron_level_info(&self, level: i64) -> Option<&ReferralLevelInfo> {
374        self.patron_levels.iter().find(|x| x.level == level)
375    }
376
377    fn require_patron_level_info(&self, level: i64) -> anyhow::Result<&ReferralLevelInfo> {
378        self.patron_level_info(level)
379            .with_context(|| format!("No patron_level_info in config with level={level}"))
380    }
381
382    fn projectile(&self, projectile_id: ProjectileId) -> Option<&Projectile> {
383        self.projectiles.iter().find(|p| p.id == projectile_id)
384    }
385
386    fn require_projectile(&self, projectile_id: ProjectileId) -> anyhow::Result<&Projectile> {
387        self.projectile(projectile_id)
388            .with_context(|| format!("No projectile in config with id={projectile_id}"))
389    }
390
391    fn quest(&self, quest_id: uuid::Uuid) -> Option<&QuestTemplate> {
392        self.quests.iter().find(|q| q.id == quest_id)
393    }
394
395    fn require_quest(&self, quest_id: uuid::Uuid) -> anyhow::Result<&QuestTemplate> {
396        self.quest(quest_id)
397            .with_context(|| format!("No quest in config with id={quest_id}"))
398    }
399
400    fn quest_by_code(&self, code: &str) -> Option<&QuestTemplate> {
401        self.quests.iter().find(|q| q.code.as_deref() == Some(code))
402    }
403
404    fn skin(&self, skin_id: SkinId) -> Option<&ConfigSkin> {
405        self.skins.iter().find(|s| s.id == skin_id)
406    }
407
408    fn require_skin(&self, skin_id: SkinId) -> anyhow::Result<&ConfigSkin> {
409        self.skin(skin_id)
410            .with_context(|| format!("No skin in config with id={skin_id}"))
411    }
412
413    fn vassal_task_template(&self, task_template_id: uuid::Uuid) -> Option<&VassalTaskTemplate> {
414        self.vassal_tasks.iter().find(|t| t.id == task_template_id)
415    }
416
417    fn require_vassal_task_template(
418        &self,
419        task_template_id: uuid::Uuid,
420    ) -> anyhow::Result<&VassalTaskTemplate> {
421        self.vassal_task_template(task_template_id)
422            .with_context(|| {
423                format!("No vassal_task_template in config with id={task_template_id}")
424            })
425    }
426
427    fn cheat_script(&self, cheat_script_id: CheatScriptId) -> Option<&CheatScript> {
428        self.cheat_scripts.iter().find(|c| c.id == cheat_script_id)
429    }
430
431    fn talent(&self, talent_id: TalentId) -> Option<&TalentTemplate> {
432        self.talents.iter().find(|t| t.id == talent_id)
433    }
434
435    fn require_talent(&self, talent_id: TalentId) -> anyhow::Result<&TalentTemplate> {
436        self.talent(talent_id)
437            .with_context(|| format!("No talent in config with id={talent_id}"))
438    }
439
440    fn allowed_wishlist_rarity_ids(&self, ability_case_level: i64) -> Vec<AbilityRarityId> {
441        self.ability_case_settings_by_level(ability_case_level)
442            .map(|settings| settings.allowed_wishlist_rarity_ids.clone())
443            .unwrap_or_default()
444    }
445
446    fn pet_template(&self, pet_id: PetId) -> Option<&PetTemplate> {
447        self.pet_templates.iter().find(|t| t.id == pet_id)
448    }
449
450    fn require_pet_template(&self, pet_id: PetId) -> anyhow::Result<&PetTemplate> {
451        self.pet_template(pet_id)
452            .with_context(|| format!("No pet_template in config with id={pet_id}"))
453    }
454
455    fn pet_rarity(&self, rarity_id: PetRarityId) -> Option<&PetRarity> {
456        self.pet_rarities.iter().find(|r| r.id == rarity_id)
457    }
458
459    fn pet_level(&self, rarity_id: PetRarityId, level: i64) -> Option<&PetLevel> {
460        self.pet_levels
461            .iter()
462            .find(|x| x.rarity_id == rarity_id && x.level == level)
463    }
464
465    fn pet_slots_for_chapter_level(&self, chapter_level: i64) -> Option<u64> {
466        self.pet_slots_levels
467            .iter()
468            .rev()
469            .find(|level| level.from_chapter_level <= chapter_level)
470            .map(|level| level.pet_slots)
471    }
472
473    fn pet_case_settings_by_level(&self, level: i64) -> Option<&PetCasesSettingsByLevel> {
474        self.pet_cases_settings.iter().find(|x| x.level == level)
475    }
476
477    fn require_pet_case_settings_by_level(
478        &self,
479        level: i64,
480    ) -> anyhow::Result<&PetCasesSettingsByLevel> {
481        self.pet_case_settings_by_level(level)
482            .with_context(|| format!("No pet_case_settings with level={level}"))
483    }
484
485    fn allowed_pet_wishlist_rarity_ids(
486        &self,
487        pet_case_level: i64,
488    ) -> Vec<essences::pets::PetRarityId> {
489        self.pet_case_settings_by_level(pet_case_level)
490            .map(|settings| settings.allowed_wishlist_rarity_ids.clone())
491            .unwrap_or_default()
492    }
493}