summaryrefslogtreecommitdiff
path: root/src/spell_type.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/spell_type.cc')
-rw-r--r--src/spell_type.cc472
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;
+ }
+}