diff options
Diffstat (limited to 'src/spell_type.cc')
-rw-r--r-- | src/spell_type.cc | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/src/spell_type.cc b/src/spell_type.cc new file mode 100644 index 00000000..33de3d7a --- /dev/null +++ b/src/spell_type.cc @@ -0,0 +1,472 @@ +#include "spell_type.h" +#include "string_list.h" +#include "range.h" +#include "device_allocation.h" +#include "dice.h" + +#include "angband.h" + +#include <type_traits> + +#define SCHOOL_IDXS_MAX 3 + +/** + * Spell type definition. + */ +struct spell_type +{ + cptr name; /* Name */ + byte skill_level; /* Required level (to learn) */ + string_list *description; /* List of strings */ + + casting_result (*effect_func)(int o_idx); /* 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 */ + struct device_allocation *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; + + dice_type activation_timeout; /* Timeout for activation (if any) */ + + int school_idxs_count; + s32b school_idxs[3]; +}; + +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_init(spell_type *spell, cptr name) +{ + assert(spell != NULL); + + static_assert(std::is_pod<spell_type>::value, "Cannot memset non-POD type"); + memset(spell, 0, sizeof(spell_type)); + + spell->name = name; + spell->description = NULL; + spell->effect_func = NULL; + spell->info_func = NULL; + spell->lasting_func = NULL; + spell->depend_func = NULL; + + spell->device_allocation = NULL; + + spell->school_idxs_count = 0; + + spell->random_type = -1; + + spell->castable_while_blind = FALSE; + spell->castable_while_confused = FALSE; + + spell_type_set_inertia(spell, -1, -1); +} + +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)(int o_idx)) +{ + 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 o_idx), + 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)(int o_idx)) +{ + 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)(int o_idx)) +{ + 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)(int o_idx)) +{ + 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)(int o_idx)) +{ + 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)(int o_idx), + 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_activation_timeout(spell_type *spell, cptr timeout_s) +{ + assert(spell != NULL); + + dice_parse_checked(&spell->activation_timeout, timeout_s); +} + +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); + + string_list_append(&spell->description, 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); + + sglib_device_allocation_add(&spell->device_allocation, a); +} + +spell_type *spell_type_new(cptr name) +{ + spell_type *spell = new spell_type; + assert(spell != NULL); + spell_type_init(spell, name); + 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, int o_idx) +{ + assert(spell->effect_func != NULL); + return spell->effect_func(o_idx); +} + +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, void (*callback)(void *data, cptr text), void *data) +{ + string_list *sl; + struct sglib_string_list_iterator it; + + assert(callback != NULL); + + for (sl = sglib_string_list_it_init(&it, spell->description); + sl != NULL; + sl = sglib_string_list_it_next(&it)) + { + callback(data, sl->s); + } +} + +long spell_type_roll_charges(spell_type *spell) +{ + return dice_roll(&spell->device_charges); +} + +void spell_type_activation_description(spell_type *spell, char *buf) +{ + char turns[32]; + + dice_print(&spell->activation_timeout, turns); + + assert(spell->description != NULL); + assert(spell->description->s != NULL); + + sprintf(buf, "%s every %s turns", spell->description->s, turns); +} + +int spell_type_activation_roll_timeout(spell_type *spell) +{ + return dice_roll(&spell->activation_timeout); +} + +device_allocation *spell_type_device_allocation(spell_type *spell, byte tval) +{ + struct sglib_device_allocation_iterator it; + device_allocation *device_allocation; + + for (device_allocation = sglib_device_allocation_it_init(&it, spell->device_allocation); + device_allocation != NULL; + device_allocation = sglib_device_allocation_it_next(&it)) + { + if (device_allocation->tval == tval) + { + return device_allocation; + } + } + + 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; +} + +bool_ spell_type_school_foreach(spell_type *spell, bool_ (*callback)(void *data, s32b school_idx), void *data) +{ + int i; + + for (i = 0; i < spell->school_idxs_count; i++) + { + if (!callback(data, spell->school_idxs[i])) + { + return FALSE; + } + } + + return TRUE; +} + +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; + } +} |