diff options
author | Bardur Arantsson <bardur@scientician.net> | 2012-06-30 08:51:51 +0200 |
---|---|---|
committer | Bardur Arantsson <bardur@scientician.net> | 2012-06-30 20:40:26 +0200 |
commit | 763a1c383895f5f04d025ba6ebf79aee9425df70 (patch) | |
tree | baaed2501a0a9815ee95261d856661244128c682 | |
parent | f7e87bc98111f97ca489e1f13999058a7df8171e (diff) |
Change spell_type to a semi-ADT
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/angband.h | 1 | ||||
-rw-r--r-- | src/cmd5.c | 5 | ||||
-rw-r--r-- | src/cmd6.c | 40 | ||||
-rw-r--r-- | src/dungeon.c | 5 | ||||
-rw-r--r-- | src/externs.h | 12 | ||||
-rw-r--r-- | src/lua_bind.c | 32 | ||||
-rw-r--r-- | src/object1.c | 36 | ||||
-rw-r--r-- | src/object2.c | 44 | ||||
-rw-r--r-- | src/spell_type.c | 465 | ||||
-rw-r--r-- | src/spell_type.h | 103 | ||||
-rw-r--r-- | src/spell_type_fwd.h | 27 | ||||
-rw-r--r-- | src/spells1.c | 4 | ||||
-rw-r--r-- | src/spells3.c | 52 | ||||
-rw-r--r-- | src/spells4.c | 143 | ||||
-rw-r--r-- | src/spells5.c | 3020 | ||||
-rw-r--r-- | src/spells6.c | 178 | ||||
-rw-r--r-- | src/store.c | 5 | ||||
-rw-r--r-- | src/types.h | 66 | ||||
-rw-r--r-- | src/variable.c | 2 |
20 files changed, 2262 insertions, 1979 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 50bb33de..03c1771b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ SET(SRCS monster1.c monster2.c monster3.c xtra1.c xtra2.c skills.c powers.c gods.c spells1.c spells2.c spells3.c spells4.c spells5.c spells6.c + spell_type.c corrupt.c joke.c mimic.c status.c files.c notes.c loadsave.c string_list.c cmd1.c cmd2.c cmd3.c cmd4.c cmd5.c cmd6.c cmd7.c diff --git a/src/angband.h b/src/angband.h index 93e3b76e..6bfbb984 100644 --- a/src/angband.h +++ b/src/angband.h @@ -55,6 +55,7 @@ extern "C" { */ #include "defines.h" #include "types.h" +#include "spell_type_fwd.h" #include "externs.h" #include "plots.h" @@ -15,6 +15,7 @@ #include <assert.h> +#include "spell_type.h" #include "quark.h" /* Maximum number of tries for teleporting */ @@ -2135,7 +2136,7 @@ bool_ is_ok_spell(s32b spell_idx, object_type *o_ptr) return FALSE; } - if (o_ptr->pval < spell->minimum_pval) + if (o_ptr->pval < spell_type_minimum_pval(spell)) { return FALSE; } @@ -2454,7 +2455,7 @@ void do_cmd_copy_spell() if (spell == -1) return; /* Spells that cannot be randomly created cannot be copied */ - if (can_spell_random(spell) <= 0) + if (spell_type_random_type(spell_at(spell)) <= 0) { msg_print("This spell cannot be copied."); return; @@ -12,6 +12,7 @@ #include "angband.h" +#include "spell_type.h" /* * Forward declare @@ -3666,9 +3667,8 @@ static void activate_stick(s16b s, bool_ *obvious, bool_ *use_charge) assert(obvious != NULL); assert(use_charge != NULL); - assert(spell->effect_func != NULL); - ret = spell->effect_func(-1); + ret = spell_type_produce_effect(spell, -1); switch (ret) { @@ -5029,35 +5029,6 @@ void do_cmd_activate(void) msg_print("Oops. That object cannot be activated."); } - -static void get_activation_desc(char *buf, int spl) -{ - spell_type *spell = spell_at(spl); - char turns[32]; - - dice_print(&spell->activation_duration, turns); - - assert(spell->description != NULL); - assert(spell->description->s != NULL); - - sprintf(buf, "%s every %s turns", - spell->description->s, - turns); -} - -static int get_activation_timeout(int spl) -{ - spell_type *spell = spell_at(spl); - return dice_roll(&spell->activation_duration); -} - -static void activate_activation(long s, int item) -{ - spell_type *spell = spell_at(s); - assert(spell->effect_func != NULL); - spell->effect_func(item); -} - const char *activation_aux(object_type * o_ptr, bool_ doit, int item) { static char buf[256]; @@ -5100,14 +5071,15 @@ const char *activation_aux(object_type * o_ptr, bool_ doit, int item) /* Negative means a unified spell index */ if (spell < 0) { + struct spell_type *spell_ptr = spell_at(-spell); if (doit) { - activate_activation(-spell, item); - o_ptr->timeout = get_activation_timeout(-spell); + spell_type_produce_effect(spell_ptr, item); + o_ptr->timeout = spell_type_activation_roll_timeout(spell_ptr); } else { - get_activation_desc(buf, -spell); + spell_type_activation_description(spell_ptr, buf); return buf; } } diff --git a/src/dungeon.c b/src/dungeon.c index ae8d6912..a74fed2c 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -15,6 +15,7 @@ #include <assert.h> #include "quark.h" +#include "spell_type.h" #define TY_CURSE_CHANCE 100 #define DG_CURSE_CHANCE 50 @@ -801,9 +802,7 @@ bool_ decays(object_type *o_ptr) static int process_lasting_spell(s16b music) { spell_type *spell = spell_at(-music); - - assert(spell->lasting_func != NULL); - return spell->lasting_func(); + return spell_type_produce_effect_lasting(spell); } static void gere_class_special() diff --git a/src/externs.h b/src/externs.h index cab134d7..290a3152 100644 --- a/src/externs.h +++ b/src/externs.h @@ -542,7 +542,7 @@ extern int max_bg_idx; extern s32b extra_savefile_parts; extern bool_ player_char_health; extern s16b school_spells_count; -extern spell_type school_spells[SCHOOL_SPELLS_MAX]; +extern spell_type *school_spells[SCHOOL_SPELLS_MAX]; extern s16b schools_count; extern school_type schools[SCHOOLS_MAX]; extern int project_time; @@ -1894,7 +1894,6 @@ char *varda_star_kindler_info(); /* spells4.c */ SGLIB_DEFINE_LIST_PROTOTYPES(spell_idx_list, compare_spell_idx, next); -SGLIB_DEFINE_LIST_PROTOTYPES(school_idx, compare_school_idx, next); extern s32b SCHOOL_AIR; extern s32b SCHOOL_AULE; @@ -1922,10 +1921,6 @@ extern s32b SCHOOL_VARDA; extern s32b SCHOOL_WATER; extern s32b SCHOOL_YAVANNA; -void school_idx_init(school_idx *e, s32b i); -school_idx *school_idx_new(s32b i); -void school_idx_add_new(school_idx **list, s32b i); - void print_spell_desc(int s, int y); void init_school_books(); school_book_type *school_books_at(int sval); @@ -1938,7 +1933,6 @@ int spell_x(int sval, int pval, int i); bool_ school_book_contains_spell(int sval, s32b spell_idx); void lua_cast_school_spell(s32b spell_idx, bool_ no_cost); -void spell_description_add_line(s32b spell_idx, cptr line); void device_allocation_init(device_allocation *device_allocation, byte tval); device_allocation *device_allocation_new(byte tval); @@ -1952,7 +1946,6 @@ void dice_print(dice_type *dice, char *buf); void school_spells_init(); spell_type *spell_at(s32b index); s16b get_random_spell(s16b random_type, int lev); -bool_ check_spell_depends(spell_type *spell); /* spells6.c */ @@ -2330,7 +2323,6 @@ extern int find_module(cptr name); /* lua_bind.c */ -extern s16b can_spell_random(s16b spell_idx); extern bool_ get_magic_power(int *sn, magic_power *powers, int max_powers, void (*power_info)(char *p, int power), int plev, int cast_stat); extern s16b add_new_power(cptr name, cptr desc, cptr gain, cptr lose, byte level, byte cost, byte stat, byte diff); @@ -2366,8 +2358,6 @@ extern timer_type *TIMER_AGGRAVATE_EVIL; void timer_aggravate_evil_enable(); void timer_aggravate_evil_callback(); -cptr get_spell_info(s32b s); - /* skills.c */ extern void dump_skills(FILE *fff); extern s16b find_skill(cptr name); diff --git a/src/lua_bind.c b/src/lua_bind.c index d6657bff..a15e9eb8 100644 --- a/src/lua_bind.c +++ b/src/lua_bind.c @@ -11,12 +11,10 @@ */ #include "angband.h" + #include <assert.h> -s16b can_spell_random(s16b spell_idx) -{ - return spell_at(spell_idx)->random_type; -} +#include "spell_type.h" /* * Monsters @@ -42,7 +40,7 @@ s32b lua_get_level(spell_type *spell, s32b lvl, s32b max, s32b min, s32b bonus) { s32b tmp; - tmp = lvl - ((spell->skill_level - 1) * (SKILL_STEP / 10)); + tmp = lvl - ((spell_type_skill_level(spell) - 1) * (SKILL_STEP / 10)); if (tmp >= (SKILL_STEP / 10)) /* We require at least one spell level */ tmp += bonus; @@ -80,9 +78,9 @@ s32b get_level_device(s32b s, s32b max, s32b min) lvl = lvl + (get_level_use_stick * SKILL_STEP); /* Sticks are limited */ - if (lvl - ((spell->skill_level + 1) * SKILL_STEP) >= get_level_max_stick * SKILL_STEP) + if (lvl - ((spell_type_skill_level(spell) + 1) * SKILL_STEP) >= get_level_max_stick * SKILL_STEP) { - lvl = (get_level_max_stick + spell->skill_level - 1) * SKILL_STEP; + lvl = (get_level_max_stick + spell_type_skill_level(spell) - 1) * SKILL_STEP; } /* / 10 because otherwise we can overflow a s32b and we can use a u32b because the value can be negative @@ -97,20 +95,22 @@ s32b get_level_device(s32b s, s32b max, s32b min) int get_mana(s32b s) { spell_type *spell = spell_at(s); - return get_level(s, spell->mana_range.max, spell->mana_range.min); + range_type mana_range; + spell_type_mana_range(spell, &mana_range); + return get_level(s, mana_range.max, mana_range.min); } /** Returns spell chance of failure for spell */ s32b spell_chance(s32b s) { - spell_type *s_ptr = &school_spells[s]; + spell_type *s_ptr = spell_at(s); int level = get_level(s, 50, 1); /* Extract the base spell failure rate */ if (get_level_use_stick > -1) { int minfail; - s32b chance = s_ptr->failure_rate; + s32b chance = spell_type_failure_rate(s_ptr); /* Reduce failure rate by "effective" level adjustment */ chance -= (level - 1); @@ -123,10 +123,10 @@ s32b spell_chance(s32b s) } else { - s32b chance = s_ptr->failure_rate; + s32b chance = spell_type_failure_rate(s_ptr); int mana = get_mana(s); int cur_mana = get_power(s); - int stat = s_ptr->casting_stat; + int stat = spell_type_casting_stat(s_ptr); int stat_ind = p_ptr->stat_ind[stat]; int minfail; @@ -340,11 +340,3 @@ void timer_aggravate_evil_callback() dispel_evil(0); } } - -cptr get_spell_info(s32b s) -{ - spell_type *spell = spell_at(s); - - assert(spell->info_func != NULL); - return spell->info_func(); -} diff --git a/src/object1.c b/src/object1.c index 3b17e8c2..504bc9c9 100644 --- a/src/object1.c +++ b/src/object1.c @@ -13,6 +13,7 @@ #include "angband.h" #include "quark.h" +#include "spell_type.h" /* * Hack -- note that "TERM_MULTI" is now just "TERM_VIOLET". @@ -1662,7 +1663,10 @@ void object_desc(char *buf, object_type *o_ptr, int pref, int mode) case TV_BOOK: { basenm = k_name + k_ptr->name; - if (o_ptr->sval == 255) modstr = school_spells[o_ptr->pval].name; + if (o_ptr->sval == 255) + { + modstr = spell_type_name(spell_at(o_ptr->pval)); + } break; } @@ -1941,7 +1945,7 @@ void object_desc(char *buf, object_type *o_ptr, int pref, int mode) if (((o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_STAFF))) { - t = object_desc_str(t, school_spells[o_ptr->pval2].name); + t = object_desc_str(t, spell_type_name(spell_at(o_ptr->pval2))); if (mode >= 1) { s32b bonus = o_ptr->pval3 & 0xFFFF; @@ -2021,7 +2025,7 @@ void object_desc(char *buf, object_type *o_ptr, int pref, int mode) /* It contains a spell */ if ((known) && (f5 & TR5_SPELL_CONTAIN) && (o_ptr->pval2 != -1)) { - t = object_desc_str(t, format(" [%s]", school_spells[o_ptr->pval2].name)); + t = object_desc_str(t, format(" [%s]", spell_type_name(spell_at(o_ptr->pval2)))); } /* Add symbiote hp here, after the "fake-artifact" name. --dsb */ @@ -2799,20 +2803,12 @@ void display_ammo_damage(object_type *o_ptr) } /* - * Describe the device spell + * Output spell description */ -static void print_device_desc(int s) +static void print_device_desc_callback(void *data, cptr text) { - string_list *sl; - struct sglib_string_list_iterator it; - - for (sl = sglib_string_list_it_init(&it, school_spells[s].description); - sl != NULL; - sl = sglib_string_list_it_next(&it)) - { - text_out("\n"); - text_out(sl->s); - } + text_out("\n"); + text_out(text); } /* @@ -2828,22 +2824,24 @@ void describe_device(object_type *o_ptr) /* Enter device mode */ set_stick_mode(o_ptr); - text_out("\nSpell description:"); - print_device_desc(o_ptr->pval2); + text_out("\nSpell description:\n"); + spell_type_description_foreach(spell_at(o_ptr->pval2), + print_device_desc_callback, + NULL); text_out("\nSpell level: "); sprintf(buf, FMTs32b, get_level(o_ptr->pval2, 50, 0)); text_out_c(TERM_L_BLUE, buf); text_out("\nMinimum Magic Device level to increase spell level: "); - text_out_c(TERM_L_BLUE, format("%d", school_spells[o_ptr->pval2].skill_level)); + text_out_c(TERM_L_BLUE, format("%d", spell_type_skill_level(spell_at(o_ptr->pval2)))); text_out("\nSpell fail: "); sprintf(buf, FMTs32b, spell_chance(o_ptr->pval2)); text_out_c(TERM_GREEN, buf); text_out("\nSpell info: "); - text_out_c(TERM_YELLOW, get_spell_info(o_ptr->pval2)); + text_out_c(TERM_YELLOW, spell_type_info(spell_at(o_ptr->pval2))); /* Leave device mode */ unset_stick_mode(); diff --git a/src/object2.c b/src/object2.c index cf413c4c..b82691ea 100644 --- a/src/object2.c +++ b/src/object2.c @@ -12,6 +12,8 @@ #include "angband.h" +#include "spell_type.h" + /* * Calculate the player's total inventory weight. */ @@ -1200,7 +1202,7 @@ s32b object_value_real(object_type *o_ptr) if (f5 & TR5_SPELL_CONTAIN) { if (o_ptr->pval2 != -1) - value += 5000 + 500 * school_spells[o_ptr->pval2].skill_level; + value += 5000 + 500 * spell_type_skill_level(spell_at(o_ptr->pval2)); else value += 5000; } @@ -1282,7 +1284,7 @@ s32b object_value_real(object_type *o_ptr) case TV_WAND: { /* Par for the spell */ - value *= school_spells[o_ptr->pval2].skill_level; + value *= spell_type_skill_level(spell_at(o_ptr->pval2)); /* Take the average of the base and max spell levels */ value *= (((o_ptr->pval3 >> 16) & 0xFFFF) + (o_ptr->pval3 & 0xFFFF)) / 2; /* Hack */ @@ -1297,7 +1299,7 @@ s32b object_value_real(object_type *o_ptr) case TV_STAFF: { /* Par for the spell */ - value *= school_spells[o_ptr->pval2].skill_level; + value *= spell_type_skill_level(spell_at(o_ptr->pval2)); /* Take the average of the base and max spell levels */ value *= (((o_ptr->pval3 >> 16) & 0xFFFF) + (o_ptr->pval3 & 0xFFFF)) / 2; /* Hack */ @@ -1314,7 +1316,7 @@ s32b object_value_real(object_type *o_ptr) if (o_ptr->sval == 255) { /* Pay extra for the spell */ - value = value * school_spells[o_ptr->pval].skill_level; + value = value * spell_type_skill_level(spell_at(o_ptr->pval)); } /* Done */ break; @@ -2536,7 +2538,7 @@ static bool_ make_ego_item(object_type *o_ptr, bool_ good) void charge_stick(object_type *o_ptr) { spell_type *spell = spell_at(o_ptr->pval2); - o_ptr->pval = dice_roll(&spell->device_charges); + o_ptr->pval = spell_type_roll_charges(spell); } /* @@ -3225,28 +3227,6 @@ static void a_m_aux_3(object_type *o_ptr, int level, int power) } } - -/* - * Get device allocation for a given spell and tval - */ -static device_allocation *get_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; -} - /* * Get a spell for a given stick(wand, staff, rod) */ @@ -3258,10 +3238,10 @@ long get_random_stick(byte tval, int level) { long spell_idx = rand_int(school_spells_count); spell_type *spell = spell_at(spell_idx); - device_allocation *device_allocation = get_device_allocation(spell, tval); + device_allocation *device_allocation = spell_type_device_allocation(spell, tval); if ((device_allocation != NULL) && - (rand_int(spell->skill_level * 3) < level) && + (rand_int(spell_type_skill_level(spell) * 3) < level) && (magik(100 - device_allocation->rarity))) { return spell_idx; @@ -3299,7 +3279,8 @@ static int randomized_level_in_range(range_type *range, int level) static int get_stick_base_level(byte tval, int level, int spl) { spell_type *spell = spell_at(spl); - device_allocation *device_allocation = get_device_allocation(spell, tval); + device_allocation *device_allocation = spell_type_device_allocation(spell, tval); + assert(device_allocation != NULL); return randomized_level_in_range(&device_allocation->base_level, level); } @@ -3309,7 +3290,8 @@ static int get_stick_base_level(byte tval, int level, int spl) static int get_stick_max_level(byte tval, int level, int spl) { spell_type *spell = spell_at(spl); - device_allocation *device_allocation = get_device_allocation(spell, tval); + device_allocation *device_allocation = spell_type_device_allocation(spell, tval); + assert(device_allocation != NULL); return randomized_level_in_range(&device_allocation->max_level, level); } diff --git a/src/spell_type.c b/src/spell_type.c new file mode 100644 index 00000000..b8bec0cd --- /dev/null +++ b/src/spell_type.c @@ -0,0 +1,465 @@ +#include "spell_type.h" + +#include "angband.h" + +#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 */ + 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 */ + + 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 */ + 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); + + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 = malloc(sizeof(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; + } +} diff --git a/src/spell_type.h b/src/spell_type.h new file mode 100644 index 00000000..32d6c7b6 --- /dev/null +++ b/src/spell_type.h @@ -0,0 +1,103 @@ +#ifndef H_e7e01ebf_e19f_439d_b88d_cad51446a7a0 +#define H_e7e01ebf_e19f_439d_b88d_cad51446a7a0 + +#include "spell_type_fwd.h" + +#include "h-type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Forward declarations + */ +struct device_allocation; +struct range_type; + +/* + * Casting type + */ +typedef enum { USE_SPELL_POINTS, USE_PIETY } casting_type; + +/* + * Does the spell appear on spell random books? + */ +typedef enum { RANDOM, NO_RANDOM } random_type; + +/* + * Spell functions + */ + +void spell_type_init(spell_type *spell, cptr name); +void spell_type_init_music(spell_type *spell, + s16b minimum_pval, + char* (*info_func)(), + casting_result (*effect_func)(int o_idx)); +void spell_type_init_music_lasting(spell_type *spell, + s16b minimum_pval, + char* (*info_func)(), + casting_result (*effect_func)(int o_idx), + int (*lasting_func)()); +void spell_type_init_mage(spell_type *spell, + random_type random_type, + s32b school_idx, + char* (*info_func)(), + casting_result (*effect_func)(int o_idx)); +void spell_type_init_priest(spell_type *spell, + s32b school_idx, + char* (*info_func)(), + casting_result (*effect_func)(int o_idx)); +void spell_type_init_device(spell_type *spell, + char* (*info_func)(), + casting_result (*effect_func)(int o_idx)); +void spell_type_init_demonology(spell_type *spell, + char* (*info_func)(), + casting_result (*effect_func)(int o_idx)); +void spell_type_init_geomancy(spell_type *spell, + char* (*info_func)(), + casting_result (*effect_func)(int o_idx), + bool_ (*depend_func)()); + +void spell_type_set_activation_timeout(spell_type *spell, cptr timeout_s); +void spell_type_set_inertia(spell_type *spell, s32b difficulty, s32b delay); +void spell_type_set_difficulty(spell_type *spell, byte skill_level, s32b failure_rate); +void spell_type_set_mana(spell_type *spell, s32b min, s32b max); +void spell_type_set_castable_while_blind(spell_type *spell, bool_ value); +void spell_type_set_castable_while_confused(spell_type *spell, bool_ value); +void spell_type_describe(spell_type *spell, cptr line); + +void spell_type_add_school(spell_type *spell, s32b school_idx); + +void spell_type_set_device_charges(spell_type *spell, cptr charges_s); +void spell_type_add_device_allocation(spell_type *spell, struct device_allocation *a); + +spell_type *spell_type_new(cptr name); + +int spell_type_produce_effect_lasting(spell_type *spell); +casting_result spell_type_produce_effect(spell_type *spell, int o_idx); +cptr spell_type_name(spell_type *spell); +int spell_type_skill_level(spell_type *spell); +void spell_type_description_foreach(spell_type *spell, void (*callback)(void *data, cptr text), void *data); +long spell_type_roll_charges(spell_type *spell); +void spell_type_activation_description(spell_type *spell, char *buf); +int spell_type_activation_roll_timeout(spell_type *spell); +struct device_allocation *spell_type_device_allocation(spell_type *spell, byte tval); +bool_ spell_type_uses_piety_to_cast(spell_type *spell); +bool_ spell_type_castable_while_blind(spell_type *spell); +bool_ spell_type_castable_while_confused(spell_type *spell); +s16b spell_type_minimum_pval(spell_type *spell); +s16b spell_type_random_type(spell_type *spell); +bool_ spell_type_school_foreach(spell_type *spell, bool_ (*callback)(void *data, s32b school_idx), void *data); +bool_ spell_type_inertia(spell_type *spell, s32b *difficulty, s32b *delay); +s32b spell_type_failure_rate(spell_type *spell); +s16b spell_type_casting_stat(spell_type *spell); +cptr spell_type_info(spell_type *spell); +void spell_type_mana_range(spell_type *spell, struct range_type *range); +bool_ spell_type_dependencies_satisfied(spell_type *spell); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/src/spell_type_fwd.h b/src/spell_type_fwd.h new file mode 100644 index 00000000..4664592c --- /dev/null +++ b/src/spell_type_fwd.h @@ -0,0 +1,27 @@ +#ifndef H_ce003b12_cf58_444f_a927_5451f6dd8af1 +#define H_ce003b12_cf58_444f_a927_5451f6dd8af1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Spell effect function result + */ +typedef enum { + NO_CAST, /* Spell not cast; user aborted */ + CAST_OBVIOUS, /* Cast; caster discovers effect (devices) */ + CAST_HIDDEN /* Cast; caster does NOT discover effect (devices) */ +} casting_result; + +/* + * Forward declaration of the spell_type + */ +typedef struct spell_type spell_type; +struct spell_type; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/src/spells1.c b/src/spells1.c index e82d708a..9981f2be 100644 --- a/src/spells1.c +++ b/src/spells1.c @@ -12,6 +12,8 @@ #include "angband.h" +#include "spell_type.h" + /* 1/x chance of reducing stats (for elemental attacks) */ #define HURT_CHANCE 32 @@ -1258,7 +1260,7 @@ void spellbinder_trigger() cmsg_print(TERM_L_GREEN, "The spellbinder is triggered!"); for (i = 0; i < p_ptr->spellbinder_num; i++) { - msg_format("Triggering spell %s.", school_spells[p_ptr->spellbinder[i]].name); + msg_format("Triggering spell %s.", spell_type_name(spell_at(p_ptr->spellbinder[i]))); lua_cast_school_spell(p_ptr->spellbinder[i], TRUE); } p_ptr->spellbinder_num = 0; diff --git a/src/spells3.c b/src/spells3.c index bb67ac61..269e861a 100644 --- a/src/spells3.c +++ b/src/spells3.c @@ -2,6 +2,8 @@ #include <assert.h> +#include "spell_type.h" + s32b NOXIOUSCLOUD = -1; /* Identifier */ s32b AIRWINGS = -1; /* Identifier */ s32b INVISIBILITY; @@ -2357,7 +2359,7 @@ casting_result meta_spellbinder(int item) msg_print("With the spells: "); for (i = 0; i < p_ptr->spellbinder_num; i++) { - msg_print(school_spells[p_ptr->spellbinder[i]].name); + msg_print(spell_type_name(spell_at(p_ptr->spellbinder[i]))); } /* Doesn't cost anything */ @@ -2400,7 +2402,7 @@ casting_result meta_spellbinder(int item) p_ptr->spellbinder_num = 0; return CAST_OBVIOUS; } else { - if (school_spells[s].skill_level > 7 + get_level_s(SPELLBINDER, 35)) + if (spell_type_skill_level(spell_at(s)) > 7 + get_level_s(SPELLBINDER, 35)) { msg_format("You are only allowed spells with a base level of " FMTs32b ".", (7 + get_level_s(SPELLBINDER, 35))); return CAST_OBVIOUS; @@ -2503,7 +2505,7 @@ void meta_inertia_control_hook_birth_objects() casting_result meta_inertia_control(int item) { - s32b s; + s32b s, difficulty, delay; spell_type *spell; if (p_ptr->inertia_controlled_spell != -1) @@ -2522,27 +2524,26 @@ casting_result meta_inertia_control(int item) spell = spell_at(s); - if ((spell->inertia_difficulty < 0) || - (spell->inertia_delay < 0)) + if (!spell_type_inertia(spell, &difficulty, &delay)) { msg_print("This spell inertia flow can not be controlled."); stop_inertia_controlled_spell(); return NO_CAST; } - if (spell->inertia_difficulty > get_level_s(INERTIA_CONTROL, 10)) + if (difficulty > get_level_s(INERTIA_CONTROL, 10)) { - msg_format("This spell inertia flow(%d) is too strong to be controlled by your current spell.", spell->inertia_difficulty); + msg_format("This spell inertia flow(" FMTs32b ") is too strong to be controlled by your current spell.", difficulty); stop_inertia_controlled_spell(); return NO_CAST; } p_ptr->inertia_controlled_spell = s; TIMER_INERTIA_CONTROL->enabled = TRUE; - TIMER_INERTIA_CONTROL->delay = spell->inertia_delay; - TIMER_INERTIA_CONTROL->countdown = TIMER_INERTIA_CONTROL->delay; + TIMER_INERTIA_CONTROL->delay = delay; + TIMER_INERTIA_CONTROL->countdown = delay; p_ptr->update |= PU_MANA; - msg_format("Inertia flow controlling spell %s.", school_spells[s].name); + msg_format("Inertia flow controlling spell %s.", spell_type_name(spell_at(s))); return CAST_OBVIOUS; } @@ -2938,6 +2939,20 @@ char *tulkas_whirlwind_info() return ""; } +static bool_ check_school_is_udun(void *data, s32b school_idx) +{ + int *count = (int *) data; + + if ((school_idx == SCHOOL_UDUN) || + (school_idx == SCHOOL_MELKOR)) + { + (*count)++; + } + + /* Keep going */ + return TRUE; +} + /* Return the number of Udun/Melkor spells in a given book */ int udun_in_book(s32b sval, s32b pval) { @@ -2957,20 +2972,7 @@ int udun_in_book(s32b sval, s32b pval) spell_idx = sglib_spell_idx_list_it_next(&it)) { spell_type *spell = spell_at(spell_idx->i); - school_idx *school_idx = NULL; - struct sglib_school_idx_iterator sit; - - for (school_idx = sglib_school_idx_it_init(&sit, spell->schools); - school_idx != NULL; - school_idx = sglib_school_idx_it_next(&sit)) - { - int sch = school_idx->i; - if ((sch == SCHOOL_UDUN) || - (sch == SCHOOL_MELKOR)) - { - count++; - } - } + spell_type_school_foreach(spell, check_school_is_udun, &count); } return count; @@ -2996,7 +2998,7 @@ int levels_in_book(s32b sval, s32b pval) s32b s = spell_idx->i; spell_type *spell = spell_at(s); - levels += spell->skill_level; + levels += spell_type_skill_level(spell); } return levels; diff --git a/src/spells4.c b/src/spells4.c index f3809b7b..c977742d 100644 --- a/src/spells4.c +++ b/src/spells4.c @@ -2,6 +2,8 @@ #include <assert.h> +#include "spell_type.h" + school_book_type school_books[SCHOOL_BOOKS_SIZE]; s32b SCHOOL_AIR; @@ -37,52 +39,9 @@ static int compare_spell_idx(spell_idx_list *a, spell_idx_list *b) SGLIB_DEFINE_LIST_FUNCTIONS(spell_idx_list, compare_spell_idx, next); -static int compare_school_idx(school_idx *a, school_idx *b) -{ - return SGLIB_NUMERIC_COMPARATOR(a->i, b->i); -} - -SGLIB_DEFINE_LIST_FUNCTIONS(school_idx, compare_school_idx, next); - -void school_idx_init(school_idx *e, s32b i) -{ - assert(e != NULL); - - e->i = i; - e->next = NULL; -} - -school_idx *school_idx_new(s32b i) -{ - school_idx *e = malloc(sizeof(school_idx)); - assert(e != NULL); - - school_idx_init(e, i); - - return e; -} - -void school_idx_add_new(school_idx **list, s32b i) -{ - school_idx *e = school_idx_new(i); - assert(e != NULL); - - sglib_school_idx_add(list, e); -} - static bool_ uses_piety_to_cast(int s) { - return spell_at(s)->casting_type == USE_PIETY; -} - -static bool_ castable_while_blind(int s) -{ - return spell_at(s)->castable_while_blind; -} - -static bool_ castable_while_confused(int s) -{ - return spell_at(s)->castable_while_confused; + return spell_type_uses_piety_to_cast(spell_at(s)); } /** Describe what type of energy the spell uses for casting */ @@ -110,31 +69,36 @@ s32b get_power(s32b s) return uses_piety_to_cast(s) ? p_ptr->grace : p_ptr->csp; } +static void print_spell_desc_callback(void *data, cptr text) +{ + int *y = (int *) data; + + c_prt(TERM_L_BLUE, text, *y, 0); + (*y) += 1; +} + /* Output the describtion when it is used as a spell */ void print_spell_desc(int s, int y) { - string_list *sl; - struct sglib_string_list_iterator it; + spell_type *spell = spell_at(s); - for (sl = sglib_string_list_it_init(&it, school_spells[s].description); - sl != NULL; - sl = sglib_string_list_it_next(&it)) - { - c_prt(TERM_L_BLUE, sl->s, y, 0); - y++; - } + spell_type_description_foreach(spell, + print_spell_desc_callback, + &y); - if (uses_piety_to_cast(s)) + if (spell_type_uses_piety_to_cast(spell)) { c_prt(TERM_L_WHITE, "It uses piety to cast.", y, 0); y++; } - if (castable_while_blind(s)) + + if (spell_type_castable_while_blind(spell)) { c_prt(TERM_ORANGE, "It is castable even while blinded.", y, 0); y++; } - if (castable_while_confused(s)) + + if (spell_type_castable_while_confused(spell)) { c_prt(TERM_ORANGE, "It is castable even while confused.", y, 0); y++; @@ -478,30 +442,30 @@ void random_book_setup(s16b sval, s32b spell_idx) } } -static void spell_school_name(char *buf, spell_type *spell) +static bool_ spell_school_name_callback(void *data, s32b sch) { - school_idx *school_idx = NULL; - struct sglib_school_idx_iterator sit; - bool_ first = TRUE; - - buf[0] = '\0'; + school_type *school = school_at(sch); + char *buf = (char *) data; - for (school_idx = sglib_school_idx_it_init(&sit, spell->schools); - school_idx != NULL; - school_idx = sglib_school_idx_it_next(&sit)) + /* Add separator? */ + if (buf[0] != '\0') { - int sch = school_idx->i; - school_type *school = school_at(sch); - /* Add separator? */ - if (!first) - { - strcat(buf, "/"); - } - first = FALSE; - - /* Add school name */ - strcat(buf, school->name); + strcat(buf, "/"); } + + /* Add school name */ + strcat(buf, school->name); + + /* Keep going */ + return TRUE; +} + +static void spell_school_name(char *buf, spell_type *spell) +{ + buf[0] = '\0'; + spell_type_school_foreach(spell, + spell_school_name_callback, + buf); } int print_spell(cptr label_, byte color, int y, s32b s) @@ -510,7 +474,7 @@ int print_spell(cptr label_, byte color, int y, s32b s) bool_ na; spell_type *spell = spell_at(s); char sch_str[128]; - cptr spell_info = get_spell_info(s); + cptr spell_info = spell_type_info(spell); cptr label = (label_ == NULL) ? "" : label_; char level_str[8] = "n/a"; char buf[128]; @@ -525,7 +489,7 @@ int print_spell(cptr label_, byte color, int y, s32b s) sprintf(buf, "%s%-20s%-16s %s %4d %3d%% %s", label, - school_spells[s].name, + spell_type_name(spell_at(s)), sch_str, level_str, get_mana(s), @@ -575,16 +539,10 @@ int print_book(s16b sval, s32b pval, object_type *obj) return y; } -static bool_ call_spell_function(s32b s) -{ - spell_type *spell = spell_at(s); - assert(spell->effect_func != NULL); - return (spell->effect_func(-1) != NO_CAST); -} - void lua_cast_school_spell(s32b s, bool_ no_cost) { bool_ use = FALSE; + spell_type *spell = spell_at(s); /* No magic? */ if (p_ptr->antimagic > 0) @@ -604,14 +562,16 @@ void lua_cast_school_spell(s32b s, bool_ no_cost) if (!no_cost) { /* Require lite */ - if (!castable_while_blind(s) && ((p_ptr->blind > 0) || no_lite())) + if (!spell_type_castable_while_blind(spell) && + ((p_ptr->blind > 0) || no_lite())) { msg_print("You cannot see!"); return; } /* Not when confused */ - if (!castable_while_confused(s) && (p_ptr->confused > 0)) + if (!spell_type_castable_while_confused(spell) && + (p_ptr->confused > 0)) { msg_print("You are too confused!"); return; @@ -634,7 +594,7 @@ void lua_cast_school_spell(s32b s, bool_ no_cost) /* Invoke the spell effect */ if (!magik(spell_chance(s))) { - use = call_spell_function(s); + use = (spell_type_produce_effect(spell, -1) != NO_CAST); } else { @@ -652,7 +612,7 @@ void lua_cast_school_spell(s32b s, bool_ no_cost) } else { - call_spell_function(s); + spell_type_produce_effect(spell, -1); } /* Use the mana/piety */ @@ -670,11 +630,6 @@ void lua_cast_school_spell(s32b s, bool_ no_cost) p_ptr->window |= PW_PLAYER; } -void spell_description_add_line(s32b spell_idx, cptr line) -{ - string_list_append(&school_spells[spell_idx].description, line); -} - void device_allocation_init(device_allocation *device_allocation, byte tval) { assert(device_allocation != NULL); diff --git a/src/spells5.c b/src/spells5.c index d2d9eda2..7ad0d3b9 100644 --- a/src/spells5.c +++ b/src/spells5.c @@ -1,45 +1,15 @@ #include <angband.h> -#include <assert.h> - -typedef enum { RANDOM, NO_RANDOM } random_type; - -static void spell_inertia_init(spell_type *spell, s32b diff, s32b delay) -{ - spell->inertia_difficulty = diff; - spell->inertia_delay = delay; -} - -static void spell_init(spell_type *spell) -{ - memset(spell, 0, sizeof(spell_type)); - - spell->name = NULL; - spell->description = NULL; - spell->effect_func = NULL; - spell->info_func = NULL; - spell->lasting_func = NULL; - spell->depend_func = NULL; - - spell->device_allocation = NULL; - spell->schools = NULL; - spell->random_type = -1; - - spell_inertia_init(spell, -1, -1); +#include <assert.h> - spell->castable_while_blind = FALSE; - spell->castable_while_confused = FALSE; -} +#include "spell_type.h" static spell_type *spell_new(s32b *index, cptr id, cptr name) { assert(school_spells_count < SCHOOL_SPELLS_MAX); - spell_type *spell = &school_spells[school_spells_count]; - - spell_init(spell); - spell->name = name; - + spell_type *spell = spell_type_new(name); + school_spells[school_spells_count] = spell; *index = school_spells_count; school_spells_count++; @@ -51,7 +21,7 @@ spell_type *spell_at(s32b index) assert(index >= 0); assert(index < school_spells_count); - return &school_spells[index]; + return school_spells[index]; } int find_spell(cptr name) @@ -60,8 +30,7 @@ int find_spell(cptr name) for (i = 0; i < school_spells_count; i++) { - spell_type *spell = spell_at(i); - if (streq(spell->name, name)) + if (streq(spell_type_name(spell_at(i)), name)) { return i; } @@ -80,8 +49,8 @@ s16b get_random_spell(s16b random_type, int level) s16b spl = rand_int(school_spells_count); spell_type *spell = spell_at(spl); - if ((can_spell_random(spl) == random_type) && - (rand_int(spell->skill_level * 3) < level)) + if ((spell_type_random_type(spell) == random_type) && + (rand_int(spell_type_skill_level(spell) * 3) < level)) { return spl; } @@ -90,106 +59,47 @@ s16b get_random_spell(s16b random_type, int level) return -1; } -bool_ check_spell_depends(spell_type *spell) -{ - assert(spell != NULL); - - if (spell->depend_func != NULL) { - return spell->depend_func(); - } else { - return TRUE; - } -} - -static void spell_init_music(spell_type *spell, s16b minimum_pval) -{ - assert(spell != NULL); - /* 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->schools, SCHOOL_MUSIC); -} - -static void spell_init_mage(spell_type *spell, random_type random_type) -{ - assert(spell != NULL); - - 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); - } -} - -static void spell_init_priest(spell_type *spell) -{ - assert(spell != NULL); - - spell->random_type = SKILL_SPIRITUALITY; - spell->casting_type = USE_PIETY; - spell->casting_stat = A_WIS; -} - static void spells_init_tome() { { spell_type *spell = spell_new(&DEVICE_LEBOHAUM, "DEVICE_LEBOHAUM", "Artifact Lebauhaum"); - dice_parse_checked(&spell->activation_duration, "3"); - string_list_append(&spell->description, "sing a cheerful song"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 0, 0); - spell->info_func = device_lebohaum_info; - spell->effect_func = device_lebohaum; - spell->failure_rate = 0; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_set_activation_timeout(spell, "3"); + spell_type_describe(spell, "sing a cheerful song"); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, 0); + spell_type_init_device(spell, + device_lebohaum_info, + device_lebohaum); } { spell_type *spell = spell_new(&DEVICE_DURANDIL, "DEVICE_DURANDIL", "Artifact Durandil"); - dice_parse_checked(&spell->activation_duration, "3"); - string_list_append(&spell->description, "sing a cheerful song"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 0, 0); - spell->info_func = device_durandil_info; - spell->effect_func = device_durandil; - spell->failure_rate = 0; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_set_activation_timeout(spell, "3"); + spell_type_describe(spell, "sing a cheerful song"); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, 0); + spell_type_init_device(spell, + device_durandil_info, + device_durandil); } { spell_type *spell = spell_new(&DEVICE_THUNDERLORDS, "DEVICE_THUNDERLORDS", "Artifact Thunderlords"); - string_list_append(&spell->description, "A thunderlord will appear to transport you quickly to the surface."); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 1, 1); - spell->info_func = device_thunderlords_info; - spell->effect_func = device_thunderlords; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "A thunderlord will appear to transport you quickly to the surface."); + spell_type_set_mana(spell, 1, 1); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_device(spell, + device_thunderlords_info, + device_thunderlords); - dice_parse_checked(&spell->device_charges, "3+d3"); + spell_type_set_device_charges(spell, "3+d3"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 999; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 1, 1); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } } @@ -198,2139 +108,2073 @@ static void spells_init_theme() { { spell_type *spell = spell_new(&GROW_ATHELAS, "GROW_ATHELAS", "Grow Athelas"); - string_list_append(&spell->description, "Cures the Black Breath"); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - range_init(&spell->mana_range, 60, 100); - spell->info_func = nature_grow_athelas_info; - spell->effect_func = nature_grow_athelas; - spell->failure_rate = 95; - spell->skill_level = 30; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Cures the Black Breath"); + spell_type_set_mana(spell, 60, 100); + spell_type_set_difficulty(spell, 30, 95); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_NATURE, + nature_grow_athelas_info, + nature_grow_athelas); - dice_parse_checked(&spell->device_charges, "1+d3"); + spell_type_set_device_charges(spell, "1+d3"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 85; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 15, 45); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&AULE_FIREBRAND, "AULE_FIREBRAND", "Firebrand"); - string_list_append(&spell->description, "Imbues your melee weapon with fire to deal more damage"); - string_list_append(&spell->description, "At level 15 it spreads over a 1 radius zone around your target"); - string_list_append(&spell->description, "At level 30 it deals holy fire damage"); - school_idx_add_new(&spell->schools, SCHOOL_AULE); - range_init(&spell->mana_range, 10, 100); - spell->info_func = aule_firebrand_info; - spell->effect_func = aule_firebrand_spell; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_priest(spell); + spell_type_describe(spell, "Imbues your melee weapon with fire to deal more damage"); + spell_type_describe(spell, "At level 15 it spreads over a 1 radius zone around your target"); + spell_type_describe(spell, "At level 30 it deals holy fire damage"); + spell_type_set_mana(spell, 10, 100); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_priest(spell, + SCHOOL_AULE, + aule_firebrand_info, + aule_firebrand_spell); } { spell_type *spell = spell_new(&AULE_ENCHANT_WEAPON, "AULE_ENCHANT_WEAPON", "Enchant Weapon"); - string_list_append(&spell->description, "Tries to enchant a weapon to-hit"); - string_list_append(&spell->description, "At level 5 it also enchants to-dam"); - string_list_append(&spell->description, "At level 45 it enhances the special powers of magical weapons"); - string_list_append(&spell->description, "The might of the enchantment increases with the level"); - school_idx_add_new(&spell->schools, SCHOOL_AULE); - range_init(&spell->mana_range, 100, 200); - spell->info_func = aule_enchant_weapon_info; - spell->effect_func = aule_enchant_weapon_spell; - spell->failure_rate = 20; - spell->skill_level = 10; - spell_init_priest(spell); + spell_type_describe(spell, "Tries to enchant a weapon to-hit"); + spell_type_describe(spell, "At level 5 it also enchants to-dam"); + spell_type_describe(spell, "At level 45 it enhances the special powers of magical weapons"); + spell_type_describe(spell, "The might of the enchantment increases with the level"); + spell_type_set_mana(spell, 100, 200); + spell_type_set_difficulty(spell, 10, 20); + spell_type_init_priest(spell, + SCHOOL_AULE, + aule_enchant_weapon_info, + aule_enchant_weapon_spell); } { spell_type *spell = spell_new(&AULE_ENCHANT_ARMOUR, "AULE_ENCHANT_ARMOUR", "Enchant Armour"); - string_list_append(&spell->description, "Tries to enchant a piece of armour"); - string_list_append(&spell->description, "At level 20 it also enchants to-hit and to-dam"); - string_list_append(&spell->description, "At level 40 it enhances the special powers of magical armour"); - string_list_append(&spell->description, "The might of the enchantment increases with the level"); - school_idx_add_new(&spell->schools, SCHOOL_AULE); - range_init(&spell->mana_range, 100, 200); - spell->info_func = aule_enchant_armour_info; - spell->effect_func = aule_enchant_armour_spell; - spell->failure_rate = 20; - spell->skill_level = 15; - spell_init_priest(spell); + spell_type_describe(spell, "Tries to enchant a piece of armour"); + spell_type_describe(spell, "At level 20 it also enchants to-hit and to-dam"); + spell_type_describe(spell, "At level 40 it enhances the special powers of magical armour"); + spell_type_describe(spell, "The might of the enchantment increases with the level"); + spell_type_set_mana(spell, 100, 200); + spell_type_set_difficulty(spell, 15, 20); + spell_type_init_priest(spell, + SCHOOL_AULE, + aule_enchant_armour_info, + aule_enchant_armour_spell); } { spell_type *spell = spell_new(&AULE_CHILD, "AULE_CHILD", "Child of Aule"); - string_list_append(&spell->description, "Summons a levelled Dwarven warrior to help you battle the forces"); - string_list_append(&spell->description, "of Morgoth"); - school_idx_add_new(&spell->schools, SCHOOL_AULE); - range_init(&spell->mana_range, 200, 500); - spell->info_func = aule_child_info; - spell->effect_func = aule_child_spell; - spell->failure_rate = 40; - spell->skill_level = 20; - spell_init_priest(spell); + spell_type_describe(spell, "Summons a levelled Dwarven warrior to help you battle the forces"); + spell_type_describe(spell, "of Morgoth"); + spell_type_set_mana(spell, 200, 500); + spell_type_set_difficulty(spell, 20, 40); + spell_type_init_priest(spell, + SCHOOL_AULE, + aule_child_info, + aule_child_spell); } { spell_type *spell = spell_new(&VARDA_LIGHT_VALINOR, "VARDA_LIGHT_VALINOR", "Light of Valinor"); - string_list_append(&spell->description, "Lights a room"); - string_list_append(&spell->description, "At level 3 it starts damaging monsters"); - string_list_append(&spell->description, "At level 15 it starts creating a more powerful kind of light"); - school_idx_add_new(&spell->schools, SCHOOL_VARDA); - range_init(&spell->mana_range, 1, 100); - spell->info_func = varda_light_of_valinor_info; - spell->effect_func = varda_light_of_valinor_spell; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_priest(spell); + spell_type_describe(spell, "Lights a room"); + spell_type_describe(spell, "At level 3 it starts damaging monsters"); + spell_type_describe(spell, "At level 15 it starts creating a more powerful kind of light"); + spell_type_set_mana(spell, 1, 100); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_priest(spell, + SCHOOL_VARDA, + varda_light_of_valinor_info, + varda_light_of_valinor_spell); } { spell_type *spell = spell_new(&VARDA_CALL_ALMAREN, "VARDA_CALL_ALMAREN", "Call of Almaren"); - string_list_append(&spell->description, "Banishes evil beings"); - string_list_append(&spell->description, "At level 20 it dispels evil beings"); - school_idx_add_new(&spell->schools, SCHOOL_VARDA); - range_init(&spell->mana_range, 5, 150); - spell->info_func = varda_call_of_almaren_info; - spell->effect_func = varda_call_of_almaren_spell; - spell->failure_rate = 20; - spell->skill_level = 10; - spell_init_priest(spell); + spell_type_describe(spell, "Banishes evil beings"); + spell_type_describe(spell, "At level 20 it dispels evil beings"); + spell_type_set_mana(spell, 5, 150); + spell_type_set_difficulty(spell, 10, 20); + spell_type_init_priest(spell, + SCHOOL_VARDA, + varda_call_of_almaren_info, + varda_call_of_almaren_spell); } { spell_type *spell = spell_new(&VARDA_EVENSTAR, "VARDA_EVENSTAR", "Evenstar"); - string_list_append(&spell->description, "Maps and lights the whole level."); - string_list_append(&spell->description, "At level 40 it maps and lights the whole level,"); - string_list_append(&spell->description, "in addition to letting you know yourself better"); - string_list_append(&spell->description, "and identifying your whole pack."); - school_idx_add_new(&spell->schools, SCHOOL_VARDA); - range_init(&spell->mana_range, 20, 200); - spell->info_func = varda_evenstar_info; - spell->effect_func = varda_evenstar_spell; - spell->failure_rate = 20; - spell->skill_level = 20; - spell_init_priest(spell); + spell_type_describe(spell, "Maps and lights the whole level."); + spell_type_describe(spell, "At level 40 it maps and lights the whole level,"); + spell_type_describe(spell, "in addition to letting you know yourself better"); + spell_type_describe(spell, "and identifying your whole pack."); + spell_type_set_mana(spell, 20, 200); + spell_type_set_difficulty(spell, 20, 20); + spell_type_init_priest(spell, + SCHOOL_VARDA, + varda_evenstar_info, + varda_evenstar_spell); } { spell_type *spell = spell_new(&VARDA_STARKINDLER, "VARDA_STARKINDLER", "Star Kindler"); - string_list_append(&spell->description, "Does multiple bursts of light damage."); - string_list_append(&spell->description, "The damage increases with level."); - school_idx_add_new(&spell->schools, SCHOOL_VARDA); - range_init(&spell->mana_range, 50, 250); - spell->info_func = varda_star_kindler_info; - spell->effect_func = varda_star_kindler_spell; - spell->failure_rate = 20; - spell->skill_level = 30; - spell_init_priest(spell); + spell_type_describe(spell, "Does multiple bursts of light damage."); + spell_type_describe(spell, "The damage increases with level."); + spell_type_set_mana(spell, 50, 250); + spell_type_set_difficulty(spell, 30, 20); + spell_type_init_priest(spell, + SCHOOL_VARDA, + varda_star_kindler_info, + varda_star_kindler_spell); } { spell_type *spell = spell_new(&ULMO_BELEGAER, "ULMO_BELEGAER", "Song of Belegaer"); - string_list_append(&spell->description, "Channels the power of the Great Sea into your fingertips."); - string_list_append(&spell->description, "Sometimes it can blast through its first target."); - school_idx_add_new(&spell->schools, SCHOOL_ULMO); - range_init(&spell->mana_range, 1, 100); - spell->info_func = ulmo_song_of_belegaer_info; - spell->effect_func = ulmo_song_of_belegaer_spell; - spell->failure_rate = 25; - spell->skill_level = 1; - spell_init_priest(spell); + spell_type_describe(spell, "Channels the power of the Great Sea into your fingertips."); + spell_type_describe(spell, "Sometimes it can blast through its first target."); + spell_type_set_mana(spell, 1, 100); + spell_type_set_difficulty(spell, 1, 25); + spell_type_init_priest(spell, + SCHOOL_ULMO, + ulmo_song_of_belegaer_info, + ulmo_song_of_belegaer_spell); } { spell_type *spell = spell_new(&ULMO_DRAUGHT_ULMONAN, "ULMO_DRAUGHT_ULMONAN", "Draught of Ulmonan"); - string_list_append(&spell->description, "Fills you with a draught with powerful curing effects,"); - string_list_append(&spell->description, "prepared by Ulmo himself."); - string_list_append(&spell->description, "Level 1: blindness, poison, cuts and stunning"); - string_list_append(&spell->description, "Level 10: drained STR, DEX and CON"); - string_list_append(&spell->description, "Level 20: parasites and mimicry"); - school_idx_add_new(&spell->schools, SCHOOL_ULMO); - range_init(&spell->mana_range, 25, 200); - spell->info_func = ulmo_draught_of_ulmonan_info; - spell->effect_func = ulmo_draught_of_ulmonan_spell; - spell->failure_rate = 50; - spell->skill_level = 15; - spell_init_priest(spell); + spell_type_describe(spell, "Fills you with a draught with powerful curing effects,"); + spell_type_describe(spell, "prepared by Ulmo himself."); + spell_type_describe(spell, "Level 1: blindness, poison, cuts and stunning"); + spell_type_describe(spell, "Level 10: drained STR, DEX and CON"); + spell_type_describe(spell, "Level 20: parasites and mimicry"); + spell_type_set_mana(spell, 25, 200); + spell_type_set_difficulty(spell, 15, 50); + spell_type_init_priest(spell, + SCHOOL_ULMO, + ulmo_draught_of_ulmonan_info, + ulmo_draught_of_ulmonan_spell); } { spell_type *spell = spell_new(&ULMO_CALL_ULUMURI, "ULMO_CALL_ULUMURI", "Call of the Ulumuri"); - string_list_append(&spell->description, "Summons a leveled water spirit or elemental"); - string_list_append(&spell->description, "to fight for you"); - school_idx_add_new(&spell->schools, SCHOOL_ULMO); - range_init(&spell->mana_range, 50, 300); - spell->info_func = ulmo_call_of_the_ulumuri_info; - spell->effect_func = ulmo_call_of_the_ulumuri_spell; - spell->failure_rate = 75; - spell->skill_level = 20; - spell_init_priest(spell); + spell_type_describe(spell, "Summons a leveled water spirit or elemental"); + spell_type_describe(spell, "to fight for you"); + spell_type_set_mana(spell, 50, 300); + spell_type_set_difficulty(spell, 20, 75); + spell_type_init_priest(spell, + SCHOOL_ULMO, + ulmo_call_of_the_ulumuri_info, + ulmo_call_of_the_ulumuri_spell); } { spell_type *spell = spell_new(&ULMO_WRATH, "ULMO_WRATH", "Wrath of Ulmo"); - string_list_append(&spell->description, "Conjures up a sea storm."); - string_list_append(&spell->description, "At level 30 it turns into a more forceful storm."); - school_idx_add_new(&spell->schools, SCHOOL_ULMO); - range_init(&spell->mana_range, 100, 400); - spell->info_func = ulmo_wrath_of_ulmo_info; - spell->effect_func = ulmo_wrath_of_ulmo_spell; - spell->failure_rate = 95; - spell->skill_level = 30; - spell_init_priest(spell); + spell_type_describe(spell, "Conjures up a sea storm."); + spell_type_describe(spell, "At level 30 it turns into a more forceful storm."); + spell_type_set_mana(spell, 100, 400); + spell_type_set_difficulty(spell, 30, 95); + spell_type_init_priest(spell, + SCHOOL_ULMO, + ulmo_wrath_of_ulmo_info, + ulmo_wrath_of_ulmo_spell); } { spell_type *spell = spell_new(&MANDOS_TEARS_LUTHIEN, "MANDOS_TEARS_LUTHIEN", "Tears of Luthien"); - string_list_append(&spell->description, "Calls upon the spirit of Luthien to ask Mandos for healing and succour."); - school_idx_add_new(&spell->schools, SCHOOL_MANDOS); - range_init(&spell->mana_range, 10, 100); - spell->info_func = mandos_tears_of_luthien_info; - spell->effect_func = mandos_tears_of_luthien_spell; - spell->failure_rate = 25; - spell->skill_level = 5; - spell_init_priest(spell); + spell_type_describe(spell, "Calls upon the spirit of Luthien to ask Mandos for healing and succour."); + spell_type_set_mana(spell, 10, 100); + spell_type_set_difficulty(spell, 5, 25); + spell_type_init_priest(spell, + SCHOOL_MANDOS, + mandos_tears_of_luthien_info, + mandos_tears_of_luthien_spell); } { spell_type *spell = spell_new(&MANDOS_SPIRIT_FEANTURI, "MANDOS_SPIRIT_FEANTURI", "Feanturi"); - string_list_append(&spell->description, "Channels the power of Mandos to cure fear and confusion."); - string_list_append(&spell->description, "At level 20 it restores lost INT and WIS"); - string_list_append(&spell->description, "At level 30 it cures hallucinations and restores a percentage of lost sanity"); - school_idx_add_new(&spell->schools, SCHOOL_MANDOS); - range_init(&spell->mana_range, 40, 200); - spell->info_func = mandos_spirit_of_the_feanturi_info; - spell->effect_func = mandos_spirit_of_the_feanturi_spell; - spell->failure_rate = 50; - spell->skill_level = 10; - spell_init_priest(spell); + spell_type_describe(spell, "Channels the power of Mandos to cure fear and confusion."); + spell_type_describe(spell, "At level 20 it restores lost INT and WIS"); + spell_type_describe(spell, "At level 30 it cures hallucinations and restores a percentage of lost sanity"); + spell_type_set_mana(spell, 40, 200); + spell_type_set_difficulty(spell, 10, 50); + spell_type_init_priest(spell, + SCHOOL_MANDOS, + mandos_spirit_of_the_feanturi_info, + mandos_spirit_of_the_feanturi_spell); } { spell_type *spell = spell_new(&MANDOS_TALE_DOOM, "MANDOS_TALE_DOOM", "Tale of Doom"); - string_list_append(&spell->description, "Allows you to predict the future for a short time."); - school_idx_add_new(&spell->schools, SCHOOL_MANDOS); - range_init(&spell->mana_range, 60, 300); - spell->info_func = mandos_tale_of_doom_info; - spell->effect_func = mandos_tale_of_doom_spell; - spell->failure_rate = 75; - spell->skill_level = 25; - spell_init_priest(spell); + spell_type_describe(spell, "Allows you to predict the future for a short time."); + spell_type_set_mana(spell, 60, 300); + spell_type_set_difficulty(spell, 25, 75); + spell_type_init_priest(spell, + SCHOOL_MANDOS, + mandos_tale_of_doom_info, + mandos_tale_of_doom_spell); } { spell_type *spell = spell_new(&MANDOS_CALL_HALLS, "MANDOS_CALL_HALLS", "Call to the Halls"); - string_list_append(&spell->description, "Summons a leveled spirit from the Halls of Mandos"); - string_list_append(&spell->description, "to fight for you."); - school_idx_add_new(&spell->schools, SCHOOL_MANDOS); - range_init(&spell->mana_range, 80, 400); - spell->info_func = mandos_call_to_the_halls_info; - spell->effect_func = mandos_call_to_the_halls_spell; - spell->failure_rate = 95; - spell->skill_level = 30; - spell_init_priest(spell); + spell_type_describe(spell, "Summons a leveled spirit from the Halls of Mandos"); + spell_type_describe(spell, "to fight for you."); + spell_type_set_mana(spell, 80, 400); + spell_type_set_difficulty(spell, 30, 95); + spell_type_init_priest(spell, + SCHOOL_MANDOS, + mandos_call_to_the_halls_info, + mandos_call_to_the_halls_spell); } { spell_type *spell = spell_new(&DEVICE_THUNDERLORDS, "DEVICE_THUNDERLORDS", "Artifact Thunderlords"); - string_list_append(&spell->description, "An Eagle of Manwe will appear to transport you quickly to the town."); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 1, 1); - spell->info_func = device_thunderlords_info; - spell->effect_func = device_thunderlords; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "An Eagle of Manwe will appear to transport you quickly to the town."); + spell_type_set_mana(spell, 1, 1); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_device(spell, + device_thunderlords_info, + device_thunderlords); - dice_parse_checked(&spell->device_charges, "5+d5"); + spell_type_set_device_charges(spell, "5+d5"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 999; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 1, 1); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_RADAGAST, "DEVICE_RADAGAST", "Artifact Radagast"); - dice_parse_checked(&spell->activation_duration, "15000"); - string_list_append(&spell->description, "purity and health"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 0, 0); - spell->info_func = device_radagast_info; - spell->effect_func = device_radagast; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_set_activation_timeout(spell, "15000"); + spell_type_describe(spell, "purity and health"); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_device(spell, + device_radagast_info, + device_radagast); } { spell_type *spell = spell_new(&DEVICE_VALAROMA, "DEVICE_VALAROMA", "Artifact Valaroma"); - dice_parse_checked(&spell->activation_duration, "250"); - string_list_append(&spell->description, "banish evil (level x5)"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 0, 0); - spell->info_func = device_valaroma_info; - spell->effect_func = device_valaroma; - spell->failure_rate = 25; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_set_activation_timeout(spell, "250"); + spell_type_describe(spell, "banish evil (level x5)"); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, 25); + spell_type_init_device(spell, + device_valaroma_info, + device_valaroma); } } void school_spells_init() { + /* Zero out spell array */ + { + int i = 0; + for (i = 0; i < SCHOOL_SPELLS_MAX; i++) + { + school_spells[i] = NULL; + } + } + + /* Spells */ { spell_type *spell = spell_new(&GLOBELIGHT, "GLOBELIGHT", "Globe of Light"); - string_list_append(&spell->description, "Creates a globe of pure light"); - string_list_append(&spell->description, "At level 3 it starts damaging monsters"); - string_list_append(&spell->description, "At level 15 it starts creating a more powerful kind of light"); - school_idx_add_new(&spell->schools, SCHOOL_FIRE); - range_init(&spell->mana_range, 2, 15); - spell_inertia_init(spell, 1, 40); - spell->info_func = fire_globe_of_light_info; - spell->effect_func = fire_globe_of_light; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "10+d5"); + spell_type_describe(spell, "Creates a globe of pure light"); + spell_type_describe(spell, "At level 3 it starts damaging monsters"); + spell_type_describe(spell, "At level 15 it starts creating a more powerful kind of light"); + spell_type_set_mana(spell, 2, 15); + spell_type_set_inertia(spell, 1, 40); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_FIRE, + fire_globe_of_light_info, + fire_globe_of_light); + + spell_type_set_device_charges(spell, "10+d5"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 7; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 10, 45); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&FIREFLASH, "FIREFLASH", "Fireflash"); - string_list_append(&spell->description, "Conjures a ball of fire to burn your foes to ashes"); - string_list_append(&spell->description, "At level 20 it turns into a ball of holy fire"); - school_idx_add_new(&spell->schools, SCHOOL_FIRE); - range_init(&spell->mana_range, 5, 70); - spell->info_func = fire_fireflash_info; - spell->effect_func = fire_fireflash; - spell->failure_rate = 35; - spell->skill_level = 10; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d5"); + spell_type_describe(spell, "Conjures a ball of fire to burn your foes to ashes"); + spell_type_describe(spell, "At level 20 it turns into a ball of holy fire"); + spell_type_set_mana(spell, 5, 70); + spell_type_set_difficulty(spell, 10, 35); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_FIRE, + fire_fireflash_info, + fire_fireflash); + + spell_type_set_device_charges(spell, "5+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 35; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 15, 35); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&FIERYAURA, "FIERYAURA", "Fiery Shield"); - string_list_append(&spell->description, "Creates a shield of fierce flames around you"); - string_list_append(&spell->description, "At level 8 it turns into a greater kind of flame that can not be resisted"); - school_idx_add_new(&spell->schools, SCHOOL_FIRE); - range_init(&spell->mana_range, 20, 60); - spell_inertia_init(spell, 2, 15); - spell->info_func = fire_fiery_shield_info; - spell->effect_func = fire_fiery_shield; - spell->failure_rate = 50; - spell->skill_level = 20; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "3+d5"); + spell_type_describe(spell, "Creates a shield of fierce flames around you"); + spell_type_describe(spell, "At level 8 it turns into a greater kind of flame that can not be resisted"); + spell_type_set_mana(spell, 20, 60); + spell_type_set_inertia(spell, 2, 15); + spell_type_set_difficulty(spell, 20, 50); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_FIRE, + fire_fiery_shield_info, + fire_fiery_shield); + + spell_type_set_device_charges(spell, "3+d5"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 50; range_init(&device_allocation->base_level, 1, 10); range_init(&device_allocation->max_level, 5, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&FIREWALL, "FIREWALL", "Firewall"); - string_list_append(&spell->description, "Creates a fiery wall to incinerate monsters stupid enough to attack you"); - string_list_append(&spell->description, "At level 6 it turns into a wall of hell fire"); - school_idx_add_new(&spell->schools, SCHOOL_FIRE); - range_init(&spell->mana_range, 25, 100); - spell->info_func = fire_firewall_info; - spell->effect_func = fire_firewall; - spell->failure_rate = 40; - spell->skill_level = 15; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "4+d5"); + spell_type_describe(spell, "Creates a fiery wall to incinerate monsters stupid enough to attack you"); + spell_type_describe(spell, "At level 6 it turns into a wall of hell fire"); + spell_type_set_mana(spell, 25, 100); + spell_type_set_difficulty(spell, 15, 40); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_FIRE, + fire_firewall_info, + fire_firewall); + + spell_type_set_device_charges(spell, "4+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 55; range_init(&device_allocation->base_level, 1, 10); range_init(&device_allocation->max_level, 5, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&FIREGOLEM, "FIREGOLEM", "Fire Golem"); - string_list_append(&spell->description, "Creates a fiery golem and controls it"); - string_list_append(&spell->description, "During the control the available keylist is:"); - string_list_append(&spell->description, "Movement keys: movement of the golem(depending on its speed"); - string_list_append(&spell->description, " it can move more than one square)"); - string_list_append(&spell->description, ", : pickup all items on the floor"); - string_list_append(&spell->description, "d : drop all carried items"); - string_list_append(&spell->description, "i : list all carried items"); - string_list_append(&spell->description, "m : end the possession/use golem powers"); - string_list_append(&spell->description, "Most of the other keys are disabled, you cannot interact with your"); - string_list_append(&spell->description, "real body while controlling the golem"); - string_list_append(&spell->description, "But to cast the spell you will need a lantern or a wooden torch to"); - string_list_append(&spell->description, "Create the golem from"); - school_idx_add_new(&spell->schools, SCHOOL_FIRE); - school_idx_add_new(&spell->schools, SCHOOL_MIND); - range_init(&spell->mana_range, 16, 70); - spell->info_func = fire_golem_info; - spell->effect_func = fire_golem; - spell->failure_rate = 40; - spell->skill_level = 7; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Creates a fiery golem and controls it"); + spell_type_describe(spell, "During the control the available keylist is:"); + spell_type_describe(spell, "Movement keys: movement of the golem(depending on its speed"); + spell_type_describe(spell, " it can move more than one square)"); + spell_type_describe(spell, ", : pickup all items on the floor"); + spell_type_describe(spell, "d : drop all carried items"); + spell_type_describe(spell, "i : list all carried items"); + spell_type_describe(spell, "m : end the possession/use golem powers"); + spell_type_describe(spell, "Most of the other keys are disabled, you cannot interact with your"); + spell_type_describe(spell, "real body while controlling the golem"); + spell_type_describe(spell, "But to cast the spell you will need a lantern or a wooden torch to"); + spell_type_describe(spell, "Create the golem from"); + spell_type_add_school(spell, SCHOOL_MIND); + spell_type_set_mana(spell, 16, 70); + spell_type_set_difficulty(spell, 7, 40); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_FIRE, + fire_golem_info, + fire_golem); } { spell_type *spell = spell_new(&MANATHRUST, "MANATHRUST", "Manathrust"); - string_list_append(&spell->description, "Conjures up mana into a powerful bolt"); - string_list_append(&spell->description, "The damage is irresistible and will increase with level"); - school_idx_add_new(&spell->schools, SCHOOL_MANA); - range_init(&spell->mana_range, 1, 25); - spell->info_func = mana_manathrust_info; - spell->effect_func = mana_manathrust; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "7+d10"); + spell_type_describe(spell, "Conjures up mana into a powerful bolt"); + spell_type_describe(spell, "The damage is irresistible and will increase with level"); + spell_type_set_mana(spell, 1, 25); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MANA, + mana_manathrust_info, + mana_manathrust); + + spell_type_set_device_charges(spell, "7+d10"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 5; range_init(&device_allocation->base_level, 1, 20); range_init(&device_allocation->max_level, 15, 33); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DELCURSES, "DELCURSES", "Remove Curses"); - string_list_append(&spell->description, "Remove curses of worn objects"); - string_list_append(&spell->description, "At level 20 switches to *remove curses*"); - school_idx_add_new(&spell->schools, SCHOOL_MANA); - range_init(&spell->mana_range, 20, 40); - spell_inertia_init(spell, 1, 10); - spell->info_func = mana_remove_curses_info; - spell->effect_func = mana_remove_curses; - spell->failure_rate = 30; - spell->skill_level = 10; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "3+d8"); + spell_type_describe(spell, "Remove curses of worn objects"); + spell_type_describe(spell, "At level 20 switches to *remove curses*"); + spell_type_set_mana(spell, 20, 40); + spell_type_set_inertia(spell, 1, 10); + spell_type_set_difficulty(spell, 10, 30); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MANA, + mana_remove_curses_info, + mana_remove_curses); + + spell_type_set_device_charges(spell, "3+d8"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 70; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 15, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&RESISTS, "RESISTS", "Elemental Shield"); - string_list_append(&spell->description, "Provide resistances to the four basic elements"); - school_idx_add_new(&spell->schools, SCHOOL_MANA); - range_init(&spell->mana_range, 17, 20); - spell_inertia_init(spell, 2, 25); - spell->info_func = mana_elemental_shield_info; - spell->effect_func = mana_elemental_shield; - spell->failure_rate = 40; - spell->skill_level = 20; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Provide resistances to the four basic elements"); + spell_type_set_mana(spell, 17, 20); + spell_type_set_inertia(spell, 2, 25); + spell_type_set_difficulty(spell, 20, 40); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MANA, + mana_elemental_shield_info, + mana_elemental_shield); } { spell_type *spell = spell_new(&MANASHIELD, "MANASHIELD", "Disruption Shield"); - string_list_append(&spell->description, "Uses mana instead of hp to take damage"); - string_list_append(&spell->description, "At level 5 switches to Globe of Invulnerability."); - string_list_append(&spell->description, "The spell breaks as soon as a melee, shooting, throwing or magical"); - string_list_append(&spell->description, "skill action is attempted, and lasts only a short time."); - school_idx_add_new(&spell->schools, SCHOOL_MANA); - range_init(&spell->mana_range, 50, 50); - spell_inertia_init(spell, 9, 10); - spell->info_func = mana_disruption_shield_info; - spell->effect_func = mana_disruption_shield; - spell->failure_rate = 90; - spell->skill_level = 45; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Uses mana instead of hp to take damage"); + spell_type_describe(spell, "At level 5 switches to Globe of Invulnerability."); + spell_type_describe(spell, "The spell breaks as soon as a melee, shooting, throwing or magical"); + spell_type_describe(spell, "skill action is attempted, and lasts only a short time."); + spell_type_set_mana(spell, 50, 50); + spell_type_set_inertia(spell, 9, 10); + spell_type_set_difficulty(spell, 45, 90); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MANA, + mana_disruption_shield_info, + mana_disruption_shield); } { spell_type *spell = spell_new(&TIDALWAVE, "TIDALWAVE", "Tidal Wave"); - string_list_append(&spell->description, "Summons a monstrous tidal wave that will expand and crush the"); - string_list_append(&spell->description, "monsters under its mighty waves."); - school_idx_add_new(&spell->schools, SCHOOL_WATER); - range_init(&spell->mana_range, 16, 40); - spell_inertia_init(spell, 4, 100); - spell->info_func = water_tidal_wave_info; - spell->effect_func = water_tidal_wave; - spell->failure_rate = 65; - spell->skill_level = 16; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "6+d5"); + spell_type_describe(spell, "Summons a monstrous tidal wave that will expand and crush the"); + spell_type_describe(spell, "monsters under its mighty waves."); + spell_type_set_mana(spell, 16, 40); + spell_type_set_inertia(spell, 4, 100); + spell_type_set_difficulty(spell, 16, 65); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_WATER, + water_tidal_wave_info, + water_tidal_wave); + + spell_type_set_device_charges(spell, "6+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 54; range_init(&device_allocation->base_level, 1, 10); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&ICESTORM, "ICESTORM", "Ice Storm"); - string_list_append(&spell->description, "Engulfs you in a storm of roaring cold that strikes your foes."); - string_list_append(&spell->description, "At level 10 it turns into shards of ice."); - school_idx_add_new(&spell->schools, SCHOOL_WATER); - range_init(&spell->mana_range, 30, 60); - spell_inertia_init(spell, 3, 40); - spell->info_func = water_ice_storm_info; - spell->effect_func = water_ice_storm; - spell->failure_rate = 80; - spell->skill_level = 22; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "3+d7"); + spell_type_describe(spell, "Engulfs you in a storm of roaring cold that strikes your foes."); + spell_type_describe(spell, "At level 10 it turns into shards of ice."); + spell_type_set_mana(spell, 30, 60); + spell_type_set_inertia(spell, 3, 40); + spell_type_set_difficulty(spell, 22, 80); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_WATER, + water_ice_storm_info, + water_ice_storm); + + spell_type_set_device_charges(spell, "3+d7"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 65; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 25, 45); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&ENTPOTION, "ENTPOTION", "Ent's Potion"); - string_list_append(&spell->description, "Fills up your stomach."); - string_list_append(&spell->description, "At level 5 it boldens your heart."); - string_list_append(&spell->description, "At level 12 it makes you heroic."); - school_idx_add_new(&spell->schools, SCHOOL_WATER); - range_init(&spell->mana_range, 7, 15); - spell_inertia_init(spell, 1, 30); - spell->info_func = water_ent_potion_info; - spell->effect_func = water_ent_potion; - spell->failure_rate = 35; - spell->skill_level = 6; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Fills up your stomach."); + spell_type_describe(spell, "At level 5 it boldens your heart."); + spell_type_describe(spell, "At level 12 it makes you heroic."); + spell_type_set_mana(spell, 7, 15); + spell_type_set_inertia(spell, 1, 30); + spell_type_set_difficulty(spell, 6, 35); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_WATER, + water_ent_potion_info, + water_ent_potion); } { spell_type *spell = spell_new(&VAPOR, "VAPOR", "Vapor"); - string_list_append(&spell->description, "Fills the air with toxic moisture to eradicate annoying critters."); - school_idx_add_new(&spell->schools, SCHOOL_WATER); - range_init(&spell->mana_range, 2, 12); - spell_inertia_init(spell, 1, 30); - spell->info_func = water_vapor_info; - spell->effect_func = water_vapor; - spell->failure_rate = 20; - spell->skill_level = 2; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Fills the air with toxic moisture to eradicate annoying critters."); + spell_type_set_mana(spell, 2, 12); + spell_type_set_inertia(spell, 1, 30); + spell_type_set_difficulty(spell, 2, 20); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_WATER, + water_vapor_info, + water_vapor); } { spell_type *spell = spell_new(&GEYSER, "GEYSER", "Geyser"); - string_list_append(&spell->description, "Shoots a geyser of water from your fingertips."); - string_list_append(&spell->description, "Sometimes it can blast through its first target."); - school_idx_add_new(&spell->schools, SCHOOL_WATER); - range_init(&spell->mana_range, 1, 35); - spell->info_func = water_geyser_info; - spell->effect_func = water_geyser; - spell->failure_rate = 5; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Shoots a geyser of water from your fingertips."); + spell_type_describe(spell, "Sometimes it can blast through its first target."); + spell_type_set_mana(spell, 1, 35); + spell_type_set_difficulty(spell, 1, 5); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_WATER, + water_geyser_info, + water_geyser); } { spell_type *spell = spell_new(&NOXIOUSCLOUD, "NOXIOUSCLOUD", "Noxious Cloud"); - string_list_append(&spell->description, "Creates a cloud of poison"); - string_list_append(&spell->description, "The cloud will persist for some turns, damaging all monsters passing by"); - string_list_append(&spell->description, "At spell level 30 it turns into a thick gas attacking all living beings"); - school_idx_add_new(&spell->schools, SCHOOL_AIR); - range_init(&spell->mana_range, 3, 30); - spell->info_func = air_noxious_cloud_info; - spell->effect_func = air_noxious_cloud; - spell->failure_rate = 20; - spell->skill_level = 3; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d7"); + spell_type_describe(spell, "Creates a cloud of poison"); + spell_type_describe(spell, "The cloud will persist for some turns, damaging all monsters passing by"); + spell_type_describe(spell, "At spell level 30 it turns into a thick gas attacking all living beings"); + spell_type_set_mana(spell, 3, 30); + spell_type_set_difficulty(spell, 3, 20); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_AIR, + air_noxious_cloud_info, + air_noxious_cloud); + + spell_type_set_device_charges(spell, "5+d7"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 15; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 25, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&AIRWINGS, "AIRWINGS", "Wings of Winds"); - string_list_append(&spell->description, "Grants the power of levitation"); - string_list_append(&spell->description, "At level 16 it grants the power of controlled flight"); - school_idx_add_new(&spell->schools, SCHOOL_AIR); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 30, 40); - spell_inertia_init(spell, 1, 10); - spell->info_func = air_wings_of_winds_info; - spell->effect_func = air_wings_of_winds; - spell->failure_rate = 60; - spell->skill_level = 22; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "7+d5"); + spell_type_describe(spell, "Grants the power of levitation"); + spell_type_describe(spell, "At level 16 it grants the power of controlled flight"); + spell_type_add_school(spell, SCHOOL_CONVEYANCE); + spell_type_set_mana(spell, 30, 40); + spell_type_set_inertia(spell, 1, 10); + spell_type_set_difficulty(spell, 22, 60); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_AIR, + air_wings_of_winds_info, + air_wings_of_winds); + + spell_type_set_device_charges(spell, "7+d5"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 27; range_init(&device_allocation->base_level, 1, 10); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&INVISIBILITY, "INVISIBILITY", "Invisibility"); - string_list_append(&spell->description, "Grants invisibility"); - school_idx_add_new(&spell->schools, SCHOOL_AIR); - range_init(&spell->mana_range, 10, 20); - spell_inertia_init(spell, 1, 30); - spell->info_func = air_invisibility_info; - spell->effect_func = air_invisibility; - spell->failure_rate = 50; - spell->skill_level = 16; - spell_init_mage(spell, RANDOM); - + spell_type_describe(spell, "Grants invisibility"); + spell_type_set_mana(spell, 10, 20); + spell_type_set_inertia(spell, 1, 30); + spell_type_set_difficulty(spell, 16, 50); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_AIR, + air_invisibility_info, + air_invisibility); } { spell_type *spell = spell_new(&POISONBLOOD, "POISONBLOOD", "Poison Blood"); - string_list_append(&spell->description, "Grants resist poison"); - string_list_append(&spell->description, "At level 15 it provides poison branding to wielded weapon"); - school_idx_add_new(&spell->schools, SCHOOL_AIR); - range_init(&spell->mana_range, 10, 20); - spell_inertia_init(spell, 1, 35); - spell->info_func = air_poison_blood_info; - spell->effect_func = air_poison_blood; - spell->failure_rate = 30; - spell->skill_level = 12; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "10+d15"); + spell_type_describe(spell, "Grants resist poison"); + spell_type_describe(spell, "At level 15 it provides poison branding to wielded weapon"); + spell_type_set_mana(spell, 10, 20); + spell_type_set_inertia(spell, 1, 35); + spell_type_set_difficulty(spell, 12, 30); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_AIR, + air_poison_blood_info, + air_poison_blood); + + spell_type_set_device_charges(spell, "10+d15"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 45; range_init(&device_allocation->base_level, 1, 25); range_init(&device_allocation->max_level, 35, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&THUNDERSTORM, "THUNDERSTORM", "Thunderstorm"); - string_list_append(&spell->description, "Charges up the air around you with electricity"); - string_list_append(&spell->description, "Each turn it will throw a thunder bolt at a random monster in sight"); - string_list_append(&spell->description, "The thunder does 3 types of damage, one third of lightning"); - string_list_append(&spell->description, "one third of sound and one third of light"); - school_idx_add_new(&spell->schools, SCHOOL_AIR); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - range_init(&spell->mana_range, 40, 60); - spell_inertia_init(spell, 2, 15); - spell->info_func = air_thunderstorm_info; - spell->effect_func = air_thunderstorm; - spell->failure_rate = 60; - spell->skill_level = 25; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d5"); + spell_type_describe(spell, "Charges up the air around you with electricity"); + spell_type_describe(spell, "Each turn it will throw a thunder bolt at a random monster in sight"); + spell_type_describe(spell, "The thunder does 3 types of damage, one third of lightning"); + spell_type_describe(spell, "one third of sound and one third of light"); + spell_type_add_school(spell, SCHOOL_NATURE); + spell_type_set_mana(spell, 40, 60); + spell_type_set_inertia(spell, 2, 15); + spell_type_set_difficulty(spell, 25, 60); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_AIR, + air_thunderstorm_info, + air_thunderstorm); + + spell_type_set_device_charges(spell, "5+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 85; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 25, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&STERILIZE, "STERILIZE", "Sterilize"); - string_list_append(&spell->description, "Prevents explosive breeding for a while."); - school_idx_add_new(&spell->schools, SCHOOL_AIR); - range_init(&spell->mana_range, 10, 100); - spell->info_func = air_sterilize_info; - spell->effect_func = air_sterilize; - spell->failure_rate = 50; - spell->skill_level = 20; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Prevents explosive breeding for a while."); + spell_type_set_mana(spell, 10, 100); + spell_type_set_difficulty(spell, 20, 50); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_AIR, + air_sterilize_info, + air_sterilize); - dice_parse_checked(&spell->device_charges, "7+d5"); + spell_type_set_device_charges(spell, "7+d5"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 20; range_init(&device_allocation->base_level, 1, 10); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&STONESKIN, "STONESKIN", "Stone Skin"); - string_list_append(&spell->description, "Creates a shield of earth around you to protect you"); - string_list_append(&spell->description, "At level 25 it starts dealing damage to attackers"); - school_idx_add_new(&spell->schools, SCHOOL_EARTH); - range_init(&spell->mana_range, 1, 50); - spell_inertia_init(spell, 2, 50); - spell->info_func = earth_stone_skin_info; - spell->effect_func = earth_stone_skin; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Creates a shield of earth around you to protect you"); + spell_type_describe(spell, "At level 25 it starts dealing damage to attackers"); + spell_type_set_mana(spell, 1, 50); + spell_type_set_inertia(spell, 2, 50); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_EARTH, + earth_stone_skin_info, + earth_stone_skin); } { spell_type *spell = spell_new(&DIG, "DIG", "Dig"); - string_list_append(&spell->description, "Digs a hole in a wall much faster than any shovels"); - school_idx_add_new(&spell->schools, SCHOOL_EARTH); - range_init(&spell->mana_range, 14, 14); - spell->info_func = earth_dig_info; - spell->effect_func = earth_dig; - spell->failure_rate = 20; - spell->skill_level = 12; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Digs a hole in a wall much faster than any shovels"); + spell_type_set_mana(spell, 14, 14); + spell_type_set_difficulty(spell, 12, 20); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_EARTH, + earth_dig_info, + earth_dig); - dice_parse_checked(&spell->device_charges, "15+d5"); + spell_type_set_device_charges(spell, "15+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 25; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 1, 1); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&STONEPRISON, "STONEPRISON", "Stone Prison"); - string_list_append(&spell->description, "Creates a prison of walls around you"); - string_list_append(&spell->description, "At level 10 it allows you to target a monster"); - school_idx_add_new(&spell->schools, SCHOOL_EARTH); - range_init(&spell->mana_range, 30, 50); - spell->info_func = earth_stone_prison_info; - spell->effect_func = earth_stone_prison; - spell->failure_rate = 65; - spell->skill_level = 25; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d3"); + spell_type_describe(spell, "Creates a prison of walls around you"); + spell_type_describe(spell, "At level 10 it allows you to target a monster"); + spell_type_set_mana(spell, 30, 50); + spell_type_set_difficulty(spell, 25, 65); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_EARTH, + earth_stone_prison_info, + earth_stone_prison); + + spell_type_set_device_charges(spell, "5+d3"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 57; range_init(&device_allocation->base_level, 1, 3); range_init(&device_allocation->max_level, 5, 20); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&STRIKE, "STRIKE", "Strike"); - string_list_append(&spell->description, "Creates a micro-ball of force that will push monsters backwards"); - string_list_append(&spell->description, "If the monster is caught near a wall, it'll be crushed against it"); - string_list_append(&spell->description, "At level 12 it turns into a ball of radius 1"); - school_idx_add_new(&spell->schools, SCHOOL_EARTH); - range_init(&spell->mana_range, 30, 50); - spell->info_func = earth_strike_info; - spell->effect_func = earth_strike; - spell->failure_rate = 60; - spell->skill_level = 30; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "2+d6"); + spell_type_describe(spell, "Creates a micro-ball of force that will push monsters backwards"); + spell_type_describe(spell, "If the monster is caught near a wall, it'll be crushed against it"); + spell_type_describe(spell, "At level 12 it turns into a ball of radius 1"); + spell_type_set_mana(spell, 30, 50); + spell_type_set_difficulty(spell, 30, 60); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_EARTH, + earth_strike_info, + earth_strike); + + spell_type_set_device_charges(spell, "2+d6"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 635; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 10, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&SHAKE, "SHAKE", "Shake"); - string_list_append(&spell->description, "Creates a localised earthquake"); - string_list_append(&spell->description, "At level 10 it can be targeted at any location"); - school_idx_add_new(&spell->schools, SCHOOL_EARTH); - range_init(&spell->mana_range, 25, 30); - spell_inertia_init(spell, 2, 50); - spell->info_func = earth_shake_info; - spell->effect_func = earth_shake; - spell->failure_rate = 60; - spell->skill_level = 27; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d10"); + spell_type_describe(spell, "Creates a localised earthquake"); + spell_type_describe(spell, "At level 10 it can be targeted at any location"); + spell_type_set_mana(spell, 25, 30); + spell_type_set_inertia(spell, 2, 50); + spell_type_set_difficulty(spell, 27, 60); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_EARTH, + earth_shake_info, + earth_shake); + + spell_type_set_device_charges(spell, "5+d10"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 75; range_init(&device_allocation->base_level, 1, 3); range_init(&device_allocation->max_level, 9, 20); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&BLINK, "BLINK", "Phase Door"); - string_list_append(&spell->description, "Teleports you on a small scale range"); - string_list_append(&spell->description, "At level 30 it creates void jumpgates"); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 1, 3); - spell_inertia_init(spell, 1, 5); - spell->info_func = convey_blink_info; - spell->effect_func = convey_blink; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Teleports you on a small scale range"); + spell_type_describe(spell, "At level 30 it creates void jumpgates"); + spell_type_set_mana(spell, 1, 3); + spell_type_set_inertia(spell, 1, 5); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_CONVEYANCE, + convey_blink_info, + convey_blink); } { spell_type *spell = spell_new(&DISARM, "DISARM", "Disarm"); - string_list_append(&spell->description, "Destroys doors and traps"); - string_list_append(&spell->description, "At level 10 it destroys doors and traps, then reveals and unlocks any secret"); - string_list_append(&spell->description, "doors"); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 2, 4); - spell->info_func = convey_disarm_info; - spell->effect_func = convey_disarm; - spell->failure_rate = 15; - spell->skill_level = 3; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "10+d15"); + spell_type_describe(spell, "Destroys doors and traps"); + spell_type_describe(spell, "At level 10 it destroys doors and traps, then reveals and unlocks any secret"); + spell_type_describe(spell, "doors"); + spell_type_set_mana(spell, 2, 4); + spell_type_set_difficulty(spell, 3, 15); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_CONVEYANCE, + convey_disarm_info, + convey_disarm); + + spell_type_set_device_charges(spell, "10+d15"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 4; range_init(&device_allocation->base_level, 1, 10); range_init(&device_allocation->max_level, 10, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&TELEPORT, "TELEPORT", "Teleportation"); - string_list_append(&spell->description, "Teleports you around the level. The casting time decreases with level"); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 8, 14); - spell_inertia_init(spell, 1, 10); - spell->info_func = convey_teleport_info; - spell->effect_func = convey_teleport; - spell->failure_rate = 30; - spell->skill_level = 10; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "7+d7"); + spell_type_describe(spell, "Teleports you around the level. The casting time decreases with level"); + spell_type_set_mana(spell, 8, 14); + spell_type_set_inertia(spell, 1, 10); + spell_type_set_difficulty(spell, 10, 30); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_CONVEYANCE, + convey_teleport_info, + convey_teleport); + + spell_type_set_device_charges(spell, "7+d7"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 50; range_init(&device_allocation->base_level, 1, 20); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&TELEAWAY, "TELEAWAY", "Teleport Away"); - string_list_append(&spell->description, "Teleports a line of monsters away"); - string_list_append(&spell->description, "At level 10 it turns into a ball"); - string_list_append(&spell->description, "At level 20 it teleports all monsters in sight"); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 15, 40); - spell->info_func = convey_teleport_away_info; - spell->effect_func = convey_teleport_away; - spell->failure_rate = 60; - spell->skill_level = 23; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "3+d5"); + spell_type_describe(spell, "Teleports a line of monsters away"); + spell_type_describe(spell, "At level 10 it turns into a ball"); + spell_type_describe(spell, "At level 20 it teleports all monsters in sight"); + spell_type_set_mana(spell, 15, 40); + spell_type_set_difficulty(spell, 23, 60); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_CONVEYANCE, + convey_teleport_away_info, + convey_teleport_away); + + spell_type_set_device_charges(spell, "3+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 75; range_init(&device_allocation->base_level, 1, 20); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&RECALL, "RECALL", "Recall"); - string_list_append(&spell->description, "Cast on yourself it will recall you to the surface/dungeon."); - string_list_append(&spell->description, "Cast at a monster you will swap positions with the monster."); - string_list_append(&spell->description, "Cast at an object it will fetch the object to you."); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 25, 25); - spell->info_func = convey_recall_info; - spell->effect_func = convey_recall; - spell->failure_rate = 60; - spell->skill_level = 30; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Cast on yourself it will recall you to the surface/dungeon."); + spell_type_describe(spell, "Cast at a monster you will swap positions with the monster."); + spell_type_describe(spell, "Cast at an object it will fetch the object to you."); + spell_type_set_mana(spell, 25, 25); + spell_type_set_difficulty(spell, 30, 60); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_CONVEYANCE, + convey_recall_info, + convey_recall); } { spell_type *spell = spell_new(&PROBABILITY_TRAVEL, "PROBABILITY_TRAVEL", "Probability Travel"); - string_list_append(&spell->description, "Renders you immaterial, when you hit a wall you travel through it and"); - string_list_append(&spell->description, "instantly appear on the other side of it. You can also float up and down"); - string_list_append(&spell->description, "at will"); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 30, 50); - spell_inertia_init(spell, 6, 40); - spell->info_func = convey_probability_travel_info; - spell->effect_func = convey_probability_travel; - spell->failure_rate = 90; - spell->skill_level = 35; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "1+d2"); + spell_type_describe(spell, "Renders you immaterial, when you hit a wall you travel through it and"); + spell_type_describe(spell, "instantly appear on the other side of it. You can also float up and down"); + spell_type_describe(spell, "at will"); + spell_type_set_mana(spell, 30, 50); + spell_type_set_inertia(spell, 6, 40); + spell_type_set_difficulty(spell, 35, 90); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_CONVEYANCE, + convey_probability_travel_info, + convey_probability_travel); + + spell_type_set_device_charges(spell, "1+d2"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 97; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 8, 25); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&GROWTREE, "GROWTREE", "Grow Trees"); - string_list_append(&spell->description, "Makes trees grow extremely quickly around you"); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - school_idx_add_new(&spell->schools, SCHOOL_TEMPORAL); - range_init(&spell->mana_range, 6, 30); - spell_inertia_init(spell, 5, 50); - spell->info_func = nature_grow_trees_info; - spell->effect_func = nature_grow_trees; - spell->failure_rate = 35; - spell->skill_level = 6; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Makes trees grow extremely quickly around you"); + spell_type_add_school(spell, SCHOOL_TEMPORAL); + spell_type_set_mana(spell, 6, 30); + spell_type_set_inertia(spell, 5, 50); + spell_type_set_difficulty(spell, 6, 35); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_NATURE, + nature_grow_trees_info, + nature_grow_trees); } { spell_type *spell = spell_new(&HEALING, "HEALING", "Healing"); - string_list_append(&spell->description, "Heals a percent of hitpoints"); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - range_init(&spell->mana_range, 15, 50); - spell->info_func = nature_healing_info; - spell->effect_func = nature_healing; - spell->failure_rate = 45; - spell->skill_level = 10; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Heals a percent of hitpoints"); + spell_type_set_mana(spell, 15, 50); + spell_type_set_difficulty(spell, 10, 45); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_NATURE, + nature_healing_info, + nature_healing); - dice_parse_checked(&spell->device_charges, "2+d3"); + spell_type_set_device_charges(spell, "2+d3"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 90; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 20, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&RECOVERY, "RECOVERY", "Recovery"); - string_list_append(&spell->description, "Reduces the length of time that you are poisoned"); - string_list_append(&spell->description, "At level 5 it cures poison and cuts"); - string_list_append(&spell->description, "At level 10 it restores drained stats"); - string_list_append(&spell->description, "At level 15 it restores lost experience"); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - range_init(&spell->mana_range, 10, 25); - spell_inertia_init(spell, 2, 100); - spell->info_func = nature_recovery_info; - spell->effect_func = nature_recovery; - spell->failure_rate = 60; - spell->skill_level = 15; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d10"); + spell_type_describe(spell, "Reduces the length of time that you are poisoned"); + spell_type_describe(spell, "At level 5 it cures poison and cuts"); + spell_type_describe(spell, "At level 10 it restores drained stats"); + spell_type_describe(spell, "At level 15 it restores lost experience"); + spell_type_set_mana(spell, 10, 25); + spell_type_set_inertia(spell, 2, 100); + spell_type_set_difficulty(spell, 15, 60); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_NATURE, + nature_recovery_info, + nature_recovery); + + spell_type_set_device_charges(spell, "5+d10"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 50; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 10, 30); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(®ENERATION, "REGENERATION", "Regeneration"); - string_list_append(&spell->description, "Increases your body's regeneration rate"); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - range_init(&spell->mana_range, 30, 55); - spell_inertia_init(spell, 4, 40); - spell->info_func = nature_regeneration_info; - spell->effect_func = nature_regeneration; - spell->failure_rate = 70; - spell->skill_level = 20; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Increases your body's regeneration rate"); + spell_type_set_mana(spell, 30, 55); + spell_type_set_inertia(spell, 4, 40); + spell_type_set_difficulty(spell, 20, 70); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_NATURE, + nature_regeneration_info, + nature_regeneration); } { spell_type *spell = spell_new(&SUMMONANNIMAL, "SUMMONANNIMAL", "Summon Animal"); - string_list_append(&spell->description, "Summons a leveled animal to your aid"); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - range_init(&spell->mana_range, 25, 50); - spell->info_func = nature_summon_animal_info; - spell->effect_func = nature_summon_animal; - spell->failure_rate = 90; - spell->skill_level = 25; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Summons a leveled animal to your aid"); + spell_type_set_mana(spell, 25, 50); + spell_type_set_difficulty(spell, 25, 90); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_NATURE, + nature_summon_animal_info, + nature_summon_animal); - dice_parse_checked(&spell->device_charges, "1+d3"); + spell_type_set_device_charges(spell, "1+d3"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 85; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 15, 45); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&STARIDENTIFY, "STARIDENTIFY", "Greater Identify"); - string_list_append(&spell->description, "Asks for an object and fully identify it, providing the full list of powers"); - string_list_append(&spell->description, "Cast at yourself it will reveal your powers"); - school_idx_add_new(&spell->schools, SCHOOL_DIVINATION); - range_init(&spell->mana_range, 30, 30); - spell->info_func = divination_greater_identify_info; - spell->effect_func = divination_greater_identify; - spell->failure_rate = 80; - spell->skill_level = 35; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Asks for an object and fully identify it, providing the full list of powers"); + spell_type_describe(spell, "Cast at yourself it will reveal your powers"); + spell_type_set_mana(spell, 30, 30); + spell_type_set_difficulty(spell, 35, 80); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_DIVINATION, + divination_greater_identify_info, + divination_greater_identify); } { spell_type *spell = spell_new(&IDENTIFY, "IDENTIFY", "Identify"); - string_list_append(&spell->description, "Asks for an object and identifies it"); - string_list_append(&spell->description, "At level 17 it identifies all objects in the inventory"); - string_list_append(&spell->description, "At level 27 it identifies all objects in the inventory and in a"); - string_list_append(&spell->description, "radius on the floor, as well as probing monsters in that radius"); - school_idx_add_new(&spell->schools, SCHOOL_DIVINATION); - range_init(&spell->mana_range, 10, 50); - spell->info_func = divination_identify_info; - spell->effect_func = divination_identify; - spell->failure_rate = 40; - spell->skill_level = 8; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "7+d10"); + spell_type_describe(spell, "Asks for an object and identifies it"); + spell_type_describe(spell, "At level 17 it identifies all objects in the inventory"); + spell_type_describe(spell, "At level 27 it identifies all objects in the inventory and in a"); + spell_type_describe(spell, "radius on the floor, as well as probing monsters in that radius"); + spell_type_set_mana(spell, 10, 50); + spell_type_set_difficulty(spell, 8, 40); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_DIVINATION, + divination_identify_info, + divination_identify); + + spell_type_set_device_charges(spell, "7+d10"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 45; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 15, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&VISION, "VISION", "Vision"); - string_list_append(&spell->description, "Detects the layout of the surrounding area"); - string_list_append(&spell->description, "At level 25 it maps and lights the whole level"); - school_idx_add_new(&spell->schools, SCHOOL_DIVINATION); - range_init(&spell->mana_range, 7, 55); - spell_inertia_init(spell, 2, 200); - spell->info_func = divination_vision_info; - spell->effect_func = divination_vision; - spell->failure_rate = 45; - spell->skill_level = 15; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "4+d6"); + spell_type_describe(spell, "Detects the layout of the surrounding area"); + spell_type_describe(spell, "At level 25 it maps and lights the whole level"); + spell_type_set_mana(spell, 7, 55); + spell_type_set_inertia(spell, 2, 200); + spell_type_set_difficulty(spell, 15, 45); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_DIVINATION, + divination_vision_info, + divination_vision); + + spell_type_set_device_charges(spell, "4+d6"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 60; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 10, 30); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&SENSEHIDDEN, "SENSEHIDDEN", "Sense Hidden"); - string_list_append(&spell->description, "Detects the traps in a certain radius around you"); - string_list_append(&spell->description, "At level 15 it allows you to sense invisible for a while"); - school_idx_add_new(&spell->schools, SCHOOL_DIVINATION); - range_init(&spell->mana_range, 2, 10); - spell_inertia_init(spell, 1, 10); - spell->info_func = divination_sense_hidden_info; - spell->effect_func = divination_sense_hidden; - spell->failure_rate = 25; - spell->skill_level = 5; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "1+d15"); + spell_type_describe(spell, "Detects the traps in a certain radius around you"); + spell_type_describe(spell, "At level 15 it allows you to sense invisible for a while"); + spell_type_set_mana(spell, 2, 10); + spell_type_set_inertia(spell, 1, 10); + spell_type_set_difficulty(spell, 5, 25); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_DIVINATION, + divination_sense_hidden_info, + divination_sense_hidden); + + spell_type_set_device_charges(spell, "1+d15"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 20; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 10, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&REVEALWAYS, "REVEALWAYS", "Reveal Ways"); - string_list_append(&spell->description, "Detects the doors/stairs/ways in a certain radius around you"); - school_idx_add_new(&spell->schools, SCHOOL_DIVINATION); - range_init(&spell->mana_range, 3, 15); - spell_inertia_init(spell, 1, 10); - spell->info_func = divination_reveal_ways_info; - spell->effect_func = divination_reveal_ways; - spell->failure_rate = 20; - spell->skill_level = 9; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "6+d6"); + spell_type_describe(spell, "Detects the doors/stairs/ways in a certain radius around you"); + spell_type_set_mana(spell, 3, 15); + spell_type_set_inertia(spell, 1, 10); + spell_type_set_difficulty(spell, 9, 20); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_DIVINATION, + divination_reveal_ways_info, + divination_reveal_ways); + + spell_type_set_device_charges(spell, "6+d6"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 35; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 25, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&SENSEMONSTERS, "SENSEMONSTERS", "Sense Monsters"); - string_list_append(&spell->description, "Detects all monsters near you"); - string_list_append(&spell->description, "At level 30 it allows you to sense monster minds for a while"); - school_idx_add_new(&spell->schools, SCHOOL_DIVINATION); - range_init(&spell->mana_range, 1, 20); - spell_inertia_init(spell, 1, 10); - spell->info_func = divination_sense_monsters_info; - spell->effect_func = divination_sense_monsters; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d10"); + spell_type_describe(spell, "Detects all monsters near you"); + spell_type_describe(spell, "At level 30 it allows you to sense monster minds for a while"); + spell_type_set_mana(spell, 1, 20); + spell_type_set_inertia(spell, 1, 10); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_DIVINATION, + divination_sense_monsters_info, + divination_sense_monsters); + + spell_type_set_device_charges(spell, "5+d10"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 37; range_init(&device_allocation->base_level, 1, 10); range_init(&device_allocation->max_level, 15, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&MAGELOCK, "MAGELOCK", "Magelock"); - string_list_append(&spell->description, "Magically locks a door"); - string_list_append(&spell->description, "At level 30 it creates a glyph of warding"); - string_list_append(&spell->description, "At level 40 the glyph can be placed anywhere in the field of vision"); - school_idx_add_new(&spell->schools, SCHOOL_TEMPORAL); - range_init(&spell->mana_range, 1, 35); - spell->info_func = tempo_magelock_info; - spell->effect_func = tempo_magelock; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "7+d5"); + spell_type_describe(spell, "Magically locks a door"); + spell_type_describe(spell, "At level 30 it creates a glyph of warding"); + spell_type_describe(spell, "At level 40 the glyph can be placed anywhere in the field of vision"); + spell_type_set_mana(spell, 1, 35); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_TEMPORAL, + tempo_magelock_info, + tempo_magelock); + + spell_type_set_device_charges(spell, "7+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 30; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 15, 45); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&SLOWMONSTER, "SLOWMONSTER", "Slow Monster"); - string_list_append(&spell->description, "Magically slows down the passing of time around a monster"); - string_list_append(&spell->description, "At level 20 it affects a zone"); - school_idx_add_new(&spell->schools, SCHOOL_TEMPORAL); - range_init(&spell->mana_range, 10, 15); - spell->info_func = tempo_slow_monster_info; - spell->effect_func = tempo_slow_monster; - spell->failure_rate = 35; - spell->skill_level = 10; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d5"); + spell_type_describe(spell, "Magically slows down the passing of time around a monster"); + spell_type_describe(spell, "At level 20 it affects a zone"); + spell_type_set_mana(spell, 10, 15); + spell_type_set_difficulty(spell, 10, 35); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_TEMPORAL, + tempo_slow_monster_info, + tempo_slow_monster); + + spell_type_set_device_charges(spell, "5+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 23; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&ESSENCESPEED, "ESSENCESPEED", "Essence of Speed"); - string_list_append(&spell->description, "Magically decreases the passing of time around you, making you move faster with"); - string_list_append(&spell->description, "respect to the rest of the universe."); - school_idx_add_new(&spell->schools, SCHOOL_TEMPORAL); - range_init(&spell->mana_range, 20, 40); - spell_inertia_init(spell, 5, 20); - spell->info_func = tempo_essence_of_speed_info; - spell->effect_func = tempo_essence_of_speed; - spell->failure_rate = 50; - spell->skill_level = 15; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "3+d3"); + spell_type_describe(spell, "Magically decreases the passing of time around you, making you move faster with"); + spell_type_describe(spell, "respect to the rest of the universe."); + spell_type_set_mana(spell, 20, 40); + spell_type_set_inertia(spell, 5, 20); + spell_type_set_difficulty(spell, 15, 50); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_TEMPORAL, + tempo_essence_of_speed_info, + tempo_essence_of_speed); + + spell_type_set_device_charges(spell, "3+d3"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 80; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 10, 39); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&BANISHMENT, "BANISHMENT", "Banishment"); - string_list_append(&spell->description, "Disrupts the space/time continuum in your area and teleports all monsters away."); - string_list_append(&spell->description, "At level 15 it may also lock them in a time bubble for a while."); - school_idx_add_new(&spell->schools, SCHOOL_TEMPORAL); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 30, 40); - spell_inertia_init(spell, 5, 50); - spell->info_func = tempo_banishment_info; - spell->effect_func = tempo_banishment; - spell->failure_rate = 95; - spell->skill_level = 30; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "1+d3"); + spell_type_describe(spell, "Disrupts the space/time continuum in your area and teleports all monsters away."); + spell_type_describe(spell, "At level 15 it may also lock them in a time bubble for a while."); + spell_type_add_school(spell, SCHOOL_CONVEYANCE); + spell_type_set_mana(spell, 30, 40); + spell_type_set_inertia(spell, 5, 50); + spell_type_set_difficulty(spell, 30, 95); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_TEMPORAL, + tempo_banishment_info, + tempo_banishment); + + spell_type_set_device_charges(spell, "1+d3"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 98; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 10, 36); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&RECHARGE, "RECHARGE", "Recharge"); - string_list_append(&spell->description, "Taps on the ambient mana to recharge an object's power (charges or mana)"); - school_idx_add_new(&spell->schools, SCHOOL_META); - range_init(&spell->mana_range, 10, 100); - spell->info_func = meta_recharge_info; - spell->effect_func = meta_recharge; - spell->failure_rate = 20; - spell->skill_level = 5; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Taps on the ambient mana to recharge an object's power (charges or mana)"); + spell_type_set_mana(spell, 10, 100); + spell_type_set_difficulty(spell, 5, 20); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_META, + meta_recharge_info, + meta_recharge); } { spell_type *spell = spell_new(&SPELLBINDER, "SPELLBINDER", "Spellbinder"); - string_list_append(&spell->description, "Stores spells in a trigger."); - string_list_append(&spell->description, "When the condition is met all spells fire off at the same time"); - string_list_append(&spell->description, "This spell takes a long time to cast so you are advised to prepare it"); - string_list_append(&spell->description, "in a safe area."); - string_list_append(&spell->description, "Also it will use the mana for the Spellbinder and the mana for the"); - string_list_append(&spell->description, "selected spells"); - school_idx_add_new(&spell->schools, SCHOOL_META); - range_init(&spell->mana_range, 100, 300); - spell->info_func = meta_spellbinder_info; - spell->effect_func = meta_spellbinder; - spell->failure_rate = 85; - spell->skill_level = 20; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Stores spells in a trigger."); + spell_type_describe(spell, "When the condition is met all spells fire off at the same time"); + spell_type_describe(spell, "This spell takes a long time to cast so you are advised to prepare it"); + spell_type_describe(spell, "in a safe area."); + spell_type_describe(spell, "Also it will use the mana for the Spellbinder and the mana for the"); + spell_type_describe(spell, "selected spells"); + spell_type_set_mana(spell, 100, 300); + spell_type_set_difficulty(spell, 20, 85); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_META, + meta_spellbinder_info, + meta_spellbinder); } { spell_type *spell = spell_new(&DISPERSEMAGIC, "DISPERSEMAGIC", "Disperse Magic"); - string_list_append(&spell->description, "Dispels a lot of magic that can affect you, be it good or bad"); - string_list_append(&spell->description, "Level 1: blindness and light"); - string_list_append(&spell->description, "Level 5: confusion and hallucination"); - string_list_append(&spell->description, "Level 10: speed (both bad or good) and light speed"); - string_list_append(&spell->description, "Level 15: stunning, meditation, cuts"); - string_list_append(&spell->description, "Level 20: hero, super hero, bless, shields, afraid, parasites, mimicry"); - school_idx_add_new(&spell->schools, SCHOOL_META); - range_init(&spell->mana_range, 30, 60); - spell_inertia_init(spell, 1, 5); - spell->info_func = meta_disperse_magic_info; - spell->effect_func = meta_disperse_magic; - spell->failure_rate = 40; - spell->skill_level = 15; - spell->castable_while_blind = TRUE; - spell->castable_while_confused = TRUE; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "5+d5"); + spell_type_describe(spell, "Dispels a lot of magic that can affect you, be it good or bad"); + spell_type_describe(spell, "Level 1: blindness and light"); + spell_type_describe(spell, "Level 5: confusion and hallucination"); + spell_type_describe(spell, "Level 10: speed (both bad or good) and light speed"); + spell_type_describe(spell, "Level 15: stunning, meditation, cuts"); + spell_type_describe(spell, "Level 20: hero, super hero, bless, shields, afraid, parasites, mimicry"); + spell_type_set_mana(spell, 30, 60); + spell_type_set_inertia(spell, 1, 5); + spell_type_set_difficulty(spell, 15, 40); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_set_castable_while_confused(spell, TRUE); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_META, + meta_disperse_magic_info, + meta_disperse_magic); + + spell_type_set_device_charges(spell, "5+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 25; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 5, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&TRACKER, "TRACKER", "Tracker"); - string_list_append(&spell->description, "Tracks down the last teleportation that happened on the level and teleports"); - string_list_append(&spell->description, "you to it"); - school_idx_add_new(&spell->schools, SCHOOL_META); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 50, 50); - spell->info_func = meta_tracker_info; - spell->effect_func = meta_tracker; - spell->failure_rate = 95; - spell->skill_level = 30; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Tracks down the last teleportation that happened on the level and teleports"); + spell_type_describe(spell, "you to it"); + spell_type_add_school(spell, SCHOOL_CONVEYANCE); + spell_type_set_mana(spell, 50, 50); + spell_type_set_difficulty(spell, 30, 95); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_META, + meta_tracker_info, + meta_tracker); } { spell_type *spell = spell_new(&INERTIA_CONTROL, "INERTIA_CONTROL", "Inertia Control"); - string_list_append(&spell->description, "Changes the energy flow of a spell to be continuously recasted"); - string_list_append(&spell->description, "at a given interval. The inertia controlled spell reduces your"); - string_list_append(&spell->description, "maximum mana by four times its cost."); - school_idx_add_new(&spell->schools, SCHOOL_META); - range_init(&spell->mana_range, 300, 700); - spell->info_func = meta_inertia_control_info; - spell->effect_func = meta_inertia_control; - spell->failure_rate = 95; - spell->skill_level = 37; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Changes the energy flow of a spell to be continuously recasted"); + spell_type_describe(spell, "at a given interval. The inertia controlled spell reduces your"); + spell_type_describe(spell, "maximum mana by four times its cost."); + spell_type_set_mana(spell, 300, 700); + spell_type_set_difficulty(spell, 37, 95); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_META, + meta_inertia_control_info, + meta_inertia_control); } { spell_type *spell = spell_new(&CHARM, "CHARM", "Charm"); - string_list_append(&spell->description, "Tries to manipulate the mind of a monster to make it friendly"); - string_list_append(&spell->description, "At level 15 it turns into a ball"); - string_list_append(&spell->description, "At level 35 it affects all monsters in sight"); - school_idx_add_new(&spell->schools, SCHOOL_MIND); - range_init(&spell->mana_range, 1, 20); - spell->info_func = mind_charm_info; - spell->effect_func = mind_charm; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "7+d5"); + spell_type_describe(spell, "Tries to manipulate the mind of a monster to make it friendly"); + spell_type_describe(spell, "At level 15 it turns into a ball"); + spell_type_describe(spell, "At level 35 it affects all monsters in sight"); + spell_type_set_mana(spell, 1, 20); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MIND, + mind_charm_info, + mind_charm); + + spell_type_set_device_charges(spell, "7+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 35; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 20, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&CONFUSE, "CONFUSE", "Confuse"); - string_list_append(&spell->description, "Tries to manipulate the mind of a monster to confuse it"); - string_list_append(&spell->description, "At level 15 it turns into a ball"); - string_list_append(&spell->description, "At level 35 it affects all monsters in sight"); - school_idx_add_new(&spell->schools, SCHOOL_MIND); - range_init(&spell->mana_range, 5, 30); - spell->info_func = mind_confuse_info; - spell->effect_func = mind_confuse; - spell->failure_rate = 20; - spell->skill_level = 5; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "3+d4"); + spell_type_describe(spell, "Tries to manipulate the mind of a monster to confuse it"); + spell_type_describe(spell, "At level 15 it turns into a ball"); + spell_type_describe(spell, "At level 35 it affects all monsters in sight"); + spell_type_set_mana(spell, 5, 30); + spell_type_set_difficulty(spell, 5, 20); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MIND, + mind_confuse_info, + mind_confuse); + + spell_type_set_device_charges(spell, "3+d4"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 45; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 20, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&ARMOROFFEAR, "ARMOROFFEAR", "Armor of Fear"); - string_list_append(&spell->description, "Creates a shield of pure fear around you. Any monster attempting to hit you"); - string_list_append(&spell->description, "must save or flee"); - school_idx_add_new(&spell->schools, SCHOOL_MIND); - range_init(&spell->mana_range, 10, 50); - spell_inertia_init(spell, 2, 20); - spell->info_func = mind_armor_of_fear_info; - spell->effect_func = mind_armor_of_fear; - spell->failure_rate = 35; - spell->skill_level = 10; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Creates a shield of pure fear around you. Any monster attempting to hit you"); + spell_type_describe(spell, "must save or flee"); + spell_type_set_mana(spell, 10, 50); + spell_type_set_inertia(spell, 2, 20); + spell_type_set_difficulty(spell, 10, 35); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MIND, + mind_armor_of_fear_info, + mind_armor_of_fear); } { spell_type *spell = spell_new(&STUN, "STUN", "Stun"); - string_list_append(&spell->description, "Tries to manipulate the mind of a monster to stun it"); - string_list_append(&spell->description, "At level 20 it turns into a ball"); - school_idx_add_new(&spell->schools, SCHOOL_MIND); - range_init(&spell->mana_range, 10, 90); - spell->info_func = mind_stun_info; - spell->effect_func = mind_stun; - spell->failure_rate = 45; - spell->skill_level = 15; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Tries to manipulate the mind of a monster to stun it"); + spell_type_describe(spell, "At level 20 it turns into a ball"); + spell_type_set_mana(spell, 10, 90); + spell_type_set_difficulty(spell, 15, 45); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_MIND, + mind_stun_info, + mind_stun); } { spell_type *spell = spell_new(&DRAIN, "DRAIN", "Drain"); - string_list_append(&spell->description, "Drains the mana contained in wands, staves and rods to increase yours"); - school_idx_add_new(&spell->schools, SCHOOL_UDUN); - school_idx_add_new(&spell->schools, SCHOOL_MANA); - range_init(&spell->mana_range, 0, 0); - spell->info_func = udun_drain_info; - spell->effect_func = udun_drain; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Drains the mana contained in wands, staves and rods to increase yours"); + spell_type_add_school(spell, SCHOOL_MANA); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_UDUN, + udun_drain_info, + udun_drain); } { spell_type *spell = spell_new(&GENOCIDE, "GENOCIDE", "Genocide"); - string_list_append(&spell->description, "Genocides all monsters of a race on the level"); - string_list_append(&spell->description, "At level 10 it can genocide all monsters near you"); - school_idx_add_new(&spell->schools, SCHOOL_UDUN); - school_idx_add_new(&spell->schools, SCHOOL_NATURE); - range_init(&spell->mana_range, 50, 50); - spell->info_func = udun_genocide_info; - spell->effect_func = udun_genocide; - spell->failure_rate = 90; - spell->skill_level = 25; - spell_init_mage(spell, RANDOM); - - dice_parse_checked(&spell->device_charges, "2+d2"); + spell_type_describe(spell, "Genocides all monsters of a race on the level"); + spell_type_describe(spell, "At level 10 it can genocide all monsters near you"); + spell_type_add_school(spell, SCHOOL_NATURE); + spell_type_set_mana(spell, 50, 50); + spell_type_set_difficulty(spell, 25, 90); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_UDUN, + udun_genocide_info, + udun_genocide); + + spell_type_set_device_charges(spell, "2+d2"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 85; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 5, 15); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&WRAITHFORM, "WRAITHFORM", "Wraithform"); - string_list_append(&spell->description, "Turns you into an immaterial being"); - school_idx_add_new(&spell->schools, SCHOOL_UDUN); - school_idx_add_new(&spell->schools, SCHOOL_CONVEYANCE); - range_init(&spell->mana_range, 20, 40); - spell_inertia_init(spell, 4, 30); - spell->info_func = udun_wraithform_info; - spell->effect_func = udun_wraithform; - spell->failure_rate = 95; - spell->skill_level = 30; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Turns you into an immaterial being"); + spell_type_add_school(spell, SCHOOL_CONVEYANCE); + spell_type_set_mana(spell, 20, 40); + spell_type_set_inertia(spell, 4, 30); + spell_type_set_difficulty(spell, 30, 95); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_UDUN, + udun_wraithform_info, + udun_wraithform); } { spell_type *spell = spell_new(&FLAMEOFUDUN, "FLAMEOFUDUN", "Flame of Udun"); - string_list_append(&spell->description, "Turns you into a powerful Balrog"); - school_idx_add_new(&spell->schools, SCHOOL_UDUN); - school_idx_add_new(&spell->schools, SCHOOL_FIRE); - range_init(&spell->mana_range, 70, 100); - spell_inertia_init(spell, 7, 15); - spell->info_func = udun_flame_of_udun_info; - spell->effect_func = udun_flame_of_udun; - spell->failure_rate = 95; - spell->skill_level = 35; - spell_init_mage(spell, RANDOM); + spell_type_describe(spell, "Turns you into a powerful Balrog"); + spell_type_add_school(spell, SCHOOL_FIRE); + spell_type_set_mana(spell, 70, 100); + spell_type_set_inertia(spell, 7, 15); + spell_type_set_difficulty(spell, 35, 95); + spell_type_init_mage(spell, + RANDOM, + SCHOOL_UDUN, + udun_flame_of_udun_info, + udun_flame_of_udun); } { spell_type *spell = spell_new(&CALL_THE_ELEMENTS, "CALL_THE_ELEMENTS", "Call the Elements"); - string_list_append(&spell->description, "Randomly creates various elements around you"); - string_list_append(&spell->description, "Each type of element chance is controlled by your level"); - string_list_append(&spell->description, "in the corresponding skill"); - string_list_append(&spell->description, "At level 17 it can be targeted"); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 2, 20); - spell->info_func = geomancy_call_the_elements_info; - spell->effect_func = geomancy_call_the_elements; - spell->failure_rate = 10; - spell->skill_level = 1; - spell->castable_while_blind = TRUE; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Randomly creates various elements around you"); + spell_type_describe(spell, "Each type of element chance is controlled by your level"); + spell_type_describe(spell, "in the corresponding skill"); + spell_type_describe(spell, "At level 17 it can be targeted"); + spell_type_set_mana(spell, 2, 20); + spell_type_set_difficulty(spell, 1, 10); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_mage(spell, + NO_RANDOM, + SCHOOL_GEOMANCY, + geomancy_call_the_elements_info, + geomancy_call_the_elements); } { spell_type *spell = spell_new(&CHANNEL_ELEMENTS, "CHANNEL_ELEMENTS", "Channel Elements"); - string_list_append(&spell->description, "Draws on the caster's immediate environs to form an attack or other effect."); - string_list_append(&spell->description, "Grass/Flower heals."); - string_list_append(&spell->description, "Water creates water bolt attacks."); - string_list_append(&spell->description, "Ice creates ice bolt attacks."); - string_list_append(&spell->description, "Sand creates a wall of thick, blinding, burning sand around you."); - string_list_append(&spell->description, "Lava creates fire bolt attacks."); - string_list_append(&spell->description, "Deep lava creates fire ball attacks."); - string_list_append(&spell->description, "Chasm creates darkness bolt attacks."); - string_list_append(&spell->description, "At Earth level 18, darkness becomes nether."); - string_list_append(&spell->description, "At Water level 8, water attacks become beams with a striking effect."); - string_list_append(&spell->description, "At Water level 12, ice attacks become balls of ice shards."); - string_list_append(&spell->description, "At Water level 18, water attacks push monsters back."); - string_list_append(&spell->description, "At Fire level 15, fire become hellfire."); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 3, 30); - spell->info_func = geomancy_channel_elements_info; - spell->effect_func = geomancy_channel_elements; - spell->failure_rate = 20; - spell->skill_level = 3; - spell->castable_while_blind = TRUE; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Draws on the caster's immediate environs to form an attack or other effect."); + spell_type_describe(spell, "Grass/Flower heals."); + spell_type_describe(spell, "Water creates water bolt attacks."); + spell_type_describe(spell, "Ice creates ice bolt attacks."); + spell_type_describe(spell, "Sand creates a wall of thick, blinding, burning sand around you."); + spell_type_describe(spell, "Lava creates fire bolt attacks."); + spell_type_describe(spell, "Deep lava creates fire ball attacks."); + spell_type_describe(spell, "Chasm creates darkness bolt attacks."); + spell_type_describe(spell, "At Earth level 18, darkness becomes nether."); + spell_type_describe(spell, "At Water level 8, water attacks become beams with a striking effect."); + spell_type_describe(spell, "At Water level 12, ice attacks become balls of ice shards."); + spell_type_describe(spell, "At Water level 18, water attacks push monsters back."); + spell_type_describe(spell, "At Fire level 15, fire become hellfire."); + spell_type_set_mana(spell, 3, 30); + spell_type_set_difficulty(spell, 3, 20); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_mage(spell, + NO_RANDOM, + SCHOOL_GEOMANCY, + geomancy_channel_elements_info, + geomancy_channel_elements); } { spell_type *spell = spell_new(&ELEMENTAL_WAVE, "ELEMENTAL_WAVE", "Elemental Wave"); - string_list_append(&spell->description, "Draws on an adjacent special square to project a slow-moving"); - string_list_append(&spell->description, "wave of that element in that direction"); - string_list_append(&spell->description, "Abyss squares cannot be channeled into a wave."); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 15, 50); - spell->info_func = geomancy_elemental_wave_info; - spell->effect_func = geomancy_elemental_wave; - spell->failure_rate = 20; - spell->skill_level = 15; - spell->castable_while_blind = TRUE; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Draws on an adjacent special square to project a slow-moving"); + spell_type_describe(spell, "wave of that element in that direction"); + spell_type_describe(spell, "Abyss squares cannot be channeled into a wave."); + spell_type_set_mana(spell, 15, 50); + spell_type_set_difficulty(spell, 15, 20); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_mage(spell, + NO_RANDOM, + SCHOOL_GEOMANCY, + geomancy_elemental_wave_info, + geomancy_elemental_wave); } { spell_type *spell = spell_new(&VAPORIZE, "VAPORIZE", "Vaporize"); - string_list_append(&spell->description, "Draws upon your immediate environs to form a cloud of damaging vapors"); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 3, 30); - spell->info_func = geomancy_vaporize_info; - spell->effect_func = geomancy_vaporize; - spell->depend_func = geomancy_vaporize_depends; - spell->failure_rate = 15; - spell->skill_level = 4; - spell->castable_while_blind = TRUE; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Draws upon your immediate environs to form a cloud of damaging vapors"); + spell_type_set_mana(spell, 3, 30); + spell_type_set_difficulty(spell, 4, 15); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_geomancy( + spell, + geomancy_vaporize_info, + geomancy_vaporize, + geomancy_vaporize_depends); } { spell_type *spell = spell_new(&GEOLYSIS, "GEOLYSIS", "Geolysis"); - string_list_append(&spell->description, "Burrows deeply and slightly at random into a wall,"); - string_list_append(&spell->description, "leaving behind tailings of various different sorts of walls in the passage."); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 15, 40); - spell->info_func = geomancy_geolysis_info; - spell->effect_func = geomancy_geolysis; - spell->depend_func = geomancy_geolysis_depends; - spell->failure_rate = 15; - spell->skill_level = 7; - spell->castable_while_blind = TRUE; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Burrows deeply and slightly at random into a wall,"); + spell_type_describe(spell, "leaving behind tailings of various different sorts of walls in the passage."); + spell_type_set_mana(spell, 15, 40); + spell_type_set_difficulty(spell, 7, 15); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_geomancy( + spell, + geomancy_geolysis_info, + geomancy_geolysis, + geomancy_geolysis_depends); } { spell_type *spell = spell_new(&DRIPPING_TREAD, "DRIPPING_TREAD", "Dripping Tread"); - string_list_append(&spell->description, "Causes you to leave random elemental forms behind as you walk"); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 15, 25); - spell->info_func = geomancy_dripping_tread_info; - spell->effect_func = geomancy_dripping_tread; - spell->depend_func = geomancy_dripping_tread_depends; - spell->failure_rate = 15; - spell->skill_level = 10; - spell->castable_while_blind = TRUE; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Causes you to leave random elemental forms behind as you walk"); + spell_type_set_mana(spell, 15, 25); + spell_type_set_difficulty(spell, 10, 15); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_geomancy( + spell, + geomancy_dripping_tread_info, + geomancy_dripping_tread, + geomancy_dripping_tread_depends); } { spell_type *spell = spell_new(&GROW_BARRIER, "GROW_BARRIER", "Grow Barrier"); - string_list_append(&spell->description, "Creates impassable terrain (walls, trees, etc.) around you."); - string_list_append(&spell->description, "At level 20 it can be projected around another area."); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 30, 40); - spell->info_func = geomancy_grow_barrier_info; - spell->effect_func = geomancy_grow_barrier; - spell->depend_func = geomancy_grow_barrier_depends; - spell->failure_rate = 15; - spell->skill_level = 12; - spell->castable_while_blind = TRUE; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Creates impassable terrain (walls, trees, etc.) around you."); + spell_type_describe(spell, "At level 20 it can be projected around another area."); + spell_type_set_mana(spell, 30, 40); + spell_type_set_difficulty(spell, 12, 15); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_geomancy( + spell, + geomancy_grow_barrier_info, + geomancy_grow_barrier, + geomancy_grow_barrier_depends); } { spell_type *spell = spell_new(&ELEMENTAL_MINION, "ELEMENTAL_MINION", "Elemental Minion"); - string_list_append(&spell->description, "Summons a minion from a nearby element."); - string_list_append(&spell->description, "Walls can summon Earth elmentals, Xorns and Xarens"); - string_list_append(&spell->description, "Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms"); - string_list_append(&spell->description, "and Sky Drakes"); - string_list_append(&spell->description, "Sandwalls and lava can summon Fire elementals and Ancient red dragons"); - string_list_append(&spell->description, "Icewall, and water can summon Water elementals, Water trolls and Water demons"); - school_idx_add_new(&spell->schools, SCHOOL_GEOMANCY); - range_init(&spell->mana_range, 40, 80); - spell->info_func = geomancy_elemental_minion_info; - spell->effect_func = geomancy_elemental_minion; - spell->failure_rate = 25; - spell->skill_level = 20; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Summons a minion from a nearby element."); + spell_type_describe(spell, "Walls can summon Earth elmentals, Xorns and Xarens"); + spell_type_describe(spell, "Dark Pits can summon Air elementals, Ancient blue dragons, Great Storm Wyrms"); + spell_type_describe(spell, "and Sky Drakes"); + spell_type_describe(spell, "Sandwalls and lava can summon Fire elementals and Ancient red dragons"); + spell_type_describe(spell, "Icewall, and water can summon Water elementals, Water trolls and Water demons"); + spell_type_set_mana(spell, 40, 80); + spell_type_set_difficulty(spell, 20, 25); + spell_type_init_geomancy( + spell, + geomancy_elemental_minion_info, + geomancy_elemental_minion, + NULL); } { spell_type *spell = spell_new(&ERU_SEE, "ERU_SEE", "See the Music"); - string_list_append(&spell->description, "Allows you to 'see' the Great Music from which the world"); - string_list_append(&spell->description, "originates, allowing you to see unseen things"); - string_list_append(&spell->description, "At level 10 it allows you to see your surroundings"); - string_list_append(&spell->description, "At level 20 it allows you to cure blindness"); - string_list_append(&spell->description, "At level 30 it allows you to fully see all the level"); - school_idx_add_new(&spell->schools, SCHOOL_ERU); - range_init(&spell->mana_range, 1, 50); - spell->info_func = eru_see_the_music_info; - spell->effect_func = eru_see_the_music; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_priest(spell); - spell->castable_while_blind = TRUE; + spell_type_describe(spell, "Allows you to 'see' the Great Music from which the world"); + spell_type_describe(spell, "originates, allowing you to see unseen things"); + spell_type_describe(spell, "At level 10 it allows you to see your surroundings"); + spell_type_describe(spell, "At level 20 it allows you to cure blindness"); + spell_type_describe(spell, "At level 30 it allows you to fully see all the level"); + spell_type_set_mana(spell, 1, 50); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_priest(spell, + SCHOOL_ERU, + eru_see_the_music_info, + eru_see_the_music); + spell_type_set_castable_while_blind(spell, TRUE); } { spell_type *spell = spell_new(&ERU_LISTEN, "ERU_LISTEN", "Listen to the Music"); - string_list_append(&spell->description, "Allows you to listen to the Great Music from which the world"); - string_list_append(&spell->description, "originates, allowing you to understand the meaning of things"); - string_list_append(&spell->description, "At level 14 it allows you to identify all your pack"); - string_list_append(&spell->description, "At level 30 it allows you to identify all items on the level"); - school_idx_add_new(&spell->schools, SCHOOL_ERU); - range_init(&spell->mana_range, 15, 200); - spell->info_func = eru_listen_to_the_music_info; - spell->effect_func = eru_listen_to_the_music; - spell->failure_rate = 25; - spell->skill_level = 7; - spell_init_priest(spell); + spell_type_describe(spell, "Allows you to listen to the Great Music from which the world"); + spell_type_describe(spell, "originates, allowing you to understand the meaning of things"); + spell_type_describe(spell, "At level 14 it allows you to identify all your pack"); + spell_type_describe(spell, "At level 30 it allows you to identify all items on the level"); + spell_type_set_mana(spell, 15, 200); + spell_type_set_difficulty(spell, 7, 25); + spell_type_init_priest(spell, + SCHOOL_ERU, + eru_listen_to_the_music_info, + eru_listen_to_the_music); } { spell_type *spell = spell_new(&ERU_UNDERSTAND, "ERU_UNDERSTAND", "Know the Music"); - string_list_append(&spell->description, "Allows you to understand the Great Music from which the world"); - string_list_append(&spell->description, "originates, allowing you to know the full abilities of things"); - string_list_append(&spell->description, "At level 10 it allows you to *identify* all your pack"); - school_idx_add_new(&spell->schools, SCHOOL_ERU); - range_init(&spell->mana_range, 200, 600); - spell->info_func = eru_know_the_music_info; - spell->effect_func = eru_know_the_music; - spell->failure_rate = 50; - spell->skill_level = 30; - spell_init_priest(spell); + spell_type_describe(spell, "Allows you to understand the Great Music from which the world"); + spell_type_describe(spell, "originates, allowing you to know the full abilities of things"); + spell_type_describe(spell, "At level 10 it allows you to *identify* all your pack"); + spell_type_set_mana(spell, 200, 600); + spell_type_set_difficulty(spell, 30, 50); + spell_type_init_priest(spell, + SCHOOL_ERU, + eru_know_the_music_info, + eru_know_the_music); } { spell_type *spell = spell_new(&ERU_PROT, "ERU_PROT", "Lay of Protection"); - string_list_append(&spell->description, "Creates a circle of safety around you"); - school_idx_add_new(&spell->schools, SCHOOL_ERU); - range_init(&spell->mana_range, 400, 400); - spell->info_func = eru_lay_of_protection_info; - spell->effect_func = eru_lay_of_protection; - spell->failure_rate = 80; - spell->skill_level = 35; - spell_init_priest(spell); + spell_type_describe(spell, "Creates a circle of safety around you"); + spell_type_set_mana(spell, 400, 400); + spell_type_set_difficulty(spell, 35, 80); + spell_type_init_priest(spell, + SCHOOL_ERU, + eru_lay_of_protection_info, + eru_lay_of_protection); } { spell_type *spell = spell_new(&MANWE_SHIELD, "MANWE_SHIELD", "Wind Shield"); - string_list_append(&spell->description, "It surrounds you with a shield of wind that deflects blows from evil monsters"); - string_list_append(&spell->description, "At level 10 it increases your armour rating"); - string_list_append(&spell->description, "At level 20 it retaliates against monsters that melee you"); - school_idx_add_new(&spell->schools, SCHOOL_MANWE); - range_init(&spell->mana_range, 100, 500); - spell->info_func = manwe_wind_shield_info; - spell->effect_func = manwe_wind_shield; - spell->failure_rate = 30; - spell->skill_level = 10; - spell_init_priest(spell); + spell_type_describe(spell, "It surrounds you with a shield of wind that deflects blows from evil monsters"); + spell_type_describe(spell, "At level 10 it increases your armour rating"); + spell_type_describe(spell, "At level 20 it retaliates against monsters that melee you"); + spell_type_set_mana(spell, 100, 500); + spell_type_set_difficulty(spell, 10, 30); + spell_type_init_priest(spell, + SCHOOL_MANWE, + manwe_wind_shield_info, + manwe_wind_shield); } { spell_type *spell = spell_new(&MANWE_AVATAR, "MANWE_AVATAR", "Avatar"); - string_list_append(&spell->description, "It turns you into a full grown Maia"); - school_idx_add_new(&spell->schools, SCHOOL_MANWE); - range_init(&spell->mana_range, 1000, 1000); - spell->info_func = manwe_avatar_info; - spell->effect_func = manwe_avatar; - spell->failure_rate = 80; - spell->skill_level = 35; - spell_init_priest(spell); + spell_type_describe(spell, "It turns you into a full grown Maia"); + spell_type_set_mana(spell, 1000, 1000); + spell_type_set_difficulty(spell, 35, 80); + spell_type_init_priest(spell, + SCHOOL_MANWE, + manwe_avatar_info, + manwe_avatar); } { spell_type *spell = spell_new(&MANWE_BLESS, "MANWE_BLESS", "Manwe's Blessing"); - string_list_append(&spell->description, "Manwe's Blessing removes your fears, blesses you and surrounds you with"); - string_list_append(&spell->description, "holy light"); - string_list_append(&spell->description, "At level 10 it also grants heroism"); - string_list_append(&spell->description, "At level 20 it also grants super heroism"); - string_list_append(&spell->description, "At level 30 it also grants holy luck and life protection"); - school_idx_add_new(&spell->schools, SCHOOL_MANWE); - range_init(&spell->mana_range, 10, 100); - spell->info_func = manwe_blessing_info; - spell->effect_func = manwe_blessing; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_priest(spell); + spell_type_describe(spell, "Manwe's Blessing removes your fears, blesses you and surrounds you with"); + spell_type_describe(spell, "holy light"); + spell_type_describe(spell, "At level 10 it also grants heroism"); + spell_type_describe(spell, "At level 20 it also grants super heroism"); + spell_type_describe(spell, "At level 30 it also grants holy luck and life protection"); + spell_type_set_mana(spell, 10, 100); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_priest(spell, + SCHOOL_MANWE, + manwe_blessing_info, + manwe_blessing); } { spell_type *spell = spell_new(&MANWE_CALL, "MANWE_CALL", "Manwe's Call"); - string_list_append(&spell->description, "Manwe's Call summons a Great Eagle to help you battle the forces"); - string_list_append(&spell->description, "of Morgoth"); - school_idx_add_new(&spell->schools, SCHOOL_MANWE); - range_init(&spell->mana_range, 200, 500); - spell->info_func = manwe_call_info; - spell->effect_func = manwe_call; - spell->failure_rate = 40; - spell->skill_level = 20; - spell_init_priest(spell); + spell_type_describe(spell, "Manwe's Call summons a Great Eagle to help you battle the forces"); + spell_type_describe(spell, "of Morgoth"); + spell_type_set_mana(spell, 200, 500); + spell_type_set_difficulty(spell, 20, 40); + spell_type_init_priest(spell, + SCHOOL_MANWE, + manwe_call_info, + manwe_call); } { spell_type *spell = spell_new(&TULKAS_AIM, "TULKAS_AIM", "Divine Aim"); - string_list_append(&spell->description, "It makes you more accurate in combat"); - string_list_append(&spell->description, "At level 20 all your blows are critical hits"); - school_idx_add_new(&spell->schools, SCHOOL_TULKAS); - range_init(&spell->mana_range, 30, 500); - spell->info_func = tulkas_divine_aim_info; - spell->effect_func = tulkas_divine_aim; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_priest(spell); + spell_type_describe(spell, "It makes you more accurate in combat"); + spell_type_describe(spell, "At level 20 all your blows are critical hits"); + spell_type_set_mana(spell, 30, 500); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_priest(spell, + SCHOOL_TULKAS, + tulkas_divine_aim_info, + tulkas_divine_aim); } { spell_type *spell = spell_new(&TULKAS_WAVE, "TULKAS_WAVE", "Wave of Power"); - string_list_append(&spell->description, "It allows you to project a number of melee blows across a distance"); - school_idx_add_new(&spell->schools, SCHOOL_TULKAS); - range_init(&spell->mana_range, 200, 200); - spell->info_func = tulkas_wave_of_power_info; - spell->effect_func = tulkas_wave_of_power; - spell->failure_rate = 75; - spell->skill_level = 20; - spell_init_priest(spell); + spell_type_describe(spell, "It allows you to project a number of melee blows across a distance"); + spell_type_set_mana(spell, 200, 200); + spell_type_set_difficulty(spell, 20, 75); + spell_type_init_priest(spell, + SCHOOL_TULKAS, + tulkas_wave_of_power_info, + tulkas_wave_of_power); } { spell_type *spell = spell_new(&TULKAS_SPIN, "TULKAS_SPIN", "Whirlwind"); - string_list_append(&spell->description, "It allows you to spin around and hit all monsters nearby"); - school_idx_add_new(&spell->schools, SCHOOL_TULKAS); - range_init(&spell->mana_range, 100, 100); - spell->info_func = tulkas_whirlwind_info; - spell->effect_func = tulkas_whirlwind; - spell->failure_rate = 45; - spell->skill_level = 10; - spell_init_priest(spell); + spell_type_describe(spell, "It allows you to spin around and hit all monsters nearby"); + spell_type_set_mana(spell, 100, 100); + spell_type_set_difficulty(spell, 10, 45); + spell_type_init_priest(spell, + SCHOOL_TULKAS, + tulkas_whirlwind_info, + tulkas_whirlwind); } { spell_type *spell = spell_new(&MELKOR_CURSE, "MELKOR_CURSE", "Curse"); - string_list_append(&spell->description, "It curses a monster, reducing its melee power"); - string_list_append(&spell->description, "At level 5 it can be auto-casted (with no piety cost) while fighting"); - string_list_append(&spell->description, "At level 15 it also reduces armor"); - string_list_append(&spell->description, "At level 25 it also reduces speed"); - string_list_append(&spell->description, "At level 35 it also reduces max life (but it is never fatal)"); - school_idx_add_new(&spell->schools, SCHOOL_MELKOR); - range_init(&spell->mana_range, 50, 300); - spell->info_func = melkor_curse_info; - spell->effect_func = melkor_curse; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_priest(spell); + spell_type_describe(spell, "It curses a monster, reducing its melee power"); + spell_type_describe(spell, "At level 5 it can be auto-casted (with no piety cost) while fighting"); + spell_type_describe(spell, "At level 15 it also reduces armor"); + spell_type_describe(spell, "At level 25 it also reduces speed"); + spell_type_describe(spell, "At level 35 it also reduces max life (but it is never fatal)"); + spell_type_set_mana(spell, 50, 300); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_priest(spell, + SCHOOL_MELKOR, + melkor_curse_info, + melkor_curse); } { spell_type *spell = spell_new(&MELKOR_CORPSE_EXPLOSION, "MELKOR_CORPSE_EXPLOSION", "Corpse Explosion"); - string_list_append(&spell->description, "It makes corpses in an area around you explode for a percent of their"); - string_list_append(&spell->description, "hit points as damage"); - school_idx_add_new(&spell->schools, SCHOOL_MELKOR); - range_init(&spell->mana_range, 100, 500); - spell->info_func = melkor_corpse_explosion_info; - spell->effect_func = melkor_corpse_explosion; - spell->failure_rate = 45; - spell->skill_level = 10; - spell_init_priest(spell); + spell_type_describe(spell, "It makes corpses in an area around you explode for a percent of their"); + spell_type_describe(spell, "hit points as damage"); + spell_type_set_mana(spell, 100, 500); + spell_type_set_difficulty(spell, 10, 45); + spell_type_init_priest(spell, + SCHOOL_MELKOR, + melkor_corpse_explosion_info, + melkor_corpse_explosion); } { spell_type *spell = spell_new(&MELKOR_MIND_STEAL, "MELKOR_MIND_STEAL", "Mind Steal"); - string_list_append(&spell->description, "It allows your spirit to temporarily leave your own body, which will"); - string_list_append(&spell->description, "be vulnerable, to control one of your enemies body."); - school_idx_add_new(&spell->schools, SCHOOL_MELKOR); - range_init(&spell->mana_range, 1000, 3000); - spell->info_func = melkor_mind_steal_info; - spell->effect_func = melkor_mind_steal; - spell->failure_rate = 90; - spell->skill_level = 20; - spell_init_priest(spell); + spell_type_describe(spell, "It allows your spirit to temporarily leave your own body, which will"); + spell_type_describe(spell, "be vulnerable, to control one of your enemies body."); + spell_type_set_mana(spell, 1000, 3000); + spell_type_set_difficulty(spell, 20, 90); + spell_type_init_priest(spell, + SCHOOL_MELKOR, + melkor_mind_steal_info, + melkor_mind_steal); } { spell_type *spell = spell_new(&YAVANNA_CHARM_ANIMAL, "YAVANNA_CHARM_ANIMAL", "Charm Animal"); - string_list_append(&spell->description, "It tries to tame an animal"); - school_idx_add_new(&spell->schools, SCHOOL_YAVANNA); - range_init(&spell->mana_range, 10, 100); - spell->info_func = yavanna_charm_animal_info; - spell->effect_func = yavanna_charm_animal; - spell->failure_rate = 30; - spell->skill_level = 1; - spell_init_priest(spell); + spell_type_describe(spell, "It tries to tame an animal"); + spell_type_set_mana(spell, 10, 100); + spell_type_set_difficulty(spell, 1, 30); + spell_type_init_priest(spell, + SCHOOL_YAVANNA, + yavanna_charm_animal_info, + yavanna_charm_animal); } { spell_type *spell = spell_new(&YAVANNA_GROW_GRASS, "YAVANNA_GROW_GRASS", "Grow Grass"); - string_list_append(&spell->description, "Create a floor of grass around you. While on grass and praying"); - string_list_append(&spell->description, "a worshipper of Yavanna will know a greater regeneration rate"); - school_idx_add_new(&spell->schools, SCHOOL_YAVANNA); - range_init(&spell->mana_range, 70, 150); - spell->info_func = yavanna_grow_grass_info; - spell->effect_func = yavanna_grow_grass; - spell->failure_rate = 65; - spell->skill_level = 10; - spell_init_priest(spell); + spell_type_describe(spell, "Create a floor of grass around you. While on grass and praying"); + spell_type_describe(spell, "a worshipper of Yavanna will know a greater regeneration rate"); + spell_type_set_mana(spell, 70, 150); + spell_type_set_difficulty(spell, 10, 65); + spell_type_init_priest(spell, + SCHOOL_YAVANNA, + yavanna_grow_grass_info, + yavanna_grow_grass); } { spell_type *spell = spell_new(&YAVANNA_TREE_ROOTS, "YAVANNA_TREE_ROOTS", "Tree Roots"); - string_list_append(&spell->description, "Creates roots deep in the floor from your feet, making you more stable and able"); - string_list_append(&spell->description, "to make stronger attacks, but prevents any movement (even teleportation)."); - string_list_append(&spell->description, "It also makes you recover from stunning almost immediately."); - school_idx_add_new(&spell->schools, SCHOOL_YAVANNA); - range_init(&spell->mana_range, 50, 1000); - spell->info_func = yavanna_tree_roots_info; - spell->effect_func = yavanna_tree_roots; - spell->failure_rate = 70; - spell->skill_level = 15; - spell_init_priest(spell); + spell_type_describe(spell, "Creates roots deep in the floor from your feet, making you more stable and able"); + spell_type_describe(spell, "to make stronger attacks, but prevents any movement (even teleportation)."); + spell_type_describe(spell, "It also makes you recover from stunning almost immediately."); + spell_type_set_mana(spell, 50, 1000); + spell_type_set_difficulty(spell, 15, 70); + spell_type_init_priest(spell, + SCHOOL_YAVANNA, + yavanna_tree_roots_info, + yavanna_tree_roots); } { spell_type *spell = spell_new(&YAVANNA_WATER_BITE, "YAVANNA_WATER_BITE", "Water Bite"); - string_list_append(&spell->description, "Imbues your melee weapon with a natural stream of water"); - string_list_append(&spell->description, "At level 25, it spreads over a 1 radius zone around your target"); - school_idx_add_new(&spell->schools, SCHOOL_YAVANNA); - range_init(&spell->mana_range, 150, 300); - spell->info_func = yavanna_water_bite_info; - spell->effect_func = yavanna_water_bite; - spell->failure_rate = 90; - spell->skill_level = 20; - spell_init_priest(spell); + spell_type_describe(spell, "Imbues your melee weapon with a natural stream of water"); + spell_type_describe(spell, "At level 25, it spreads over a 1 radius zone around your target"); + spell_type_set_mana(spell, 150, 300); + spell_type_set_difficulty(spell, 20, 90); + spell_type_init_priest(spell, + SCHOOL_YAVANNA, + yavanna_water_bite_info, + yavanna_water_bite); } { spell_type *spell = spell_new(&YAVANNA_UPROOT, "YAVANNA_UPROOT", "Uproot"); - string_list_append(&spell->description, "Awakes a tree to help you battle the forces of Morgoth"); - school_idx_add_new(&spell->schools, SCHOOL_YAVANNA); - range_init(&spell->mana_range, 250, 350); - spell->info_func = yavanna_uproot_info; - spell->effect_func = yavanna_uproot; - spell->failure_rate = 95; - spell->skill_level = 35; - spell_init_priest(spell); + spell_type_describe(spell, "Awakes a tree to help you battle the forces of Morgoth"); + spell_type_set_mana(spell, 250, 350); + spell_type_set_difficulty(spell, 35, 95); + spell_type_init_priest(spell, + SCHOOL_YAVANNA, + yavanna_uproot_info, + yavanna_uproot); } { spell_type *spell = spell_new(&DEMON_BLADE, "DEMON_BLADE", "Demon Blade"); - string_list_append(&spell->description, "Imbues your blade with fire to deal more damage"); - string_list_append(&spell->description, "At level 30 it deals hellfire damage"); - string_list_append(&spell->description, "At level 45 it spreads over a 1 radius zone around your target"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 4, 44); - spell->info_func = demonology_demon_blade_info; - spell->effect_func = demonology_demon_blade; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); - - dice_parse_checked(&spell->device_charges, "3+d7"); + spell_type_describe(spell, "Imbues your blade with fire to deal more damage"); + spell_type_describe(spell, "At level 30 it deals hellfire damage"); + spell_type_describe(spell, "At level 45 it spreads over a 1 radius zone around your target"); + spell_type_set_mana(spell, 4, 44); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_demonology(spell, + demonology_demon_blade_info, + demonology_demon_blade); + + spell_type_set_device_charges(spell, "3+d7"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 75; range_init(&device_allocation->base_level, 1, 17); range_init(&device_allocation->max_level, 20, 40); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEMON_MADNESS, "DEMON_MADNESS", "Demon Madness"); - string_list_append(&spell->description, "Fire 2 balls in opposite directions of randomly chaos, confusion or charm"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 5, 20); - spell->info_func = demonology_demon_madness_info; - spell->effect_func = demonology_demon_madness; - spell->failure_rate = 25; - spell->skill_level = 10; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Fire 2 balls in opposite directions of randomly chaos, confusion or charm"); + spell_type_set_mana(spell, 5, 20); + spell_type_set_difficulty(spell, 10, 25); + spell_type_init_demonology(spell, + demonology_demon_madness_info, + demonology_demon_madness); } { spell_type *spell = spell_new(&DEMON_FIELD, "DEMON_FIELD", "Demon Field"); - string_list_append(&spell->description, "Fires a cloud of deadly nexus over a radius of 7"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 20, 60); - spell->info_func = demonology_demon_field_info; - spell->effect_func = demonology_demon_field; - spell->failure_rate = 60; - spell->skill_level = 20; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Fires a cloud of deadly nexus over a radius of 7"); + spell_type_set_mana(spell, 20, 60); + spell_type_set_difficulty(spell, 20, 60); + spell_type_init_demonology(spell, + demonology_demon_field_info, + demonology_demon_field); } { spell_type *spell = spell_new(&DOOM_SHIELD, "DOOM_SHIELD", "Doom Shield"); - string_list_append(&spell->description, "Raises a mirror of pain around you, doing very high damage to your foes"); - string_list_append(&spell->description, "that dare hit you, but greatly reduces your armour class"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 2, 30); - spell->info_func = demonology_doom_shield_info; - spell->effect_func = demonology_doom_shield; - spell->failure_rate = 10; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Raises a mirror of pain around you, doing very high damage to your foes"); + spell_type_describe(spell, "that dare hit you, but greatly reduces your armour class"); + spell_type_set_mana(spell, 2, 30); + spell_type_set_difficulty(spell, 1, 10); + spell_type_init_demonology(spell, + demonology_doom_shield_info, + demonology_doom_shield); } { spell_type *spell = spell_new(&UNHOLY_WORD, "UNHOLY_WORD", "Unholy Word"); - string_list_append(&spell->description, "Kills a pet to heal you"); - string_list_append(&spell->description, "There is a chance that the pet won't die but will turn against you"); - string_list_append(&spell->description, "it will decrease with higher level"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 15, 45); - spell->info_func = demonology_unholy_word_info; - spell->effect_func = demonology_unholy_word; - spell->failure_rate = 55; - spell->skill_level = 25; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Kills a pet to heal you"); + spell_type_describe(spell, "There is a chance that the pet won't die but will turn against you"); + spell_type_describe(spell, "it will decrease with higher level"); + spell_type_set_mana(spell, 15, 45); + spell_type_set_difficulty(spell, 25, 55); + spell_type_init_demonology(spell, + demonology_unholy_word_info, + demonology_unholy_word); } { spell_type *spell = spell_new(&DEMON_CLOAK, "DEMON_CLOAK", "Demon Cloak"); - string_list_append(&spell->description, "Raises a mirror that can reflect bolts and arrows for a time"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 10, 40); - spell->info_func = demonology_demon_cloak_info; - spell->effect_func = demonology_demon_cloak; - spell->failure_rate = 70; - spell->skill_level = 20; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Raises a mirror that can reflect bolts and arrows for a time"); + spell_type_set_mana(spell, 10, 40); + spell_type_set_difficulty(spell, 20, 70); + spell_type_init_demonology(spell, + demonology_demon_cloak_info, + demonology_demon_cloak); } { spell_type *spell = spell_new(&DEMON_SUMMON, "DEMON_SUMMON", "Summon Demon"); - string_list_append(&spell->description, "Summons a leveled demon to your side"); - string_list_append(&spell->description, "At level 35 it summons a high demon"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 10, 50); - spell->info_func = demonology_summon_demon_info; - spell->effect_func = demonology_summon_demon; - spell->failure_rate = 30; - spell->skill_level = 5; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Summons a leveled demon to your side"); + spell_type_describe(spell, "At level 35 it summons a high demon"); + spell_type_set_mana(spell, 10, 50); + spell_type_set_difficulty(spell, 5, 30); + spell_type_init_demonology(spell, + demonology_summon_demon_info, + demonology_summon_demon); } { spell_type *spell = spell_new(&DISCHARGE_MINION, "DISCHARGE_MINION", "Discharge Minion"); - string_list_append(&spell->description, "The targeted pet will explode in a burst of gravity"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 20, 50); - spell->info_func = demonology_discharge_minion_info; - spell->effect_func = demonology_discharge_minion; - spell->failure_rate = 30; - spell->skill_level = 10; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "The targeted pet will explode in a burst of gravity"); + spell_type_set_mana(spell, 20, 50); + spell_type_set_difficulty(spell, 10, 30); + spell_type_init_demonology(spell, + demonology_discharge_minion_info, + demonology_discharge_minion); } { spell_type *spell = spell_new(&CONTROL_DEMON, "CONTROL_DEMON", "Control Demon"); - string_list_append(&spell->description, "Attempts to control a demon"); - school_idx_add_new(&spell->schools, SCHOOL_DEMON); - range_init(&spell->mana_range, 30, 70); - spell->info_func = demonology_control_demon_info; - spell->effect_func = demonology_control_demon; - spell->failure_rate = 55; - spell->skill_level = 25; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Attempts to control a demon"); + spell_type_set_mana(spell, 30, 70); + spell_type_set_difficulty(spell, 25, 55); + spell_type_init_demonology(spell, + demonology_control_demon_info, + demonology_control_demon); } { spell_type *spell = spell_new(&DEVICE_HEAL_MONSTER, "DEVICE_HEAL_MONSTER", "Heal Monster"); - string_list_append(&spell->description, "Heals a monster"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 5, 20); - spell->info_func = device_heal_monster_info; - spell->effect_func = device_heal_monster; - spell->failure_rate = 15; - spell->skill_level = 3; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Heals a monster"); + spell_type_set_mana(spell, 5, 20); + spell_type_set_difficulty(spell, 3, 15); + spell_type_init_device(spell, + device_heal_monster_info, + device_heal_monster); - dice_parse_checked(&spell->device_charges, "10+d10"); + spell_type_set_device_charges(spell, "10+d10"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 17; range_init(&device_allocation->base_level, 1, 15); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_SPEED_MONSTER, "DEVICE_SPEED_MONSTER", "Haste Monster"); - string_list_append(&spell->description, "Haste a monster"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 10, 10); - spell->info_func = device_haste_monster_info; - spell->effect_func = device_haste_monster; - spell->failure_rate = 30; - spell->skill_level = 10; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Haste a monster"); + spell_type_set_mana(spell, 10, 10); + spell_type_set_difficulty(spell, 10, 30); + spell_type_init_device(spell, + device_haste_monster_info, + device_haste_monster); - dice_parse_checked(&spell->device_charges, "10+d5"); + spell_type_set_device_charges(spell, "10+d5"); { device_allocation *device_allocation = device_allocation_new(TV_WAND); device_allocation->rarity = 7; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 20, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_WISH, "DEVICE_WISH", "Wish"); - string_list_append(&spell->description, "This grants you a wish, beware of what you ask for!"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 400, 400); - spell->info_func = device_wish_info; - spell->effect_func = device_wish; - spell->failure_rate = 99; - spell->skill_level = 50; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "This grants you a wish, beware of what you ask for!"); + spell_type_set_mana(spell, 400, 400); + spell_type_set_difficulty(spell, 50, 99); + spell_type_init_device(spell, + device_wish_info, + device_wish); - dice_parse_checked(&spell->device_charges, "1+d2"); + spell_type_set_device_charges(spell, "1+d2"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 98; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 1, 1); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_SUMMON, "DEVICE_SUMMON", "Summon"); - string_list_append(&spell->description, "Summons hostile monsters near you"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 5, 25); - spell->info_func = device_summon_monster_info; - spell->effect_func = device_summon_monster; - spell->failure_rate = 20; - spell->skill_level = 5; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Summons hostile monsters near you"); + spell_type_set_mana(spell, 5, 25); + spell_type_set_difficulty(spell, 5, 20); + spell_type_init_device(spell, + device_summon_monster_info, + device_summon_monster); - dice_parse_checked(&spell->device_charges, "1+d20"); + spell_type_set_device_charges(spell, "1+d20"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 13; range_init(&device_allocation->base_level, 1, 40); range_init(&device_allocation->max_level, 25, 50); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_MANA, "DEVICE_MANA", "Mana"); - string_list_append(&spell->description, "Restores a part(or all) of your mana"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 1, 1); - spell->info_func = device_mana_info; - spell->effect_func = device_mana; - spell->failure_rate = 80; - spell->skill_level = 30; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "Restores a part(or all) of your mana"); + spell_type_set_mana(spell, 1, 1); + spell_type_set_difficulty(spell, 30, 80); + spell_type_init_device(spell, + device_mana_info, + device_mana); - dice_parse_checked(&spell->device_charges, "2+d3"); + spell_type_set_device_charges(spell, "2+d3"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 78; range_init(&device_allocation->base_level, 1, 5); range_init(&device_allocation->max_level, 20, 35); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_NOTHING, "DEVICE_NOTHING", "Nothing"); - string_list_append(&spell->description, "It does nothing."); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 0, 0); - spell->info_func = device_nothing_info; - spell->effect_func = device_nothing; - spell->failure_rate = 0; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_describe(spell, "It does nothing."); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, 0); + spell_type_init_device(spell, + device_nothing_info, + device_nothing); - dice_parse_checked(&spell->device_charges, "0+d0"); + spell_type_set_device_charges(spell, "0+d0"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 3; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 1, 1); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } { @@ -2338,228 +2182,230 @@ void school_spells_init() device_allocation->rarity = 3; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 1, 1); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_MAGGOT, "DEVICE_MAGGOT", "Artifact Maggot"); - dice_parse_checked(&spell->activation_duration, "10+d50"); - string_list_append(&spell->description, "terrify"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 7, 7); - spell->info_func = device_maggot_info; - spell->effect_func = device_maggot; - spell->failure_rate = 20; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_set_activation_timeout(spell, "10+d50"); + spell_type_describe(spell, "terrify"); + spell_type_set_mana(spell, 7, 7); + spell_type_set_difficulty(spell, 1, 20); + spell_type_init_device(spell, + device_maggot_info, + device_maggot); } { spell_type *spell = spell_new(&DEVICE_HOLY_FIRE, "DEVICE_HOLY_FIRE", "Holy Fire of Mithrandir"); - string_list_append(&spell->description, "The Holy Fire created by this staff will deeply(double damage) burn"); - string_list_append(&spell->description, "all that is evil."); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 50, 150); - spell->info_func = device_holy_fire_info; - spell->effect_func = device_holy_fire; - spell->failure_rate = 75; - spell->skill_level = 30; - spell_init_mage(spell, NO_RANDOM); - - dice_parse_checked(&spell->device_charges, "2+d5"); + spell_type_describe(spell, "The Holy Fire created by this staff will deeply(double damage) burn"); + spell_type_describe(spell, "all that is evil."); + spell_type_set_mana(spell, 50, 150); + spell_type_set_difficulty(spell, 30, 75); + spell_type_init_device(spell, + device_holy_fire_info, + device_holy_fire); + + spell_type_set_device_charges(spell, "2+d5"); { device_allocation *device_allocation = device_allocation_new(TV_STAFF); device_allocation->rarity = 999; range_init(&device_allocation->base_level, 1, 1); range_init(&device_allocation->max_level, 35, 35); - sglib_device_allocation_add(&spell->device_allocation, device_allocation); + spell_type_add_device_allocation(spell, device_allocation); } } { spell_type *spell = spell_new(&DEVICE_ETERNAL_FLAME, "DEVICE_ETERNAL_FLAME", "Artifact Eternal Flame"); - dice_parse_checked(&spell->activation_duration, "0"); - string_list_append(&spell->description, "Imbuing an object with the eternal fire"); - school_idx_add_new(&spell->schools, SCHOOL_DEVICE); - range_init(&spell->mana_range, 0, 0); - spell->info_func = device_eternal_flame_info; - spell->effect_func = device_eternal_flame; - spell->failure_rate = 0; - spell->skill_level = 1; - spell_init_mage(spell, NO_RANDOM); + spell_type_set_activation_timeout(spell, "0"); + spell_type_describe(spell, "Imbuing an object with the eternal fire"); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, 0); + spell_type_init_device(spell, + device_eternal_flame_info, + device_eternal_flame); } { spell_type *spell = spell_new(&MUSIC_STOP, "MUSIC_STOP", "Stop singing(I)"); - string_list_append(&spell->description, "Stops the current song, if any."); - range_init(&spell->mana_range, 0, 0); - spell->info_func = music_stop_singing_info; - spell->effect_func = music_stop_singing_spell; - spell->failure_rate = -400; - spell->skill_level = 1; - spell->castable_while_blind = TRUE; - spell_init_music(spell, 1); + spell_type_describe(spell, "Stops the current song, if any."); + spell_type_set_mana(spell, 0, 0); + spell_type_set_difficulty(spell, 1, -400); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_music(spell, + 1, + music_stop_singing_info, + music_stop_singing_spell); } { spell_type *spell = spell_new(&MUSIC_HOLD, "MUSIC_HOLD", "Holding Pattern(I)"); - string_list_append(&spell->description, "Slows down all monsters listening the song."); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 1, 10); - spell->info_func = music_holding_pattern_info; - spell->effect_func = music_holding_pattern_spell; - spell->lasting_func = music_holding_pattern_lasting; - spell->failure_rate = 20; - spell->skill_level = 1; - spell->castable_while_blind = TRUE; - spell_init_music(spell, 1); + spell_type_describe(spell, "Slows down all monsters listening the song."); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 1, 10); + spell_type_set_difficulty(spell, 1, 20); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_music_lasting( + spell, + 1, + music_holding_pattern_info, + music_holding_pattern_spell, + music_holding_pattern_lasting); } { spell_type *spell = spell_new(&MUSIC_CONF, "MUSIC_CONF", "Illusion Pattern(II)"); - string_list_append(&spell->description, "Tries to confuse all monsters listening the song."); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 2, 15); - spell->info_func = music_illusion_pattern_info; - spell->effect_func = music_illusion_pattern_spell; - spell->lasting_func = music_illusion_pattern_lasting; - spell->failure_rate = 30; - spell->skill_level = 5; - spell->castable_while_blind = TRUE; - spell_init_music(spell, 2); + spell_type_describe(spell, "Tries to confuse all monsters listening the song."); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 2, 15); + spell_type_set_difficulty(spell, 5, 30); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_music_lasting( + spell, + 2, + music_illusion_pattern_info, + music_illusion_pattern_spell, + music_illusion_pattern_lasting); } { spell_type *spell = spell_new(&MUSIC_STUN, "MUSIC_STUN", "Stun Pattern(IV)"); - string_list_append(&spell->description, "Stuns all monsters listening the song."); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 3, 25); - spell->info_func = music_stun_pattern_info; - spell->effect_func = music_stun_pattern_spell; - spell->lasting_func = music_stun_pattern_lasting; - spell->failure_rate = 45; - spell->skill_level = 10; - spell->castable_while_blind = TRUE; - spell_init_music(spell, 4); + spell_type_describe(spell, "Stuns all monsters listening the song."); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 3, 25); + spell_type_set_difficulty(spell, 10, 45); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_music_lasting( + spell, + 4, + music_stun_pattern_info, + music_stun_pattern_spell, + music_stun_pattern_lasting); } { spell_type *spell = spell_new(&MUSIC_LITE, "MUSIC_LITE", "Song of the Sun(I)"); - string_list_append(&spell->description, "Provides light as long as you sing."); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 1, 1); - spell->info_func = music_song_of_the_sun_info; - spell->effect_func = music_song_of_the_sun_spell; - spell->lasting_func = music_song_of_the_sun_lasting; - spell->failure_rate = 20; - spell->skill_level = 1; - spell->castable_while_blind = TRUE; - spell_init_music(spell, 1); + spell_type_describe(spell, "Provides light as long as you sing."); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 1, 1); + spell_type_set_difficulty(spell, 1, 20); + spell_type_set_castable_while_blind(spell, TRUE); + spell_type_init_music_lasting( + spell, + 1, + music_song_of_the_sun_info, + music_song_of_the_sun_spell, + music_song_of_the_sun_lasting); } { spell_type *spell = spell_new(&MUSIC_HEAL, "MUSIC_HEAL", "Flow of Life(II)"); - string_list_append(&spell->description, "Heals you as long as you sing."); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 5, 30); - spell->info_func = music_flow_of_life_info; - spell->effect_func = music_flow_of_life_spell; - spell->lasting_func = music_flow_of_life_lasting; - spell->failure_rate = 35; - spell->skill_level = 7; - spell_init_music(spell, 2); + spell_type_describe(spell, "Heals you as long as you sing."); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 5, 30); + spell_type_set_difficulty(spell, 7, 35); + spell_type_init_music_lasting( + spell, + 2, + music_flow_of_life_info, + music_flow_of_life_spell, + music_flow_of_life_lasting); } { spell_type *spell = spell_new(&MUSIC_HERO, "MUSIC_HERO", "Heroic Ballad(II)"); - string_list_append(&spell->description, "Increases melee accuracy"); - string_list_append(&spell->description, "At level 10 it increases it even more and reduces armour a bit"); - string_list_append(&spell->description, "At level 20 it increases it again"); - string_list_append(&spell->description, "At level 25 it grants protection against chaos and confusion"); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 4, 14); - spell->info_func = music_heroic_ballad_info; - spell->effect_func = music_heroic_ballad_spell; - spell->lasting_func = music_heroic_ballad_lasting; - spell->failure_rate = 45; - spell->skill_level = 10; - spell_init_music(spell, 2); + spell_type_describe(spell, "Increases melee accuracy"); + spell_type_describe(spell, "At level 10 it increases it even more and reduces armour a bit"); + spell_type_describe(spell, "At level 20 it increases it again"); + spell_type_describe(spell, "At level 25 it grants protection against chaos and confusion"); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 4, 14); + spell_type_set_difficulty(spell, 10, 45); + spell_type_init_music_lasting( + spell, + 2, + music_heroic_ballad_info, + music_heroic_ballad_spell, + music_heroic_ballad_lasting); } { spell_type *spell = spell_new(&MUSIC_TIME, "MUSIC_TIME", "Hobbit Melodies(III)"); - string_list_append(&spell->description, "Greatly increases your reflexes allowing you to block more melee blows."); - string_list_append(&spell->description, "At level 15 it also makes you faster."); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 10, 30); - spell->info_func = music_hobbit_melodies_info; - spell->effect_func = music_hobbit_melodies_spell; - spell->lasting_func = music_hobbit_melodies_lasting; - spell->failure_rate = 70; - spell->skill_level = 20; - spell_init_music(spell, 3); + spell_type_describe(spell, "Greatly increases your reflexes allowing you to block more melee blows."); + spell_type_describe(spell, "At level 15 it also makes you faster."); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 10, 30); + spell_type_set_difficulty(spell, 20, 70); + spell_type_init_music_lasting( + spell, + 3, + music_hobbit_melodies_info, + music_hobbit_melodies_spell, + music_hobbit_melodies_lasting); } { spell_type *spell = spell_new(&MUSIC_MIND, "MUSIC_MIND", "Clairaudience(IV)"); - string_list_append(&spell->description, "Allows you to sense monster minds as long as you sing."); - string_list_append(&spell->description, "At level 10 it identifies all objects in a radius on the floor,"); - string_list_append(&spell->description, "as well as probing monsters in that radius."); - string_list_append(&spell->description, "Consumes the amount of mana each turn."); - range_init(&spell->mana_range, 15, 30); - spell->info_func = music_clairaudience_info; - spell->effect_func = music_clairaudience_spell; - spell->lasting_func = music_clairaudience_lasting; - spell->failure_rate = 75; - spell->skill_level = 25; - spell_init_music(spell, 4); + spell_type_describe(spell, "Allows you to sense monster minds as long as you sing."); + spell_type_describe(spell, "At level 10 it identifies all objects in a radius on the floor,"); + spell_type_describe(spell, "as well as probing monsters in that radius."); + spell_type_describe(spell, "Consumes the amount of mana each turn."); + spell_type_set_mana(spell, 15, 30); + spell_type_set_difficulty(spell, 25, 75); + spell_type_init_music_lasting( + spell, + 4, + music_clairaudience_info, + music_clairaudience_spell, + music_clairaudience_lasting); } { spell_type *spell = spell_new(&MUSIC_BLOW, "MUSIC_BLOW", "Blow(I)"); - string_list_append(&spell->description, "Produces a powerful, blowing, sound all around you."); - range_init(&spell->mana_range, 3, 30); - spell->info_func = music_blow_info; - spell->effect_func = music_blow_spell; - spell->failure_rate = 20; - spell->skill_level = 4; - spell_init_music(spell, 1); + spell_type_describe(spell, "Produces a powerful, blowing, sound all around you."); + spell_type_set_mana(spell, 3, 30); + spell_type_set_difficulty(spell, 4, 20); + spell_type_init_music(spell, + 1, + music_blow_info, + music_blow_spell); } { spell_type *spell = spell_new(&MUSIC_WIND, "MUSIC_WIND", "Gush of Wind(II)"); - string_list_append(&spell->description, "Produces a outgoing gush of wind that sends monsters away."); - range_init(&spell->mana_range, 15, 45); - spell->info_func = music_gush_of_wind_info; - spell->effect_func = music_gush_of_wind_spell; - spell->failure_rate = 30; - spell->skill_level = 14; - spell_init_music(spell, 2); + spell_type_describe(spell, "Produces a outgoing gush of wind that sends monsters away."); + spell_type_set_mana(spell, 15, 45); + spell_type_set_difficulty(spell, 14, 30); + spell_type_init_music(spell, + 2, + music_gush_of_wind_info, + music_gush_of_wind_spell); } { spell_type *spell = spell_new(&MUSIC_YLMIR, "MUSIC_YLMIR", "Horns of Ylmir(III)"); - string_list_append(&spell->description, "Produces an earth shaking sound."); - range_init(&spell->mana_range, 25, 30); - spell->info_func = music_horns_of_ylmir_info; - spell->effect_func = music_horns_of_ylmir_spell; - spell->failure_rate = 20; - spell->skill_level = 20; - spell_init_music(spell, 3); + spell_type_describe(spell, "Produces an earth shaking sound."); + spell_type_set_mana(spell, 25, 30); + spell_type_set_difficulty(spell, 20, 20); + spell_type_init_music(spell, + 3, + music_horns_of_ylmir_info, + music_horns_of_ylmir_spell); } { spell_type *spell = spell_new(&MUSIC_AMBARKANTA, "MUSIC_AMBARKANTA", "Ambarkanta(IV)"); - string_list_append(&spell->description, "Produces a reality shaking sound that transports you to a nearly"); - string_list_append(&spell->description, "identical reality."); - range_init(&spell->mana_range, 70, 70); - spell->info_func = music_ambarkanta_info; - spell->effect_func = music_ambarkanta_spell; - spell->failure_rate = 60; - spell->skill_level = 25; - spell_init_music(spell, 4); + spell_type_describe(spell, "Produces a reality shaking sound that transports you to a nearly"); + spell_type_describe(spell, "identical reality."); + spell_type_set_mana(spell, 70, 70); + spell_type_set_difficulty(spell, 25, 60); + spell_type_init_music(spell, + 4, + music_ambarkanta_info, + music_ambarkanta_spell); } /* Module-specific spells */ diff --git a/src/spells6.c b/src/spells6.c index 37e4c42c..5db4e18e 100644 --- a/src/spells6.c +++ b/src/spells6.c @@ -2,6 +2,8 @@ #include <assert.h> +#include "spell_type.h" + static int compare_school_provider(school_provider *a, school_provider *b) { return SGLIB_NUMERIC_COMPARATOR(a->deity_idx, b->deity_idx); @@ -150,122 +152,132 @@ long get_provided_levels(school_type *school) return 0; } -void get_level_school(s32b spell_idx, s32b max, s32b min, s32b *level, bool_ *na) +typedef struct get_level_school_callback_data get_level_school_callback_data; +struct get_level_school_callback_data { + bool_ allow_spell_power; + long bonus; + long lvl; + long num; +}; + +static bool_ get_level_school_callback(void *data_, int school_idx) { - spell_type *spell = spell_at(spell_idx); - school_idx *school_idx = NULL; - struct sglib_school_idx_iterator sit; - bool_ allow_spell_power = TRUE; - long lvl, num, bonus; + get_level_school_callback_data *data = data_; + school_type *school = school_at(school_idx); + long r = 0, s = 0, p = 0, ok = 0; - assert(level != NULL); - assert(na != NULL); + /* Does it require we worship a specific god? */ + if ((school->deity_idx > 0) && + (school->deity_idx != p_ptr->pgod)) + { + return FALSE; + } - lvl = 0; - num = 0; - bonus = 0; + /* Take the basic skill value */ + r = s_info[school->skill].value; /* Do we pass tests? */ - if (!check_spell_depends(spell)) + if ((school->depends_satisfied != NULL) && + (!school->depends_satisfied())) { - *level = min; - *na = TRUE; - return; + return FALSE; } - /* Go through all the spell's schools. */ - for (school_idx = sglib_school_idx_it_init(&sit, spell->schools); - school_idx != NULL; - school_idx = sglib_school_idx_it_next(&sit)) + /* Include effects of Sorcery (if applicable) */ + if (school->sorcery) { - school_type *school = school_at(school_idx->i); - long r = 0, s = 0, p = 0, ok = 0; + s = s_info[SKILL_SORCERY].value; + } - /* Does it require we worship a specific god? */ - if ((school->deity_idx > 0) && - (school->deity_idx != p_ptr->pgod)) - { - *level = min; - *na = TRUE; - return; - } + /* Include effects of Spell Power? Every school must + * allow use of Spell Power for it to apply. */ + if (!school->spell_power) + { + data->allow_spell_power = FALSE; + } - /* Take the basic skill value */ - r = s_info[school->skill].value; + /* Calculate effects of provided levels */ + p = get_provided_levels(school); - /* Do we pass tests? */ - if ((school->depends_satisfied != NULL) && - (!school->depends_satisfied())) - { - *level = min; - *na = TRUE; - return; - } + /* Find the highest of Skill, Sorcery and Provided levels. */ + ok = r; + if (ok < s) + { + ok = s; + } + if (ok < p) + { + ok = p; + } - /* Include effects of Sorcery (if applicable) */ - if (school->sorcery) - { - s = s_info[SKILL_SORCERY].value; - } + /* Do we need to add a special bonus? */ + if (school->bonus_levels != NULL) + { + data->bonus += (school->bonus_levels() * (SKILL_STEP / 10)); + } - /* Include effects of Spell Power? Every school must - * allow use of Spell Power for it to apply. */ - if (!school->spell_power) - { - allow_spell_power = FALSE; - } + /* All schools must be non-zero to be able to use it. */ + if (ok <= 0) + { + return FALSE; + } - /* Calculate effects of provided levels */ - p = get_provided_levels(school); + /* Apply it */ + data->lvl += ok; + data->num += 1; - /* Find the highest of Skill, Sorcery and Provided levels. */ - ok = r; - if (ok < s) - { - ok = s; - } - if (ok < p) - { - ok = p; - } + /* Keep going */ + return TRUE; +} - /* Do we need to add a special bonus? */ - if (school->bonus_levels != NULL) - { - bonus += (school->bonus_levels() * (SKILL_STEP / 10)); - } +void get_level_school(s32b spell_idx, s32b max, s32b min, s32b *level, bool_ *na) +{ + spell_type *spell = spell_at(spell_idx); - /* All schools must be non-zero to be able to use it. */ - if (ok <= 0) - { - *level = min; - *na = TRUE; - return; - } + assert(level != NULL); + assert(na != NULL); - /* Apply it */ - lvl = lvl + ok; - num = num + 1; + /* Do we pass tests? */ + if (!spell_type_dependencies_satisfied(spell)) + { + *level = min; + *na = TRUE; + return; + } + + /* Set up initial state */ + get_level_school_callback_data data; + data.allow_spell_power = TRUE; + data.bonus = 0; + data.lvl = 0; + data.num = 0; + + /* Go through all the spell's schools. */ + if (!spell_type_school_foreach(spell, get_level_school_callback, &data)) + { + *level = min; + *na = TRUE; + return; } /* Add the Spellpower skill as a bonus on top */ - if (allow_spell_power) + if (data.allow_spell_power) { - bonus += (get_skill_scale(SKILL_SPELL, 20) * (SKILL_STEP / 10)); + data.bonus += (get_skill_scale(SKILL_SPELL, 20) * (SKILL_STEP / 10)); } /* Add bonus from objects */ - bonus += (p_ptr->to_s * (SKILL_STEP / 10)); + data.bonus += (p_ptr->to_s * (SKILL_STEP / 10)); /* We divide by 10 because otherwise we can overflow a s32b * and we can use a u32b because the value can be negative. * The loss of information should be negligible since 1 skill * point is 1000 internally. */ - lvl = (lvl / num) / 10; - lvl = lua_get_level(spell, lvl, max, min, bonus); + data.lvl = (data.lvl / data.num) / 10; + data.lvl = lua_get_level(spell, data.lvl, max, min, data.bonus); /* Result */ - *level = lvl; + *level = data.lvl; *na = FALSE; } diff --git a/src/store.c b/src/store.c index 3114380c..6cdaad4a 100644 --- a/src/store.c +++ b/src/store.c @@ -12,6 +12,7 @@ #include "angband.h" +#include "spell_type.h" #include "quark.h" #define STORE_GENERAL_STORE "General Store" @@ -834,7 +835,7 @@ static bool_ store_will_buy(object_type *o_ptr) if ((o_ptr->tval == TV_BOOK) && (o_ptr->sval == BOOK_RANDOM) && - (can_spell_random(o_ptr->pval) == SKILL_SPIRITUALITY)) + (spell_type_random_type(spell_at(o_ptr->pval)) == SKILL_SPIRITUALITY)) { return TRUE; } @@ -892,7 +893,7 @@ static bool_ store_will_buy(object_type *o_ptr) if ((o_ptr->tval == TV_BOOK) && (o_ptr->sval == BOOK_RANDOM) && - (can_spell_random(o_ptr->pval) == SKILL_MAGIC)) + (spell_type_random_type(spell_at(o_ptr->pval)) == SKILL_MAGIC)) { return TRUE; } diff --git a/src/types.h b/src/types.h index 825e25ab..c921d028 100644 --- a/src/types.h +++ b/src/types.h @@ -2569,72 +2569,6 @@ struct skill_type u32b flags1; /* Skill flags */ }; - -/* - * School index list. - */ -typedef struct school_idx school_idx; -struct school_idx { - s32b i; /* School index */ - school_idx *next; /* for list */ -}; - - -/* - * Casting type - */ -typedef enum { USE_SPELL_POINTS, USE_PIETY } casting_type; - - -/* - * Spell effect function result - */ -typedef enum { - NO_CAST, /* Spell not cast; user aborted */ - CAST_OBVIOUS, /* Cast; caster discovers effect (devices) */ - CAST_HIDDEN /* Cast; caster does NOT discover effect (devices) */ -} casting_result; - -/* - * The spell function must provide the desc - */ -typedef struct spell_type spell_type; -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 */ - 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 */ - - 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 */ - 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_duration; /* Duration for activation (if any) */ - - school_idx *schools; -}; - typedef struct school_provider school_provider; struct school_provider { diff --git a/src/variable.c b/src/variable.c index 2ec4f7bc..84ca93ee 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1383,7 +1383,7 @@ bool_ player_char_health; * The spell list of schools */ s16b school_spells_count = 0; -spell_type school_spells[SCHOOL_SPELLS_MAX]; +spell_type *school_spells[SCHOOL_SPELLS_MAX]; s16b schools_count = 0; school_type schools[SCHOOLS_MAX]; |