// PUBLIC MODIFIERS
    public SpellCastResult TryCast(Mage caster, string spellcode_uppercase, ref int crystals)
    {
        SpellCastResult result = new SpellCastResult();
        Spell spell = null;

        if (spellcode_dict.ContainsKey(spellcode_uppercase))
        {
            spell = spellcode_dict[spellcode_uppercase];

            // check prerequisites
            result.on_cooldown = spell.IsOnCooldown();
            result.not_enough_resources = spell.cost > crystals;
            result.not_enough_free_slots = spell.GetFreeSlotsRequired() > caster.NumFreeSlots();

            if (!result.on_cooldown && !result.not_enough_free_slots && !result.not_enough_resources)
            {
                // successful cast
                crystals -= spell.cost;
                spell.Cast(caster);
                result.success = true;
            }
        }
        else
        {
            // bad spell code
            result.invalid_spell_code = true;
        }

        // return and events
        result.spell = spell;
        if (event_spell_cast != null) event_spell_cast(result);
        return result;
    }