core logic
Guide for core logic
Core Magic System Implementation
File: src/systems/skills/magic.rs
Key Components
1. Data Structures (Loaded from mantras.json)
#[derive(Deserialize, Clone)]
pub struct CombatSpell {
pub spell_id: String,
pub name: String,
pub level_req: i32,
pub bijas: Vec<BijaRequirement>,
pub max_hit: i32,
pub xp: f32,
pub spell_tier: String,
}
#[derive(Deserialize, Clone)]
pub struct BijaRequirement {
pub bija_id: String,
pub quantity: i64,
}
#[derive(Deserialize, Clone)]
pub struct TeleportRecipe {
pub teleport_id: String,
pub name: String,
pub level_req: i32,
pub coconut_bijas: Vec<CoconutBijaSlot>,
pub charged_coconut_id: String,
pub destination: String,
pub xp: f32,
}
#[derive(Deserialize, Clone)]
pub struct CoconutBijaSlot {
pub eye: i32,
pub bija_id: String,
}2. Active Spell Component
#[derive(Component, Clone, Debug)]
pub struct ActiveSpell {
pub spell_id: String,
}Attached to player entity to track currently selected combat spell.
Event Handlers
SelectSpellEvent
Purpose: Player selects/deselects a spell from Spell Book UI
#[derive(Event)]
pub struct SelectSpellEvent {
pub player: Entity,
pub spell_id: Option<String>,
}Logic:
- If
spell_idis Some: Insert/updateActiveSpellcomponent - If
spell_idis None: RemoveActiveSpellcomponent
CastSpellEvent
Purpose: Player casts their active spell on a target
#[derive(Event)]
pub struct CastSpellEvent {
pub player: Entity,
pub target: Entity,
}Logic:
- Check player has
ActiveSpellcomponent - Look up spell data from
SkillsData.combat_spells - Verify player's Magic level >= spell's
level_req - Check inventory for required bijas
- Consume bijas from inventory
- Calculate damage (random 0 to
max_hit) - Apply damage to target's
CombatStats - Grant Magic XP to player
- Log combat message
Key Implementation Detail:
// Convert bija_id string to ItemId hash
let bija_item_id = ItemId(string_to_id(&bija.bija_id));PrepareCoconutEvent
Purpose: Player charges a coconut with 3 bijas to create teleport item
#[derive(Event)]
pub struct PrepareCoconutEvent {
pub player: Entity,
pub recipe_id: String,
}Logic:
- Look up recipe from
SkillsData.teleport_recipes - Verify player's Magic level >= recipe's
level_req - Check inventory for empty coconut (
coconutitem) - Check inventory for all 3 required bijas
- Consume coconut + 3 bijas
- Add charged teleport item to inventory
- Grant Magic XP
Critical Fix:
// Must pass items_db to add_item
inventory.add_item(charged_id, 1, &game_data.items)?;BreakCoconutEvent
Purpose: Player uses charged teleport to teleport
#[derive(Event)]
pub struct BreakCoconutEvent {
pub player: Entity,
pub charged_coconut_id: ItemId,
}Logic:
- Find recipe by matching
charged_coconut_id - Verify player has the charged teleport in inventory
- Consume the teleport item
- Log destination (actual teleport TODO)
- Grant Magic XP
Integration with SkillsData
File:
src/systems/data/mod.rs#[derive(Resource)]
pub struct SkillsData {
// ... existing fields
pub combat_spells: HashMap<String, CombatSpell>,
pub utility_spells: Vec<UtilitySpell>,
pub teleport_recipes: Vec<TeleportRecipe>,
}Loading Logic:
pub fn load_skills_data() -> Result<SkillsData, Box<dyn std::error::Error>> {
// Load mantras.json
let mantras_path = "data/mantras.json";
let mantras_data = std::fs::read_to_string(mantras_path)?;
let mantras: MantrasData = serde_json::from_str(&mantras_data)?;
// Convert combat_spells Vec to HashMap
let combat_spells = mantras.combat_spells.into_iter()
.map(|spell| (spell.spell_id.clone(), spell))
.collect();
Ok(SkillsData {
combat_spells,
utility_spells: mantras.utility_spells,
teleport_recipes: mantras.teleport_recipes,
// ... other fields
})
}Common Patterns
Level Checking
let magic_level = skills.get_level(SkillType::Magic);
if magic_level < spell.level_req {
warn!("Player level {} too low for spell (requires {})", magic_level, spell.level_req);
return;
}Bija Consumption
for bija in &spell.bijas {
let bija_id = ItemId(string_to_id(&bija.bija_id));
if inventory.count_item(bija_id) < bija.quantity {
warn!("Not enough {} (need {})", bija.bija_id, bija.quantity);
return;
}
}
// Consume after validation
for bija in &spell.bijas {
let bija_id = ItemId(string_to_id(&bija.bija_id));
inventory.remove_item(bija_id, bija.quantity);
}XP Granting
skills.add_xp(SkillType::Magic, spell.xp);Compilation Fixes Applied
- Fixed
add_itemcall: Added&game_data.itemsparameter - Removed old magic integration: Commented out legacy rune-checking in
combat/mod.rs - Updated imports: Changed
ItemIdimport path to match refactored inventory module - Type casting: Added
as i32for level comparisons in UI