From cdd7d69532c9ec405c4b2a7c746f46a4b94b0a80 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Wed, 10 Aug 2011 02:40:29 +0000 Subject: [PATCH] * [+] why did i get a gift from yumi in the middle of a battle? - [+] need alignment. f_alignment. default neutral. - [+] slight change to armour damage calc - [+] thrown poisoned weapons don't work! - [+] holy aura spell. lv3 cleric. * [+] are kobolds working properly?? seem buggy * [+] calmed down a war hound with a mushroom. - [+] use wisdom for checks for unwise things, not iq. * [+] hecta should only care about attacking evil creatures if they were NOT hostile. - [+] optimise: - [+] use getflags() more often. - [+] lookforobs() - redo code for ai wanting things. * [+] precalclos - 28% * [+] hasbetterweapon() - [+] haslos - 27.3% - [+] when you move now, you don't have los to your previous cell on the first drawscreen when your turn starts!!!!! - [+] ai is coming too close before firing ranged weapons. allow them to stay within 2 - maxrange if they have a weapon. - [+] also let them fire form furhter away! * [+] give healing potion to hurt (intelligent) lf to calm them down? * [+] Amberon (m) purity, righteousness * [+] Hecta - female, death, undead, evil, night * [+] Felix - male, thieves, greed * [+] bug - i found jimbo dead! - [+] cave vault (different wall types, boulder at the entrance, lots of food, bears) --- ai.c | 350 +++++++++++---------- ai.h | 5 +- attack.c | 78 +++-- defs.h | 29 +- flag.c | 39 ++- god.c | 253 ++++++++++++++-- io.c | 244 ++++++++++----- lf.c | 334 +++++++++++++++----- lf.h | 1 + map.c | 30 +- move.c | 58 ++-- move.h | 4 +- nexus.c | 34 ++- objects.c | 889 ++++++++++++++++++++++++++++-------------------------- objects.h | 5 +- save.c | 2 +- spell.c | 286 ++++++++++-------- spell.h | 2 +- 18 files changed, 1683 insertions(+), 960 deletions(-) diff --git a/ai.c b/ai.c index 8bc9921..1b303f4 100644 --- a/ai.c +++ b/ai.c @@ -18,6 +18,9 @@ extern lifeform_t *player; extern enum ERROR reason; +extern flag_t *retflag[]; +extern int nretflags; + int wantdb = B_TRUE; void addignorecell(lifeform_t *lf, cell_t *c) { @@ -124,9 +127,11 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { castok = B_FALSE; } - for (f = lf->flags->first ; f ; f = f->next) { - if ( (castok && (f->id == F_CANCAST)) || - (f->id == F_CANWILL)) { + if (castok) { + int i; + getflags(lf->flags, F_CANCAST, F_CANWILL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (aispellok(lf, f->val[0], victim, F_AICASTTOATTACK)) { poss[nposs] = f->val[0]; nposs++; @@ -152,7 +157,7 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { enum OBTYPE aigetfleespell(lifeform_t *lf) { flag_t *f; enum OBTYPE poss[MAXPILEOBS]; - int nposs = 0; + int nposs = 0,i; int db = B_FALSE; lifeform_t *fleefrom; @@ -166,12 +171,12 @@ enum OBTYPE aigetfleespell(lifeform_t *lf) { } - for (f = lf->flags->first ; f ; f = f->next) { - if ((f->id == F_CANCAST) || (f->id == F_CANWILL)) { - if (aispellok(lf, f->val[0], fleefrom, F_AICASTTOFLEE)) { - poss[nposs] = f->val[0]; - nposs++; - } + getflags(lf->flags, F_CANCAST, F_CANWILL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (aispellok(lf, f->val[0], fleefrom, F_AICASTTOFLEE)) { + poss[nposs] = f->val[0]; + nposs++; } } @@ -241,7 +246,7 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l return NULL; } -object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) { +object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range) { int db = B_FALSE; enum ATTRBRACKET iqb; object_t *o; @@ -256,7 +261,6 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) { return NULL; } - o = getfirearm(lf); if (o && getammo(o)) { if (db) { @@ -265,6 +269,7 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) { if (db) dblog(".oO { will fire my gun (%s) at target. }",gunname); } *ra = RA_GUN; + *range = getfirearmrange(o); return o; } @@ -280,6 +285,7 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) { if (db) dblog(".oO { will zap %s instead of moving }", o->type->name); *ra = RA_WAND; + *range = getvisrange(lf); // ie unlimited return o; } } @@ -290,12 +296,14 @@ object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) { if (o) { if (db) dblog(".oO { will throw %s at my target }", o->type->name); *ra = RA_THROW; + *range = getmaxthrowrange(lf, o); return o; } } if (db) dblog(".oO { found no ranged attack. }"); *ra = RA_NONE; + *range = 0; return NULL; } @@ -360,16 +368,18 @@ void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victi nposs = 0; for (i = 0; i < lf->nlos; i++) { - object_t *o; - for (o = lf->los[i]->obpile->first ; o ; o = o->next) { - if (!hasflag(o->flags, F_NOPICKUP) && - getobweight(o) <= maxweight) { - poss[nposs] = o; - nposs++; - if (nposs >= MAXPILEOBS) break; + if (lf->los[i] != lf->cell) { + object_t *o; + for (o = lf->los[i]->obpile->first ; o ; o = o->next) { + if (!hasflag(o->flags, F_NOPICKUP) && + getobweight(o) <= maxweight) { + poss[nposs] = o; + nposs++; + if (nposs >= MAXPILEOBS) break; + } } + if (nposs >= MAXPILEOBS) break; } - if (nposs >= MAXPILEOBS) break; } // should always be true since we check this in aispellok if (nposs > 0) { @@ -491,6 +501,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { enum OBTYPE spell; object_t *rangedob = NULL; enum RANGEATTACK rangedattack = RA_NONE; + int shootrange = 0; int movefailed = B_FALSE; // pet movement @@ -575,16 +586,18 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { nposs = 0; for (i = 0; i < lf->nlos; i++) { - object_t *o; - for (o = lf->los[i]->obpile->first ; o ; o = o->next) { - if (!hasflag(o->flags, F_NOPICKUP) && - getobweight(o) <= maxweight) { - poss[nposs] = o; - nposs++; - if (nposs >= MAXPILEOBS) break; + if (lf->los[i] != lf->cell) { + object_t *o; + for (o = lf->los[i]->obpile->first ; o ; o = o->next) { + if (!hasflag(o->flags, F_NOPICKUP) && + getobweight(o) <= maxweight) { + poss[nposs] = o; + nposs++; + if (nposs >= MAXPILEOBS) break; + } } + if (nposs >= MAXPILEOBS) break; } - if (nposs >= MAXPILEOBS) break; } if (nposs > 0) { spellob = poss[rnd(0,nposs-1)]; @@ -625,11 +638,13 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // see if we have a ranged attack. if so, adjust wantdist // to maintain distance. - rangedob = aigetrangedattack(lf, &rangedattack); + rangedob = aigetrangedattack(lf, &rangedattack, &shootrange); - if (rangedattack != RA_NONE) { - if (wantdistmin < 2) wantdistmin = 2; - if (wantdistmax < wantdistmin) wantdistmax = wantdistmin; + if (rangedattack != RA_NONE) { // ie if we found a ranged attack + // stay out of target's attack range + if (wantdistmin < 2) wantdistmin = 2; + // and stay within range for our ranged attack + if (wantdistmax < wantdistmin) wantdistmax = shootrange; } } // end if attackok @@ -648,8 +663,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { movefailed = B_TRUE; } } else if (dist < wantdistmin) { - if (db) dblog(".oO { moving away from target. }"); - if (!moveawayfrom(lf, target->cell, DT_ORTH)) { + if (db) dblog(".oO { moving away from target to maintain mindist %d. }", wantdistmin); + if (!moveawayfrom(lf, target->cell, DT_ORTH, B_KEEPLOF)) { // maintain LOF // success return B_FALSE; } else { @@ -868,6 +883,12 @@ int aipickupok(lifeform_t *lf, object_t *o) { } int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target) { + // non-humanoids can only use food. + if (!lfhasflag(lf, F_HUMANOID)) { + if (o->type->obclass->id != OC_FOOD) { + return B_FALSE; + } + } switch (o->type->id) { case OT_POT_INVIS: case OT_WAND_INVIS: @@ -964,7 +985,7 @@ void aiturn(lifeform_t *lf) { if (isoutdoors(lf->cell->map) && pctchance(20)) { object_t *o; say(lf, "Thanks for getting me out!", SV_TALK); - o = addob(master->pack, "manual"); + o = addobfast(master->pack, OT_MANUAL); if (o) { char obname[BUFLEN]; say(lf, "Here, let me teach you something as a reward.", SV_TALK); @@ -1012,11 +1033,11 @@ void aiturn(lifeform_t *lf) { if (f) { if (pctchance(f->val[0])) { flag_t *poss[MAXCANDIDATES]; - int nposs = 0; - for (f = lf->flags->first ;f ; f = f->next) { - if (f->id == F_RANDOMTALK) { - poss[nposs++] = f; - } + int nposs = 0,i; + + getflags(lf->flags, F_RANDOMTALK, F_NONE); + for (i = 0; i < nretflags; i++) { + poss[nposs++] = retflag[i]; } if (nposs) { int vol; @@ -1186,7 +1207,7 @@ void aiturn(lifeform_t *lf) { if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) && !hasobwithflag(target->cell->obpile, F_DEEPWATER)) { // move away! - if (!moveawayfrom(lf, target->cell, DT_ORTH)) { + if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE)) { return; } } @@ -1326,26 +1347,30 @@ void aiturn(lifeform_t *lf) { newtarget = NULL; for (n = 0; n < lf->nlos; n++) { lifeform_t *who; - who = lf->los[n]->lf; - if (who && cansee(lf, who)) { - if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) || - lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) { - if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name); - newtarget = who; - break; - } + if (lf->los[n] != lf->cell) { + who = lf->los[n]->lf; + if (who && cansee(lf, who)) { + if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) || + lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) { + if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name); + newtarget = who; + break; + } + } } } if (!newtarget) { // now look for enemies for (n = 0; n < lf->nlos; n++) { - lifeform_t *who; - who = lf->los[n]->lf; - if (who && cansee(lf, who)) { - if (areenemies(lf, who)) { - if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name); - newtarget = who; - break; + if (lf->los[n] != lf->cell) { + lifeform_t *who; + who = lf->los[n]->lf; + if (who && cansee(lf, who)) { + if (areenemies(lf, who)) { + if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name); + newtarget = who; + break; + } } } } @@ -1588,14 +1613,16 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG nposs = 0; for (i = 0; i < lf->nlos; i++) { - object_t *o; - for (o = lf->los[i]->obpile->first ; o ; o = o->next) { - if (!hasflag(o->flags, F_NOPICKUP) && - getobweight(o) <= maxweight) { - ok = B_TRUE; - break; + if (lf->los[i] != lf->cell) { + object_t *o; + for (o = lf->los[i]->obpile->first ; o ; o = o->next) { + if (!hasflag(o->flags, F_NOPICKUP) && + getobweight(o) <= maxweight) { + ok = B_TRUE; + break; + } + if (ok) break; } - if (ok) break; } } } else if (ot->id == OT_S_CHARM) { @@ -1683,6 +1710,12 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_S_SLOW) && (lfhasflag(victim, F_SLOWACT) || lfhasflag(victim, F_SLOWACTMOVE)) ) { specificcheckok = B_FALSE; } + if ((ot->id == OT_S_SMITEGOOD) && (getalignment(victim) != AL_GOOD)) { + specificcheckok = B_FALSE; + } + if ((ot->id == OT_S_SMITEEVIL) && (getalignment(victim) != AL_EVIL)) { + specificcheckok = B_FALSE; + } if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) { specificcheckok = B_FALSE; } @@ -1749,6 +1782,40 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG return B_TRUE; } +int aiwants(lifeform_t *lf, object_t *o, int *covets) { + enum OBTYPE oid[MAXPILEOBS]; + int oidcovet[MAXPILEOBS]; + int noids = 0; + enum FLAG wantflag[MAXPILEOBS]; + int wantflagcovet[MAXPILEOBS]; + int nwantflags = 0; + makewantedoblist(lf, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet); + return aiwants_real(lf, o, covets, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet); +} + +int aiwants_real(lifeform_t *lf, object_t *o, int *covets, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet) { + int i; + for (i = 0; i < *noids; i++) { + if (oid[i] == o->type->id) { + if (covets) { + *covets = oidcovet[i]; + } + return B_TRUE; + } + } + for (i = 0; i < *nwantflags; i++) { + if (hasflag(o->flags, wantflag[i])) { + if ((wantflag[i] == F_EDIBLE) && !caneat(lf, o)) { // special case + } else { + if (covets) { + *covets = wantflagcovet[i]; + } + return B_TRUE; + } + } + } + return B_FALSE; +} lifeform_t *gettargetlf(lifeform_t *lf) { flag_t *f; @@ -1794,9 +1861,10 @@ object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op) { } + // returns B_TRUE if we did something int lookforobs(lifeform_t *lf) { - object_t *o; + object_t *o,*nexto; enum OBTYPE oid[MAXPILEOBS]; int oidcovet[MAXPILEOBS]; int noids = 0; @@ -1805,11 +1873,11 @@ int lookforobs(lifeform_t *lf) { int nwantflags = 0; flag_t *f; cell_t *c; - int n; int i; int db = B_FALSE; lifeform_t *target; int targdist = 999; + int covets = B_FALSE; target = gettargetlf(lf); if (target) { @@ -1822,67 +1890,27 @@ int lookforobs(lifeform_t *lf) { db = B_FALSE; } - // construct a list of objects which we want - noids = 0; - for (f = lf->flags->first ; f ; f = f->next) { - if (f->id == F_WANTS) { - oid[noids] = f->val[0]; - oidcovet[noids] = (f->val[1] == B_COVETS) ? B_TRUE : B_FALSE; - noids++; - } else if (f->id == F_WANTSOBFLAG) { - wantflag[nwantflags] = f->val[0]; - wantflagcovet[noids] = (f->val[1] == B_COVETS) ? B_TRUE : B_FALSE; - nwantflags++; - } - } - - if (hasflag(lf->flags, F_HUNGER)) { - // monsters dont normaly need to eat. if they have hunger, it's due - // to a spell. - wantflag[nwantflags] = F_EDIBLE; - wantflagcovet[nwantflags] = B_TRUE; - nwantflags++; - } + makewantedoblist(lf, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet); // current cell has an object we want? - o = hasobmulti(lf->cell->obpile, oid, noids); - if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) { - int getit = B_TRUE; - - // if we are in battle only go for it if we covet it - if (target) { - int nn; - for (nn = 0; nn < noids; nn++) { - if (oid[nn] == o->id) break; + for (o = lf->cell->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (aiwants_real(lf, o, &covets, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet)) { + int getit = B_TRUE; + // if we are in battle only go for it if we covet it + if (target && !covets) getit = B_FALSE; + if (isdangerousob(o, lf, B_TRUE) || !aipickupok(lf, o)) getit = B_FALSE; + if (getit) { + if (db) dblog(".oO { current cell has ob i want (%s) }",o->type->name); + // try to pick it up + if (!aipickup(lf, o)) return B_TRUE; + if (db) dblog(".oO { pickup of %s failed, trying to eat! }",o->type->name); + if (!eat(lf, o)) return B_TRUE; + if (db) dblog(".oO { eating %s failed }",o->type->name); } - if (!oidcovet[nn]) getit = B_FALSE; - } - if (getit) { - if (db) dblog(".oO { current cell has ob i want (%s) }",o->type->name); - // try to pick it up - if (!aipickup(lf, o)) return B_TRUE; - if (db) dblog(".oO { pickup of %s failed, trying to eat! }",o->type->name); - if (!eat(lf, o)) return B_TRUE; - if (db) dblog(".oO { eating %s failed }",o->type->name); - } - } - // has an object with a flag we want? - for (n = 0; n < nwantflags; n++) { - o = hasobwithflag(lf->cell->obpile, wantflag[n]); - - // if we are in battle only go for it if we covet it - if (target && !wantflagcovet[n]) continue; - - if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o) && (canpickup(lf, o, 1) || caneat(lf,o)) ) { - if (db) dblog(".oO { current cell has ob with flag i want (%s) }",o->type->name); - // try to pick it up - if (!aipickup(lf, o)) return B_TRUE; - if (db) dblog(".oO { pickup of %s with wantflag failed, trying to eat! }",o->type->name); - if (!eat(lf, o)) return B_TRUE; - if (db) dblog(".oO { eating %s with wantflag failed }",o->type->name); - } } + // current cell has better weapon? if (lfhasflag(lf, F_HUMANOID) && hasbp(lf, BP_WEAPON)) { f = hasflag(lf->flags, F_WANTSBETTERWEP); @@ -1924,44 +1952,30 @@ int lookforobs(lifeform_t *lf) { int gothere = B_FALSE; c = lf->los[i]; - if (!c->lf && !lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) { + if ((c != lf->cell) && !c->lf && !lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) { int celldist; celldist = getcelldist(lf->cell, c); - o = hasobmulti(c->obpile, oid, noids); - if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) { - // if we are in battle only go for it if we covet it and - // it's closer than our target - if (target) { - int nn; - for (nn = 0; nn < noids; nn++) { - if (oid[nn] == o->id) break; - } - if (oidcovet[nn]) { - if (celldist <= targdist) { - if (db) dblog(".oO { remote cell has ob i want (%s). setting f_targetcell. }",o->type->name); - gothere = B_TRUE; + for (o = c->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (aiwants_real(lf, o, &covets, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet)) { + gothere = B_TRUE; + + // if we are in battle only go for it if we covet it and + // it's closer than our target + if (target) { + if (!covets || (celldist > targdist)) { + gothere = B_FALSE; } } - } else { - if (db) dblog(".oO { remote cell has ob i want (%s). setting f_targetcell. }",o->type->name); - gothere = B_TRUE; - } - } - - if (!gothere) { - // has an object with a flag we want? - for (n = 0; n < nwantflags; n++) { - // if we are in battle only go for it if we covet it - if (target && !wantflagcovet[n]) continue; - - o = hasobwithflag(c->obpile, wantflag[n]); - if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o)) { - if (db) dblog(".oO { remote cell has ob with flag i want (%s) }", o->type->name); - gothere = B_TRUE; + + if (gothere) { + if (db) dblog(".oO { remote cell has ob i want (%s). setting f_targetcell. }",o->type->name); + break; } - } - } + } // end if aiwantsthisob + } // end foreach ob in cell + if (!gothere) { if (lfhasflag(lf, F_HUMANOID) && hasbp(lf, BP_WEAPON)) { // remote cell has better weapon? @@ -1999,7 +2013,6 @@ int lookforobs(lifeform_t *lf) { } } - if (gothere) { // cast a spell? if (cancast(lf, OT_S_CALLWIND, NULL) && haslof(lf->cell, c, LOF_NEED, NULL)) { @@ -2020,6 +2033,35 @@ int lookforobs(lifeform_t *lf) { return B_FALSE; } +void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet) { + int i; + flag_t *f; + + // construct a list of objects which we want + *noids = 0; + getflags(lf->flags, F_WANTS, F_WANTSOBFLAG, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->id == F_WANTS) { + oid[*noids] = f->val[0]; + oidcovet[*noids] = (f->val[1] == B_COVETS) ? B_TRUE : B_FALSE; + (*noids)++; + } else if (f->id == F_WANTSOBFLAG) { + wantflag[*nwantflags] = f->val[0]; + wantflagcovet[*nwantflags] = (f->val[1] == B_COVETS) ? B_TRUE : B_FALSE; + (*nwantflags)++; + } + } + + if (hasflag(lf->flags, F_HUNGER)) { + // monsters dont normaly need to eat. if they have hunger, it's due + // to a spell. + wantflag[*nwantflags] = F_EDIBLE; + wantflagcovet[*nwantflags] = B_TRUE; + (*nwantflags)++; + } +} + // try to use an item with the given flag on ourself. // returns B_FALSE if successful int useitemwithflag(lifeform_t *lf, enum FLAG whichflag) { diff --git a/ai.h b/ai.h index adb9a83..7d25426 100644 --- a/ai.h +++ b/ai.h @@ -5,7 +5,7 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit); enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim); enum OBTYPE aigetfleespell(lifeform_t *lf); cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *lasty, int *lastdir); -object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra); +object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra, int *range); void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose); object_t *aigetwand(lifeform_t *lf, enum FLAG purpose); flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int timelimit); @@ -17,8 +17,11 @@ int aipickupok(lifeform_t *lf, object_t *o); int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target); int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose); void aiturn(lifeform_t *lf); +int aiwants(lifeform_t *lf, object_t *o, int *covets); +int aiwants_real(lifeform_t *lf, object_t *o, int *covets, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet); lifeform_t *gettargetlf(lifeform_t *lf); object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op); object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op); int lookforobs(lifeform_t *lf); +void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet); int useitemwithflag(lifeform_t *lf, enum FLAG whichflag); diff --git a/attack.c b/attack.c index b2f1d48..e3ee76c 100644 --- a/attack.c +++ b/attack.c @@ -24,6 +24,9 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty object_t *armour = NULL; int damtaken = 0; + // first of all, only apply some of the damage + dam /= 2; + // figure out what bit of armour was hit if (dam == 0) { return 0; @@ -99,23 +102,31 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int *dam, enum DAMTYPE damtype) { int db = B_FALSE; + int newdam = 0; // armour can't stop armour-piercing weapons if (hasflag(wep->flags, F_ARMOURPIERCE)) { reduceamt = 0; } - if (db) { - if (reduceamt > 0) { - dblog("Armour reduces dam by %d to %d.",reduceamt,dam); - } else { - dblog("No armour dam reduction."); + // figure out reduced damage value + if (dam) { + newdam = *dam; + if ((*dam >= 1) && (reduceamt >= 0)) { + newdam -= reduceamt; + limit(&newdam, 1, NA); // don't reduce to <1 damage } - } - if (dam && (reduceamt >= 0)) { - *dam -= reduceamt; - if (*dam < 0) *dam = 0; - } + + if (db) { + if ((*dam >= 1) && (reduceamt > 0)) { + dblog("Armour reduces dam=%d by %d to %d.",*dam,reduceamt,newdam); + } else { + dblog("No armour dam reduction."); + } + } + + *dam = newdam; + } } @@ -267,7 +278,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { ot = findot(f->val[0]); if (ot) { - wep[nweps] = addob(op, ot->name); + wep[nweps] = addobfast(op, ot->id); validwep[nweps] = B_TRUE; damflag[nweps] = f; nweps++; @@ -681,6 +692,12 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } + if (i == 0) { + if (lfhasflag(lf, F_HOLYAURA) && isvulnto(victim->flags, DT_HOLY)) { + damtype[i] = DT_HOLY; + } + } + // modify based on resistances adjustdamlf(victim, &dam[i], damtype[i]); //dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); @@ -706,6 +723,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) fatal = B_TRUE; } + // monsters feigning death? if (lfhasflag(victim, F_FEIGNINGDEATH)) { killflagsofid(victim->flags, F_FEIGNINGDEATH); @@ -846,12 +864,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } else { strcpy(buf, attackername2); } - losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, NULL); // victim's armour loses hp if (reduceamt) { - applyarmourdamage(victim, wep, reduceamt, damtype[i]); + applyarmourdamage(victim, wep, dam[i], damtype[i]); // train armour practice(victim, SK_ARMOUR, 1); } @@ -1078,11 +1095,31 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (isplayer(lf)) { if (attackedfriend) { angergodmaybe(R_GODMERCY, 100); - } else if (attackedhelpless) { - angergodmaybe(R_GODMERCY, 50); - } else if (lfhasflag(lf, F_USEDPOISON)) { + angergodmaybe(R_GODPURITY, 100); + switch (getalignment(victim)) { + case AL_EVIL: + angergodmaybe(R_GODDEATH, 20); // even more + break; + case AL_GOOD: + angergodmaybe(R_GODPURITY, 20); // even more + break; + default: + break; + } + } + if (attackedhelpless) { + angergodmaybe(R_GODMERCY, 100); + angergodmaybe(R_GODPURITY, 100); + if (getalignment(victim) != AL_EVIL) { + pleasegodmaybe(R_GODTHIEVES, 5); + pleasegodmaybe(R_GODDEATH, 10); + } + } + if (lfhasflag(lf, F_USEDPOISON)) { killflagsofid(lf->flags, F_USEDPOISON); + angergodmaybe(R_GODPURITY, 100); angergodmaybe(R_GODMERCY, 50); + pleasegodmaybe(R_GODDEATH, 3); } } @@ -1199,6 +1236,9 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { // object loses hp takedamage(o, dam[i], damtype[i]); + if (isplayer(lf) && hasflag(o->flags, F_LOCKED)) { + angergodmaybe(R_GODTHIEVES, 25); + } } // end foreach damtype @@ -1389,11 +1429,13 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam return "incinerate"; } } else if (damtype == DT_HOLY) { - switch (rnd(1,2)) { + switch (rnd(1,3)) { case 1: return "smite"; case 2: return "cleanse"; + case 3: + return "purify"; } } else if (damtype == DT_PIERCE) { if (pct <= 5) { @@ -1962,7 +2004,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { if (f->id == F_FLAMESTRIKE) { if (!hasob(where->obpile, OT_FIRESMALL)) { // ignite! - addob(where->obpile, "small fire"); + addobfast(where->obpile, OT_FIRESMALL); // announce if (haslos(player, where)) { msg("^wA column of fire erupts from the ground!"); diff --git a/defs.h b/defs.h index cbd4fa6..9d08c47 100644 --- a/defs.h +++ b/defs.h @@ -661,7 +661,7 @@ enum RACECLASS { RC_UNDEAD, }; -#define MAXGODS 3 +#define MAXGODS 4 enum RACE { R_NONE = 0, @@ -677,9 +677,10 @@ enum RACE { R_PRISONER, R_TOWNGUARD, // gods - R_GODDEATH, - R_GODGREED, - R_GODMERCY, + R_GODPURITY, // amberon + R_GODTHIEVES, // felix + R_GODDEATH, // hecta + R_GODMERCY, // yumi // monsters R_BEHOLDER, R_BUGBEAR, @@ -992,6 +993,7 @@ enum OBTYPE { OT_S_BLINDNESS, OT_S_POISONBOLT, OT_S_POSSESSION, + OT_S_SMITEGOOD, OT_S_STENCH, // -- divination OT_S_DETECTAURA, @@ -1038,10 +1040,12 @@ enum OBTYPE { OT_S_SLOW, OT_S_LEVITATION, OT_S_FLIGHT, - // -- life + // -- life / cleric OT_S_HEALING, OT_S_HEALINGMIN, OT_S_HEALINGMAJ, + OT_S_HOLYAURA, + OT_S_SMITEEVIL, OT_S_SPEAKDEAD, OT_S_TURNUNDEAD, // -- mental / psionic @@ -1174,6 +1178,7 @@ enum OBTYPE { OT_WAND_POLYMORPH, OT_WAND_REVEALHIDDEN, OT_WAND_SLOW, + OT_WAND_TURNUNDEAD, OT_WAND_WEAKNESS, OT_WAND_WONDER, // tools - unique @@ -1514,6 +1519,13 @@ enum ALLEGIENCE { AL_FRIENDLY, // will help you fight }; +enum ALIGNMENT { + AL_NONE, + AL_GOOD, + AL_NEUTRAL, + AL_EVIL, +}; + enum POISONSEVERITY { PS_DISEASE, PS_POISON, @@ -1858,8 +1870,11 @@ enum FLAG { F_DONEDARKMSG, // tells the game not to say 'it is very dark here' F_DONELISTEN, // supress further 'you hear xx' messages this turn. // lifeform flags / lf flags + F_ALIGNMENT, // v0 = al_good, al_neutral, al_evil. default neutral. F_PIETY, // for god lifeforms - tracks player's piety with them F_PRAYEDTO, // player has prayed to this god before. + F_GAVEMONEY, // v0 tracks how much money we gave away this turn + // used for r_godgreed anger effects. F_COUNTER, // generic counter flag for race abilities. F_DEBUG, // debugging enabled F_ACCURACYMOD, // modify your accuracy by val0 @@ -2166,6 +2181,8 @@ enum FLAG { F_PARALYZED,// cannot do anything F_PRONE, // lying on the ground F_FROZEN, // made of ice + F_HOLYAURA, // holy aura - attacks deal holy damage to vulnerable + // enemies. F_LEVITATING, // like flying but uncontrolled F_MAGSHIELD,// magnetic shield F_NAUSEATED, // lf has a stench penalty of v0 (-v0*10 to hit). @@ -2335,6 +2352,8 @@ enum PIETYLEV { #define B_FALSE (0) #define B_TRUE (-1) +#define B_KEEPLOF (-1) + #define B_MALE (0) #define B_FEMALE (-1) diff --git a/flag.c b/flag.c index 5b0ced4..b6e2d67 100644 --- a/flag.c +++ b/flag.c @@ -19,6 +19,8 @@ extern int statdirty; extern lifeform_t *player; +int flagdb = B_FALSE; + altflagval_t *addaltval(flag_t *f, enum FLAG id, int val1, int val2, int val3, char *text) { f->altval = malloc(sizeof(altflagval_t)); f->altval->id = id; @@ -441,37 +443,40 @@ flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception) { owner = fp->owner; int pos; int l,r; - int iter = 0; + int iter = 0,subiter = 0; int db = B_FALSE; + if (flagdb) db = B_TRUE; + if (db) dblog("hasflag %d in flagpile with %d entries", id, fp->nitems); // binary search for this flag id. l = 0; r = fp->nitems-1; while (!searchfrom) { - if (db) dblog(" iter#%d: l=%d,r=%d", iter, l, r); + //if (db) dblog(" iter#%d: l=%d,r=%d", iter, l, r); if (r < l) { // NOT FOUND. - if (db) dblog(" r < l: not found!"); + //if (db) dblog(" r < l: not found!"); break; } else if (fp->item[l]->id > id) { // NOT FOUND. - if (db) dblog(" leftid %d > wantid %d. not found!",fp->item[l]->id, id); + //if (db) dblog(" leftid %d > wantid %d. not found!",fp->item[l]->id, id); break; } else if (fp->item[r]->id < id) { // NOT FOUND. - if (db) dblog(" rightid %d > wantid %d. not found!",fp->item[r]->id, id); + //if (db) dblog(" rightid %d > wantid %d. not found!",fp->item[r]->id, id); break; } // half way inbetween l and r pos = ((l+r)/2); f = fp->item[pos]; - if (db) dblog(" iter#%d: pos=%d. item here is %d (looking for %d)", iter, pos, f->id, id); + //if (db) dblog(" iter#%d: pos=%d. item here is %d (looking for %d)", iter, pos, f->id, id); if (f->id == id) { // go back to first occurence while (f->prev && (f->prev->id == id)) { f = f->prev; + iter++; } searchfrom = f; break; @@ -482,6 +487,7 @@ flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception) { // go right l = pos+1; } + iter++; } @@ -499,10 +505,11 @@ flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception) { break; } else { f = f->next; + subiter++; } } - if (db) dblog("finished - %s", foundflag ? "found it" : "NOT FOUND"); + if (db) dblog("finished - %s - iter=%d, subiter=%d", foundflag ? "found it" : "NOT FOUND",iter,subiter); return foundflag; /* @@ -553,33 +560,36 @@ flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, ch int iter = 0; int db = B_FALSE; - if (db) dblog("hasflag %d in flagpile with %d entries", id, fp->nitems); + if (flagdb) db = B_TRUE; + + //if (db) dblog("hasflag %d in flagpile with %d entries", id, fp->nitems); // binary search for this flag id. l = 0; r = fp->nitems-1; while (!searchfrom) { - if (db) dblog(" iter#%d: l=%d,r=%d", iter, l, r); + //if (db) dblog(" iter#%d: l=%d,r=%d", iter, l, r); if (r < l) { // NOT FOUND. - if (db) dblog(" r < l: not found!"); + //if (db) dblog(" r < l: not found!"); break; } else if (fp->item[l]->id > id) { // NOT FOUND. - if (db) dblog(" leftid %d > wantid %d. not found!",fp->item[l]->id, id); + //if (db) dblog(" leftid %d > wantid %d. not found!",fp->item[l]->id, id); break; } else if (fp->item[r]->id < id) { // NOT FOUND. - if (db) dblog(" rightid %d > wantid %d. not found!",fp->item[r]->id, id); + //if (db) dblog(" rightid %d > wantid %d. not found!",fp->item[r]->id, id); break; } // half way inbetween l and r pos = ((l+r)/2); f = fp->item[pos]; - if (db) dblog(" iter#%d: pos=%d. item here is %d (looking for %d)", iter, pos, f->id, id); + //if (db) dblog(" iter#%d: pos=%d. item here is %d (looking for %d)", iter, pos, f->id, id); if (f->id == id) { // go back to first occurence while (f->prev && (f->prev->id == id)) { + iter++; f = f->prev; } searchfrom = f; @@ -591,6 +601,7 @@ flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, ch // go right l = pos+1; } + iter++; } @@ -612,7 +623,7 @@ flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, ch f = f->next; } - if (db) dblog("finished - %s", foundflag ? "found it" : "NOT FOUND"); + if (db) dblog("finished - %s - iter=%d", foundflag ? "found it" : "NOT FOUND", iter ); return foundflag; diff --git a/god.c b/god.c index b200a0e..fedc7b1 100644 --- a/god.c +++ b/god.c @@ -75,6 +75,7 @@ void angergod(enum RACE rid, int amt) { nposs++; } } + for (f = player->flags->first ; f ; f = f->next) { if ((f->lifetime == FROMGODGIFT) && (f->obfrom == god->race->id)) { poss[nposs] = f; @@ -95,13 +96,14 @@ void angergod(enum RACE rid, int amt) { // then... if (piety > -100) { + int i,n; // minor bad stuff switch (rid) { case R_GODDEATH: castspell(god, OT_S_DRAINLIFE, player, NULL, player->cell); castspell(god, OT_S_PAIN, player, NULL, player->cell); break; - case R_GODGREED: + case R_GODTHIEVES: // take a random object msg("\"Yoink!\""); castspell(god, OT_S_CONFISCATE, player, NULL, player->cell); @@ -112,11 +114,32 @@ void angergod(enum RACE rid, int amt) { a = rnd(0,MAXATTS-1); modattr(player, a, -1); break; + case R_GODPURITY: + // remove blessings + msg("\"Your actions do not befit the bearer of blessed objects!\""); + nposs = 0; + for (o = player->pack->first ; o ; o = o->next) { + if (isblessed(o)) { + poss[nposs++] = o; + } + } + n = rnd(1,3); + if (nposs < n) n = nposs; + for (i = 0; i < n; i++) { + o = (object_t *)poss[rnd(0,nposs-1)]; + while (!isblessed(o)) { + // pick again... + o = (object_t *)poss[rnd(0,nposs-1)]; + } + curseob(o); + } + break; default: break; } } else if (piety > -200) { object_t *o; + int n,i; // major bad stuff switch (god->race->id) { case R_GODDEATH: @@ -134,11 +157,11 @@ void angergod(enum RACE rid, int amt) { case 2: // summon undead msg("\"Destroy him, my pets!\""); - summonlfs(god, player->cell, RC_UNDEAD, SZ_ANY, 3, PERMENANT); + summonlfs(god, player->cell, RC_UNDEAD, SZ_ANY, AL_EVIL, 3, PERMENANT); break; } break; - case R_GODGREED: + case R_GODTHIEVES: o = getweapon(player); msg("\"Allow me to lighten your load a little...\""); if (o) { // take player's weapon @@ -159,6 +182,36 @@ void angergod(enum RACE rid, int amt) { modattr(player, a, -1); } + break; + case R_GODPURITY: + switch (rnd(1,2)) { + case 1: + // break objects + msg("\"Time for a lesson in materialism!\""); + nposs = 0; + for (o = player->pack->first ; o ; o = o->next) { + if (hasflag(o->flags, F_DAMAGABLE) && !hasflag(o->flags, F_DEAD)) { + poss[nposs++] = o; + } + } + n = rnd(1,3); + if (nposs < n) n = nposs; + for (i = 0; i < n; i++) { + char obname[BUFLEN]; + o = (object_t *)poss[rnd(0,nposs-1)]; + // damage it + getobname(o, obname, o->amt); + msg("Your %s %s struck by divine force!", (o->amt == 1) ? "is" : "are", + noprefix(obname)); + takedamage(o, roll("2d4"), DT_DIRECT); + } + break; + case 2: + // summon holy creautes + msg("\"Destroy him, my pets!\""); + summonlfs(god, player->cell, RC_ANY, SZ_ANY, AL_GOOD, 3, PERMENANT); + break; + } break; default: break; @@ -289,9 +342,9 @@ int godgiftmaybe(enum RACE rid) { god = findgod(rid); piety = getpiety(rid); - if (piety >= 100) { + if (piety >= 200) { int chance; - // ie. 100 -> 2% + // ie. 200 -> 4% // ie. 500 -> 10% chance = piety / 50; if (pctchance(chance)) { // if this is true, you get a gift. @@ -302,6 +355,61 @@ int godgiftmaybe(enum RACE rid) { godsay(god->race->id, "I bestow a gift upon you, mortal!"); strcpy(obtogive, ""); switch (god->race->id) { + case R_GODPURITY: + while (rollagain) { + int n,nposs,i; + object_t *poss[MAXCANDIDATES],*o; + flag_t *f; + object_t *wep; + rollagain = B_FALSE; + switch (rnd(1,6)) { + case 1: + sprintf(obtogive, "2-4 blessed potions of water"); + break; + case 2: + sprintf(obtogive, "blessed great weapon"); + break; + case 3: + sprintf(obtogive, "wand of turn undead"); + break; + case 4: // bless your weapon + wep = getweapon(player); + if (wep && !isblessed(wep)) { + blessob(wep); + } else { + rollagain = B_TRUE; + } + break; + case 5: // holy aura + if (lfhasflag(player, F_HOLYAURA)) { + rollagain = B_TRUE; + } else { + f = addtempflag(player->flags, F_PRODUCESLIGHT, 3, NA, NA, NULL, FROMGODGIFT); + f->obfrom = god->race->id; + f = addtempflag(player->flags, F_HOLYAURA, NA, NA, NA, NULL, FROMGODGIFT); + f->obfrom = god->race->id; + } + break; + case 6: // bless 1-3 obs + nposs = 0; + n = rnd(1,3); // num to bless + for (o = player->pack->first ; o ; o = o->next) { + if (!isblessed(o)) { + poss[nposs++] = o; + } + } + if (nposs < n) n = nposs; + for (i = 0; i < n; i++) { + o = poss[rnd(0,nposs-1)]; + while (isblessed(o)) { + o = poss[rnd(0,nposs-1)]; + } + blessob(o); + } + break; + } + } + break; case R_GODDEATH: while (rollagain) { flag_t *f; @@ -343,7 +451,41 @@ int godgiftmaybe(enum RACE rid) { } } break; - case R_GODGREED: + case R_GODTHIEVES: + while (rollagain) { + rollagain = B_FALSE; + switch (rnd(1,7)) { + case 1: + if (getskill(player, SK_TECHUSAGE) >= gettechlevel(OT_LOCKHACKER)) { + sprintf(obtogive, "lock hacker"); + } else { + sprintf(obtogive, "3-6 blessed lockpicks"); + } + break; + case 2: + if (onein(6)) { + sprintf(obtogive, "large bag of holding"); + } else { + sprintf(obtogive, "bag of holding"); + } + break; + case 3: + sprintf(obtogive, "safebox"); + break; + case 4: + sprintf(obtogive, "wand of opening"); + break; + case 5: + sprintf(obtogive, "wand of invisibility"); + break; + case 6: + sprintf(obtogive, "3-6 potions of invisibility"); + break; + case 7: + sprintf(obtogive, "leather boots of stealth"); + break; + } + } break; case R_GODMERCY: while (rollagain) { @@ -445,8 +587,26 @@ void pleasegod(enum RACE rid, int amt) { modpiety(rid, amt); // announce - msg("You feel like %s approves of your actions.", lfname); - godgiftmaybe(rid); + if (hasflag(lf->flags, F_PRAYEDTO)) { + switch (rid) { + case R_GODDEATH: + msg("You feel a thrill of unholy ecstasy."); + break; + case R_GODMERCY: + msg("You feel a sense of peace."); + break; + case R_GODPURITY: + msg("You hear a distant choir singing."); + break; + case R_GODTHIEVES: + msg("You feel a guilty pleasure."); + break; + default: + msg("You feel like %s approves of your actions.", lfname); + break; + } + godgiftmaybe(rid); + } } void pleasegodmaybe(enum RACE rid, int amt) { @@ -485,9 +645,30 @@ int prayto(lifeform_t *lf, lifeform_t *god) { if (godisangry(god->race->id)) { // get even more angry angergod(god->race->id, PIETYPRAYLOSS); - return B_FALSE; - } else if (piety <= 99) { + } + + // sacrifices if god isn't angry. + if (god->race->id == R_GODPURITY) { + object_t *o,*nexto; + int donesomething = B_FALSE; + for (o = lf->cell->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (iscursed(o) && (o->blessknown)) { + char buf[BUFLEN]; + getobname(o, buf, o->amt); + msg("%s explode%s in a shower of sparks!",buf, (o->amt == 1) ? "s" : ""); + removeob(o,ALL); + donesomething = B_TRUE; + } + } + pleasegodmaybe(god->race->id, 5); + return B_FALSE; + } + + + + if (piety <= 99) { // piety between 0 and 99 = ignored //godsay(god->race->id, "Stop pestering me!"); angergod(god->race->id, 0); @@ -501,6 +682,40 @@ int prayto(lifeform_t *lf, lifeform_t *god) { switch (god->race->id) { lifeform_t *l; int donesomething = B_FALSE; + cell_t *c; + object_t *o; + object_t *oposs[MAXPILEOBS]; + int noposs = 0; + case R_GODPURITY: + msg("\"Witness the holy radiance of purity!\""); + c = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); + if (c) { + dospelleffects(god, OT_S_LIGHT, 10, NULL, NULL, c, B_BLESSED, NULL, B_TRUE); + } + // get list of cursed obs + noposs = 0; + for (o = lf->pack->first ; o ; o = o->next) { + if (iscursed(o)) { + oposs[noposs++] = o; + } + } + if (noposs) { + o = oposs[rnd(0,noposs-1)]; + blessob(o); + } + // smite evil + for (l = lf->cell->map->lf ; l ; l = l->next) { + if (getalignment(l) == AL_EVIL) { + if (haslof(lf->cell, l->cell, LOF_WALLSTOP, NULL)) { + // smite them + castspell(god, OT_S_SMITEEVIL, l, NULL, l->cell); + } + } + } + // turn undead + castspell(god, OT_S_TURNUNDEAD, lf, NULL, NULL); + + break; case R_GODDEATH: msg("\"Behold, the power of death!\""); for (l = lf->cell->map->lf ; l ; l = l->next) { @@ -511,7 +726,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { dospelleffects(god, OT_S_ANIMATEDEAD, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); dospelleffects(god, OT_S_DARKNESS, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); break; - case R_GODGREED: + case R_GODTHIEVES: if (isinbattle(lf)) { lifeform_t *l; int donesomething = B_FALSE; @@ -551,14 +766,16 @@ int prayto(lifeform_t *lf, lifeform_t *god) { cell_t *c; object_t *o; c = player->los[i]; - o = hascloseddoor(c); - if (o && hasflag(o->flags, F_LOCKED)) { - if (first) { - msg("\"Access granted!\""); - first = B_FALSE; + if (c != player->cell) { + o = hascloseddoor(c); + if (o && hasflag(o->flags, F_LOCKED)) { + if (first) { + msg("\"Access granted!\""); + first = B_FALSE; + } + killflagsofid(o->flags, F_LOCKED); + noise(c, NULL, NC_OTHER, 2, "the click of a lock.", NULL); } - killflagsofid(o->flags, F_LOCKED); - noise(c, NULL, NC_OTHER, 2, "the click of a lock.", NULL); } } } diff --git a/io.c b/io.c index 353b1a2..6ee1558 100644 --- a/io.c +++ b/io.c @@ -618,6 +618,7 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src // show what we are over in msg bar strcpy(buf, ""); if (haslos(player, c)) { + int i; // can see the cell... if (c->lf) { if (cansee(player, c->lf)) { @@ -780,17 +781,21 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src } } + if (lfhasflag(c->lf, F_HOLYAURA)) { + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, "holyaura"); + } if (lfhasflag(c->lf, F_RAGE)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "enraged"); } - for (f = c->lf->flags->first ; f ; f = f->next) { - if (f->id == F_RETALIATE) { - if (strlen(extrainfo)) strcat(extrainfo, ", "); - strcat(extrainfo, f->text); - } + getflags(c->lf->flags, F_RETALIATE, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, f->text); } wep = getweapon(c->lf); @@ -1425,6 +1430,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_HOLYAURA: + msg("%s %s surrounded by a holy aura!", lfname, isplayer(lf) ? "are" : "is"); + donesomething = B_TRUE; + break; case F_LEVITATING: msg("%s begin%s to levitate in the air!",lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; @@ -1937,6 +1946,10 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_HOLYAURA: + msg("%s%s holy aura vanishes.", lfname, getpossessive(lfname)); + donesomething = B_TRUE; + break; case F_LEVITATING: msg("%s %s down to the ground.", lfname, isplayer(lf) ? "float" : "floats"); donesomething = B_TRUE; @@ -3127,21 +3140,23 @@ void describeob(object_t *o) { mvwprintw(mainwin, y, 0, " It can hold up to %d of the following kind(s) of ammo:",f->val[0]); y++; strcpy(buf, ""); - for (ff = o->flags->first; ff ; ff = ff->next) { - if (ff->id == F_AMMOOB) { - objecttype_t *ot; - ot = findot(ff->val[0]); - if (ot) { - if (streq(buf, "")) { + + + getflags(o->flags, F_AMMOOB, F_NONE); + for (i = 0; i < nretflags; i++) { + objecttype_t *ot; + ff = retflag[i]; + ot = findot(ff->val[0]); + if (ot) { + if (streq(buf, "")) { + sprintf(buf, " %s",ot->name); + } else { + if (strlen(buf) >= 60) { + mvwprintw(mainwin, y, 0, "%s",buf); y++; sprintf(buf, " %s",ot->name); } else { - if (strlen(buf) >= 60) { - mvwprintw(mainwin, y, 0, "%s",buf); y++; - sprintf(buf, " %s",ot->name); - } else { - strcat(buf, ", "); - strcat(buf, ot->name); - } + strcat(buf, ", "); + strcat(buf, ot->name); } } } @@ -3667,6 +3682,9 @@ void describeob(object_t *o) { case F_DETECTAURAS: mvwprintw(mainwin, y, 0, "%s allows you to detect blessings or curses.", buf); y++; break; + case F_HOLYAURA: + mvwprintw(mainwin, y, 0, "%s surrounds you with a holy aura.", buf); y++; + break; case F_LEVITATING: mvwprintw(mainwin, y, 0, "%s causes you to levitate.", buf); y++; break; @@ -4116,8 +4134,8 @@ void docomms(lifeform_t *lf) { } } - if ((lf->race->id == R_BEGGAR) && countmoney(player)) { - addchoice(&prompt, 'd', "(donate a gold coin)", NULL, NULL); + if (isadjacent(lf->cell, player->cell)) { + addchoice(&prompt, 'd', "(donate an item)", NULL, NULL); } f = lfhasflag(lf, F_OWNSSHOP); @@ -4139,6 +4157,8 @@ void docomms(lifeform_t *lf) { lifeform_t *lf2 = NULL; char lfname2[BUFLEN]; char buf2[BUFLEN]; + int count; + object_t *o, *givenob = NULL; case 'a': sprintf(buf, "Tell %s to attack who?",lfname); sprintf(buf2, "%s->Attack->",lfname); @@ -4169,56 +4189,115 @@ void docomms(lifeform_t *lf) { aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME); } break; - case 'd': // donate to beggar - givemoney(player, lf, 1); // we already checked that we had enough. - if (countmoney(lf) == 1) { - i = rnd(1,100); - if (i <= 5) { // attack you - sayphrase(lf, SP_BEGATTACK, SV_SHOUT, NA, NULL); - fightback(lf, player); - } else if (i <= 10) { // limited wish - // change to a god. - lf = godappears(R_GODGREED, lf->cell); - // behold! i am me! - say(lf, "Behold mortal! It is I, Avamon!", SV_SHOUT); - say(lf, "For your selfless act, I grant you a wish.", SV_TALK); - // grant a wish. - castspell(lf, OT_S_WISHLIMITED, player, NULL, NULL); - say(lf, "Until next time, mortal!", SV_TALK); - unsummon(lf, B_TRUE); - } else if (i <= 20) { // identify - object_t *poss[MAXPILEOBS],*o; - int nposs = 0; - sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); - // get random unknown item from player's pack - for (o = player->pack->first ; o ; o = o->next){ - if (!isknown(o)) { - poss[nposs++] = o; + case 'd': // donate + + // ask what to give + sprintf(buf, "What will you give to %s?",lfname); + o = askobject(player->pack, buf, &count, AO_NONE); + if (o) { + if (o->type->id == OT_GOLD) { + getobname(o, buf, count); + givemoney(player, lf, count); + msg("You give %s to %s.", buf, lfname); + } else { + givenob = moveob(o, lf->pack, count); + if (givenob) { + getobname(givenob, buf, givenob->amt); + // successful - announce + msg("You give %s to %s.", buf, lfname); + } + } + } + + if (givenob) { + if ((lf->race->id == R_BEGGAR) && (givenob->type->id == OT_GOLD)) { + // begger effects + if (countmoney(lf) == 1) { + i = rnd(1,100); + if (i <= 5) { // attack you + sayphrase(lf, SP_BEGATTACK, SV_SHOUT, NA, NULL); + fightback(lf, player); + } else if (i <= 10) { // limited wish + // change to a god. + lf = godappears(R_GODMERCY, lf->cell); + // behold! i am me! + say(lf, "Behold mortal! It is I, Yumi!", SV_SHOUT); + say(lf, "For your selfless act, I grant you a wish.", SV_TALK); + // grant a wish. + castspell(lf, OT_S_WISHLIMITED, player, NULL, NULL); + say(lf, "Until next time, mortal!", SV_TALK); + unsummon(lf, B_TRUE); + } else if (i <= 20) { // identify + object_t *poss[MAXPILEOBS],*o; + int nposs = 0; + sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); + // get random unknown item from player's pack + for (o = player->pack->first ; o ; o = o->next){ + if (!isknown(o)) { + poss[nposs++] = o; + } + } + if (nposs) { + char oldobname[BUFLEN]; + char newobname[BUFLEN]; + o = poss[rnd(0,nposs-1)]; + + getobname(o, oldobname, o->amt); + makeknown(o->type->id); + getobname(o, newobname, o->amt); + msg("%s points at your pack.", lfname); + msg("Hey I recognise %s %s.", + (o->amt == 1) ? "that" : "those", + oldobname); + msg("%s %s.", + (o->amt == 1) ? "It's" : "They're", + newobname); + } + } else { // nothing + sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); + } + } else { + // they already had some money + sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); + } + pleasegodmaybe(R_GODPURITY, 10); + pleasegodmaybe(R_GODMERCY, 20); + } else { + // not giving money to a begger + enum ATTRBRACKET iqb; + iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); + // chance of calming hostile intelligen, monsters + if ((getallegiance(lf) == AL_HOSTILE) && (iqb >= IQ_ANIMAL) && cansee(lf, player)) { + int mod = 0; + int covets = B_FALSE; + // healing object and they were bleeding? + if (isbleeding(lf) && hasflag(givenob->flags, F_AIHEALITEM)) { + if (aiobok(lf, givenob, lf)) { + mod += 3; + } + } + // object which ai wants? + if (aiwants(lf, givenob, &covets)) { + if (covets) { + mod += 5; + } else { + mod += 3; + } + } + + // TODO: only get speech bonus if humanoid+intelligent + mod += getskill(player, SK_SPEECH); + + if (skillcheckvs(player, SC_MORALE, mod, lf, SC_MORALE, 0)) { + // TODO: if humanoid+intelligent, say thanks. + makepeaceful(lf); + // TODO: chance of becoming a pet? + pleasegodmaybe(R_GODMERCY, 5); } } - if (nposs) { - char oldobname[BUFLEN]; - char newobname[BUFLEN]; - o = poss[rnd(0,nposs-1)]; - - getobname(o, oldobname, o->amt); - makeknown(o->type->id); - getobname(o, newobname, o->amt); - msg("%s points at your pack.", lfname); - msg("Hey I recognise %s %s.", - (o->amt == 1) ? "that" : "those", - oldobname); - msg("%s %s.", - (o->amt == 1) ? "It's" : "They're", - newobname); - } - } else { // nothing - sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); } - } else { - // they already had some money - sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); - } + } // end if givenob + break; case 'g': sprintf(buf, "Tell %s to go where?",lfname); @@ -4248,6 +4327,7 @@ void docomms(lifeform_t *lf) { // can't afford it msg("You can't afford to pay $%d.", moneyowing); } else { + int angeramt = 0; object_t *o; // mark all items as paid for for (o = player->pack->first ; o ; o = o->next) { @@ -4256,6 +4336,7 @@ void docomms(lifeform_t *lf) { killflag(f); getobname(o, buf, o->amt); msg("You buy %s.", buf); + angeramt += 25; // get it identified? if (!isknown(o) && (countmoney(player) >= SHOPIDENTPRICE)) { char buf2[BUFLEN]; @@ -4264,6 +4345,7 @@ void docomms(lifeform_t *lf) { ch2 = askchar(buf2, "yn","n", B_TRUE); if (ch2 == 'y') { if (givemoney(player, lf, SHOPIDENTPRICE)) { + angeramt += 25; identify(o); real_getobname(o, buf, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness msgnocap("%c - %s",o->letter, buf); @@ -5321,7 +5403,7 @@ void dohelp(char helpmode) { } } else if (helpmode == 'g') { int i; - centre(mainwin,C_WHITE, 0, "SKILL REFERENCE"); + centre(mainwin,C_WHITE, 0, "GOD REFERENCE"); y = 2; initprompt(&prompt, "Describe which god (ESC when done)?"); @@ -5755,7 +5837,11 @@ void dothrow(obpile_t *op) { } if (getcelldist(player->cell, where) > maxdist) { - msg("You can't throw %s that far!",buf); + if (maxdist < 1) { + msg("%s is too heavy to throw!",buf, (o->amt == 1) ? "is" : "are"); + } else { + msg("You can't throw %s that far!",buf); + } } else { throwat(player, o, where); } @@ -6048,9 +6134,21 @@ void initgfx(void) { // create windows //msgwin = newwin(1, vieww, 0, 0); msgwin = newwin(msgwinh, vieww, 0, 0); + if (!msgwin) { + dblog("Error creating msgwin."); + exit(1); + } gamewin = newwin(viewh, vieww, msgwinh, 0); + if (!gamewin) { + dblog("Error creating gamewin."); + exit(1); + } //statwin = newwin(statwinh, vieww, msgwinh + viewh + statwinh - 2 ,0); statwin = newwin(statwinh, vieww, SCREENH - statwinh,0); + if (!statwin) { + dblog("Error creating statwin."); + exit(1); + } statdirty = B_TRUE; redraw(); @@ -8053,12 +8151,11 @@ void showlfstats(lifeform_t *lf, int showall) { // unarmed attacks op = addobpile(NULL, NULL, NULL); for (f = lf->flags->first ; f ; f = f->next) { - if (f->id == F_HASATTACK) { object_t *o; objecttype_t *ot; ot = findot(f->val[0]); - o = addob(op, ot->name); + o = addobfast(op, ot->id); if (o) { char dambuf[BUFLEN]; strcpy(dambuf, ""); @@ -9063,6 +9160,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, buf); y++; } + f = lfhasknownflag(lf, F_HOLYAURA); + if (f && (f->known)) { + mvwprintw(mainwin, y, 0, "%s %s surrounded by a holy aura.", you(lf), is(lf)); + y++; + } f = lfhasknownflag(lf, F_QUICKBITE); if (f && (f->known)) { sprintf(buf,"%s can bite wounded enemies for extra damage.", you(lf)); diff --git a/lf.c b/lf.c index ebfec6b..31e0c7c 100644 --- a/lf.c +++ b/lf.c @@ -948,7 +948,7 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { return B_FALSE; } - if (gettechlevel(o) > getskill(lf, SK_TECHUSAGE)) { + if (gettechlevel(o->type->id) > getskill(lf, SK_TECHUSAGE)) { reason = E_NOTKNOWN; return B_FALSE; } @@ -1297,6 +1297,20 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar // successful cast? if (!rv) { practice(lf, SK_SPELLCASTING, 1); + if (isplayer(lf)) { + switch (getschool(sid)) { + case SS_DEATH: + pleasegodmaybe(R_GODDEATH, getspelllevel(sid)); + angergodmaybe(R_GODPURITY, getspelllevel(sid)*5); + break; + case SS_LIFE: + pleasegodmaybe(R_GODPURITY, getspelllevel(sid)); + angergodmaybe(R_GODDEATH, getspelllevel(sid)*5); + break; + default: + break; + } + } } return rv; @@ -1761,6 +1775,13 @@ void die(lifeform_t *lf) { // award xp (but not if another monster killed it) if (hasflag(lf->flags, F_KILLEDBYPLAYER)) { awardxpfor(lf,100); + if ((getalignment(lf) == AL_EVIL) || isundead(lf)) { + pleasegodmaybe(R_GODPURITY, 3); + } else if (getalignment(lf) == AL_GOOD) { + pleasegodmaybe(R_GODDEATH, 3); + } else { // ie. neutral + pleasegodmaybe(R_GODDEATH, 1); + } } } @@ -2133,7 +2154,7 @@ int digdown(lifeform_t *lf, object_t *o) { msg("%s digs a hole in the floor."); } - addob(lf->cell->obpile, "hole in the ground"); + addobfast(lf->cell->obpile, OT_HOLEINGROUND); // takes a lot of time if (o) { @@ -2172,8 +2193,7 @@ int digup(lifeform_t *lf, object_t *o) { // add some stones here addob(lf->cell->obpile, "20-50 stones"); - - addob(lf->cell->obpile, "hole in the roof"); + addobfast(lf->cell->obpile, OT_HOLEINROOF); // takes a LOT of time since gravity is against us if (o) { @@ -2481,7 +2501,7 @@ int eat(lifeform_t *lf, object_t *o) { // special case for bananas if (o->type->id == OT_BANANA) { object_t *skin; - skin = addob(lf->pack, "banana skin"); + skin = addobfast(lf->pack, OT_BANANASKIN); if (skin) { if (isplayer(lf)) { char skinname[BUFLEN]; @@ -2489,7 +2509,7 @@ int eat(lifeform_t *lf, object_t *o) { msgnocap("%c - %s", skin->letter, skinname); } } else { - skin = addob(lf->cell->obpile, "banana skin"); + skin = addobfast(lf->cell->obpile, OT_BANANASKIN); if (skin && cansee(player, lf)) { char skinname[BUFLEN]; getobname(skin, skinname, 1); @@ -2518,8 +2538,9 @@ int eat(lifeform_t *lf, object_t *o) { } + // eating your pet is very bad! if (isplayer(lf) && hasflagval(o->flags, F_PETOF, player->id, NA, NA, NULL)) { - angergodmaybe(R_GODMERCY, 150); + angergodmaybe(R_GODPURITY, 150); stopeating = B_TRUE; } @@ -3100,9 +3121,11 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) { int i, nposs = 0; // darkjump for (i = 0; i < lf->nlos; i++) { - if (cellwalkable(lf, lf->los[i], NULL) && isdark(lf->los[i])) { - poss[nposs] = lf->los[i]; - nposs++; + if (lf->los[i] != lf->cell) { + if (cellwalkable(lf, lf->los[i], NULL) && isdark(lf->los[i])) { + poss[nposs] = lf->los[i]; + nposs++; + } } } if (nposs) { @@ -3286,8 +3309,10 @@ int flee(lifeform_t *lf) { // if the flag is temporary, keep fleeing and wait for it to time out normally fleefrom = thisone; } + // player let something flee? if (isplayer(thisone)) { pleasegodmaybe(R_GODMERCY, 5); + angergodmaybe(R_GODDEATH, 25); } } } @@ -3341,7 +3366,7 @@ int flee(lifeform_t *lf) { } } // move away from them - if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH)) { + if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE)) { return B_TRUE; } } @@ -3664,6 +3689,15 @@ void getadjallies(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int * } } +enum ALIGNMENT getalignment(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_ALIGNMENT); + if (!f) { + return AL_NONE; + } + return f->val[0]; +} + enum ALLEGIENCE getallegiance(lifeform_t *lf) { flag_t *f; f = lfhasflag(lf, F_CHARMEDBY); @@ -3899,10 +3933,14 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { if ((f->id == F_ATTRMOD) && (f->val[0] == attr)) { val += f->val[1]; } - if ((f->id == F_DRUNK) && (attr == A_DEX)) { - if (hasjob(lf, J_PIRATE)) { - val += f->val[0]; - } else { + if (f->id == F_DRUNK) { + if (attr == A_DEX) { + if (hasjob(lf, J_PIRATE)) { + val += f->val[0]; + } else { + val -= f->val[0]; + } + } else if (attr == A_WIS) { val -= f->val[0]; } } @@ -3937,7 +3975,7 @@ int getavgdam(lifeform_t *lf, int forxp) { objecttype_t *ot; ot = findot(f->val[0]); - o = addob(op, ot->name); + o = addobfast(op, ot->id); getdamrange(f, &min,&max); thisavg = ((float)min + (float)max) / 2.0; @@ -4132,7 +4170,7 @@ int getevasion(lifeform_t *lf) { } // dexterity mod - ev += (getstatmod(lf, A_DEX) / 2); + ev += (getstatmod(lf, A_DEX) / 10); // you are easier to hit if you're glowing if (hasflag(lf->flags, F_PRODUCESLIGHT)) { @@ -4221,7 +4259,7 @@ object_t *getbestweapon(lifeform_t *lf) { ot = findot(retflag[i]->val[0]); if (ot) { - o = addob(op, ot->name); + o = addobfast(op, ot->id); if (isweapon(o) && !isfirearm(o) && canweild(lf, o) && isbetterwepthan(o, bestwep)) { bestwep = o; @@ -5202,9 +5240,11 @@ lifeform_t *getnearbypeaceful(lifeform_t *lf) { int nposs = 0; // peaceful enemy in los ? for (i = 0; i < lf->nlos; i++) { - l = lf->los[i]->lf; - if (l && (getallegiance(l) == AL_PEACEFUL)) { - poss[nposs] = l; + if (lf->los[i] != lf->cell) { + l = lf->los[i]->lf; + if (l && (getallegiance(l) == AL_PEACEFUL)) { + poss[nposs] = l; + } } } if (nposs) { @@ -6382,6 +6422,16 @@ int givemoney(lifeform_t *from, lifeform_t *to, int amt) { togold += amt; } + + if (isplayer(from)) { + flag_t *f; + f = lfhasflag(from, F_GAVEMONEY); + if (f) { + f->val[0] += amt; + } else { + addflag(from->flags, F_GAVEMONEY, amt, NA, NA, NULL); + } + } return B_FALSE; } @@ -6712,7 +6762,7 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { skill_t *sk; object_t *o; // give that weapon - o = addob(lf->pack, ot->name); + o = addobfast(lf->pack, ot->id); // give one extra rank of skill in this weapon sk = getobskill(o); @@ -6854,7 +6904,7 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { region_t *r; regionthing_t *rt = NULL; int i; - o = addob(lf->pack, "map"); + o = addobfast(lf->pack, OT_MAP); assert(o); // find first worldmap village r = findregion(RG_WORLDMAP); @@ -7157,6 +7207,7 @@ int lockpick(lifeform_t *lf, object_t *target, object_t *device) { char obname[BUFLEN]; int faileffect; int difficulty = 20; // default, never used though + int bonus = 0; lockflag = hasflag(target->flags, F_LOCKED); if (lockflag) { @@ -7174,13 +7225,15 @@ int lockpick(lifeform_t *lf, object_t *target, object_t *device) { f = hasflag(device->flags, F_PICKLOCKS); assert(f); + bonus = f->val[0]; + if (isblessed(device)) bonus += 5; faileffect = f->val[1]; // take time taketime(lf, getactspeed(lf) ); - // TODO: different difficulty based on doors (maybe part of F_LOCKED flag) - if (skillcheck(lf, SC_OPENLOCKS, difficulty, f->val[0])) { + + if (skillcheck(lf, SC_OPENLOCKS, difficulty, bonus )) { // success! // announce if (isplayer(lf) || cansee(player, lf)) { @@ -7198,6 +7251,8 @@ int lockpick(lifeform_t *lf, object_t *target, object_t *device) { } // training practice(lf, SK_LOCKPICKING, 1); + // gods + if (isplayer(lf)) pleasegodmaybe(R_GODTHIEVES, 5); } else { // failed! if (faileffect == B_DIEONFAIL) { @@ -7406,6 +7461,17 @@ int haslos(lifeform_t *viewer, cell_t *dest) { if (viewer->cell->map != dest->map) return B_FALSE; + // can we use pre-calced los? + // + if ((viewer->cell->map->lf == viewer) && viewer->los) { + for (i = 0;i < viewer->nlos; i++) { + if (viewer->los[i] == dest) { + return B_TRUE; + } + } + return B_FALSE; + } + map = dest->map; x1 = viewer->cell->x; @@ -7923,6 +7989,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); @@ -8134,6 +8201,7 @@ void initrace(void) { // human monsters... addrace(R_BANDITLDR, "bandit leader", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); addflag(lastrace->flags, F_DEMANDSBRIBE, NA, NA, NA, NULL); @@ -8157,6 +8225,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 100, 1, 3, "bandit"); addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -8254,8 +8323,98 @@ void initrace(void) { addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - // gods + // gods - kep sorted alphabetically + addrace(R_GODPURITY, "Amberon", 90, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "20"); + addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10"); + addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "18"); + addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "16"); + addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "16"); + addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "16"); + addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 50, NA, NA, NULL); + addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed +3 flaming longsword"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 blessed potions of water"); + //addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_RARITY, NA, NA, NULL); // ie. everything + addflag(lastrace->flags, F_STARTSKILL, SK_SS_LIFE, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_FIRSTAID, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "gestures imperiously"); + // god abilities + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Purity"); + addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_LIGHT, NA, NA, "pw:10;"); + // may cast all life spells + for (ot = objecttype ; ot ; ot = ot->next) { + if ((ot->obclass->id == OC_SPELL) && (getspellschool(ot->id) == SS_LIFE)) { + addflag(lastrace->flags, F_CANWILL, ot->id, NA, NA, "pw:10;"); + } + } + + addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); + // likes/dislikes + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "destroying the undead"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing evil creatures"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "blessing objects"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "acts of charity"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "casting holy spells"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "sacrificing cursed objects through prayer"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "attacking good, peaceful or helpless creatures"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of poison"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "cursing objects"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "eating pets"); + + + addrace(R_GODTHIEVES, "Felix", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); + addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "20"); + addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10"); + addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "9"); + addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "10"); + addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "8"); + addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "6"); + addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+5 dagger of sharpness"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed ring of hunger"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 huge bags of holding"); + //addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_RARITY, NA, NA, NULL); // ie. everything + addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_BACKSTAB, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_THROWING, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "waves his hand"); + // god abilities + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Thieves"); + addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_CALLWIND, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_CONFISCATE, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_HUNGER, NA, NA, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); + // likes/dislikes + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "backstabbing"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "stealing items"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "lockpicking"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "purchasing items"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "giving away or discarding money"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "opening locked objects through force"); + + addrace(R_GODDEATH, "Hecta", 100, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "16"); addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "20"); addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "15"); @@ -8286,44 +8445,20 @@ void initrace(void) { } addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); + // likes + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing (especially the good-aligned)"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "attacking the helpless"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "casting necromancy spells"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "cursing objects"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "allowing enemies to flee"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "magical healing"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "bestowing blessings"); + addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "casting holy spells"); + - addrace(R_GODGREED, "Avamon", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); - addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "20"); - addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10"); - addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "9"); - addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "10"); - addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "8"); - addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "6"); - addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL); - addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, 30, NA, NA, NULL); - addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); - addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); - addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+5 dagger of sharpness"); - addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed ring of hunger"); - addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 huge bags of holding"); - //addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); - addflag(lastrace->flags, F_WANTSOBFLAG, F_RARITY, NA, NA, NULL); // ie. everything - addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_MASTER, NA, NULL); - addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_MASTER, NA, NULL); - addflag(lastrace->flags, F_STARTSKILL, SK_BACKSTAB, PR_MASTER, NA, NULL); - addflag(lastrace->flags, F_STARTSKILL, SK_THROWING, PR_MASTER, NA, NULL); - addflag(lastrace->flags, F_STARTSKILL, SK_CLIMBING, PR_MASTER, NA, NULL); - addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "waves his hand"); - // god abilities - addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Thieves"); - addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); - addflag(lastrace->flags, F_OBESE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, "pw:10;"); - addflag(lastrace->flags, F_CANWILL, OT_S_CALLWIND, NA, NA, "pw:10;"); - addflag(lastrace->flags, F_CANWILL, OT_S_CONFISCATE, NA, NA, "pw:10;"); - addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); - addflag(lastrace->flags, F_CANWILL, OT_S_HUNGER, NA, NA, "pw:1;"); - addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); addrace(R_GODMERCY, "Yumi", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 95, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "10"); addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10"); @@ -8352,6 +8487,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "the successful casting of healing spells"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "allowing fleeing creatures to escape"); + addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "acts of charity"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "natural healing"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "attacking the innocent"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "sneak attacks"); @@ -8361,6 +8497,7 @@ void initrace(void) { // monsters addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VHIGH, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); @@ -8433,6 +8570,7 @@ void initrace(void) { // special attack handled in attack.c addrace(R_CREEPINGCLAW, "creeping claw", 3, 'x', C_YELLOW, MT_FLESH, RC_MAGIC); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL); @@ -8457,6 +8595,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); addrace(R_DARKMANTLE, "darkmantle", 70, 'U', C_BLUE, MT_FLESH, RC_MAGIC); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTHIDDENPCT, 80, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL); @@ -8516,6 +8655,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addrace(R_GIANTHILL, "hill giant", 160, 'H', C_GREY, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 55, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 55, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -8547,6 +8687,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL); addrace(R_GIANTFIRE, "fire giant", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL); @@ -8578,6 +8719,7 @@ void initrace(void) { addrace(R_GIANTFIREFC, "fire giant forgecaller", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GIANTFIRE; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "fire giant corpse"); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 48, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -8613,6 +8755,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL); addrace(R_GIANTFIRETITAN, "fire titan", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 40, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_ENORMOUS, NA, NA, NULL); @@ -8644,6 +8787,7 @@ void initrace(void) { // TODO: storm titan addrace(R_GNOLL, "gnoll", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 3, NA, ""); @@ -8669,6 +8813,7 @@ void initrace(void) { addrace(R_GNOLLHM, "gnoll huntmaster", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GNOLL; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); @@ -8698,6 +8843,7 @@ void initrace(void) { addrace(R_GNOLLMR, "gnoll marauder", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GNOLL; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); @@ -8724,6 +8870,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addrace(R_GOBLIN, "goblin", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_FEIGNDEATH, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, NULL); @@ -8753,6 +8900,7 @@ void initrace(void) { addrace(R_GOBLINWAR, "goblin warrior", 30, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GOBLIN; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); @@ -8780,6 +8928,7 @@ void initrace(void) { addrace(R_GOBLINSHOOTER, "goblin sharpshooter", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GOBLIN; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); @@ -8810,6 +8959,7 @@ void initrace(void) { addrace(R_GOBLINHEXER, "goblin hexer", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GOBLIN; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); @@ -8838,6 +8988,7 @@ void initrace(void) { addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin"); addrace(R_HOBGOBLIN, "hobgoblin", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 73, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 73, NA, NULL); @@ -8868,6 +9019,7 @@ void initrace(void) { addrace(R_HOBGOBLINWAR, "hobgoblin warrior", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_HOBGOBLIN; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 60, NA, NULL); @@ -8901,6 +9053,7 @@ void initrace(void) { // TODO: hobgoblin warcaster addrace(R_KOBOLD, "kobold", 18, 'k', C_BROWN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL); addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); @@ -8916,6 +9069,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_DEX, AT_HIGH, NA, NULL); addflag(lastrace->flags, F_STARTOBDT, 20, DT_PIERCE, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 25, OC_POTION, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_THROWING, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-3 darts"); addflag(lastrace->flags, F_STARTOB, 10, NA, NA, "javelin"); addflag(lastrace->flags, F_STARTOB, 15, NA, NA, "buckler"); @@ -8974,6 +9128,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL); addrace(R_LURKINGHORROR, "lurking horror", 100, 'U', C_MAGENTA, MT_FLESH, RC_DEMON); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); @@ -9000,6 +9155,7 @@ void initrace(void) { addrace(R_MINOTAUR, "minotaur", 130, 'H', C_BROWN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 62, NA, NULL); @@ -9014,8 +9170,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "5-7"); addflag(lastrace->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_VHIGH, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4"); - addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4"); + addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4+6"); + addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4+6"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "+2 heavy flail"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "greataxe"); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); @@ -9029,6 +9185,7 @@ void initrace(void) { addrace(R_OGRE, "ogre", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); @@ -9058,6 +9215,7 @@ void initrace(void) { addrace(R_OGRESAVAGE, "ogre savage", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_OGRE; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL); @@ -9087,6 +9245,7 @@ void initrace(void) { addrace(R_OGREWARHULK, "ogre warhulk", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_OGRE; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL); @@ -9115,6 +9274,7 @@ void initrace(void) { addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "orc warrior"); addrace(R_ORC, "orc", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL); @@ -9144,6 +9304,7 @@ void initrace(void) { addrace(R_ORCWARRIOR, "orc warrior", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_ORC; + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); @@ -9200,6 +9361,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addrace(R_PEGASUS, "pegasus", 130, 'Q', C_GREY, MT_FLESH, RC_MAGIC); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 57, NA, ""); addflag(lastrace->flags, F_RARITY, H_FOREST, 57, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL); @@ -9227,6 +9389,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL); addrace(R_POLTERGEIST, "poltergeist", 50, 'p', C_GREEN, MT_FLESH, RC_UNDEAD); // sPirit + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9254,6 +9417,7 @@ void initrace(void) { addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL); addrace(R_SATYR, "satyr", 80, 'h', C_GREEN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL); @@ -9285,6 +9449,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL); addrace(R_SHADOWCAT, "shadowcat", 5, 'f', C_BLUE, MT_FLESH, RC_MAGIC); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); @@ -9355,6 +9520,7 @@ void initrace(void) { addrace(R_TROLL, "troll", 100, 't', C_GREEN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); @@ -9780,6 +9946,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addflag(lastrace->flags, F_FLEEONHPPCT, 60, NA, NA, ""); addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL); @@ -9805,6 +9972,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling"); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addrace(R_DOGDEATH, "death hound", 40, 'd', C_MAGENTA, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); @@ -10456,6 +10624,7 @@ void initrace(void) { // undead addrace(R_ZOMBIE, "zombie", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "6"); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); @@ -10477,6 +10646,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addrace(R_SKELETON, "skeleton", 20, 'Z', C_GREY, MT_BONE, RC_UNDEAD); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "5-20 bones"); addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); @@ -10496,6 +10666,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addrace(R_GHAST, "ghast", 50, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); @@ -10516,6 +10687,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addrace(R_GHOST, "ghost", 50, 'p', C_BLUE, MT_MAGIC, RC_UNDEAD); // p for sPirit + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); @@ -10536,6 +10708,7 @@ void initrace(void) { // their previous corpse. use f_mycorpse->oid for this. addrace(R_GHOUL, "ghoul", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); @@ -10556,6 +10729,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addrace(R_VAMPIRE, "vampire", 75, 'V', C_BLUE, MT_FLESH, RC_UNDEAD); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXHIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, AT_VHIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_WIS, AT_GTAVERAGE, NA, NULL); @@ -11396,7 +11570,7 @@ void addtrail(lifeform_t *lf, int dir) { } else { char buf[BUFLENTINY]; sprintf(buf, "%d", lf->id); - footprint = addob(lf->cell->obpile, "footprint"); + footprint = addobfast(lf->cell->obpile, OT_FOOTPRINT); addtempflag(footprint->flags, F_TRAIL, lf->race->id, fpdir, S_SIGHT, buf, getfootprinttime(lf)); } } @@ -11409,7 +11583,7 @@ void addtrail(lifeform_t *lf, int dir) { } else { char buf[BUFLENTINY]; sprintf(buf, "%d", lf->id); - scent = addob(lf->cell->obpile, "scent"); + scent = addobfast(lf->cell->obpile, OT_SCENT); addtempflag(scent->flags, F_TRAIL, lf->race->id, dir, S_SMELL, buf, SCENTTIME); } } @@ -13258,14 +13432,14 @@ void precalclos(lifeform_t *lf) { cell_t *c; cell_t **los; int maxvisrange; - int oldnlos = -1,nlos = 0; + int nlos = 0; int i; los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); + // free existing structures if (lf->los) { - oldnlos = lf->nlos; free(lf->los); lf->los = NULL; } @@ -13275,7 +13449,8 @@ void precalclos(lifeform_t *lf) { for (x = lf->cell->x - maxvisrange; x <= lf->cell->x + maxvisrange ; x++) { c = getcellat(lf->cell->map, x, y); // - if (c && (c != lf->cell) && haslos(lf, c)) { + //if (c && (c != lf->cell) && haslos(lf, c)) { + if (c && haslos(lf, c)) { los[nlos] = c; nlos++; } @@ -14992,6 +15167,9 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { break; } } // end foreach steal + + if (isplayer(lf)) pleasegodmaybe(R_GODTHIEVES, 5+numgot); + return B_FALSE; } @@ -15496,6 +15674,18 @@ void turneffectslf(lifeform_t *lf) { } } + // gods get angry + if (isplayer(lf)) { + f = lfhasflag(lf, F_GAVEMONEY); + if (f) { + int angeramt; + angeramt = f->val[0]; + limit(&angeramt, 25, NA); + angergodmaybe(R_GODTHIEVES, angeramt); + killflag(f); + } + } + // get more hungry modhunger(lf, 1); @@ -15826,7 +16016,7 @@ void turneffectslf(lifeform_t *lf) { if (!asleep) { if (poisoncausesvomit(f->val[0])) { - addob(lf->cell->obpile, "pool of vomit"); + addobfast(lf->cell->obpile, OT_VOMITPOOL); } loseconcentration(lf); } @@ -16664,7 +16854,7 @@ int validateraces(void) { cell_t fakecell; map_t fakemap; - // add flags based on raceclass + // add flags based on raceclass, and fill in missing alignments for (r = firstrace ; r ; r = r->next) { if (r->raceclass->id == RC_AQUATIC) { addflag(r->flags, F_HASSKILL, SK_SWIMMING, PR_MASTER, NA, NULL); @@ -16706,6 +16896,10 @@ int validateraces(void) { addflag(r->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); addflag(r->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); } + + if (!hasflag(r->flags, F_ALIGNMENT)) { + addflag(r->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); + } } // generate xp list diff --git a/lf.h b/lf.h index ea21b46..e5cfd52 100644 --- a/lf.h +++ b/lf.h @@ -89,6 +89,7 @@ void gainxp(lifeform_t *lf, long amt); void genxplist(void); int getactspeed(lifeform_t *lf); void getadjallies(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *nadjallies); +enum ALIGNMENT getalignment(lifeform_t *lf); enum ALLEGIENCE getallegiance(lifeform_t *lf); int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs); object_t *getarmour(lifeform_t *lf, enum BODYPART bp); diff --git a/map.c b/map.c index 42c8af0..02b52d4 100644 --- a/map.c +++ b/map.c @@ -395,7 +395,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int ot = NULL; } if (ot) { - addob(lf->pack, ot->name); + addobfast(lf->pack, ot->id); } } } @@ -1492,6 +1492,15 @@ int countcellexitsfor(lifeform_t *lf) { return exits; } +int countlfs(map_t *map) { + lifeform_t *lf; + int count = 0; + for (lf = map->lf ; lf ; lf = lf->next) { + count++; + } + return count; +} + // void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) { int wantrooms = B_TRUE; @@ -1736,7 +1745,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) { c = getrandomroomcell(map, ANYROOM); } - o = addob(c->obpile, "staircase going up"); + o = addobfast(c->obpile, OT_STAIRSUP); // have to force these stairs to go back to a different region. f = hasflag(o->flags, F_CLIMBABLE); f->val[1] = map->region->parentregion->id; @@ -1745,7 +1754,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ // special case: first dungeon level has barriers over the exit stairs if (map->region->rtype->id == RG_FIRSTDUNGEON) { if (c->lf) killlf(c->lf); - addob(c->obpile, "magical barrier"); + addobfast(c->obpile, OT_MAGICBARRIER); } } else { for (i = 0; i < map->region->rtype->stairsperlev; i++) { @@ -1753,7 +1762,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) { c = getrandomroomcell(map, ANYROOM); } - o = addob(c->obpile, "staircase going up"); + o = addobfast(c->obpile, OT_STAIRSUP); linkstairs(o, NULL); } } @@ -1765,7 +1774,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) { c = getrandomroomcell(map, ANYROOM); } - o = addob(c->obpile, "staircase going down"); + o = addobfast(c->obpile, OT_STAIRSDOWN); linkstairs(o, NULL); } } @@ -1999,6 +2008,11 @@ void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t assert(lf); // add to god list godlf[ngodlfs++] = lf; + if (ngodlfs > MAXGODS) { + dblog("Error - number of gods(%d) exceeds MAXGODS.",ngodlfs); + msg("Error - number of gods(%d) exceeds MAXGODS.",ngodlfs); + exit(1); + } } } } @@ -2695,7 +2709,7 @@ void createpit(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *e // clear it setcelltype(c, CT_CORRIDOR); // put an exit here - o = addobject(c->obpile, "hole in the roof", B_FALSE, B_FALSE); + o = addobject(c->obpile, NULL, B_FALSE, B_FALSE, OT_HOLEINROOF); assert(o); // link it linkstairs(o, entryob); @@ -2952,7 +2966,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int if (cc && (mydist <= (range+1))) { if (cc->lf && !isdead(cc->lf)) { // move away from centre of explosion - knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS), 2, NULL, 40-(mydist*10)); + knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 2, NULL, 40-(mydist*10)); } } } @@ -4102,7 +4116,7 @@ int linkholes(map_t *map) { } // note we specifically say DONT link the new hole, to avoid an infinite // loop! - newob = addobject(c2->obpile, ot->name, B_FALSE, B_FALSE); + newob = addobject(c2->obpile, NULL, B_FALSE, B_FALSE, ot->id); // link holes manually now. linkstairs(newob, o); diff --git a/move.c b/move.c index 5474ccc..bb006e6 100644 --- a/move.c +++ b/move.c @@ -435,7 +435,7 @@ int dorandommove(lifeform_t *lf, int badmovesok, int restonfail) { // src is where something is // dst is what we are going away from // wantcheck is whether to check for dangerous things before considering a direction valid -int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype) { +int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype, int keepinlof) { int d; cell_t *c; int maxdist=-1,bestdir=D_NONE; @@ -463,8 +463,6 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d // destination is the thing we're fleeing from! thisdist = 0; } else { - - if (wantcheck) { if (srclf) { if (canandwillmove(srclf, d, &error)) { @@ -487,6 +485,12 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d } } + if (keepinlof) { + if (!haslof(c, dst, LOF_NEED, NULL)) { + ok = B_FALSE; + } + } + if (ok) { if (dirtype == DT_ORTH) { thisdist = getcelldistorth(c, dst); @@ -791,7 +795,7 @@ int makeorthogonal(int dir) { } // see 'movetowards' for description of dirtype -int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype ) { +int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof ) { int dir; int rv = B_TRUE; @@ -801,7 +805,7 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype ) { } // move away from them - dir = getdiraway(lf->cell, dst, lf, B_TRUE, dirtype); + dir = getdiraway(lf->cell, dst, lf, B_TRUE, dirtype, keepinlof); if (dir == D_NONE) { rv = B_TRUE; } else { @@ -1179,11 +1183,12 @@ int movelf(lifeform_t *lf, cell_t *newcell) { for (l = newcell->map->lf ; l ; l = l->next) { if (l != lf) { flag_t *alarm; - if (haslos(l, newcell)) { + //if (haslos(l, newcell)) { + if (cansee(l, lf)) { int dointerrupt = B_FALSE; if (isplayer(l)) { - if (cansee(l, lf) && areenemies(lf, l)) { + if (areenemies(lf, l)) { if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_TRAINING)) { // TODO: also check for isresting(l), if we have allies standing watch getlfnamea(lf, lfname); @@ -1191,8 +1196,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } dointerrupt = B_TRUE; } - } else { - if (isplayer(lf) && areallies(lf, l)) { + } else if (isplayer(lf)) { + if (areallies(lf, l)) { // remember player's last known loc f = lfhasflag(l, F_PETOF); if (f) { @@ -1471,7 +1476,7 @@ int opendoor(lifeform_t *lf, object_t *o) { if (isplayer(lf)) { // has known trap? if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { - if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { + if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { char ch; sprintf(buf,"Really open %s?", obname); ch = askchar(buf,"yn","n", B_TRUE); @@ -1488,7 +1493,7 @@ int opendoor(lifeform_t *lf, object_t *o) { dir = getdirtowards(doorcell, lf->cell, NULL, B_FALSE, DT_ORTH); pastdoorcell = getcellindir(doorcell, dir); if (pastdoorcell && getcellwaterdepth(pastdoorcell, NULL)) { - if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { + if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { char ch; sprintf(buf,"Your hear running water behind %s. Really open it?", obname); ch = askchar(buf,"yn","n", B_TRUE); @@ -2024,7 +2029,6 @@ int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke) { addob(lf->cell->obpile, "cloud of smoke"); } movelf(lf, c); -// addob(lf->cell->obpile, "cloud of smoke"); if (cansee(player, lf)) { redraw(); // redraw screen @@ -2070,20 +2074,22 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { if (isplayer(lf) && !lfhasflag(lf, F_SNEAK)) { if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) { - char ques[BUFLEN]; - char ch; - if ((errcode == E_AVOIDOB) && rdata) { - char obname[BUFLEN]; - object_t *avoidob; - avoidob = (object_t *)rdata; - getobname(avoidob, obname, avoidob->amt); - sprintf(ques, "Really %s into %s?", getmoveverb(lf), obname); - } else { - sprintf(ques, "Really %s there?", getmoveverb(lf)); - } - ch = askchar(ques, "yn","n", B_TRUE); - if (ch != 'y') { - return B_TRUE; + if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { + char ques[BUFLEN]; + char ch; + if ((errcode == E_AVOIDOB) && rdata) { + char obname[BUFLEN]; + object_t *avoidob; + avoidob = (object_t *)rdata; + getobname(avoidob, obname, avoidob->amt); + sprintf(ques, "Really %s into %s?", getmoveverb(lf), obname); + } else { + sprintf(ques, "Really %s there?", getmoveverb(lf)); + } + ch = askchar(ques, "yn","n", B_TRUE); + if (ch != 'y') { + return B_TRUE; + } } } } diff --git a/move.h b/move.h index d78043f..aa4961a 100644 --- a/move.h +++ b/move.h @@ -8,12 +8,12 @@ int closedoorat(lifeform_t *lf, cell_t *c); int closedoor(lifeform_t *lf, object_t *o); int diropposite(int dir); int dorandommove(lifeform_t *lf, int badmovesok, int restonfail); -int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype); +int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype, int keepinlof); int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype); int getwalkoffdir(lifeform_t *lf, int dir); int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff); int makeorthogonal(int dir); -int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype); +int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof); int moveclear(lifeform_t *lf, int dir, enum ERROR *error); int moveeffects(lifeform_t *lf); int movelf(lifeform_t *lf, cell_t *newcell); diff --git a/nexus.c b/nexus.c index ca031c6..2798c36 100644 --- a/nexus.c +++ b/nexus.c @@ -44,6 +44,9 @@ int numnpcnames; extern vault_t *firstvault; +extern flag_t *retflag[]; +extern int nretflags; + glyph_t playerglyph,tempglyph; double startticks,lastticks; @@ -1434,7 +1437,8 @@ void timeeffectsworld(map_t *map) { timeleft += firstlftime; // now do effects based on time... while (timeleft >= TICK_INTERVAL) { - flag_t *f, *nextf; + flag_t *f; + int i; timeleft -= TICK_INTERVAL; @@ -1476,24 +1480,22 @@ void timeeffectsworld(map_t *map) { // now finish off water spread noredraw = B_TRUE; - for (f = map->flags->first ; f ; f = nextf) { - nextf = f->next; - if (f->id == F_NEWWATERDEPTH) { - cell_t *c; - c = getcellat(map, f->val[0], f->val[1]); - if (c) { - if (f->val[2] > DP_NONE) { - o = hasobwithflag(c->obpile, F_DEEPWATER); - if (!o) { - o = addob(c->obpile, "water"); - } + + getflags(map->flags, F_NEWWATERDEPTH, F_NONE); + for (i = 0; i < nretflags; i++) { + cell_t *c; + f = retflag[i]; + c = getcellat(map, f->val[0], f->val[1]); + if (c) { + if (f->val[2] > DP_NONE) { + o = hasobwithflag(c->obpile, F_DEEPWATER); + if (!o) { + o = addobfast(c->obpile, OT_WATERDEEP); } - - setwaterdepth(c, f->val[2]); } - killflag(f); - continue; + setwaterdepth(c, f->val[2]); } + killflag(f); } noredraw = B_FALSE; diff --git a/objects.c b/objects.c index f08bc6e..3369674 100644 --- a/objects.c +++ b/objects.c @@ -402,7 +402,11 @@ void addocnoun(objectclass_t *oc, char *text) { // create a new object, stacking ok object_t *addob(obpile_t *where, char *name) { - return addobject(where, name, B_TRUE, B_TRUE); + return addobject(where, name, B_TRUE, B_TRUE, OT_NONE); +} + +object_t *addobfast(obpile_t *where, enum OBTYPE oid) { + return addobject(where, NULL, B_TRUE, B_TRUE, oid); } // create a new object @@ -411,17 +415,17 @@ object_t *addob(obpile_t *where, char *name) { // object with o->amt set, instead of // creating new obejct entries. // NOTE: This function MUST return number of obs created via global "nretobs" -object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes) { +object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes, enum OBTYPE forceoid) { objecttype_t *ot; object_t *o = NULL; - char *p,*nsp,*p2; + char *p,*nsp; char numstringmin[BUFLEN]; char numstringmax[BUFLEN]; int howmany = 1; int i; int db = B_FALSE; flag_t *f; - char *localname; + char *localname = NULL; int wantblessed = B_UNCURSED; race_t *corpserace = NULL; int dorandombrand = B_FALSE; @@ -429,6 +433,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes brand_t *br; obmod_t *om; obmod_t *wantom[MAXOBMODS]; + int bonus = 0; int nom = 0; int n; int bookcontents = -1; @@ -450,312 +455,358 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes nadded = 0; nretobs = 0; - localname = strdup(name); - - // check for premods. eg. "flaming xxx" "frozen xxx" etc - for (om = firstobmod ; om ; om = om->next) { - if (db) dblog("DB: checking for '%s' in '%s'",om->prefix, localname); - if (strstr(localname, om->prefix)) { - localname = strrep(localname, om->prefix, "", NULL); - if (db) dblog("DB: found obmod prefix '%s'",om->prefix); - - wantom[nom] = om; - nom++; - } - } - - if (db) { - dblog("DB: called addobject() for %s, canstack = %d",localname, canstack); - } - if (where->owner && hasflag(where->owner->flags, F_NOPACK)) { if (db) dblog("error giving ob '%s' - owner isn't allowed to carry objects!", name); nretobs = 0; return NULL; } - // we CAN place objects in solid cells - for example, - // placing a fire on top of a wooden door. - /* - if (where->where) { - if (where->where->type != (celltype_t *)DUMMYCELLTYPE) { - assert(!where->where->type->solid); + if (forceoid != OT_NONE) { + ot = findot(forceoid); + howmany = 1; + if (db) { + dblog("DB: called addobject() for forceoid %s, canstack = %d",ot->name, canstack); } - } - */ + } else { + char *p2; + localname = strdup(name); - // parse name string - nsp = numstringmin; - for (p = localname ; isdigit(*p) ; p++) { - *nsp = *p; - nsp++; - } - *nsp = '\0'; + if (db) { + dblog("DB: called addobject() for %s, canstack = %d",localname, canstack); + } - // we have a range... - if (*p == '-') { - nsp = numstringmax; - p++; - for ( ; isdigit(*p) ; p++) { + // check for premods. eg. "flaming xxx" "frozen xxx" etc + for (om = firstobmod ; om ; om = om->next) { + if (db) dblog("DB: checking for '%s' in '%s'",om->prefix, localname); + if (strstr(localname, om->prefix)) { + localname = strrep(localname, om->prefix, "", NULL); + if (db) dblog("DB: found obmod prefix '%s'",om->prefix); + + wantom[nom] = om; + nom++; + } + } + + + // parse name string + nsp = numstringmin; + for (p = localname ; isdigit(*p) ; p++) { *nsp = *p; nsp++; } *nsp = '\0'; - } else { - strcpy(numstringmax,numstringmin); - } - - // are we giving multiple objects? - if (strlen(numstringmin) > 0) { - int min,max; - // first increment name string pointer - // past any spaces - while (!isalpha(*p)) p++; - - // now figure out how many - min = atoi(numstringmin); - max = atoi(numstringmax); - if (min == max) { - howmany = min; + // we have a range... + if (*p == '-') { + nsp = numstringmax; + p++; + for ( ; isdigit(*p) ; p++) { + *nsp = *p; + nsp++; + } + *nsp = '\0'; } else { - howmany = rnd(min,max); + strcpy(numstringmax,numstringmin); } - } else { - howmany = 1; - } + // "p" should now point at the start of the actual + // object name. - // handle prefixes. strip them off as we go. - donesomething = B_TRUE; - while (donesomething) { - int n; - donesomething = B_FALSE; + // are we giving multiple objects? + if (strlen(numstringmin) > 0) { + int min,max; + // first increment name string pointer + // past any spaces + while (!isalpha(*p)) p++; - // water flags - for (n = DP_MAX; n >= DP_FIRST; n--) { - char wpre[BUFLEN]; - sprintf(wpre, "%s ", getwaterdepthname(n)); - if (strstarts(p, wpre)) { - wantdepth = n; - p += strlen(wpre); - p++; // go past space - donesomething = B_TRUE; - break; + // now figure out how many + min = atoi(numstringmin); + max = atoi(numstringmax); + if (min == max) { + howmany = min; + } else { + howmany = rnd(min,max); } + } else { + howmany = 1; } - if (donesomething) continue; - if (strstarts(p, "blessed ")) { - if (db) dblog("DB: ob is blessed (%s)",p); - wantblessed = B_BLESSED; - p += strlen("blessed "); - donesomething = B_TRUE; - } else if (strstarts(p, "uncursed ")) { - if (db) dblog("DB: ob is uncursed (%s)",p); - wantblessed = B_UNCURSED; - p += strlen("uncursed "); - donesomething = B_TRUE; - } else if (strstarts(p, "cursed ")) { - if (db) dblog("DB: ob is cursed (%s)",p); - wantblessed = B_CURSED; - p += strlen("cursed "); - donesomething = B_TRUE; - // door flags - } else if (strstarts(p, "locked ")) { - doorflag[ndoorflags++] = F_LOCKED; - p += strlen("locked "); - donesomething = B_TRUE; - } else if (strstarts(p, "jammed ")) { - doorflag[ndoorflags++] = F_JAMMED; - p += strlen("jammed "); - donesomething = B_TRUE; - } else if (strstarts(p, "secret ")) { - doorflag[ndoorflags++] = F_SECRET; - p += strlen("secret "); - donesomething = B_TRUE; - // tool flags - } else if (strstarts(p, "lit ")) { - wantlit = B_TRUE; - p += strlen("lit "); - donesomething = B_TRUE; - // rarity - } else if (strstarts(p, "common ")) { - wantrarity = RR_COMMON; - p += strlen("common "); - donesomething = B_TRUE; - } else if (strstarts(p, "uncommon ")) { - wantrarity = RR_UNCOMMON; - p += strlen("uncommon "); - donesomething = B_TRUE; - } else if (strstarts(p, "rare ")) { - wantrarity = RR_RARE; - p += strlen("rare "); - donesomething = B_TRUE; - } else if (strstarts(p, "very rare ")) { - wantrarity = RR_VERYRARE; - p += strlen("very rare "); - donesomething = B_TRUE; - // weapon "goodness" - } else if (strstarts(p, "average ")) { - wantgoodness = G_AVERAGE; - p += strlen("average "); - donesomething = B_TRUE; - } else if (strstarts(p, "good ")) { - wantgoodness = G_GOOD; - if (onein(4)) wantblessed = B_BLESSED; - p += strlen("good "); - donesomething = B_TRUE; - } else if (strstarts(p, "great ")) { - wantgoodness = G_GREAT; - if (onein(3)) wantblessed = B_BLESSED; - if (onein(10)) dorandombrand = B_TRUE; - p += strlen("great "); - donesomething = B_TRUE; - } else if (strstarts(p, "excellent ")) { - wantgoodness = G_EXCELLENT; - if (onein(2)) wantblessed = B_BLESSED; - if (onein(4)) dorandombrand = B_TRUE; - p += strlen("excellent "); - donesomething = B_TRUE; - // brands - } else if (strstarts(p, "branded ")) { - dorandombrand = B_TRUE; - p += strlen("branded "); - donesomething = B_TRUE; - } else if (strstarts(p, "trapped ")) { - trapchance = 100; - p += strlen("trapped "); - donesomething = B_TRUE; - } - } - - if (strstr(p, "holy water") || strstr(p, "incompetence")) { - if (db) dblog("DB: ob is blessed (%s)",p); - wantblessed = B_BLESSED; - } - - //////////////////////////////////// - // handle special object names - //////////////////////////////////// - if (strstr(p, "corpse")) { - int len; - char racename[BUFLEN]; - p2 = strstr(p, "corpse"); - len = p2 - p; - snprintf(racename, len, "%s",p); - - corpserace = findracebyname(racename); - ot = findot(OT_CORPSE); - } else if (strstr(p, "statue of ")) { - char racename[BUFLEN]; - - // go to end - p2 = strstr(p, "statue of "); - p2 += 10; // now on either 'a' or 'an' - p2++; // now on either ' ' or 'n' - for (;*p2 != ' ';p2++); - p2++; - // now at start of name - sprintf(racename, "%s",p2); - - corpserace = findracebyname(racename); - ot = findot(OT_STATUE); - } else if (strstr(p, " head")) { - int len; - char racename[BUFLEN]; - p2 = strstr(p, " head"); - len = p2 - p + 1; - snprintf(racename, len, "%s",p); - - corpserace = findracebyname(racename); - ot = findot(OT_HEAD); - } else if (strstarts(p, "sign ")) { - char *pp; - pp = strchr(p, '\"'); - if (pp) { - char sbuf[BUFLEN]; - char *sbp; - sbp = sbuf; - pp++; - - while (*pp && (*pp != '\"')) { - *sbp = *pp; - sbp++; - pp++; + bonus = 0; + // handle for bonuses. eg. "+1" + p2 = strchr(p, '+'); + if (p2) { + char *p3; + char numbuf[BUFLENSMALL]; + p3 = numbuf; + p++; + while (isdigit(*p2)) { + *p3 = *p2; + p2++; + p3++; } - *sbp = '\0'; - signtext = strdup(sbuf); + *p3 = '\0'; + bonus += atoi(numbuf); } - ot = findot(OT_SIGN); - } else if (strstr(p, "spellbook of ")) { - char *pp; - pp = p + 13; - if (*pp) { - objecttype_t *spelltype = NULL; - spelltype = findspelln(pp); - if (spelltype) { - bookcontents = spelltype->id; + // check for penalties. eg. "-1" + p2 = strchr(p, '-'); + if (p2) { + char *p3; + char numbuf[BUFLENSMALL]; + p3 = numbuf; + p2++; + while (isdigit(*p2)) { + *p3 = *p2; + p2++; + p3++; } + *p3 = '\0'; + bonus -= atoi(numbuf); } - ot = findot(OT_SPELLBOOK); - } else if (strstr(p, "manual of ")) { - char *pp; - pp = p + 10; - if (*pp) { - skill_t *sk; - sk = findskillbyname(pp); - if (sk) { - bookcontents = sk->id; - } - } - ot = findot(OT_MANUAL); - //////////////////////////////////// - // also handle generic names - //////////////////////////////////// - } else { - objectclass_t *oc; - char tempname[BUFLEN]; - int found = B_FALSE; - // check for things like "weapon" or "random ring" - for (oc = objectclass; oc ; oc = oc->next) { - int i; - int matched = B_FALSE; - for (i = 0; i < oc->nnouns; i++) { - sprintf(tempname, "random %s", oc->noun[i]); - if (strstarts(p, tempname) || streq(p, oc->noun[i])) { - matched = B_TRUE; - } + // handle prefixes. strip them off as we go. + donesomething = B_TRUE; + while (donesomething) { + int n; + donesomething = B_FALSE; - if (matched) { - int minrarity,maxrarity; - // want a specific rarity? - rrtorarity(wantrarity, &minrarity, &maxrarity); - - ot = getrandomobofclass(oc->id, minrarity, maxrarity); - if (ot) { - found = B_TRUE; - break; - } + // water flags + for (n = DP_MAX; n >= DP_FIRST; n--) { + char wpre[BUFLEN]; + sprintf(wpre, "%s ", getwaterdepthname(n)); + if (strstarts(p, wpre)) { + wantdepth = n; + p += strlen(wpre); + p++; // go past space + donesomething = B_TRUE; + break; } } - if (found) break; - } + if (donesomething) continue; - if (!found) { - // look up the object name - if (db) dblog("DB: Looking for object name '%s'", p ); - ot = findotn(p); - if (!ot) { - //if (gamestarted) msg("DB: No match for object name '%s'", p ); - if (db) dblog("DB: No match for object name '%s'", p ); - nretobs = 0; - return NULL; + if (strstarts(p, "blessed ")) { + if (db) dblog("DB: ob is blessed (%s)",p); + wantblessed = B_BLESSED; + p += strlen("blessed "); + donesomething = B_TRUE; + } else if (strstarts(p, "uncursed ")) { + if (db) dblog("DB: ob is uncursed (%s)",p); + wantblessed = B_UNCURSED; + p += strlen("uncursed "); + donesomething = B_TRUE; + } else if (strstarts(p, "cursed ")) { + if (db) dblog("DB: ob is cursed (%s)",p); + wantblessed = B_CURSED; + p += strlen("cursed "); + donesomething = B_TRUE; + // door flags + } else if (strstarts(p, "locked ")) { + doorflag[ndoorflags++] = F_LOCKED; + p += strlen("locked "); + donesomething = B_TRUE; + } else if (strstarts(p, "jammed ")) { + doorflag[ndoorflags++] = F_JAMMED; + p += strlen("jammed "); + donesomething = B_TRUE; + } else if (strstarts(p, "secret ")) { + doorflag[ndoorflags++] = F_SECRET; + p += strlen("secret "); + donesomething = B_TRUE; + // tool flags + } else if (strstarts(p, "lit ")) { + wantlit = B_TRUE; + p += strlen("lit "); + donesomething = B_TRUE; + // rarity + } else if (strstarts(p, "common ")) { + wantrarity = RR_COMMON; + p += strlen("common "); + donesomething = B_TRUE; + } else if (strstarts(p, "uncommon ")) { + wantrarity = RR_UNCOMMON; + p += strlen("uncommon "); + donesomething = B_TRUE; + } else if (strstarts(p, "rare ")) { + wantrarity = RR_RARE; + p += strlen("rare "); + donesomething = B_TRUE; + } else if (strstarts(p, "very rare ")) { + wantrarity = RR_VERYRARE; + p += strlen("very rare "); + donesomething = B_TRUE; + // weapon "goodness" + } else if (strstarts(p, "average ")) { + wantgoodness = G_AVERAGE; + p += strlen("average "); + donesomething = B_TRUE; + } else if (strstarts(p, "good ")) { + wantgoodness = G_GOOD; + if (onein(4)) wantblessed = B_BLESSED; + p += strlen("good "); + donesomething = B_TRUE; + } else if (strstarts(p, "great ")) { + wantgoodness = G_GREAT; + if (onein(3)) wantblessed = B_BLESSED; + if (onein(10)) dorandombrand = B_TRUE; + p += strlen("great "); + donesomething = B_TRUE; + } else if (strstarts(p, "excellent ")) { + wantgoodness = G_EXCELLENT; + if (onein(2)) wantblessed = B_BLESSED; + if (onein(4)) dorandombrand = B_TRUE; + p += strlen("excellent "); + donesomething = B_TRUE; + // brands + } else if (strstarts(p, "branded ")) { + dorandombrand = B_TRUE; + p += strlen("branded "); + donesomething = B_TRUE; + } else if (strstarts(p, "trapped ")) { + trapchance = 100; + p += strlen("trapped "); + donesomething = B_TRUE; } } - } - if (db) dblog("DB: FOUND: ot->name = '%s'", ot->name ); + + if (strstr(p, "holy water") || strstr(p, "incompetence")) { + if (db) dblog("DB: ob is blessed (%s)",p); + wantblessed = B_BLESSED; + } + + //////////////////////////////////// + // handle special object names + //////////////////////////////////// + if (strstr(p, "corpse")) { + int len; + char racename[BUFLEN]; + p2 = strstr(p, "corpse"); + len = p2 - p; + snprintf(racename, len, "%s",p); + + corpserace = findracebyname(racename); + ot = findot(OT_CORPSE); + } else if (strstr(p, "statue of ")) { + char racename[BUFLEN]; + + // go to end + p2 = strstr(p, "statue of "); + p2 += 10; // now on either 'a' or 'an' + p2++; // now on either ' ' or 'n' + for (;*p2 != ' ';p2++); + p2++; + // now at start of name + sprintf(racename, "%s",p2); + + corpserace = findracebyname(racename); + ot = findot(OT_STATUE); + } else if (strstr(p, " head")) { + int len; + char racename[BUFLEN]; + p2 = strstr(p, " head"); + len = p2 - p + 1; + snprintf(racename, len, "%s",p); + + corpserace = findracebyname(racename); + ot = findot(OT_HEAD); + } else if (strstarts(p, "sign ")) { + char *pp; + pp = strchr(p, '\"'); + if (pp) { + char sbuf[BUFLEN]; + char *sbp; + sbp = sbuf; + pp++; + + while (*pp && (*pp != '\"')) { + *sbp = *pp; + sbp++; + pp++; + } + *sbp = '\0'; + signtext = strdup(sbuf); + } + ot = findot(OT_SIGN); + } else if (strstr(p, "spellbook of ")) { + char *pp; + pp = p + 13; + if (*pp) { + objecttype_t *spelltype = NULL; + spelltype = findspelln(pp); + if (spelltype) { + bookcontents = spelltype->id; + } + } + ot = findot(OT_SPELLBOOK); + } else if (strstr(p, "manual of ")) { + char *pp; + pp = p + 10; + if (*pp) { + skill_t *sk; + sk = findskillbyname(pp); + if (sk) { + bookcontents = sk->id; + } + } + ot = findot(OT_MANUAL); + //////////////////////////////////// + // also handle generic names + //////////////////////////////////// + } else { + objectclass_t *oc; + char tempname[BUFLEN]; + int found = B_FALSE; + + // check for things like "weapon" or "random ring" + for (oc = objectclass; oc ; oc = oc->next) { + int i; + int matched = B_FALSE; + for (i = 0; i < oc->nnouns; i++) { + sprintf(tempname, "random %s", oc->noun[i]); + if (strstarts(p, tempname) || streq(p, oc->noun[i])) { + matched = B_TRUE; + } + + if (matched) { + int minrarity,maxrarity; + // want a specific rarity? + rrtorarity(wantrarity, &minrarity, &maxrarity); + + ot = getrandomobofclass(oc->id, minrarity, maxrarity); + if (ot) { + found = B_TRUE; + break; + } + } + } + if (found) break; + } + + if (!found) { + // look up the object name + if (db) dblog("DB: Looking for object name '%s'", p ); + ot = findotn(p); + if (!ot) { + //if (gamestarted) msg("DB: No match for object name '%s'", p ); + if (db) dblog("DB: No match for object name '%s'", p ); + nretobs = 0; + return NULL; + } + } + } + if (db) dblog("DB: FOUND: ot->name = '%s'", ot->name ); + + // check for specific brands. eg. "xxx of pyromania" + // NOTE: this will override any random brands from "branded" + for (br = firstbrand ; br ; br = br->next) { + if (strstr(localname, br->suffix)) { + // does this brand apply to this objecttype? + if (brandappliesto(br, ot)) { + wantbrand = br; + break; + } + } + } + } // end if forceoid given + //////////////////////////////////// // we now have the objecttype! @@ -1082,9 +1133,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes // other special changes we need to make based on what was // asked for if ((gamemode != GM_LOADING) && o) { - char *p2; - int bonus = 0; - // corpses - fill in details if (o->type->id == OT_CORPSE) { flag_t *rf, *cf; @@ -1325,44 +1373,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } } - - // check for bonuses. eg. "+1" - p2 = strchr(p, '+'); - if (p2) { - char *p3; - char numbuf[BUFLENSMALL]; - p3 = numbuf; - - p2++; - - while (isdigit(*p2)) { - *p3 = *p2; - p2++; - p3++; - } - *p3 = '\0'; - - bonus += atoi(numbuf); - } - // check for penalties. eg. "-1" - p2 = strchr(p, '-'); - if (p2) { - char *p3; - char numbuf[BUFLENSMALL]; - p3 = numbuf; - - p2++; - - while (isdigit(*p2)) { - *p3 = *p2; - p2++; - p3++; - } - *p3 = '\0'; - - bonus -= atoi(numbuf); - } - // if no bonus yet, get one based on 'wantgoodness' if (!bonus) { switch (wantgoodness) { @@ -1387,11 +1397,9 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } } - if (bonus) { - if (hasflag(o->flags, F_ENCHANTABLE)) { - // for swords, armour etc - addflag_real(o->flags, F_BONUS, bonus, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); - } + if (bonus && hasflag(o->flags, F_ENCHANTABLE)) { + // for swords, armour etc + addflag_real(o->flags, F_BONUS, bonus, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); } // special rings which get randomized... @@ -1431,24 +1439,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } // now apply a random brand if we wanted one - if (dorandombrand) { + if (!wantbrand && dorandombrand) { wantbrand = getrandombrandfor(ot); } } - // check for specific brands. eg. "xxx of pyromania" - // NOTE: this will override any random brands from "branded" - for (br = firstbrand ; br ; br = br->next) { - if (strstr(name, br->suffix)) { - // does this brand apply to this objecttype? - if (brandappliesto(br, o->type)) { - wantbrand = br; - break; - } - } - } - + // apply the brand if (wantbrand) { if (brandappliesto(wantbrand, o->type)) { copyflags(o->flags, wantbrand->flags, FROMBRAND); @@ -1456,43 +1453,12 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } } - if (where->owner) { // new owner gains "hold confer" flags conferred by this object giveobflags(where->owner, o, F_HOLDCONFER); } // special cases - /* - if (o->type->id == OT_VENDINGMACHINE) { - char buf[BUFLEN]; - cell_t *loc; - loc = getoblocation(o); - // populate with objects - for (i = 0; i < 10; i++) { - objecttype_t *ot2; - strcpy(buf, ""); - while (!strcmp(buf, "")) { - real_getrandomob(loc->map, buf, RO_NONE, NA, loc->map->depth + rnd(10,15), NA, getobsize(o)-1); - // replace "1 potion" with "a potion" - if (strstr(buf, "1 ") == buf) { - char temp[BUFLEN]; - strcpy(temp, buf); - sprintf(buf, "a %s",temp + 2); - } - // make sure you can hold it - ot2 = findotn(buf); - if (!ot2 || - hasflag(ot2->flags, F_NOPICKUP) || - hasflag(ot2->flags, F_IMPASSABLE) ) { - strcpy(buf, ""); - } - } - - addflag(o->flags, F_CONTAINSOB, 'a' + i, NA, NA, buf); - } - } - */ // ie. don't do these things when just creating objects // for validation purposes @@ -1540,7 +1506,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } // end foreach added object // don't need the name anymore. - free(localname); + if (localname) free(localname); // populate retobs for (i = 0; i < nadded; i++) { @@ -3089,12 +3055,11 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder) { } int getobbonus(object_t *o) { - flag_t *f; - int bonus = 0; - for (f = o->flags->first ; f ; f = f->next) { - if (f->id == F_BONUS) { - bonus += f->val[0]; - } + int bonus = 0,i; + + getflags(o->flags, F_BONUS, F_NONE); + for (i = 0; i < nretflags; i++) { + bonus += retflag[i]->val[0]; } return bonus; } @@ -3153,7 +3118,7 @@ int getobspellpower(object_t *o, lifeform_t *lf) { int getobvalue(object_t *o) { float price; flag_t *f; - int rarity = 0; + int rarity = 0,i; enum RARITY rr = RR_COMMON; if (o->type->id == OT_GOLD) { @@ -3170,7 +3135,9 @@ int getobvalue(object_t *o) { price += f->val[0]; } - for (f = o->flags->first ; f ; f = f->next) { + getflags(o->flags, F_ARMOURRATING, F_BONUS, F_DAM, F_EDIBLE, F_LINKSPELL, F_MANUALOF, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; // damage if (f->id == F_DAM) { int min,max; @@ -3226,7 +3193,7 @@ int getobvalue(object_t *o) { } else if (o->type->obclass->id == OC_TECH) { // tech value is based on tech level & rarity float multiplier = 1; - switch (gettechlevel(o)) { + switch (gettechlevel(o->type->id)) { case PR_INEPT: multiplier = 3.25; break; @@ -3392,7 +3359,7 @@ object_t *getrandomammo(lifeform_t *lf) { object_t *gun; object_t *o; flag_t *f; - + int i; gun = getfirearm(lf); if (!gun) { return NULL; @@ -3401,12 +3368,13 @@ object_t *getrandomammo(lifeform_t *lf) { // possible ammo. Need to allow the player to // pick a specific ammo to use. USe a flag on wep // to do this? Or a flag on the player? - for (f = gun->flags->first ; f ; f = f->next) { - if (f->id == F_AMMOOB) { - for (o = lf->pack->first ; o ; o = o->next) { - if (o->type->id == f->val[0]) { - return o; - } + + getflags(gun->flags, F_AMMOOB, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + for (o = lf->pack->first ; o ; o = o->next) { + if (o->type->id == f->val[0]) { + return o; } } } @@ -4427,8 +4395,11 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan int ok = B_TRUE; // are all of the brand flags known? for (brf = br->flags->first ; brf ; brf = brf->next) { - for (f = o->flags->first; f ; f = f->next) { - if ((f->id == brf->id) && (f->lifetime == FROMBRAND)) { + int i; + getflags(o->flags, brf->id, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->lifetime == FROMBRAND) { if (f->known || showall) { } else { ok = B_FALSE; @@ -4438,7 +4409,6 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } } } - if (ok) { strcat(localbuf, br->suffix); } @@ -5115,12 +5085,17 @@ float getshopprice(object_t *o, lifeform_t *buyer) { return val; } -enum SKILLLEVEL gettechlevel(object_t *o) { +enum SKILLLEVEL gettechlevel(enum OBTYPE oid) { flag_t *f; + objecttype_t *ot; enum SKILLLEVEL tlev = PR_INEPT; - f = hasflag(o->flags, F_TECHLEVEL); - if (f) { - tlev = f->val[0]; + ot = findot(oid); + + if (ot) { + f = hasflag(ot->flags, F_TECHLEVEL); + if (f) { + tlev = f->val[0]; + } } return tlev; } @@ -6577,6 +6552,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_SMITEGOOD, "smite good", "Instantly deals 1-^bpower*2^n damage to good creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l3 addot(OT_S_POISONBOLT, "poison bolt", "Fires a glob of venom at the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); @@ -6968,12 +6949,6 @@ void initobjects(void) { addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); - addot(OT_S_CUREPOISON, "cure poison", "Cures the target of all poisons.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); - addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); - addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_HAILSTORM, "hail storm", "Creates an intense storm of hail, causing damage to all within.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); @@ -7058,7 +7033,7 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// - // life / clearic spells + // life / cleric spells /////////////////// // l1 addot(OT_S_HEALINGMIN, "minor healing", "Restores 1-8 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); @@ -7075,6 +7050,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addot(OT_S_SMITEEVIL, "smite evil", "Instantly deals 1-^bpower*2^n damage to evil creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 10, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l3 addot(OT_S_HEALING, "healing", "Restores 10-20 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); @@ -7082,6 +7063,20 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_HOLYAURA, "holy aura", "Surrounds the target with a holy aura, causing their weapon to deal holy damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + // l4 + addot(OT_S_CUREPOISON, "cure poison", "Cures the target of all poisons.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // mental/psionic /////////////////// @@ -7165,6 +7160,7 @@ void initobjects(void) { addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_LIGHT, "light area", "Creates a temporary light source centred on the caster.\nAt Power III, you can control where the light appears.\nAt Power VIII, the light becomes permenant.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); @@ -7511,6 +7507,10 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_POLYMORPH, NA, NA, NULL); addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addot(OT_WAND_TURNUNDEAD, "wand of turn undead", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 72, RR_RARE, NULL); + addflag(lastot->flags, F_LINKSPELL, OT_S_TURNUNDEAD, NA, NA, NULL); + addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, NULL); // tools - unique addot(OT_ORBDUNGEONEXIT, "dungeon exit orb", "When operated, this magical key will disable the barriers around the dungeon exit stairs.", MT_STONE, 2, OC_TOOLS, SZ_SMALL); @@ -10303,22 +10303,23 @@ void makeknown(enum OBTYPE otid) { // // keep a list of objects and flags here, then give them afterwards. for (o = player->pack->first ; o ; o = o->next) { - if (o->type->id == otid) { - if (!isknown(o)) { - for (f = o->flags->first ; f ; f = f->next) { - if ((f->id == F_HOLDCONFER) && (f->val[2] == IFKNOWN)) { - srcob[nobs] = o; - fttogive[nobs] = F_HOLDCONFER; - nobs++; - } else if ((f->id == F_EQUIPCONFER) && (f->val[2] == IFKNOWN) && isequipped(o)) { - srcob[nobs] = o; - fttogive[nobs] = F_EQUIPCONFER; - nobs++; - } else if ((f->id == F_ACTIVATECONFER) && (f->val[2] == IFKNOWN) && isactivated(o)) { - srcob[nobs] = o; - fttogive[nobs] = F_ACTIVATECONFER; - nobs++; - } + if ((o->type->id == otid) && !isknown(o)) { + getflags(o->flags, F_ACTIVATECONFER, F_EQUIPCONFER, F_HOLDCONFER, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + + if ((f->id == F_HOLDCONFER) && (f->val[2] == IFKNOWN)) { + srcob[nobs] = o; + fttogive[nobs] = F_HOLDCONFER; + nobs++; + } else if ((f->id == F_EQUIPCONFER) && (f->val[2] == IFKNOWN) && isequipped(o)) { + srcob[nobs] = o; + fttogive[nobs] = F_EQUIPCONFER; + nobs++; + } else if ((f->id == F_ACTIVATECONFER) && (f->val[2] == IFKNOWN) && isactivated(o)) { + srcob[nobs] = o; + fttogive[nobs] = F_ACTIVATECONFER; + nobs++; } } } @@ -11072,7 +11073,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { return B_TRUE; } - if (gettechlevel(o) > getskill(lf, SK_TECHUSAGE)) { + if (gettechlevel(o->type->id) > getskill(lf, SK_TECHUSAGE)) { if (isplayer(lf)) { msg("This technology is beyond your understanding."); } @@ -11082,7 +11083,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { // has known trap? if (isplayer(lf)) { if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { - if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { + if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { char ch; sprintf(buf,"Really operate %s?", obname); ch = askchar(buf,"yn","n", B_TRUE); @@ -11999,15 +12000,25 @@ int pour(lifeform_t *lf, object_t *o) { blessob(dst); // we now know that this is holy water if (!isknown(o)) makeknown(o->type->id); + // god effects + if (isplayer(lf)) { + pleasegodmaybe(R_GODPURITY, 3); + angergodmaybe(R_GODDEATH, 15); + } } else if ((o->type->id == OT_POT_WATER) && (o->blessed == B_CURSED)) { // unholy water if (isplayer(lf)) { msg("You pour %s onto %s.", obname,dstname); } o->blessknown = B_TRUE; - // bless whatever we poured onto + // curse whatever we poured onto curseob(dst); // we now know that this is holy water if (!isknown(o)) makeknown(o->type->id); + // god effects + if (isplayer(lf)) { + pleasegodmaybe(R_GODDEATH, 3); + angergodmaybe(R_GODPURITY, 25); + } } else if (o->type->id == OT_POT_INVULN) { flag_t *f; f = hasflag(dst->flags, F_DAMAGABLE); @@ -12770,9 +12781,11 @@ int readsomething(lifeform_t *lf, object_t *o) { // only id if it does something willid = B_FALSE; } - case OT_SCR_ENCHANT: // only id if it does something - case OT_SCR_CREATEMONSTER: // only id if it does something - case OT_SCR_REMOVECURSE: // only id if it does something + case OT_SCR_ENCHANT: + case OT_SCR_CREATEMONSTER: + case OT_SCR_REMOVECURSE: + case OT_SCR_DETECTAURA: + // only id if it does something willid = B_FALSE; break; default: @@ -13128,7 +13141,6 @@ int readsomething(lifeform_t *lf, object_t *o) { } object_t *relinkob(object_t *src, obpile_t *dst) { - flag_t *f,*nextf; if (!obfits(src, dst)) return NULL; if (src->pile->owner) { @@ -13137,12 +13149,7 @@ object_t *relinkob(object_t *src, obpile_t *dst) { } // unweild - for (f = src->flags->first ; f ; f = nextf) { - nextf = f->next; - if (f->id == F_EQUIPPED) { - killflag(f); - } - } + killflagsofid(src->flags, F_EQUIPPED); // adjust letter... // gold should always have letter '$' @@ -13647,7 +13654,7 @@ object_t *splitob(object_t *o) { // doesn't matter if it goes down to zero, as we will put it back up soon. o->amt--; // give new object - newob = addobject(o->pile, o->type->name, B_NOSTACK, B_FALSE); + newob = addobject(o->pile, NULL, B_NOSTACK, B_FALSE, o->type->id); // restore count o->amt++; if (newob) { @@ -13964,16 +13971,28 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, int acc; int youhit = B_FALSE; int missiledam = 0; - object_t *newob; + object_t *newob = NULL; cell_t *newloc; int db = B_TRUE; int willcatch = B_FALSE; int announcedmiss = B_FALSE; int outofammo = B_FALSE; float multiplier; + obpile_t *op = NULL; reason = E_OK; + // giving away money + if (isplayer(thrower) && (o->type->id == OT_GOLD)) { + flag_t *f; + f = lfhasflag(thrower, F_GAVEMONEY); + if (f) { + f->val[0] += o->amt; + } else { + addflag(thrower->flags, F_GAVEMONEY, o->amt, NA, NA, NULL); + } + } + // you can't throw with as much force while swimming. if (isswimming(thrower) && !firearm) { speed /= 2; @@ -14378,6 +14397,15 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, int reduceamt = 0; int throwdam; + op = addobpile(NOOWNER, NOLOC, NULL); + + // split off new object into a fake obpile + // so we don't modify the original stack with + // things like poison rubbing off. + o = real_moveob(o, op, amt, B_FALSE); + o->birthtime = -1; + + throwdam = getthrowdam(o); dam = (int)((float)throwdam * multiplier); if (db) dblog("fireat(): dam = throwdam(%d) * speed(%d)/2 = %d",throwdam, speed, dam); @@ -14461,6 +14489,9 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // fake its birth time so that it can be damaged newob->birthtime = -1; + // now we can get rid of the fake obpile, if we used it + if (op) killobpile(op); + // gun out of ammo? if (firearm && !countobs(firearm->contents, B_FALSE)) { outofammo = B_TRUE; diff --git a/objects.h b/objects.h index d7c97b5..5cc7c72 100644 --- a/objects.h +++ b/objects.h @@ -10,7 +10,8 @@ material_t *addmaterial(enum MATERIAL id, char *name, float weightrating); objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph, int glyphcolour); void addocnoun(objectclass_t *oc, char *text); object_t *addob(obpile_t *where, char *name); -object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes); +object_t *addobfast(obpile_t *where, enum OBTYPE oid); +object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes, enum OBTYPE forceoid); int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf, enum LOFTYPE needlof); obmod_t *addobmod(enum OBMOD id, char *prefix); obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob); @@ -121,7 +122,7 @@ char *getschoolname(enum SPELLSCHOOL sch); char *getschoolnameshort(enum SPELLSCHOOL sch); int getshatterdam(object_t *o); float getshopprice(object_t *o, lifeform_t *buyer); -enum SKILLLEVEL gettechlevel(object_t *o); +enum SKILLLEVEL gettechlevel(enum OBTYPE oid); int getthrowdam(object_t *o); char *gettopobname(cell_t *c, char *retbuf); enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded); diff --git a/save.c b/save.c index 3e19b61..ac1db76 100644 --- a/save.c +++ b/save.c @@ -526,7 +526,7 @@ int loadob(FILE *f, obpile_t *op, long *id) { return B_TRUE; } // create the object - o = addobject(op, ot->name, B_NOSTACK, B_FALSE); // no stacking! + o = addobject(op, NULL, B_NOSTACK, B_FALSE, ot->id); // no stacking! // overwrite ob parameters o->id = obid; diff --git a/spell.c b/spell.c index 88dbc76..693fa04 100644 --- a/spell.c +++ b/spell.c @@ -240,9 +240,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef removeob(water,ALL); // give food if (getskill(user, SK_COOKING >= PR_EXPERT)) { - o = addob(user->pack, "jerky"); + o = addobfast(user->pack, OT_JERKY); } else { - o = addob(user->pack, "stew"); + o = addobfast(user->pack, OT_STEW); } if (o) { @@ -1547,6 +1547,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) { msg("There doesn't seem to be anything here which you could steal."); } + } else { + pleasegodmaybe(R_GODTHIEVES, 5); } } else { lifeform_t *shk; @@ -1908,19 +1910,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // destroy objects right away removedeadobs(caster->pack); - // handle cell under the caster - for (o = caster->cell->obpile->first ; o ; o = o->next) { - // destroy metal items on the ground - if (ismetal(o->material->id)) { - takedamage(o, 9999, DT_DIRECT); - if (hasflag(o->flags, F_DEAD)) { - totalmass += getobweight(o); - } - } - } - // destroy objects right away - removedeadobs(caster->cell->obpile); - for (i = 0; i < caster->nlos; i++) { targcell = caster->los[i]; for (o = targcell->obpile->first ; o ; o = o->next) { @@ -2034,16 +2023,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // animate corpses within lof of caster for (i = 0; i < target->nlos; i++) { targcell = target->los[i]; - for (o = targcell->obpile->first ; o ; o = nexto) { - nexto = o->next; - if (o->type->id == OT_CORPSE) { - lifeform_t *newlf; - newlf = makezombie(o); - if (newlf) { - if (isplayer(caster) && skillcheck(caster, A_IQ, 20, power)) { - makefriendly(newlf, PERMENANT); + if (targcell != target->cell) { + for (o = targcell->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (o->type->id == OT_CORPSE) { + lifeform_t *newlf; + newlf = makezombie(o); + if (newlf) { + if (isplayer(target) && skillcheck(target, A_IQ, 20, power)) { + makefriendly(newlf, PERMENANT); + } + donesomething = B_TRUE; } - donesomething = B_TRUE; } } } @@ -2437,7 +2428,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ powerleft = power; for (i = 0; i < caster->nlos; i++) { c = caster->los[i]; - if (c->lf && (c->lf->race->raceclass->id == RC_ANIMAL) && (gethitdice(c->lf) <= powerleft)) { + if (c->lf && (c->lf != caster) && (c->lf->race->raceclass->id == RC_ANIMAL) && (gethitdice(c->lf) <= powerleft)) { if (lfhasflag(c->lf, F_HOSTILE)) { powerleft -= gethitdice(c->lf); makepeaceful(c->lf); @@ -4173,70 +4164,82 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if ((spellid == OT_S_HEALINGMIN) && donesomething) { // minor healing will stop here - return B_FALSE; - } - - if (target->hp < target->maxhp) { - int min,max; - switch (spellid) { - case OT_S_HEALINGMIN: - default: - min = 1; max = 10; - break; - case OT_S_HEALING: - min = 10; max = 20; - break; - case OT_S_HEALINGMAJ: - min = 20; max = 30; - break; - } - gainhp(target, getspellduration(min,max,blessed) + (power*2)); - - if (isplayer(target)) { - if (target->hp >= target->maxhp) { - switch (spellid) { - case OT_S_HEALINGMIN: - msg("All of your scrapes and bruises are healed!"); - break; - case OT_S_HEALING: - default: - msg("Your wounds close themselves!"); - break; - case OT_S_HEALINGMAJ: - msg("Your injuries are healed!"); - break; - } - } else { - switch (spellid) { - case OT_S_HEALINGMIN: - msg("Some of your scrapes and bruises are healed!"); - break; - case OT_S_HEALING: - default: - msg("Some of your wounds close themselves!"); - break; - case OT_S_HEALINGMAJ: - msg("Your injuries are partially healed!"); - break; - } + } else { + if (target->hp < target->maxhp) { + int min,max; + switch (spellid) { + case OT_S_HEALINGMIN: + default: + min = 1; max = 10; + break; + case OT_S_HEALING: + min = 10; max = 20; + break; + case OT_S_HEALINGMAJ: + min = 20; max = 30; + break; } - if (seenbyplayer) *seenbyplayer = B_TRUE; - } else if (haslos(player, target->cell)) { - getlfname(target, buf); - msg("%s looks healthier!", buf); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } - donesomething = B_TRUE; - } + gainhp(target, getspellduration(min,max,blessed) + (power*2)); + + if (isplayer(target)) { + if (target->hp >= target->maxhp) { + switch (spellid) { + case OT_S_HEALINGMIN: + msg("All of your scrapes and bruises are healed!"); + break; + case OT_S_HEALING: + default: + msg("Your wounds close themselves!"); + break; + case OT_S_HEALINGMAJ: + msg("Your injuries are healed!"); + break; + } + } else { + switch (spellid) { + case OT_S_HEALINGMIN: + msg("Some of your scrapes and bruises are healed!"); + break; + case OT_S_HEALING: + default: + msg("Some of your wounds close themselves!"); + break; + case OT_S_HEALINGMAJ: + msg("Your injuries are partially healed!"); + break; + } + } + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (haslos(player, target->cell)) { + getlfname(target, buf); + msg("%s looks healthier!", buf); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + donesomething = B_TRUE; + } + } if (isplayer(target)) { if (!donesomething) { nothinghappens(); } } - if (donesomething && isplayer(caster) && !frompot) { - pleasegodmaybe(R_GODMERCY, 3); + if (donesomething && isplayer(caster)) { + if (!frompot) { + pleasegodmaybe(R_GODMERCY, 3); + } + angergodmaybe(R_GODDEATH, 20); } + // hostile monsters might calm down + if (!frompot && donesomething && isplayer(caster) && !isplayer(target) && (getallegiance(target) == AL_HOSTILE)) { + enum ATTRBRACKET iqb; + iqb = getattrbracket(getattr(target, A_IQ), A_IQ, NULL); + if ((iqb >= IQ_ANIMAL) && cansee(target, caster)) { + if (skillcheckvs(caster, SC_MORALE, 3, target, SC_MORALE, 0)) { + makepeaceful(target); + } + } + } } else if (spellid == OT_S_HOLDPORTAL) { object_t *o; if (!validatespellcell(caster, &targcell,TT_DOOR, spellid, power, frompot)) return B_TRUE; @@ -4279,6 +4282,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } } + } else if (spellid == OT_S_HOLYAURA) { + flag_t *f; + if (!target) target = caster; + + f = addtempflag(target->flags, F_HOLYAURA, B_TRUE, NA, NA, NULL, FROMSPELL); + f->obfrom = spellid; + f = addtempflag(target->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL, FROMSPELL); + f->obfrom = spellid; } else if (spellid == OT_S_ICEEDGE) { object_t *wep; enum DAMTYPE dt; @@ -4343,7 +4354,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // knock lfs away if (targcell->lf) { - knockback(targcell->lf, getdiraway(targcell, targcell, NULL, B_FALSE, DT_COMPASS), 1, NULL, 25+power); + knockback(targcell->lf, getdiraway(targcell, targcell, NULL, B_FALSE, DT_COMPASS, B_FALSE), 1, NULL, 25+power); donesomething = B_TRUE; } @@ -4554,19 +4565,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // destroy objects right away removedeadobs(caster->pack); - // handle cell under the caster - for (o = caster->cell->obpile->first ; o ; o = o->next) { - // destroy metal items on the ground - if (ismetal(o->material->id)) { - takedamage(o, 9999, DT_DIRECT); - if (hasflag(o->flags, F_DEAD)) { - totalmass += getobweight(o); - } - } - } - // destroy objects right away - removedeadobs(caster->cell->obpile); - for (i = 0; i < caster->nlos; i++) { targcell = caster->los[i]; for (o = targcell->obpile->first ; o ; o = o->next) { @@ -5258,10 +5256,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } - if (!donesomething) { + if (donesomething) { + if (isplayer(caster)) pleasegodmaybe(R_GODTHIEVES, 5); + } else { fizzle(caster); } + } } else if (spellid == OT_S_LEVITATION) { flag_t *f; @@ -5376,9 +5377,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int i; for (i = 0; i < caster->nlos; i++) { - target = caster->los[i]->lf; - if (target && areenemies(caster, target)) { - poss[nposs++] = target; + if (caster->los[i] != caster->cell) { + target = caster->los[i]->lf; + if (target && areenemies(caster, target)) { + poss[nposs++] = target; + } } } @@ -6259,6 +6262,29 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(target) || haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } + } else if ((spellid == OT_S_SMITEEVIL) || (spellid == OT_S_SMITEGOOD)) { + enum ALIGNMENT wantalign; + if (spellid == OT_S_SMITEEVIL) { + wantalign = AL_EVIL; + } else { + wantalign = AL_GOOD; + } + if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power, frompot)) return B_TRUE; + target = targcell->lf; + if (!target || (getalignment(target) != wantalign)) { + fizzle(caster); + return B_TRUE; + } + if (isplayer(target)) { + msg("The power of %s smites you!", (spellid == OT_S_SMITEEVIL) ? "good" : "evil"); + } else if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("The power of %s smites %s!", (spellid == OT_S_SMITEEVIL) ? "good" : "evil", lfname); + } + // use direct damage rather than holy, because otherwise it might be increased + // due to vulnerabilities + losehp(target, rnd(1,power*2), DT_DIRECT, caster, "a smiting"); } else if (spellid == OT_S_SOFTENEARTH) { int seen = B_FALSE; int ndone = 0; @@ -6433,7 +6459,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ poss[0] = caster->cell; nposs = 1; for (i = 0; i < caster->nlos; i++) { - poss[nposs++] = caster->los[i]; + if (caster->los[i] != caster->cell) { + poss[nposs++] = caster->los[i]; + } } // for each cell we can see... for (i = 0; i < caster->nlos; i++) { @@ -6875,11 +6903,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_THORNS) { flag_t *f; - // always targetted at caster - targcell = caster->cell; - target = caster; + if (!target) target = caster; - f = addtempflag(caster->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp thorns", FROMSPELL); + f = addtempflag(target->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp thorns", FROMSPELL); f->obfrom = spellid; } else if (spellid == OT_S_TRUESTRIKE) { if (!validatespellcell(caster, &targcell, TT_PLAYER, spellid, power, frompot)) return B_TRUE; @@ -6891,11 +6917,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ addflag(caster->flags, F_TRUESTRIKE, power, NA, NA, NULL); } else if (spellid == OT_S_TURNUNDEAD) { int i; - // works on all undead in sight + lifeform_t *lf; + if (!target) { + target = caster; + } + // works on all undead in _target's_ sight for (i = 0; i < caster->nlos; i++) { targcell = caster->los[i]; - target = targcell->lf; - if (target && isundead(target)) { + lf = targcell->lf; + if (lf && (lf != caster) && isundead(lf)) { int howlong = 10; int worked = B_TRUE; // TODO: does it work? depends on caster level & intelligence & power @@ -6904,7 +6934,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ howlong = rnd(10,20); if (worked) { // don't use scare() since it will fail due to them being undead. - addtempflag(target->flags, F_FLEEFROM, caster->id, NA, NA, NULL,howlong); + addtempflag(lf->flags, F_FLEEFROM, target->id, NA, NA, NULL,howlong); } } } @@ -6952,7 +6982,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ wantsize = SZ_ANY; break; } - ngot = summonlfs(caster, caster->cell, wantrc, wantsize, nwant, lifetime); + ngot = summonlfs(caster, caster->cell, wantrc, wantsize, AL_NONE, nwant, lifetime); if (!ngot) { fizzle(caster); return B_TRUE; @@ -7059,7 +7089,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // knock lfs away if (c->lf) { - knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS), 1, NULL, 30+power); + knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 1, NULL, 30+power); donesomething = B_TRUE; } } @@ -7075,7 +7105,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // knock lfs away if (c->lf) { - knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS), 1, NULL, 30+power); + knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 1, NULL, 30+power); donesomething = B_TRUE; } } @@ -7091,7 +7121,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // knock lfs away if (c->lf) { - knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS), 1, NULL, 30+power); + knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 1, NULL, 30+power); donesomething = B_TRUE; } } @@ -7107,7 +7137,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // knock lfs away if (c->lf) { - knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS), 1, NULL, 30+power); + knockback(c->lf, getdiraway(c, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 1, NULL, 30+power); donesomething = B_TRUE; } } @@ -8360,7 +8390,7 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) { // returns # created -int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime) { +int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, enum ALIGNMENT wantalign, int howmany, int lifetime) { lifeform_t *newlf; race_t *r = NULL; enum RACE poss[MAXCANDIDATES]; @@ -8371,16 +8401,24 @@ int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFS // determine possible types of race for (r = firstrace ; r; r = r->next) { - int ok = B_FALSE; - if ((wantrc == RC_ANY) || (r->raceclass->id == wantrc)) { + int ok = B_TRUE; + if ((wantrc != RC_ANY) && (r->raceclass->id != wantrc)) { + ok = B_FALSE; + } + + if (wantsize != SZ_ANY) { flag_t *f; - if (wantsize == SZ_ANY) { - ok = B_TRUE; - } else { - f = hasflag(r->flags, F_SIZE); - if (f && (f->val[0] == wantsize)) { - ok = B_TRUE; - } + f = hasflag(r->flags, F_SIZE); + if (f && (f->val[0] != wantsize)) { + ok = B_FALSE; + } + } + + if (wantalign != AL_NONE) { + flag_t *f; + f = hasflag(r->flags, F_ALIGNMENT); + if (f && (f->val[0] != wantalign)) { + ok = B_FALSE; } } if (ok) { @@ -8538,7 +8576,7 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e if (!frompot && where && where->lf && haslos(caster, where) && isplayer(caster) && areallies(caster, where->lf)) { // warn before targetting yourself! - if (getattrbracket(getattr(caster, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { + if (getattrbracket(getattr(caster, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { objecttype_t *sp; sp = findot(spellid); if (sp) { diff --git a/spell.h b/spell.h index 2bbf47b..208d1f4 100644 --- a/spell.h +++ b/spell.h @@ -26,7 +26,7 @@ void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYP void stopspell(lifeform_t *caster, enum OBTYPE spellid); void stopallspells(lifeform_t *lf); void stopallspellsexcept(lifeform_t *lf, ...); -int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime); +int summonlfs(lifeform_t *caster, cell_t *where, enum RACECLASS wantrc, enum LFSIZE wantsize, enum ALIGNMENT wantalign, int howmany, int lifetime); lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target); cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power, int frompot); //lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);