* [+] 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)
This commit is contained in:
Rob Pearce 2011-08-10 02:40:29 +00:00
parent 00f9d4e0bf
commit cdd7d69532
18 changed files with 1683 additions and 960 deletions

342
ai.c
View File

@ -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 (rangedattack != RA_NONE) { // ie if we found a ranged attack
// stay out of target's attack range
if (wantdistmin < 2) wantdistmin = 2;
if (wantdistmax < wantdistmin) wantdistmax = wantdistmin;
// 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) {

5
ai.h
View File

@ -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);

View File

@ -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,22 +102,30 @@ 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!");

29
defs.h
View File

@ -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)

39
flag.c
View File

@ -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;

253
god.c
View File

@ -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);
}
}
}

244
io.c
View File

@ -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));

334
lf.c
View File

@ -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

1
lf.h
View File

@ -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);

30
map.c
View File

@ -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);

58
move.c
View File

@ -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;
}
}
}
}

4
move.h
View File

@ -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);

34
nexus.c
View File

@ -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");
}
}
setwaterdepth(c, f->val[2]);
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);
}
}
killflag(f);
continue;
setwaterdepth(c, f->val[2]);
}
killflag(f);
}
noredraw = B_FALSE;

871
objects.c

File diff suppressed because it is too large Load Diff

View File

@ -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);

2
save.c
View File

@ -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;

282
spell.c
View File

@ -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,60 +4164,59 @@ 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;
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;
}
donesomething = B_TRUE;
}
if (isplayer(target)) {
@ -4234,8 +4224,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
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;
@ -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) {

View File

@ -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);