diff --git a/scripts/eressea/equipment.lua b/scripts/eressea/equipment.lua index c7bfe7dad..71fe78727 100644 --- a/scripts/eressea/equipment.lua +++ b/scripts/eressea/equipment.lua @@ -132,7 +132,7 @@ function equip_unit(u, name, flags) end local spells = set['spells'] if spells then - for name, level in ipairs(spells) do + for name, level in pairs(spells) do u:add_spell(name, level) end end diff --git a/scripts/tests/e2/spells.lua b/scripts/tests/e2/spells.lua index 70d1bffb4..02699c0b8 100644 --- a/scripts/tests/e2/spells.lua +++ b/scripts/tests/e2/spells.lua @@ -215,12 +215,12 @@ function test_bug_2517() uf = um.familiar assert_not_nil(uf) assert_equal('lynx', uf.race) - assert_nil(uf.magic) + assert_equal('gray', uf.magic) uf:add_order('LERNE Magie') um:clear_orders() um:add_order('ARBEITEN') process_orders() - assert_nil(uf.magic) + assert_equal('gray', uf.magic) uf:add_order('ZAUBERE STUFE 1 Viehheilung') process_orders() assert_equal(50, uf:get_item('money')) diff --git a/src/bind_unit.c b/src/bind_unit.c index 3f2a037ea..ddd7b742f 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -276,8 +276,12 @@ static int tolua_unit_set_guard(lua_State * L) static const char *unit_getmagic(const unit * u) { - sc_mage *mage = get_mage_depr(u); - return mage ? magic_school[mage->magietyp] : NULL; + struct sc_mage *mage = get_mage(u); + if (mage) { + magic_t mtype = mage_get_type(mage); + return magic_school[mtype]; + } + return NULL; } static int tolua_unit_get_magic(lua_State * L) @@ -289,16 +293,15 @@ static int tolua_unit_get_magic(lua_State * L) static void unit_setmagic(unit * u, const char *type) { - sc_mage *mage = get_mage(u); - int mtype; - for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { - if (strcmp(magic_school[mtype], type) == 0) - break; - } - if (mtype == MAXMAGIETYP) - return; + struct sc_mage *mage = get_mage(u); if (mage == NULL) { - mage = create_mage(u, (magic_t)mtype); + int mtype; + for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { + if (strcmp(magic_school[mtype], type) == 0) { + create_mage(u, (magic_t)mtype); + return; + } + } } } @@ -521,7 +524,7 @@ static int tolua_unit_addspell(lua_State * L) return EINVAL; } else { - unit_add_spell(u, 0, sp, level); + unit_add_spell(u, sp, level); } lua_pushinteger(L, err); @@ -748,8 +751,8 @@ static int tolua_unit_get_items(lua_State * L) static int tolua_unit_get_spells(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - sc_mage *mage = self ? get_mage_depr(self) : 0; - spellbook *sb = mage ? mage->spellbook : 0; + struct sc_mage *mage = self ? get_mage(self) : NULL; + spellbook *sb = mage_get_spellbook(mage); selist *slist = 0; if (sb) { selist **slist_ptr = &sb->spells; diff --git a/src/creport.c b/src/creport.c index 69a9ed03e..db3df6c7e 100644 --- a/src/creport.c +++ b/src/creport.c @@ -880,7 +880,7 @@ void cr_output_unit(stream *out, const faction * f, const char *xc; const char *c; int i; - sc_mage *mage; + struct sc_mage *mage; i = ualias(u); if (i > 0) @@ -957,19 +957,23 @@ void cr_output_unit(stream *out, const faction * f, } /* spells that this unit can cast */ - mage = get_mage_depr(u); + mage = get_mage(u); if (mage) { int maxlevel = effskill(u, SK_MAGIC, 0); cr_output_spells(out, u, maxlevel); for (i = 0; i != MAXCOMBATSPELLS; ++i) { - const spell *sp = mage->combatspells[i].sp; + int level; + const spell *sp = mage_get_combatspell(mage, i, &level); if (sp) { - const char *name = - translate(mkname("spell", sp->sname), spell_name(sp, lang)); + const char *name; + if (level > maxlevel) { + level = maxlevel; + } stream_printf(out, "KAMPFZAUBER %d\n", i); + name = translate(mkname("spell", sp->sname), spell_name(sp, lang)); stream_printf(out, "\"%s\";name\n", name); - stream_printf(out, "%d;level\n", mage->combatspells[i].level); + stream_printf(out, "%d;level\n", level); } } } diff --git a/src/give.c b/src/give.c index 98ceff6bf..60b728479 100644 --- a/src/give.c +++ b/src/give.c @@ -587,14 +587,12 @@ void give_unit(unit * u, unit * u2, order * ord) } } if (has_skill(u, SK_MAGIC)) { - sc_mage *mage; if (count_skill(u2->faction, SK_MAGIC) + u->number > skill_limit(u2->faction, SK_MAGIC)) { cmistake(u, ord, 155, MSG_COMMERCE); return; } - mage = get_mage_depr(u); - if (!mage || u2->faction->magiegebiet != mage->magietyp) { + if (u2->faction->magiegebiet != unit_get_magic(u)) { cmistake(u, ord, 157, MSG_COMMERCE); return; } diff --git a/src/items/xerewards.test.c b/src/items/xerewards.test.c index dc9aa2621..d135b27fb 100644 --- a/src/items/xerewards.test.c +++ b/src/items/xerewards.test.c @@ -25,7 +25,7 @@ static void test_manacrystal(CuTest *tc) { CuAssertIntEquals(tc, -1, use_manacrystal(u, itype, 1, NULL)); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error295")); test_clear_messages(u->faction); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 5); CuAssertIntEquals(tc, 0, get_spellpoints(u)); CuAssertIntEquals(tc, 1, use_manacrystal(u, itype, 1, NULL)); diff --git a/src/kernel/save.c b/src/kernel/save.c index cfa254bf4..70f40e0cf 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1293,16 +1293,6 @@ ship *read_ship(gamedata *data) return sh; } -static void fix_fam_mage(unit *u) { - sc_mage *m = get_mage(u); - if (m && m->magietyp != M_GRAY) { - /* unit should be a familiar that has aura and a spell-list */ - if (!m->spellbook) { - m->magietyp = M_GRAY; - } - } -} - static void fix_fam_triggers(unit *u) { attrib * a = a_find(u->attribs, &at_mage); attrib * am = a_find(u->attribs, &at_familiarmage); @@ -1507,20 +1497,18 @@ int read_game(gamedata *data) assert(f->units); for (u = f->units; u; u = u->nextF) { if (data->version < SPELL_LEVEL_VERSION) { - sc_mage *mage = get_mage_depr(u); + struct sc_mage *mage = get_mage(u); if (mage) { faction *f = u->faction; int skl = effskill(u, SK_MAGIC, 0); if (f->magiegebiet == M_GRAY) { - log_error("faction %s had magic=gray, fixing (%s)", factionname(f), magic_school[mage->magietyp]); - f->magiegebiet = mage->magietyp; + f->magiegebiet = mage_get_type(mage); + log_error("faction %s had magic=gray, fixing (%s)", + factionname(f), magic_school[f->magiegebiet]); } if (f->max_spelllevel < skl) { f->max_spelllevel = skl; } - if (mage->spellcount < 0) { - mage->spellcount = 0; - } } } if (u->number > 0) { diff --git a/src/kernel/types.h b/src/kernel/types.h index 34c50e0a1..2b014bc94 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -117,7 +117,7 @@ enum { MAXOPTIONS }; -typedef enum { +typedef enum magic_t { M_GRAY = 0, /* Gray */ M_ILLAUN = 1, /* Illaun */ M_TYBIED = 2, /* Tybied */ diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 4366f95dc..748c76003 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1657,34 +1657,6 @@ void u_setrace(struct unit *u, const struct race *rc) } } -void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) -{ - sc_mage *mage = m ? m : get_mage_depr(u); - - if (!mage) { - log_debug("adding new spell %s to a previously non-mage unit %s\n", sp->sname, unitname(u)); - mage = create_mage(u, u->faction ? u->faction->magiegebiet : M_GRAY); - } - if (!mage->spellbook) { - mage->spellbook = create_spellbook(0); - } - spellbook_add(mage->spellbook, sp, level); -} - -struct spellbook * unit_get_spellbook(const struct unit * u) -{ - sc_mage * mage = get_mage_depr(u); - if (mage) { - if (mage->spellbook) { - return mage->spellbook; - } - if (mage->magietyp != M_GRAY) { - return faction_get_spellbook(u->faction); - } - } - return NULL; -} - int effskill(const unit * u, skill_t sk, const region *r) { assert(u); diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 169a5ff30..930574629 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -228,8 +228,6 @@ extern "C" { int unit_max_hp(const struct unit *u); void scale_number(struct unit *u, int n); - struct spellbook * unit_get_spellbook(const struct unit * u); - void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp, int level); void remove_empty_units_in_region(struct region * r); void remove_empty_units(void); diff --git a/src/laws.c b/src/laws.c index e8b6fee17..fdf763741 100644 --- a/src/laws.c +++ b/src/laws.c @@ -2419,7 +2419,22 @@ int combatspell_cmd(unit * u, struct order *ord) } else { /* KAMPFZAUBER "" setzt diesen Kampfzauber */ - set_combatspell(u, sp, ord, level); + /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ + if (!knowsspell(u->region, u, sp)) { + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + } + else if (!u_hasspell(u, sp)) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 169, MSG_MAGIC); + } + else if (!(sp->sptyp & ISCOMBATSPELL)) { + /* Diesen Kampfzauber gibt es nicht */ + cmistake(u, ord, 171, MSG_MAGIC); + } + else { + set_combatspell(u, sp, ord, level); + } } return 0; @@ -3169,8 +3184,8 @@ static int faction_getmages(faction * f, unit ** results, int numresults) for (u = f->units; u; u = u->nextF) { if (u->number > 0) { - sc_mage *mage = get_mage_depr(u); - if (mage) { + struct sc_mage * mage = get_mage(u); + if (mage && mage_get_spellbook(mage)) { int level = effskill(u, SK_MAGIC, 0); if (level > maxlevel) { maxlevel = level; @@ -3229,11 +3244,12 @@ static void update_spells(void) unit *mages[MAXMAGES]; int i; int maxlevel = faction_getmages(f, mages, MAXMAGES); + struct spellbook *fsb; if (maxlevel && FactionSpells()) { spellbook * book = get_spellbook(magic_school[f->magiegebiet]); if (!f->spellbook) { - f->spellbook = create_spellbook(0); + f->spellbook = create_spellbook(NULL); } copy_spells(book, f->spellbook, maxlevel); if (maxlevel > f->max_spelllevel) { @@ -3241,13 +3257,14 @@ static void update_spells(void) pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); } } - show_new_spells(f, maxlevel, faction_get_spellbook(f)); + fsb = faction_get_spellbook(f); + show_new_spells(f, maxlevel, fsb); for (i = 0; i != MAXMAGES && mages[i]; ++i) { unit * u = mages[i]; - sc_mage *mage = get_mage_depr(u); - if (mage && mage->spellbook) { - int level = effskill(u, SK_MAGIC, 0); - show_new_spells(f, level, mage->spellbook); + spellbook *sb = unit_get_spellbook(u); + if (sb != fsb) { + int level = effskill(u, SK_MAGIC, NULL); + show_new_spells(f, level, sb); } } } diff --git a/src/magic.c b/src/magic.c index 0698135f0..c13785a2c 100644 --- a/src/magic.c +++ b/src/magic.c @@ -103,6 +103,78 @@ const char *magic_school[MAXMAGIETYP] = { "common" }; +struct combatspell { + int level; + const struct spell *sp; +}; + +typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + struct combatspell combatspells[MAXCOMBATSPELLS]; + struct spellbook *spellbook; +} sc_mage; + +int mage_get_spellpoints(const sc_mage *m) +{ + return m ? m->spellpoints : 0; +} + +int mage_change_spellpoints(sc_mage *m, int delta) +{ + if (m) { + int val = m->spellpoints + delta; + return m->spellpoints = (val >= 0) ? val : m->spellpoints; + } + return 0; +} + +magic_t mage_get_type(const sc_mage *m) +{ + return m ? m->magietyp : M_GRAY; +} + +const spell *mage_get_combatspell(const sc_mage *mage, int nr, int *level) +{ + assert(nr < MAXCOMBATSPELLS); + if (mage) { + if (level) { + *level = mage->combatspells[nr].level; + } + return mage->combatspells[nr].sp; + } + return NULL; +} + +void unit_set_magic(struct unit *u, enum magic_t mtype) +{ + sc_mage *mage = get_mage(u); + if (mage) { + mage->magietyp = mtype; + } +} + +magic_t unit_get_magic(const unit *u) +{ + return mage_get_type(get_mage(u)); +} + +void unit_add_spell(unit * u, struct spell * sp, int level) +{ + sc_mage *mage = get_mage(u); + + if (!mage) { + log_error("adding new spell %s to a previously non-magical unit %s\n", sp->sname, unitname(u)); + mage = create_mage(u, M_GRAY); + } + if (!mage->spellbook) { + mage->spellbook = create_spellbook(0); + } + spellbook_add(mage->spellbook, sp, level); +} + /** ** at_icastle ** TODO: separate castle-appearance from illusion-effects @@ -199,6 +271,23 @@ const building_type *icastle_type(const struct attrib *a) { extern int dice(int count, int value); +bool FactionSpells(void) +{ + static int config, rule; + if (config_changed(&config)) { + rule = config_get_int("rules.magic.factionlist", 0); + } + return rule != 0; +} + +int get_spell_level_mage(const spell * sp, void * cbdata) +{ + sc_mage *mage = (sc_mage *)cbdata; + spellbook *book = get_spellbook(magic_school[mage->magietyp]); + spellbook_entry *sbe = spellbook_get(book, sp); + return sbe ? sbe->level : 0; +} + /* ------------------------------------------------------------- */ /* aus dem alten System übriggebliegene Funktionen, die bei der * Umwandlung von alt nach neu gebraucht werden */ @@ -219,23 +308,6 @@ static void free_mage(variant *var) free(mage); } -bool FactionSpells(void) -{ - static int config, rule; - if (config_changed(&config)) { - rule = config_get_int("rules.magic.factionlist", 0); - } - return rule != 0; -} - -int get_spell_level_mage(const spell * sp, void * cbdata) -{ - sc_mage *mage = (sc_mage *)cbdata; - spellbook *book = get_spellbook(magic_school[mage->magietyp]); - spellbook_entry *sbe = spellbook_get(book, sp); - return sbe ? sbe->level : 0; -} - static int read_mage(variant *var, void *owner, struct gamedata *data) { storage *store = data->store; @@ -278,7 +350,7 @@ static int read_mage(variant *var, void *owner, struct gamedata *data) read_spellbook(&mage->spellbook, data, get_spell_level_mage, mage); } else { - read_spellbook(0, data, 0, mage); + read_spellbook(NULL, data, NULL, mage); } return AT_READ_OK; } @@ -312,9 +384,10 @@ attrib_type at_mage = { ATF_UNIQUE }; -bool is_mage(const unit * u) +bool is_mage(const struct unit * u) { - return get_mage_depr(u) != NULL; + sc_mage *m = get_mage(u); + return (m && m->magietyp != M_GRAY); } sc_mage *get_mage(const unit * u) @@ -326,12 +399,22 @@ sc_mage *get_mage(const unit * u) return NULL; } -sc_mage *get_mage_depr(const unit * u) +struct spellbook * mage_get_spellbook(const struct sc_mage * mage) { + if (mage) { + return mage->spellbook; + } + return NULL; +} + +struct spellbook * unit_get_spellbook(const struct unit * u) { - if (has_skill(u, SK_MAGIC)) { - attrib *a = a_find(u->attribs, &at_mage); - if (a) { - return (sc_mage *)a->data.v; + sc_mage * mage = get_mage(u); + if (mage) { + if (mage->spellbook) { + return mage->spellbook; + } + if (mage->magietyp != M_GRAY) { + return faction_get_spellbook(u->faction); } } return NULL; @@ -436,17 +519,15 @@ int u_hasspell(const unit *u, const struct spell *sp) int get_combatspelllevel(const unit * u, int nr) { - sc_mage *m = get_mage_depr(u); - - assert(nr < MAXCOMBATSPELLS); - if (m) { - int level = effskill(u, SK_MAGIC, 0); - if (level < m->combatspells[nr].level) { - return level; + int level; + if (mage_get_combatspell(get_mage(u), nr, &level) != NULL) { + int maxlevel = effskill(u, SK_MAGIC, 0); + if (level > maxlevel) { + return maxlevel; } - return m->combatspells[nr].level; + return level; } - return -1; + return 0; } /* ------------------------------------------------------------- */ @@ -454,40 +535,15 @@ int get_combatspelllevel(const unit * u, int nr) const spell *get_combatspell(const unit * u, int nr) { - sc_mage *m; - - assert(nr < MAXCOMBATSPELLS); - m = get_mage_depr(u); - if (m) { - return m->combatspells[nr].sp; - } - return NULL; + return mage_get_combatspell(get_mage(u), nr, NULL); } void set_combatspell(unit * u, spell * sp, struct order *ord, int level) { - sc_mage *mage = get_mage_depr(u); + sc_mage *mage = get_mage(u); int i = -1; assert(mage || !"trying to set a combat spell for non-mage"); - - /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ - if (!knowsspell(u->region, u, sp)) { - /* Fehler 'Spell not found' */ - cmistake(u, ord, 173, MSG_MAGIC); - return; - } - if (!u_hasspell(u, sp)) { - /* Diesen Zauber kennt die Einheit nicht */ - cmistake(u, ord, 169, MSG_MAGIC); - return; - } - if (!(sp->sptyp & ISCOMBATSPELL)) { - /* Diesen Kampfzauber gibt es nicht */ - cmistake(u, ord, 171, MSG_MAGIC); - return; - } - if (sp->sptyp & PRECOMBATSPELL) i = 0; else if (sp->sptyp & COMBATSPELL) @@ -502,13 +558,12 @@ void set_combatspell(unit * u, spell * sp, struct order *ord, int level) void unset_combatspell(unit * u, spell * sp) { - sc_mage *m; int nr = 0; + sc_mage *m = get_mage(u); - m = get_mage_depr(u); - if (!m) + if (!m) { return; - + } if (!sp) { int i; for (i = 0; i < MAXCOMBATSPELLS; i++) { @@ -540,26 +595,15 @@ void unset_combatspell(unit * u, spell * sp) /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ int get_spellpoints(const unit * u) { - sc_mage *m; - - m = get_mage_depr(u); - if (!m) - return 0; - - return m->spellpoints; + return mage_get_spellpoints(get_mage(u)); } void set_spellpoints(unit * u, int sp) { - sc_mage *m; - - m = get_mage_depr(u); - if (!m) - return; - - m->spellpoints = sp; - - return; + sc_mage *m = get_mage(u); + if (m) { + m->spellpoints = sp; + } } /* @@ -567,23 +611,7 @@ void set_spellpoints(unit * u, int sp) */ int change_spellpoints(unit * u, int mp) { - sc_mage *m; - int sp; - - m = get_mage_depr(u); - if (!m) { - return 0; - } - - /* verhindere negative Magiepunkte */ - sp = m->spellpoints + mp; - if (sp > 0) { - m->spellpoints = sp; - } - else { - m->spellpoints = 0; - } - return sp; + return mage_change_spellpoints(get_mage(u), mp); } /* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit @@ -593,11 +621,8 @@ static int get_spchange(const unit * u) { sc_mage *m; - m = get_mage_depr(u); - if (!m) - return 0; - - return m->spchange; + m = get_mage(u); + return m ? m->spchange : 0; } /* ein Magier kann normalerweise maximal Stufe^2.1/1.2+1 Magiepunkte @@ -645,9 +670,7 @@ int max_spellpoints(const region * r, const unit * u) int change_maxspellpoints(unit * u, int csp) { - sc_mage *m; - - m = get_mage_depr(u); + sc_mage *m = get_mage(u); if (!m) { return 0; } @@ -660,30 +683,24 @@ int change_maxspellpoints(unit * u, int csp) */ int countspells(unit * u, int step) { - sc_mage *m; - int count; - - m = get_mage_depr(u); - if (!m) { - return 0; - } - if (step == 0) { - return m->spellcount; - } - count = m->spellcount + step; - - m->spellcount = (count > 0) ? count : 0; - return m->spellcount; -} - -int spellcount(const unit *u) { - sc_mage *m = get_mage_depr(u); + sc_mage * m = get_mage(u); if (m) { + int count; + if (step == 0) { + return m->spellcount; + } + count = m->spellcount + step; + m->spellcount = (count > 0) ? count : 0; return m->spellcount; } return 0; } +int spellcount(const unit *u) { + sc_mage *m = get_mage(u); + return m ? m->spellcount : 0; +} + /** * Die Grundkosten pro Stufe werden um 2^count erhöht. countspells(u) * ist dabei die Anzahl der bereits gezauberten Sprüche @@ -2193,18 +2210,67 @@ void remove_familiar(unit * mage) } } -void create_newfamiliar(unit * mage, unit * fam) -{ - /* skills and spells: */ +static void equip_familiar(unit *fam) { + /* items, skills and spells: */ char eqname[64]; const race *rc = u_race(fam); - set_familiar(mage, fam); - snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name); if (!equip_unit(fam, eqname)) { log_info("could not perform initialization for familiar %s.\n", rc->_name); } +} + +static int copy_spell_cb(spellbook_entry *sbe, void *udata) { + spellbook *sb = (spellbook *)udata; + spell * sp = spellref_get(&sbe->spref); + if (!spellbook_get(sb, sp)) { + spellbook_add(sb, sp, sbe->level); + } + return 0; +} + +/** + * Einmalige Reparatur von Vertrauten (Bugs 2451, 2517). + */ +void fix_fam_mage(unit *u) { + sc_mage *dmage; + unit *du = unit_create(0); + + u_setrace(du, u_race(u)); + dmage = create_mage(du, M_GRAY); + equip_familiar(du); + if (dmage) { + sc_mage *mage = get_mage(u); + if (!mage) { + mage = create_mage(u, dmage->magietyp); + } + else if (dmage->magietyp != mage->magietyp) { + mage->magietyp = dmage->magietyp; + } + if (dmage->spellbook) { + if (!mage->spellbook) { + mage->spellbook = create_spellbook(NULL); + spellbook_foreach(dmage->spellbook, copy_spell_cb, mage->spellbook); + } + } + else { + if (mage->spellbook) { + spellbook_clear(mage->spellbook); + mage->spellbook = NULL; + } + } + } + free_unit(du); +} + +void create_newfamiliar(unit * mage, unit * fam) +{ + + create_mage(fam, M_GRAY); + set_familiar(mage, fam); + equip_familiar(fam); + /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ /* Wenn der Magier stirbt, dann auch der Vertraute */ add_trigger(&mage->attribs, "destroy", trigger_killunit(fam)); diff --git a/src/magic.h b/src/magic.h index 030d21864..23e4692f7 100644 --- a/src/magic.h +++ b/src/magic.h @@ -27,18 +27,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - /* ------------------------------------------------------------- */ - #define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ #define MAX_SPELLRANK 9 /* Standard-Rank 5 */ #define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ #define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ - - /* ------------------------------------------------------------- */ - #define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */ #define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */ + struct sc_mage; + struct unit; + extern const char *magic_school[MAXMAGIETYP]; extern struct attrib_type at_familiar; extern struct attrib_type at_familiarmage; @@ -99,26 +97,12 @@ extern "C" { * - Spruchliste */ - typedef struct combatspell { - int level; - const struct spell *sp; - } combatspell; - typedef struct spell_names { struct spell_names *next; const struct locale *lang; void * tokens; } spell_names; - typedef struct sc_mage { - magic_t magietyp; - int spellpoints; - int spchange; - int spellcount; - combatspell combatspells[MAXCOMBATSPELLS]; - struct spellbook *spellbook; - } sc_mage; - /* ------------------------------------------------------------- */ /* Zauberliste */ @@ -217,12 +201,22 @@ extern "C" { */ /* Magier */ - sc_mage *create_mage(struct unit *u, magic_t mtyp); + struct sc_mage *create_mage(struct unit *u, magic_t mtyp); /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an * und initialisiert den Magiertypus mit mtyp. */ - sc_mage *get_mage(const struct unit *u); - sc_mage *get_mage_depr(const struct unit *u); - /* gibt u->mage zurück, bei nicht-Magiern *NULL */ + struct sc_mage *get_mage(const struct unit *u); + + enum magic_t mage_get_type(const struct sc_mage *mage); + const struct spell *mage_get_combatspell(const struct sc_mage *mage, int nr, int *level); + struct spellbook * mage_get_spellbook(const struct sc_mage * mage); + int mage_get_spellpoints(const struct sc_mage *m); + int mage_change_spellpoints(struct sc_mage *m, int delta); + + enum magic_t unit_get_magic(const struct unit *u); + void unit_set_magic(struct unit *u, enum magic_t mtype); + struct spellbook * unit_get_spellbook(const struct unit * u); + void unit_add_spell(struct unit * u, struct spell * sp, int level); + bool is_mage(const struct unit *u); /* gibt true, wenn u->mage gesetzt. */ bool is_familiar(const struct unit *u); @@ -332,7 +326,8 @@ extern "C" { void remove_familiar(struct unit *mage); void create_newfamiliar(struct unit *mage, struct unit *familiar); void create_newclone(struct unit *mage, struct unit *familiar); - struct unit *has_clone(struct unit *mage); + + void fix_fam_mage(struct unit *u); const char *spell_info(const struct spell *sp, const struct locale *lang); diff --git a/src/magic.test.c b/src/magic.test.c index fc05f361f..9979caf6d 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -117,7 +117,7 @@ void test_pay_spell(CuTest * tc) CuAssertPtrNotNull(tc, sp); set_level(u, SK_MAGIC, 5); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); change_resource(u, get_resourcetype(R_SILVER), 1); change_resource(u, get_resourcetype(R_AURA), 3); @@ -151,7 +151,7 @@ void test_pay_spell_failure(CuTest * tc) CuAssertPtrNotNull(tc, sp); set_level(u, SK_MAGIC, 5); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); CuAssertIntEquals(tc, 1, change_resource(u, get_resourcetype(R_SILVER), 1)); CuAssertIntEquals(tc, 2, change_resource(u, get_resourcetype(R_AURA), 2)); @@ -182,7 +182,7 @@ void test_getspell_unit(CuTest * tc) r = test_create_region(0, 0, NULL); f = test_create_faction(NULL); u = test_create_unit(f, r); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); enable_skill(SK_MAGIC, true); set_level(u, SK_MAGIC, 1); @@ -193,7 +193,7 @@ void test_getspell_unit(CuTest * tc) CuAssertPtrEquals(tc, NULL, unit_getspell(u, "Herp-a-derp", lang)); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); CuAssertPtrNotNull(tc, unit_getspell(u, "Herp-a-derp", lang)); test_teardown(); } @@ -277,7 +277,7 @@ void test_set_pre_combatspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= PRECOMBATSPELL; - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); set_combatspell(u, sp, 0, 2); CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); @@ -309,7 +309,7 @@ void test_set_main_combatspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= COMBATSPELL; - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); set_combatspell(u, sp, 0, 2); CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); @@ -341,7 +341,7 @@ void test_set_post_combatspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= POSTCOMBATSPELL; - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); set_combatspell(u, sp, 0, 2); CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); @@ -371,7 +371,7 @@ void test_hasspell(CuTest * tc) sp = create_spell("testspell"); sp->sptyp |= POSTCOMBATSPELL; - unit_add_spell(u, 0, sp, 2); + unit_add_spell(u, sp, 2); set_level(u, SK_MAGIC, 1); CuAssertTrue(tc, !u_hasspell(u, sp)); @@ -407,7 +407,7 @@ void test_multi_cast(CuTest *tc) { u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); set_level(u, SK_MAGIC, 10); - unit_add_spell(u, 0, sp, 1); + unit_add_spell(u, sp, 1); CuAssertPtrEquals(tc, sp, unit_getspell(u, "Feuerball", lang)); unit_addorder(u, create_order(K_CAST, u->faction->locale, "Feuerball")); @@ -451,7 +451,7 @@ static void test_max_spellpoints(CuTest *tc) { CuAssertIntEquals(tc, 1, max_spellpoints(u->region, u)); rc->maxaura = 200; CuAssertIntEquals(tc, 2, max_spellpoints(u->region, u)); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 1); CuAssertIntEquals(tc, 3, max_spellpoints(u->region, u)); set_level(u, SK_MAGIC, 2); @@ -485,7 +485,7 @@ static void test_illusioncastle(CuTest *tc) static void test_is_mage(CuTest *tc) { unit *u; - sc_mage *mage; + struct sc_mage *mage; test_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); @@ -502,18 +502,13 @@ static void test_is_mage(CuTest *tc) { static void test_get_mage(CuTest *tc) { unit *u; - sc_mage *mage; + struct sc_mage *mage; test_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); CuAssertPtrEquals(tc, NULL, get_mage(u)); - CuAssertPtrEquals(tc, NULL, get_mage_depr(u)); CuAssertPtrNotNull(tc, mage = create_mage(u, M_CERDDOR)); CuAssertPtrEquals(tc, mage, get_mage(u)); - CuAssertPtrEquals(tc, NULL, get_mage_depr(u)); - set_level(u, SK_MAGIC, 1); - CuAssertPtrEquals(tc, mage, get_mage(u)); - CuAssertPtrEquals(tc, mage, get_mage_depr(u)); test_teardown(); } diff --git a/src/move.c b/src/move.c index 8088ddd13..c919bc041 100644 --- a/src/move.c +++ b/src/move.c @@ -1,5 +1,5 @@ /* -Copyright (c) 1998-2014, +Copyright (c) 1998-2018, Enno Rehling Katja Zedel @@ -1430,9 +1430,10 @@ int movement_speed(const unit * u) /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. * Nicht kumulativ mit anderen Beschleunigungen! */ if (mp * dk <= BP_WALKING * u_race(u)->speed && is_astral(u->region)) { - sc_mage *mage = get_mage(u); - if (mage && (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN)) { - if (has_skill(u, SK_MAGIC)) { + struct sc_mage *mage = get_mage(u); + if (mage) { + magic_t mtype = mage_get_type(mage); + if (mtype == M_TYBIED || mtype == M_ILLAUN) { mp *= 2; } } diff --git a/src/reports.c b/src/reports.c index f93eea685..3ce83a7de 100644 --- a/src/reports.c +++ b/src/reports.c @@ -637,10 +637,10 @@ static size_t spskill(char *buffer, size_t size, const struct locale * lang, bufp = STRLCPY(bufp, " ", size); if (sv->id == SK_MAGIC) { - sc_mage *mage = get_mage(u); - if (mage && mage->magietyp != M_GRAY) { - bufp = STRLCPY(bufp, LOC(lang, mkname("school", - magic_school[mage->magietyp])), size); + magic_t mtype = unit_get_magic(u); + if (mtype != M_GRAY) { + bufp = STRLCPY(bufp, + LOC(lang, mkname("school", magic_school[mtype])), size); bufp = STRLCPY(bufp, " ", size); } } diff --git a/src/spells.c b/src/spells.c index a628f1949..7707a05b7 100644 --- a/src/spells.c +++ b/src/spells.c @@ -704,13 +704,13 @@ static int sp_destroy_magic(castorder * co) static int sp_transferaura(castorder * co) { - int aura, gain, multi = 2; + int aura, used, multi = 2; unit *caster = co_get_caster(co); unit *mage = co_get_magician(co); int cast_level = co->level; spellparameter *pa = co->par; unit *u; - sc_mage *scm_dst, *scm_src = get_mage(mage); + struct sc_mage *scm_dst, *scm_src = get_mage(mage); assert(scm_src); /* wenn kein Ziel gefunden, Zauber abbrechen */ @@ -725,25 +725,29 @@ static int sp_transferaura(castorder * co) /* Wieviel Transferieren? */ aura = pa->param[1]->data.i; u = pa->param[0]->data.u; - scm_dst = get_mage_depr(u); + scm_dst = get_mage(u); if (scm_dst == NULL) { /* "Zu dieser Einheit kann ich keine Aura uebertragen." */ cmistake(caster, co->order, 207, MSG_MAGIC); return 0; } - else if (scm_src->magietyp == M_TYBIED) { - if (scm_src->magietyp != scm_dst->magietyp) - multi = 3; - } - else if (scm_src->magietyp == M_GRAY) { - if (scm_src->magietyp != scm_dst->magietyp) - multi = 4; - } - else if (scm_dst->magietyp != scm_src->magietyp) { - /* "Zu dieser Einheit kann ich keine Aura uebertragen." */ - cmistake(caster, co->order, 207, MSG_MAGIC); - return 0; + else { + magic_t src = mage_get_type(scm_src); + magic_t dst = mage_get_type(scm_dst); + if (src != dst) { + if (src == M_TYBIED) { + multi = 3; + } + else if (src == M_GRAY) { + multi = 4; + } + else { + /* "Zu dieser Einheit kann ich keine Aura uebertragen." */ + cmistake(caster, co->order, 207, MSG_MAGIC); + return 0; + } + } } if (aura < multi) { @@ -752,16 +756,15 @@ static int sp_transferaura(castorder * co) return 0; } - gain = scm_src->spellpoints; - if (gain > aura) gain = aura; - gain = gain / multi; - scm_src->spellpoints -= gain * multi; - scm_dst->spellpoints += gain; + used = mage_get_spellpoints(scm_src); + if (used > aura) used = aura; + mage_change_spellpoints(scm_src, -used); + mage_change_spellpoints(scm_dst, used / multi); /* sprintf(buf, "%s transferiert %d Aura auf %s", unitname(mage), gain, unitname(u)); */ ADDMSG(&caster->faction->msgs, msg_message("auratransfer_success", - "unit target aura", caster, u, gain)); + "unit target aura", caster, u, used)); return cast_level; } @@ -5748,14 +5751,6 @@ static int sp_eternizewall(castorder * co) return cast_level; } -static magic_t get_magic_type(const struct unit *u) { - sc_mage *mage = get_mage(u); - if (mage) { - return mage->magietyp; - } - return M_GRAY; -} - /* ------------------------------------------------------------- */ /* Name: Opfere Kraft * Stufe: 15 @@ -5810,7 +5805,7 @@ int sp_permtransfer(castorder * co) change_maxspellpoints(mage, -aura); change_spellpoints(mage, -aura); - if (get_magic_type(tu) == get_magic_type(mage)) { + if (unit_get_magic(tu) == unit_get_magic(mage)) { change_maxspellpoints(tu, aura / 2); } else { @@ -5925,6 +5920,7 @@ int sp_stealaura(castorder * co) int cast_level = co->level; double power = co->force; spellparameter *pa = co->par; + struct sc_mage *scm; /* wenn kein Ziel gefunden, Zauber abbrechen */ if (pa->param[0]->flag == TARGET_NOTFOUND) @@ -5933,17 +5929,18 @@ int sp_stealaura(castorder * co) /* Zieleinheit */ u = pa->param[0]->data.u; - if (!get_mage_depr(u)) { + scm = get_mage(u); + if (!scm) { ADDMSG(&caster->faction->msgs, msg_message("stealaura_fail", "unit target", caster, u)); ADDMSG(&u->faction->msgs, msg_message("stealaura_fail_detect", "unit", u)); return 0; } - taura = (get_mage_depr(u)->spellpoints * (rng_int() % (int)(3 * power) + 1)) / 100; + taura = (mage_get_spellpoints(scm) * (rng_int() % (int)(3 * power) + 1)) / 100; if (taura > 0) { - change_spellpoints(u, -taura); + mage_change_spellpoints(scm, -taura); change_spellpoints(mage, taura); /* sprintf(buf, "%s entzieht %s %d Aura.", unitname(mage), unitname(u), taura); */ diff --git a/src/spy.c b/src/spy.c index 53a5b4321..02590bd77 100644 --- a/src/spy.c +++ b/src/spy.c @@ -72,11 +72,11 @@ void spy_message(int spy, const unit * u, const unit * target) ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, status)); if (spy > 20) { - sc_mage *mage = get_mage_depr(target); + magic_t mtype = unit_get_magic(target); /* for mages, spells and magic school */ - if (mage) { + if (mtype != M_GRAY) { ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "spy target type", u, - target, magic_school[mage->magietyp])); + target, magic_school[mtype])); } } if (spy > 6) { diff --git a/src/study.c b/src/study.c index 90cc001ec..977e8a7eb 100644 --- a/src/study.c +++ b/src/study.c @@ -420,15 +420,16 @@ int teach_cmd(unit * teacher, struct order *ord) if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ - sc_mage *mage1 = get_mage_depr(teacher); - sc_mage *mage2 = get_mage_depr(scholar); - if (mage2 && mage1 && mage2->magietyp != M_GRAY - && mage1->magietyp != mage2->magietyp) { - if (feedback) { - ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, - "error_different_magic", "target", scholar)); + magic_t mage2 = unit_get_magic(scholar); + if (mage2 != M_GRAY) { + magic_t mage1 = unit_get_magic(teacher); + if (mage1 != mage2) { + if (feedback) { + ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, + "error_different_magic", "target", scholar)); + } + continue; } - continue; } } sk_academy = sk; @@ -622,7 +623,7 @@ int study_cmd(unit * u, order * ord) } if (sk == SK_MAGIC) { - magic_t mtyp; + magic_t mtype; if (u->number > 1) { cmistake(u, ord, 106, MSG_MAGIC); return -1; @@ -630,7 +631,7 @@ int study_cmd(unit * u, order * ord) if (is_familiar(u)) { /* Vertraute zaehlen nicht zu den Magiern einer Partei, * koennen aber nur Graue Magie lernen */ - mtyp = M_GRAY; + mtype = M_GRAY; } else if (!has_skill(u, SK_MAGIC)) { int mmax = skill_limit(u->faction, SK_MAGIC); @@ -640,24 +641,24 @@ int study_cmd(unit * u, order * ord) "amount", mmax)); return -1; } - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE || mtyp == M_GRAY) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE || mtype == M_GRAY) { /* wurde kein Magiegebiet angegeben, wird davon * ausgegangen, dass das normal gelernt werden soll */ if (u->faction->magiegebiet != 0) { - mtyp = u->faction->magiegebiet; + mtype = u->faction->magiegebiet; } else { /* Es wurde kein Magiegebiet angegeben und die Partei * hat noch keins gewaehlt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return -1; } } } - if (mtyp != u->faction->magiegebiet) { + if (mtype != u->faction->magiegebiet) { /* Es wurde versucht, ein anderes Magiegebiet zu lernen * als das der Partei */ if (u->faction->magiegebiet != 0) { @@ -667,25 +668,25 @@ int study_cmd(unit * u, order * ord) else { /* Lernt zum ersten mal Magie und legt damit das * Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; + u->faction->magiegebiet = mtype; } } - create_mage(u, mtyp); + create_mage(u, mtype); } else { /* ist schon ein Magier und kein Vertrauter */ if (u->faction->magiegebiet == 0) { /* die Partei hat noch kein Magiegebiet gewaehlt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE) { - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE) { + mtype = getmagicskill(u->faction->locale); + if (mtype == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return -1; } } /* Legt damit das Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; + u->faction->magiegebiet = mtype; } } } diff --git a/src/study.test.c b/src/study.test.c index b2ac39172..446b442bb 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -429,9 +429,9 @@ static void test_study_magic(CuTest *tc) { CuAssertIntEquals(tc, 0, study_cmd(u, u->thisorder)); CuAssertIntEquals(tc, M_GWYRRD, f->magiegebiet); CuAssertIntEquals(tc, 0, i_get(u->items, itype)); - CuAssertPtrNotNull(tc, get_mage_depr(u)); + CuAssertPtrNotNull(tc, get_mage(u)); CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error65")); - CuAssertIntEquals(tc, M_GWYRRD, get_mage_depr(u)->magietyp); + CuAssertIntEquals(tc, M_GWYRRD, unit_get_magic(u)); test_teardown(); } diff --git a/src/triggers/shock.test.c b/src/triggers/shock.test.c index 4bbd4de88..952febfd0 100644 --- a/src/triggers/shock.test.c +++ b/src/triggers/shock.test.c @@ -23,7 +23,7 @@ static void test_shock(CuTest *tc) { test_setup(); shock_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 5); set_spellpoints(u, 10); u->hp = 10; @@ -44,7 +44,7 @@ static void test_shock_low(CuTest *tc) { test_setup(); shock_setup(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); - create_mage(u, M_GRAY); + create_mage(u, M_GWYRRD); set_level(u, SK_MAGIC, 5); set_spellpoints(u, 1); u->hp = 1;