- per-faction spellbook

- new rules for gray magic
This commit is contained in:
Enno Rehling 2009-05-24 11:17:16 +00:00
parent 9b972601f7
commit 591c85d4c7
17 changed files with 445 additions and 271 deletions

View File

@ -630,6 +630,20 @@ fwriteorder(FILE * F, const struct order * ord, const struct locale * lang)
fputc('"', F);
}
static void cr_output_spells(FILE * F, spell_list * slist, const faction * f, int maxlevel)
{
if (slist) {
fprintf(F, "SPRUECHE\n");
for (;slist; slist = slist->next) {
spell * sp = slist->data;
if (sp->level <= maxlevel) {
const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale));
fprintf(F, "\"%s\"\n", name);
}
}
}
}
/* prints all that belongs to a unit */
static void
cr_output_unit(FILE * F, const region * r,
@ -845,26 +859,18 @@ cr_output_unit(FILE * F, const region * r,
/* spells */
if (is_mage(u)) {
sc_mage * mage = get_mage(u);
spell_list * slist = mage->spells;
if (slist) {
int i;
int t = effskill(u, SK_MAGIC);
fprintf(F, "SPRUECHE\n");
for (;slist; slist = slist->next) {
spell * sp = slist->data;
if (sp->level <= t) {
const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale));
fprintf(F, "\"%s\"\n", name);
}
}
for (i=0;i!=MAXCOMBATSPELLS;++i) {
const spell * sp = mage->combatspells[i].sp;
if (sp) {
const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale));
fprintf(F, "KAMPFZAUBER %d\n", i);
fprintf(F, "\"%s\";name\n", name);
fprintf(F, "%d;level\n", mage->combatspells[i].level);
}
spell_list ** slistp = get_spelllist(mage, u->faction);
int i, maxlevel = effskill(u, SK_MAGIC);
cr_output_spells(F, *slistp, f, maxlevel);
for (i=0;i!=MAXCOMBATSPELLS;++i) {
const spell * sp = mage->combatspells[i].sp;
if (sp) {
const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale));
fprintf(F, "KAMPFZAUBER %d\n", i);
fprintf(F, "\"%s\";name\n", name);
fprintf(F, "%d;level\n", mage->combatspells[i].level);
}
}
}

View File

@ -2229,7 +2229,7 @@ reshow(unit * u, struct order * ord, const char * s, param_t p)
}
/* try for a spell */
sp = get_spellfromtoken(u, s, u->faction->locale);
if (sp!=NULL && has_spell(u, sp)) {
if (sp!=NULL && u_hasspell(u, sp)) {
attrib *a = a_find(u->faction->attribs, &at_seenspell);
while (a!=NULL && a->type==&at_seenspell && a->data.v!=sp) a = a->next;
if (a!=NULL) a_remove(&u->faction->attribs, a);

View File

@ -587,7 +587,7 @@ learn_cmd(unit * u, order * ord)
if (!is_mage(u)) create_mage(u, mtyp);
} else {
/* ist schon ein Magier und kein Vertrauter */
if(u->faction->magiegebiet == 0){
if (u->faction->magiegebiet == 0) {
/* die Partei hat noch kein Magiegebiet gewählt. */
mtyp = getmagicskill(u->faction->locale);
if (mtyp == M_NONE){
@ -737,5 +737,17 @@ learn_cmd(unit * u, order * ord)
}
}
}
else if (sk==SK_MAGIC) {
sc_mage * mage = get_mage(u);
int level = eff_skill(u, SK_MAGIC, r);
if (FactionSpells() && level>u->faction->max_spelllevel) {
update_spellbook(u->faction, level);
}
if (!mage) {
mage = create_mage(u, u->faction->magiegebiet);
}
updatespelllist(u);
}
return 0;
}

View File

@ -141,7 +141,7 @@ equip_unit(struct unit * u, const struct equipment * eq)
assert(!"trying to equip spells on a non-mage!");
} else {
while (sp) {
add_spell(m, sp->data);
add_spell(get_spelllist(m, u->faction), sp->data);
sp = sp->next;
}
}

View File

