#include "spell_type.hpp" #include "range.h" #include "device_allocation.h" #include "dice.h" #include "angband.h" #include #include #include #include #define SCHOOL_IDXS_MAX 3 /** * Spell type definition. */ struct spell_type { cptr name; /* Name */ byte skill_level; /* Required level (to learn) */ std::vector m_description; /* List of strings */ casting_result (*effect_func)(); /* Spell effect function */ const char* (*info_func)(); /* Information function */ int (*lasting_func)(); /* Lasting effect function */ bool_ (*depend_func)(); /* Check dependencies */ s16b minimum_pval; /* Minimum required pval for item-based spells */ enum casting_type casting_type; /* Type of casting required */ s16b casting_stat; /* Stat used for casting */ bool_ castable_while_blind; bool_ castable_while_confused; dice_type device_charges; /* Number of charges for devices */ std::vector m_device_allocation; /* Allocation table for devices */ s16b random_type; /* Type of random items in which skill may appear */ s32b failure_rate; /* Failure rate */ s32b inertia_difficulty; /* Mana cost when used in Inertia Control */ s32b inertia_delay; /* Delay between castings */ range_type mana_range; size_t school_idxs_count; s32b school_idxs[3]; public: spell_type(cptr _name) : name(_name) , skill_level(0) , m_description() , effect_func(nullptr) , info_func(nullptr) , lasting_func(nullptr) , depend_func(nullptr) , minimum_pval(0) , casting_type(USE_SPELL_POINTS) , casting_stat(0) , castable_while_blind(FALSE) , castable_while_confused(FALSE) , device_charges({ 0, 0, 0 }) , m_device_allocation() , random_type(-1) , failure_rate(0) , inertia_difficulty(-1) , inertia_delay(-1) , mana_range({ -1, -1 }) , school_idxs_count(0) , school_idxs{ -1, -1, -1 } { } }; static void school_idx_add_new(spell_type *spell, s32b i) { assert(spell != NULL); assert(spell->school_idxs_count < SCHOOL_IDXS_MAX); spell->school_idxs[spell->school_idxs_count] = i; spell->school_idxs_count++; } void spell_type_set_inertia(spell_type *spell, s32b difficulty, s32b delay) { assert(spell != NULL); spell->inertia_difficulty = difficulty; spell->inertia_delay = delay; } void spell_type_init_music(spell_type *spell, s16b minimum_pval, const char* (*info_func)(), casting_result (*effect_func)()) { assert(spell != NULL); /* Set up callbacks */ spell->info_func = info_func; spell->effect_func = effect_func; /* Use spell points, but CHR for success/failure calculations */ spell->casting_type = USE_SPELL_POINTS; spell->casting_stat = A_CHR; spell->random_type = SKILL_MUSIC; spell->minimum_pval = minimum_pval; /* Add school */ school_idx_add_new(spell, SCHOOL_MUSIC); } void spell_type_init_music_lasting(spell_type *spell, s16b minimum_pval, const char* (*info_func)(), casting_result (*effect_func)(), int (*lasting_func)()) { spell_type_init_music( spell, minimum_pval, info_func, effect_func); spell->lasting_func = lasting_func; } void spell_type_init_mage(spell_type *spell, random_type random_type, s32b school_idx, const char* (*info_func)(), casting_result (*effect_func)()) { assert(spell != NULL); spell->info_func = info_func; spell->effect_func = effect_func; spell->casting_type = USE_SPELL_POINTS; spell->casting_stat = A_INT; switch (random_type) { case RANDOM: spell->random_type = SKILL_MAGIC; break; case NO_RANDOM: spell->random_type = -1; break; default: /* Cannot happen */ assert(FALSE); } /* Add first school */ spell_type_add_school(spell, school_idx); } void spell_type_init_priest(spell_type *spell, s32b school_idx, const char* (*info_func)(), casting_result (*effect_func)()) { assert(spell != NULL); spell->info_func = info_func; spell->effect_func = effect_func; spell->random_type = SKILL_SPIRITUALITY; spell->casting_type = USE_PIETY; spell->casting_stat = A_WIS; school_idx_add_new(spell, school_idx); } void spell_type_init_device(spell_type *spell, const char* (*info_func)(), casting_result (*effect_func)()) { assert(spell != NULL); spell_type_init_mage(spell, NO_RANDOM, SCHOOL_DEVICE, info_func, effect_func); } void spell_type_init_demonology(spell_type *spell, const char* (*info_func)(), casting_result (*effect_func)()) { spell_type_init_mage(spell, NO_RANDOM, SCHOOL_DEMON, info_func, effect_func); } void spell_type_init_geomancy(spell_type *spell, const char* (*info_func)(), casting_result (*effect_func)(), bool_ (*depend_func)()) { spell_type_init_mage(spell, NO_RANDOM, SCHOOL_GEOMANCY, info_func, effect_func); spell->depend_func = depend_func; } void spell_type_set_difficulty(spell_type *spell, byte skill_level, s32b failure_rate) { assert(spell != NULL); spell->skill_level = skill_level; spell->failure_rate = failure_rate; } void spell_type_set_mana(spell_type *spell, s32b min, s32b max) { assert(spell != NULL); range_init(&spell->mana_range, min, max); } void spell_type_set_castable_while_blind(spell_type *spell, bool_ value) { assert(spell != NULL); spell->castable_while_blind = value; } void spell_type_set_castable_while_confused(spell_type *spell, bool_ value) { assert(spell != NULL); spell->castable_while_confused = value; } void spell_type_describe(spell_type *spell, cptr line) { assert(spell != NULL); spell->m_description.push_back(std::string(line)); } void spell_type_add_school(spell_type *spell, s32b school_idx) { school_idx_add_new(spell, school_idx); } void spell_type_set_device_charges(spell_type *spell, cptr charges_s) { assert(spell != NULL); dice_parse_checked(&spell->device_charges, charges_s); } void spell_type_add_device_allocation(spell_type *spell, struct device_allocation *a) { assert(spell != NULL); assert(a != NULL); spell->m_device_allocation.push_back(a); } spell_type *spell_type_new(cptr name) { spell_type *spell = new spell_type(name); assert(spell != NULL); return spell; } int spell_type_produce_effect_lasting(spell_type *spell) { assert(spell->lasting_func != NULL); return spell->lasting_func(); } casting_result spell_type_produce_effect(spell_type *spell) { assert(spell->effect_func != NULL); return spell->effect_func(); } cptr spell_type_name(spell_type *spell) { assert(spell != NULL); return spell->name; } int spell_type_skill_level(spell_type *spell) { assert(spell != NULL); return spell->skill_level; } void spell_type_description_foreach(spell_type *spell, std::function callback) { for (auto line: spell->m_description) { callback(line); } } long spell_type_roll_charges(spell_type *spell) { return dice_roll(&spell->device_charges); } device_allocation *spell_type_device_allocation(spell_type *spell, byte tval) { for (auto device_allocation_ptr: spell->m_device_allocation) { if (device_allocation_ptr->tval == tval) { return device_allocation_ptr; } } return NULL; } bool_ spell_type_uses_piety_to_cast(spell_type *spell) { assert(spell != NULL); return spell->casting_type == USE_PIETY; } bool_ spell_type_castable_while_blind(spell_type *spell) { assert(spell != NULL); return spell->castable_while_blind; } bool_ spell_type_castable_while_confused(spell_type *spell) { assert(spell != NULL); return spell->castable_while_confused; } s16b spell_type_minimum_pval(spell_type *spell) { return spell->minimum_pval; } s16b spell_type_random_type(spell_type *spell) { return spell->random_type; } std::vector const spell_type_get_schools(spell_type *spell) { std::vector school_idxs; for (size_t i = 0; i < spell->school_idxs_count; i++) { school_idxs.push_back(spell->school_idxs[i]); } return school_idxs; } bool_ spell_type_inertia(spell_type *spell, s32b *difficulty, s32b *delay) { if ((spell->inertia_difficulty < 0) || (spell->inertia_delay < 0)) { return FALSE; } if (difficulty != NULL) { *difficulty = spell->inertia_difficulty; } if (delay != NULL) { *delay = spell->inertia_delay; } return TRUE; } cptr spell_type_info(spell_type *spell) { assert(spell != NULL); return spell->info_func(); } s32b spell_type_failure_rate(spell_type *spell) { assert(spell != NULL); return spell->failure_rate; } s16b spell_type_casting_stat(spell_type *spell) { assert(spell != NULL); return spell->casting_stat; } void spell_type_mana_range(spell_type *spell, range_type *range) { assert(spell != NULL); if (range != NULL) { *range = spell->mana_range; } } bool_ spell_type_dependencies_satisfied(spell_type *spell) { assert(spell != NULL); if (spell->depend_func != NULL) { return spell->depend_func(); } else { return TRUE; } }