@ -264,6 +264,8 @@ destroyfaction(faction * f)
if (!f->alive) return;
freelist(f->spellbook);
while (f->battles) {
struct bmsg * bm = f->battles;
f->battles = bm->next;

View File

@ -65,6 +65,8 @@ typedef struct faction {
char *email;
char *passw;
char *override;
int max_spelllevel;
struct spell_list * spellbook;
const struct locale * locale;
int lastorders; /* enno: short? */
int age; /* enno: short? */

View File

@ -201,6 +201,36 @@ free_mage(attrib * a)
free(mage);
}
int FactionSpells(void)
{
static int rules_factionspells = -1;
if (rules_factionspells<0) {
rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0);
}
return rules_factionspells;
}
void read_spellist(struct spell_list ** slistp, struct storage * store)
{
for (;;) {
spell * sp;
char spname[64];
if (store->version<SPELLNAME_VERSION) {
int i = store->r_int(store);
if (i < 0) break;
sp = find_spellbyid(M_GRAU, (spellid_t)i);
} else {
store->r_tok_buf(store, spname, sizeof(spname));
if (strcmp(spname, "end")==0) break;
sp = find_spell(M_GRAU, spname);
}
if (sp!=NULL) {
add_spell(slistp, sp);
}
}
}
static int
read_mage(attrib * a, struct storage * store)
{
@ -241,35 +271,26 @@ read_mage(attrib * a, struct storage * store)
}
}
}
for (;;) {
spell * sp;
if (store->version<SPELLNAME_VERSION) {
i = store->r_int(store);
if (i < 0) break;
sp = find_spellbyid(mage->magietyp, (spellid_t)i);
} else {
store->r_tok_buf(store, spname, sizeof(spname));
if (strcmp(spname, "end")==0) break;
sp = find_spell(mage->magietyp, spname);
}
if (sp==NULL) {
/* flag upstream to show that updatespellist() is necessary (hackish) */
mage->spellcount = -1;
continue;
}
add_spell(mage, sp);
}
read_spellist(&mage->spells, store);
return AT_READ_OK;
}
void write_spelllist(const spell_list * slist, struct storage * store)
{
while (slist!=NULL) {
spell * sp = slist->data;
store->w_tok(store, sp->sname);
slist = slist->next;
}
store->w_tok(store, "end");
}
static void
write_mage(const attrib * a, struct storage * store)
{
int i;
sc_mage *mage = (sc_mage*)a->data.v;
spell_list *slist = mage->spells;
store->w_int(store, mage->magietyp);
store->w_int(store, mage->spellpoints);
store->w_int(store, mage->spchange);
@ -277,12 +298,7 @@ write_mage(const attrib * a, struct storage * store)
store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none");
store->w_int(store, mage->combatspells[i].level);
}
while (slist!=NULL) {
spell * sp = slist->data;
store->w_tok(store, sp->sname);
slist = slist->next;
}
store->w_tok(store, "end");
write_spelllist(mage->spells, store);
}
attrib_type at_mage = {
@ -325,59 +341,13 @@ find_magetype(const unit * u)
return m->magietyp;
}
/* ------------------------------------------------------------- */
/* ein 'neuer' Magier bekommt von Anfang an alle Sprüche seines
* Magiegebietes mit einer Stufe kleiner oder gleich seinem Magietalent
* in seine List-of-known-spells. Ausgenommen mtyp 0 (M_GRAU) */
static void
createspelllist(unit *u, magic_t mtyp)
{
spell_list * slist;
int sk;
if (mtyp == M_GRAU) return;
sk = effskill(u, SK_MAGIC);
if (sk == 0) return;
for (slist=spells;slist!=NULL;slist=slist->next) {
spell * sp = slist->data;
if (sp->magietyp == mtyp && sp->level <= sk) {
if (!has_spell(u, sp)) {
add_spell(get_mage(u), sp);
}
}
}
}
/* ------------------------------------------------------------- */
/* Erzeugen eines neuen Magiers */
sc_mage *
create_mage(unit * u, magic_t mtyp)
{
sc_mage *mage;
attrib *a;
a = a_find(u->attribs, &at_mage);
if (a!=NULL) {
a_remove(&u->attribs, a);
}
a = a_add(&u->attribs, a_new(&at_mage));
mage = a->data.v;
mage->magietyp = mtyp;
createspelllist(u, mtyp);
return mage;
}
/* ------------------------------------------------------------- */
/* Ausgabe der Spruchbeschreibungen
* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher
* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft
* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der
* Spruch zu seiner List-of-known-spells hinzugefügt werden.
*/
* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher
* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft
* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der
* Spruch zu seiner List-of-known-spells hinzugefügt werden.
*/
static int
@ -427,24 +397,65 @@ already_seen(const faction * f, const spell * sp)
return false;
}
void
updatespelllist(unit * u)
{
int sk = eff_skill(u, SK_MAGIC, u->region);
spell_list * slist;
spell * sp;
struct sc_mage * mage = get_mage(u);
magic_t gebiet = find_magetype(u);
boolean ismonster = is_monsters(u->faction);
#define GRAYSPELLS 2 /* number of new gray spells per level */
#define MAXSPELLS 256
/* Nur Wyrm-Magier bekommen den Wyrmtransformationszauber */
sp = find_spellbyid(M_GRAU, SPL_BECOMEWYRM);
/** update the spellbook with a new level
* Written for Eressea 1.1
*/
void
update_spellbook(faction * f, int level)
{
spell * grayspells[MAXSPELLS];
int numspells = 0;
spell_list * slist;
for (slist=spells;slist!=NULL;slist=slist->next) {
spell * sp = slist->data;
if (sp->magietyp == M_GRAU && level<f->max_spelllevel && sp->level<=level) {
grayspells[numspells++] = sp;
} else {
if (sp->magietyp == f->magiegebiet && sp->level <= level) {
if (!has_spell(f->spellbook, sp)) {
add_spell(&f->spellbook, sp);
}
}
}
}
while (numspells>0 && level>f->max_spelllevel) {
int i;
for (i=0;i!=GRAYSPELLS;++i) {
int maxspell = numspells;
int spellno = -1;
spell * sp;
do {
if (spellno==maxspell) {
--maxspell;
}
spellno = rng_int() % maxspell;
sp = grayspells[spellno];
}
while (maxspell>0 && sp && sp->level<=f->max_spelllevel);
if (sp) {
add_spell(&f->spellbook, sp);
grayspells[spellno] = 0;
}
}
++f->max_spelllevel;
}
}
#if KARMA_MODULE
void wyrm_update(unit * u, struct sc_mage * mage, int sk)
{
spell_list * slist, ** slistp;
/* Nur Wyrm-Magier bekommen den Wyrmtransformationszauber */
spell * sp = find_spellbyid(M_GRAU, SPL_BECOMEWYRM);
if (fspecial(u->faction, FS_WYRM) && !has_spell(u, sp) && sp->level<=sk) {
add_spell(mage, find_spellbyid(M_GRAU, SPL_BECOMEWYRM));
}
#endif /* KARMA_MODULE */
/* Transformierte Wyrm-Magier bekommen Drachenodem */
if (dragonrace(u->race)) {
@ -453,36 +464,55 @@ updatespelllist(unit * u)
/* keine breaks! Wyrme sollen alle drei Zauber können.*/
case RC_WYRM:
sp = find_spellbyid(M_GRAU, SPL_WYRMODEM);
if (sp!=NULL && !has_spell(u, sp) && sp->level<=sk) {
add_spell(mage, sp);
slistp = get_spelllist(mage, u->faction);
if (sp!=NULL && !has_spell(*slistp, sp) && sp->level<=sk) {
add_spell(slistp, sp);
}
case RC_DRAGON:
sp = find_spellbyid(M_GRAU, SPL_DRAGONODEM);
if (sp!=NULL && !has_spell(u, sp) && sp->level<=sk) {
add_spell(mage, sp);
slistp = get_spelllist(mage, u->faction);
if (sp!=NULL && !has_spell(*slistp, sp) && sp->level<=sk) {
add_spell(slistp, sp);
}
case RC_FIREDRAGON:
sp = find_spellbyid(M_GRAU, SPL_FIREDRAGONODEM);
if (sp!=NULL && !has_spell(u, sp) && sp->level<=sk) {
add_spell(mage, sp);
slistp = get_spelllist(mage, u->faction);
if (sp!=NULL && !has_spell(*slistp, sp) && sp->level<=sk) {
add_spell(slistp, sp);
}
break;
}
}
return slistp;
}
#endif
void
updatespelllist(unit * u)
{
int sk = eff_skill(u, SK_MAGIC, u->region);
spell_list * slist = spells;
struct sc_mage * mage = get_mage(u);
magic_t gebiet = find_magetype(u);
boolean ismonster = is_monsters(u->faction);
/* Magier mit keinem bzw M_GRAU bekommen weder Sprüche angezeigt noch
* neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten
* Drachen, die noch den Skill Magie haben */
for (slist=spells;slist!=NULL;slist=slist->next) {
if (FactionSpells()) {
spells = u->faction->spellbook;
}
for (;slist!=NULL;slist=slist->next) {
spell * sp = slist->data;
if (sp->level<=sk) {
boolean know = has_spell(u, sp);
boolean know = u_hasspell(u, sp);
if (know || (gebiet!=M_GRAU && sp->magietyp == gebiet)) {
faction * f = u->faction;
if (!know) add_spell(mage, sp);
if (!know) add_spell(get_spelllist(mage, u->faction), sp);
if (!ismonster && !already_seen(u->faction, sp)) {
a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp;
a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp;
@ -490,18 +520,41 @@ updatespelllist(unit * u)
}
}
}
#if KARMA_MODULE
wyrm_update(u, mage, sk);
#endif /* KARMA_MODULE */
}
/* ------------------------------------------------------------- */
/* Erzeugen eines neuen Magiers */
sc_mage *
create_mage(unit * u, magic_t mtyp)
{
sc_mage *mage;
attrib *a;
a = a_find(u->attribs, &at_mage);
if (a!=NULL) {
a_remove(&u->attribs, a);
}
a = a_add(&u->attribs, a_new(&at_mage));
mage = a->data.v;
mage->magietyp = mtyp;
return mage;
}
/* ------------------------------------------------------------- */
/* Funktionen für die Bearbeitung der List-of-known-spells */
void
add_spell(sc_mage* m, spell * sp)
add_spell(spell_list ** slistp, spell * sp)
{
if (m==NULL) {
if (slistp==NULL) {
log_error(("add_spell: unit is not a mage.\n"));
} else {
spell_list ** slist = spelllist_find(&m->spells, sp);
spell_list ** slist = spelllist_find(slistp, sp);
if (*slist) {
spell * psp = (*slist)->data;
if (psp==sp) {
@ -514,16 +567,23 @@ add_spell(sc_mage* m, spell * sp)
}
boolean
has_spell(const unit *u, const spell * sp)
has_spell(spell_list * slist, const spell * sp)
{
sc_mage * m = get_mage(u);
if (m!=NULL) {
spell_list * sfind = *spelllist_find(&m->spells, sp);
if (slist!=NULL) {
spell_list * sfind = *spelllist_find(&slist, sp);
return sfind!=NULL && sfind->data==sp;
}
return false;
}
boolean
u_hasspell(const struct unit *u, const struct spell * sp)
{
sc_mage * mage = get_mage(u);
if (mage) return has_spell(mage->spells, sp);
return false;
}
/* ------------------------------------------------------------- */
/* Eingestellte Kampfzauberstufe ermitteln */
@ -572,7 +632,7 @@ set_combatspell(unit *u, spell *sp, struct order * ord, int level)
cmistake(u, ord, 173, MSG_MAGIC);
return;
}
if (!has_spell(u, sp)) {
if (!u_hasspell(u, sp)) {
/* Diesen Zauber kennt die Einheit nicht */
cmistake(u, ord, 169, MSG_MAGIC);
return;
@ -917,7 +977,7 @@ knowsspell(const region * r, const unit * u, const spell * sp)
return false;
}
/* steht der Spruch in der Spruchliste? */
if (!has_spell(u, sp)) {
if (!u_hasspell(u, sp)) {
/* ist der Spruch aus einem anderen Magiegebiet? */
if (find_magetype(u) != sp->magietyp) {
return false;
@ -1439,52 +1499,52 @@ regeneration(unit * u)
void
regeneration_magiepunkte(void)
{
region *r;
unit *u;
int aura, auramax;
double reg_aura;
int n;
region *r;
unit *u;
int aura, auramax;
double reg_aura;
int n;
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
if (u->number && is_mage(u)) {
aura = get_spellpoints(u);
auramax = max_spellpoints(r, u);
if (aura < auramax) {
struct building * b = inside_building(u);
const struct building_type * btype = b?b->type:NULL;
reg_aura = (double)regeneration(u);
for (r = regions; r; r = r->next) {
for (u = r->units; u; u = u->next) {
if (u->number && is_mage(u)) {
aura = get_spellpoints(u);
auramax = max_spellpoints(r, u);
if (aura < auramax) {
struct building * b = inside_building(u);
const struct building_type * btype = b?b->type:NULL;
reg_aura = (double)regeneration(u);
/* Magierturm erhöht die Regeneration um 75% */
/* Steinkreis erhöht die Regeneration um 50% */
if (btype) reg_aura *= btype->auraregen;
/* Magierturm erhöht die Regeneration um 75% */
/* Steinkreis erhöht die Regeneration um 50% */
if (btype) reg_aura *= btype->auraregen;
/* Bonus/Malus durch Zauber */
n = get_curseeffect(u->attribs, C_AURA, 0);
if (n>0) {
reg_aura = (reg_aura*n)/100;
}
/* Bonus/Malus durch Zauber */
n = get_curseeffect(u->attribs, C_AURA, 0);
if (n>0) {
reg_aura = (reg_aura*n)/100;
}
/* Einfluss von Artefakten */
/* TODO (noch gibs keine)*/
/* Einfluss von Artefakten */
/* TODO (noch gibs keine)*/
/* maximal Differenz bis Maximale-Aura regenerieren
* mindestens 1 Aura pro Monat */
reg_aura = MAX(1,reg_aura);
reg_aura = MIN((auramax - aura), reg_aura);
/* maximal Differenz bis Maximale-Aura regenerieren
* mindestens 1 Aura pro Monat */
reg_aura = MAX(1,reg_aura);
reg_aura = MIN((auramax - aura), reg_aura);
aura += (int)reg_aura;
ADDMSG(&u->faction->msgs, msg_message(
"regenaura", "unit region amount",
u, r, (int)reg_aura));
}
set_spellpoints(u, MIN(aura, auramax));
aura += (int)reg_aura;
ADDMSG(&u->faction->msgs, msg_message(
"regenaura", "unit region amount",
u, r, (int)reg_aura));
}
set_spellpoints(u, MIN(aura, auramax));
/* Zum letzten Mal Spruchliste aktualisieren */
updatespelllist(u);
}
}
}
/* Zum letzten Mal Spruchliste aktualisieren */
/*updatespelllist(u);*/
}
}
}
}
static boolean
@ -2871,3 +2931,11 @@ spelllist_find(spell_list ** lspells, const spell * sp)
}
return lspells;
}
extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f)
{
if (mage) {
return &mage->spells;
}
return NULL;
}

View File

@ -279,10 +279,13 @@ void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level);
/* setzt Kampfzauber */
void unset_combatspell(struct unit *u, spell *sp);
/* löscht Kampfzauber */
void add_spell(struct sc_mage *mage, spell *sp);
void add_spell(spell_list ** slistp, spell *sp);
/* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */
boolean has_spell(const struct unit *u, const struct spell * sp);
boolean has_spell(struct spell_list *slist, const struct spell * sp);
/* prüft, ob der Spruch in der Spruchliste der Einheit steht. */
boolean u_hasspell(const struct unit * u, const struct spell * sp);
/* prüft, ob der Spruch in der Spruchliste der Einheit steht. */
void update_spellbook(struct faction * f, int level);
void updatespelllist(struct unit *u);
/* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner
* als das aktuelle Magietalent ist, in die Spruchliste der Einheit
@ -376,7 +379,11 @@ extern const char * spell_name(const struct spell * sp, const struct locale * la
extern const char * curse_name(const struct curse_type * ctype, const struct locale * lang);
extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj);
extern int FactionSpells();
extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f);
extern void write_spelllist(const struct spell_list * slist, struct storage * store);
extern void read_spellist(struct spell_list ** slistp, struct storage * store);
#ifdef __cplusplus
}
#endif

View File

@ -1249,6 +1249,7 @@ readfaction(struct storage * store)
}
}
read_groups(store, f);
read_spellist(&f->spellbook, store);
return f;
}
@ -1312,6 +1313,7 @@ writefaction(struct storage * store, const faction * f)
store->w_id(store, 0);
store->w_brk(store);
write_groups(store, f->groups);
write_spelllist(f->spellbook, store);
}
int

View File

@ -258,7 +258,7 @@ unit_addspell(unit * u, const char * name)
if (strcmp(name, sp->sname)==0) {
struct sc_mage * mage = get_mage(u);
if (add) log_error(("two spells are called %s.\n", name));
add_spell(mage, sp);
add_spell(get_spelllist(mage, u->faction), sp);
add = true;
}
slist=slist->next;

View File

@ -391,6 +391,24 @@ tolua_faction_tostring(lua_State *tolua_S)
return 1;
}
static int tolua_faction_get_spells(lua_State* tolua_S)
{
faction* self = (faction*)tolua_tousertype(tolua_S, 1, 0);
spell_list * slist = self->spellbook;
if (slist) {
spell_list ** spell_ptr = (spell_list **)lua_newuserdata(tolua_S, sizeof(spell_list *));
luaL_getmetatable(tolua_S, "spell_list");
lua_setmetatable(tolua_S, -2);
*spell_ptr = slist;
lua_pushcclosure(tolua_S, tolua_spelllist_next, 1);
return 1;
}
lua_pushnil(tolua_S);
return 1;
}
void
tolua_faction_open(lua_State* tolua_S)
{
@ -410,6 +428,7 @@ tolua_faction_open(lua_State* tolua_S)
tolua_variable(tolua_S, "info", tolua_faction_get_info, tolua_faction_set_info);
tolua_variable(tolua_S, "units", tolua_faction_get_units, NULL);
tolua_variable(tolua_S, "heroes", tolua_faction_get_heroes, NULL);
tolua_variable(tolua_S, "spells", tolua_faction_get_spells, 0);
tolua_variable(tolua_S, "maxheroes", tolua_faction_get_maxheroes, NULL);
tolua_variable(tolua_S, "password", tolua_faction_get_password, tolua_faction_set_password);
tolua_variable(tolua_S, "email", tolua_faction_get_email, tolua_faction_set_email);

View File

@ -489,12 +489,13 @@ unit_addspell(unit * u, const char * name)
{
int add = 0;
spell_list * slist = spells;
spell_list ** starget = NULL;
while (slist!=NULL) {
spell * sp = slist->data;
if (strcmp(name, sp->sname)==0) {
struct sc_mage * mage = get_mage(u);
starget = get_spelllist(get_mage(u), u->faction);
if (add) log_error(("two spells are called %s.\n", name));
add_spell(mage, sp);
add_spell(starget, sp);
add = 1;
}
slist=slist->next;
@ -514,17 +515,16 @@ tolua_unit_addspell(lua_State* tolua_S)
static void
unit_removespell(unit * u, const spell * sp)
{
sc_mage * mage = get_mage(u);
if (mage!=NULL) {
spell_list ** isptr = &mage->spells;
while (*isptr && (*isptr)->data != sp) {
isptr = &(*isptr)->next;
}
if (*isptr) {
spell_list * sptr = *isptr;
*isptr = sptr->next;
free(sptr);
}
spell_list ** isptr;
isptr = get_spelllist(get_mage(u), u->faction);
while (*isptr && (*isptr)->data != sp) {
isptr = &(*isptr)->next;
}
if (*isptr) {
spell_list * sptr = *isptr;
*isptr = sptr->next;
free(sptr);
}
}
@ -719,18 +719,23 @@ static int tolua_unit_get_items(lua_State* tolua_S)
static int tolua_unit_get_spells(lua_State* tolua_S)
{
unit* self = (unit*)tolua_tousertype(tolua_S, 1, 0);
sc_mage * mage;
spell_list ** spell_ptr = (spell_list **)lua_newuserdata(tolua_S, sizeof(spell_list *));
sc_mage * mage = get_mage(self);
luaL_getmetatable(tolua_S, "spell_list");
lua_setmetatable(tolua_S, -2);
if (mage) {
spell_list ** slist = get_spelllist(mage, self->faction);
assert(slist);
if (slist) {
spell_list ** spell_ptr = (spell_list **)lua_newuserdata(tolua_S, sizeof(spell_list *));
luaL_getmetatable(tolua_S, "spell_list");
lua_setmetatable(tolua_S, -2);
mage = get_mage(self);
*spell_ptr = mage?mage->spells:0;
lua_pushcclosure(tolua_S, tolua_spelllist_next, 1);
*spell_ptr = *slist;
lua_pushcclosure(tolua_S, tolua_spelllist_next, 1);
return 1;
}
}
lua_pushnil(tolua_S);
return 1;
}

View File

@ -48,6 +48,7 @@ without prior permission by the authors of Eressea.
#include <util/attrib.h>
#include <util/base36.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/log.h>
#include <util/rand.h>
@ -775,6 +776,55 @@ tolua_write_spells(lua_State* tolua_S)
return 0;
}
static int
tolua_get_spell_text(lua_State *tolua_S)
{
const struct locale * loc = find_locale("en");
spell * self = (spell *)tolua_tousertype(tolua_S, 1, 0);
lua_pushstring(tolua_S, spell_info(self, loc));
return 1;
}
static int
tolua_get_spell_school(lua_State *tolua_S)
{
spell * self = (spell *)tolua_tousertype(tolua_S, 1, 0);
lua_pushstring(tolua_S, magietypen[self->magietyp]);
return 1;
}
static int
tolua_get_spell_level(lua_State *tolua_S)
{
spell * self = (spell *)tolua_tousertype(tolua_S, 1, 0);
lua_pushnumber(tolua_S, self->level);
return 1;
}
static int
tolua_get_spell_name(lua_State *tolua_S)
{
spell * self = (spell *)tolua_tousertype(tolua_S, 1, 0);
lua_pushstring(tolua_S, self->sname);
return 1;
}
static int tolua_get_spells(lua_State* tolua_S)
{
spell_list * slist = spells;
if (slist) {
spell_list ** spell_ptr = (spell_list **)lua_newuserdata(tolua_S, sizeof(spell_list *));
luaL_getmetatable(tolua_S, "spell_list");
lua_setmetatable(tolua_S, -2);
*spell_ptr = slist;
lua_pushcclosure(tolua_S, tolua_spelllist_next, 1);
return 1;
}
lua_pushnil(tolua_S);
return 1;
}
int
tolua_eressea_open(lua_State* tolua_S)
{
@ -801,6 +851,17 @@ tolua_eressea_open(lua_State* tolua_S)
}
tolua_endmodule(tolua_S);
tolua_cclass(tolua_S, "spell", "spell", "", NULL);
tolua_beginmodule(tolua_S, "spell");
{
tolua_function(tolua_S, "__tostring", tolua_get_spell_name);
tolua_variable(tolua_S, "name", tolua_get_spell_name, 0);
tolua_variable(tolua_S, "school", tolua_get_spell_school, 0);
tolua_variable(tolua_S, "level", tolua_get_spell_level, 0);
tolua_variable(tolua_S, "text", tolua_get_spell_text, 0);
}
tolua_endmodule(tolua_S);
tolua_function(tolua_S, "get_region_by_id", tolua_get_region_byid);
tolua_function(tolua_S, "get_faction", tolua_get_faction);
@ -874,6 +935,7 @@ tolua_eressea_open(lua_State* tolua_S)
tolua_function(tolua_S, "rng_int", tolua_rng_int);
tolua_function(tolua_S, "spells", tolua_get_spells);
tolua_function(tolua_S, "write_spells", tolua_write_spells);
}
tolua_endmodule(tolua_S);

View File

@ -114,6 +114,7 @@
<param name="nmr.removenewbie" value="0"/>
<param name="GiveRestriction" value="3"/>
<param name="hunger.long" value="0"/>
<param name="init_spells" value="0"/>
<param name="hunger.damage" value="1d9+9"/>
<param name="recruit.allow_merge" value="1"/>
<param name="study.expensivemigrants" value="1"/>
@ -124,6 +125,7 @@
<param name="rules.combat.loot" value="3"/> <!-- only self + monsters -->
<param name="rules.cavalry.skill" value="4"/>
<param name="rules.cavalry.mode" value="1"/>
<param name="rules.magic.factionlist" value="1"/>
<param name="rules.economy.taxation" value="1"/>
<param name="rules.give" value="3"/> <!-- only self + peasants -->
<param name="rules.help.mask" value="fight guard money"/>

View File

@ -9,7 +9,6 @@
<param name="hunger.damage" value="1d8+7"/>
<param name="other_race" value="demon"/>
<param name="other_cost" value="500"/>
<skill name="alchemy" modifier="1"/>
<skill name="building" modifier="1"/>
<skill name="cartmaking" modifier="-1"/>
<skill name="catapult" modifier="1"/>
@ -30,7 +29,6 @@
<function name="itemdrop" value="defaultdrops"/>
<param name="other_race" value="troll"/>
<param name="other_cost" value="500"/>
<skill name="alchemy" modifier="1"/>
<skill name="armorer" modifier="1"/>
<skill name="building" modifier="1"/>
<skill name="cartmaking" modifier="-1"/>
@ -97,7 +95,6 @@
<race name="demon" magres="0.150000" maxaura="1.000000" regaura="1.250000" recruitcost="100" maintenance="10" weight="1000" capacity="540" speed="1.000000" hp="20" ac="2" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" shapeshift="yes" giveitem="yes" giveperson="yes" giveunit="yes" getitem="yes" recruitethereal="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<function name="itemdrop" value="defaultdrops"/>
<skill name="alchemy" modifier="2"/>
<skill name="cartmaking" modifier="-2"/>
<skill name="forestry" modifier="1"/>
<skill name="herbalism" modifier="-3"/>
@ -120,7 +117,6 @@
<race name="elf" magres="0.100000" maxaura="1.000000" regaura="1.250000" recruitcost="130" maintenance="10" weight="1000" capacity="540" speed="1.000000" hp="20" damage="1d5" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" giveitem="yes" giveperson="yes" giveunit="yes" getitem="yes" equipment="yes">
<ai splitsize="10000" moverandom="yes" learn="yes"/>
<function name="itemdrop" value="defaultdrops"/>
<skill name="alchemy" modifier="-1"/>
<skill name="armorer" modifier="-1"/>
<skill name="bow" modifier="2"/>
<skill name="building" modifier="-1"/>
@ -192,7 +188,6 @@
<race name="kraken" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="2.000000" hp="300" damage="2d10" unarmedattack="0" unarmeddefense="0" attackmodifier="7" defensemodifier="7" coastal="yes" swim="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -221,7 +216,6 @@
<race name="giantturtle" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="1600" capacity="600" speed="1.000000" hp="900" ac="7" damage="2d50" unarmedattack="0" unarmeddefense="0" attackmodifier="10" defensemodifier="5" coastal="yes" swim="yes" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -245,7 +239,6 @@
<race name="dolphin" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="2.000000" hp="24" damage="1d6" unarmedattack="0" unarmeddefense="0" attackmodifier="5" defensemodifier="5" coastal="yes" swim="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -269,7 +262,6 @@
<race name="tiger" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="1.000000" hp="30" damage="2d6" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="3" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -295,7 +287,6 @@
<race name="hellcat" magres="0.500000" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="1.000000" hp="40" damage="2d6" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="4" walk="yes" teach="no" giveitem="yes" getitem="yes" resistpierce="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -321,7 +312,6 @@
<race name="owl" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="1.000000" hp="9" damage="1d4" unarmedattack="0" unarmeddefense="0" attackmodifier="2" defensemodifier="4" fly="yes" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -350,7 +340,6 @@
<skill name="riding" modifier="-1"/>
<skill name="melee" modifier="-1"/>
<skill name="polearm" modifier="-1"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -376,7 +365,6 @@
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="magic" modifier="1"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -400,7 +388,6 @@
<race name="imp" magres="0.500000" maxaura="1.000000" regaura="1.000000" weight="500" capacity="540" speed="1.000000" hp="10" ac="1" damage="1d4" unarmedattack="0" unarmeddefense="0" attackmodifier="5" defensemodifier="4" fly="yes" walk="yes" teach="no" giveitem="yes" getitem="yes" equipment="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -427,7 +414,6 @@
<race name="ghost" magres="0.800000" maxaura="0.500000" regaura="0.100000" weight="500" capacity="540" speed="1.000000" hp="30" ac="5" damage="2d6" unarmedattack="0" unarmeddefense="0" attackmodifier="5" defensemodifier="8" scarepeasants="yes" fly="yes" walk="yes" teach="no" giveitem="yes" getitem="yes" equipment="yes" invinciblenonmagic="yes">
<ai splitsize="5000"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -456,7 +442,6 @@
<ai splitsize="5000"/>
<function name="name" value="namegeneric"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -482,7 +467,6 @@
<race name="unicorn" magres="0.900000" maxaura="1.500000" regaura="1.500000" weight="5000" capacity="2000" speed="2.000000" hp="40" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="4" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="9999"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -532,7 +516,6 @@
<race name="songdragon" magres="0.990000" maxaura="1.000000" regaura="1.000000" weight="1000" capacity="600" speed="1.500000" hp="40" ac="1" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="1" fly="yes" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="9999"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -562,7 +545,6 @@
<race name="rat" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="100" capacity="540" speed="1.000000" hp="10" damage="1d4" unarmedattack="0" unarmeddefense="0" attackmodifier="1" defensemodifier="1" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="9999"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -588,7 +570,6 @@
<race name="eagle" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="1.500000" hp="15" damage="2d3" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="2" fly="yes" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="9999"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -613,7 +594,6 @@
<race name="tunnelworm" magres="0.800000" maxaura="0.000000" regaura="0.000000" weight="30000" capacity="10000" speed="1.000000" hp="300" ac="6" damage="3d20" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="1" scarepeasants="yes" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="99999"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="10"/>
<skill name="bow" modifier="-99"/>
@ -640,7 +620,6 @@
<race name="lynx" magres="0.000000" maxaura="0.000000" regaura="0.000000" weight="500" capacity="540" speed="1.000000" hp="20" damage="2d3" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="5" walk="yes" teach="no" giveitem="yes" getitem="yes">
<ai splitsize="99999"/>
<function name="initfamiliar" value="oldfamiliars"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>
@ -681,7 +660,6 @@
</race>
<race name="toad" magres="0.200000" maxaura="1.000000" regaura="1.000000" maintenance="10" weight="100" capacity="540" speed="1.000000" hp="10" damage="1d2" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" giveitem="yes" giveperson="yes" giveunit="yes" getitem="yes" walk="yes">
<ai splitsize="1" learn="yes"/>
<skill name="alchemy" modifier="-10"/>
<skill name="crossbow" modifier="-10"/>
<skill name="mining" modifier="-10"/>
<skill name="bow" modifier="-10"/>
@ -707,7 +685,6 @@
</race>
<race name="smurf" weight="1000" capacity="540" speed="1.000000" hp="10" damage="1d2" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" giveperson="yes" giveunit="yes" getitem="yes" walk="yes">
<ai splitsize="1" learn="yes"/>
<skill name="alchemy" modifier="-10"/>
<skill name="crossbow" modifier="-10"/>
<skill name="mining" modifier="-10"/>
<skill name="bow" modifier="-10"/>
@ -846,7 +823,6 @@
<race name="clone" magres="0.900000" maxaura="0.000000" regaura="0.000000" weight="1000" capacity="540" speed="1.000000" hp="40" damage="0d0" unarmedattack="-2" unarmeddefense="-2" playerrace="yes" walk="yes" canlearn="no" teach="no" noheal="yes">
<ai splitsize="10000"/>
<skill name="alchemy" modifier="-99"/>
<skill name="crossbow" modifier="-99"/>
<skill name="mining" modifier="-99"/>
<skill name="bow" modifier="-99"/>

View File

@ -174,21 +174,6 @@
</spell>
<!-- gray magic -->
<spell name="create_runesword" type="gray" ship="true" rank="5" level="6" index="135">
<function name="cast" value="lua_castspell"/>
<resource name="aura" amount="100" cost="fixed"/>
<resource name="permaura" amount="1" cost="fixed"/>
<resource name="money" amount="1000" cost="fixed"/>
<resource name="laensword" amount="1" cost="fixed"/>
</spell>
<spell name="create_chastitybelt" type="gray" ship="true" rank="5" level="7" index="134">
<function name="cast" value="lua_castspell"/>
<resource name="aura" amount="50" cost="fixed"/>
<resource name="permaura" amount="1" cost="fixed"/>
<resource name="money" amount="3000" cost="fixed"/>
</spell>
<spell name="create_focus" type="gray" ship="true" rank="5" level="9" index="2">
<function name="cast" value="lua_castspell"/>
<resource name="aura" amount="100" cost="fixed"/>

View File

@ -1,45 +1,45 @@
local function test_rename()
free_game()
local r = region.create(0, 0, "plain")
local f = faction.create("enno@eressea.de", "human", "de")
local u = unit.create(f, r)
u:add_item("aoh", 1)
assert(u:get_item("ao_healing")==1)
free_game()
local r = region.create(0, 0, "plain")
local f = faction.create("enno@eressea.de", "human", "de")
local u = unit.create(f, r)
u:add_item("aoh", 1)
assert(u:get_item("ao_healing")==1)
end
local function test_pure()
free_game()
local r = region.create(0, 0, "plain")
free_game()
local r = region.create(0, 0, "plain")
end
local function test_read_write()
free_game()
local r = region.create(0, 0, "plain")
local f = faction.create("enno@eressea.de", "human", "de")
local u = unit.create(f, r)
u.number = 2
local fno = f.id
local uno = u.id
local result = 0
assert(r.terrain=="plain")
result = write_game("test_read_write.dat", "binary")
assert(result==0)
assert(get_region(0, 0)~=nil)
assert(get_faction(fno)~=nil)
assert(get_unit(uno)~=nil)
r = nil
f = nil
u = nil
free_game()
assert(get_region(0, 0)==nil)
assert(get_faction(fno)==nil)
assert(get_unit(uno)==nil)
result = read_game("test_read_write.dat", "binary")
assert(result==0)
assert(get_region(0, 0)~=nil)
assert(get_faction(fno)~=nil)
assert(get_unit(uno)~=nil)
free_game()
free_game()
local r = region.create(0, 0, "plain")
local f = faction.create("enno@eressea.de", "human", "de")
local u = unit.create(f, r)
u.number = 2
local fno = f.id
local uno = u.id
local result = 0
assert(r.terrain=="plain")
result = write_game("test_read_write.dat", "binary")
assert(result==0)
assert(get_region(0, 0)~=nil)
assert(get_faction(fno)~=nil)
assert(get_unit(uno)~=nil)
r = nil
f = nil
u = nil
free_game()
assert(get_region(0, 0)==nil)
assert(get_faction(fno)==nil)
assert(get_unit(uno)==nil)
result = read_game("test_read_write.dat", "binary")
assert(result==0)
assert(get_region(0, 0)~=nil)
assert(get_faction(fno)~=nil)
assert(get_unit(uno)~=nil)
free_game()
end
local function test_gmtool()
@ -245,6 +245,31 @@ local function test_recruit()
-- assert(u:get_item("money")==10)
end
local function test_spells()
free_game()
local r = region.create(0, 0, "plain")
local f = faction.create("enno@eressea.de", "human", "de")
local u = unit.create(f, r)
u.race = "elf"
u.number = 1
u:clear_orders()
u:add_item("money", 10000)
u:set_skill("magic", 5)
u:add_order("LERNE MAGIE Tybied")
process_orders()
local sp
local nums = 0
if f.spells~=nil then
for sp in f.spells do
nums = nums + 1
end
end
for sp in u.spells do
nums = nums - 1
end
assert(nums==0)
end
local function test_produce()
free_game()
local r = region.create(0, 0, "plain")
@ -327,10 +352,11 @@ tests = {
["events"] = test_events,
["produce"] = test_produce,
["rename"] = test_rename,
["recruit"] = test_recruit
["recruit"] = test_recruit,
["spells"] = test_spells
}
mytests = {
["alliance"] = test_alliance
["spells"] = test_spells
}
fail = 0
for k, v in pairs(tests) do