- [+] monster which is horrific - penalties if you can see it! (or you

just can't attack?)
- [+] glow bug corpse in empty flask
* [+] auto hit if paralyzed/frozen
- [+] allomancer has permenant detect metal
- [+] remove detect metal spell
- [+] make detect magic last way longer (at least triple)
* [+] change scrolls to wands:
* [+] on "behead", leave head?
- [+] allomancer way to heal using metal? like absorb metal but costs
      more.
* [+] way to see spell descriptions
* [+] replace most occurensces of getmovespeed() with getactionspeed()
* [+] "sprint" ability
- [+] remove curse scroll!
- [+] need average IQ to know if something is rotting!
- [+] make mosnters rest.
- [+] create monster needs to cope with 'xxx wizard'
    - [+] ie. if no match on name, look for job suffixes
    - [+] if found, strip it, make the monsters (force no job!), then
          apply the job
- [+] rotting corpses turn into bones
* [+] Monster wizards start with a _random_ book, not flamedart.
- [+] 'R'esting bug.
    - [+] waited forever. NEver gained any hp!
    - [+] need to somehow check when resting that we _ARE_ actually
          gaining hp... ?
This commit is contained in:
Rob Pearce 2011-02-15 18:21:33 +00:00
parent 86ee482ce3
commit 4f89ab33f8
25 changed files with 4684 additions and 23520 deletions

319
ai.c
View File

@ -16,8 +16,105 @@
extern lifeform_t *player;
extern enum ERROR reason;
int wantdb = B_TRUE;
enum OBTYPE aigetattackspell(lifeform_t *lf) {
flag_t *f;
enum OBTYPE poss[MAXPILEOBS];
int nposs = 0;
int db = B_FALSE;
if (lfhasflag(lf, F_DEBUG)) {
db = B_TRUE;
}
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_CANWILL) {
poss[nposs] = f->val[0];
nposs++;
} else if (f->id == F_CANCAST) {
objecttype_t *ot;
ot = findot(f->val[0]);
if (cancast(lf, f->val[0], NULL)) {
if (hasflag(ot->flags, F_AICASTATVICTIM) || hasflag(ot->flags, F_AICASTATSELF) || hasflag(ot->flags, F_AICASTANYWHERE)) {
if (db) {
dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?");
}
//TODO :ooo only add if we have an AICAST flag!
poss[nposs] = f->val[0];
nposs++;
} else {
if (db) {
dblog(".oO { cant cast %s - dont know where to target it }", ot ? ot->name : "?unkownspell?");
}
}
} else {
if (db) {
if (ot) {
dblog(".oO { can't cast %s right now (mpcost=%d, i have %d) }",
ot ? ot->name : "?unkownspell?",
getmpcost(ot->id), lf->mp);
} else {
dblog(".oO { can't cast ?unknownspell? right now }");
}
}
}
}
}
// select a random one
if (nposs > 0) {
int sel;
sel = rnd(0,nposs-1);
return poss[sel];
}
return OT_NONE;
}
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob) {
if (hasflag(spelltype->flags, F_AICASTATVICTIM)) {
if (spelllf) *spelllf = victim;
if (spellcell) *spellcell = victim->cell;
if (spellob) *spellob = NULL;
} else if (hasflag(spelltype->flags, F_AICASTATSELF)) {
if (spelllf) *spelllf = lf;
if (spellcell) *spellcell = lf->cell;
if (spellob) *spellob = NULL;
} else if (hasflag(spelltype->flags, F_AICASTANYWHERE)) {
if (spelllf) *spelllf = NULL;
if (spellcell) *spellcell = NULL;
if (spellob) *spellob = NULL;
} else {
// default - at victim.
if (spelllf) *spelllf = victim;
if (spellcell) *spellcell = victim->cell;
if (spellob) *spellob = NULL;
}
}
object_t * aigetwand(lifeform_t *lf) {
object_t *o;
object_t *poss[MAXPILEOBS];
int nposs = 0;
for (o = lf->pack->first ; o ; o = o->next) {
// wand with charges left?
if ((o->type->obclass->id == OC_WAND) && (getcharges(o) > 0)) {
// do we know how to use it?
if (hasflag(o->flags, F_AICASTATVICTIM) || hasflag(o->flags, F_AICASTATSELF) || hasflag(o->flags, F_AICASTANYWHERE)) {
// TODO: if castatself, check whether we actually need to (ie. healing etc)
poss[nposs] = o;
nposs++;
}
}
}
if (nposs > 0) {
return poss[rnd(0,nposs-1)];
}
return NULL;
}
void aimove(lifeform_t *lf) {
int wantdb = B_TRUE;
int db = B_FALSE;
object_t *curwep,*bestwep, *o;
object_t *curgun,*bestgun;
@ -33,11 +130,19 @@ void aimove(lifeform_t *lf) {
/*
if (wantdb && haslos(player, lf->cell)) {
db = B_TRUE;
} else {
db = B_FALSE;
}
*/
if (wantdb && lfhasflag(lf, F_DEBUG)) {
db = B_TRUE;
} else {
db = B_FALSE;
}
if (db) {
char lfname[BUFLEN];
@ -132,15 +237,15 @@ void aimove(lifeform_t *lf) {
// can we attack with spells (ie. ones which target the victim)?
spell = getattackspell(lf);
spell = aigetattackspell(lf);
if (spell != OT_NONE) {
int spellfailed = B_FALSE;
lifeform_t *spelllf = NULL;
cell_t *spellcell = NULL;
object_t *spellob = NULL;
objecttype_t *st;
st = findot(spell);
if (db) {
objecttype_t *st;
st = findot(spell);
dblog(".oO { will cast attack spell: %s }", st->name);
}
@ -179,9 +284,8 @@ void aimove(lifeform_t *lf) {
spelllf = target;
spellcell = target->cell;
} else {
spelllf = target;
spellcell = target->cell;
spellob = NULL;
// pick targets based on spell flags
aigetspelltarget(lf, st, target, &spelllf, &spellcell, &spellob);
}
@ -193,32 +297,60 @@ void aimove(lifeform_t *lf) {
}
}
// can we attack by firing something?
gun = getfirearm(lf);
if (goingtomove && gun && getammo(lf)) {
setguntarget(lf, target);
if (!shoot(lf)) {
// succesful
return;
} else {
if (db) dblog(".oO { shoot gun failed! }");
// if not adjacent, check for guns, wands, throwing
if (goingtomove && (getcelldist(lf->cell, target->cell) > 1)) {
// can we attack by firing something?
gun = getfirearm(lf);
if (goingtomove && gun && getammo(lf)) {
setguntarget(lf, target);
if (!shoot(lf)) {
// succesful
return;
} else {
if (db) dblog(".oO { shoot gun failed! }");
}
}
}
// can we attack by throwing something?
if (goingtomove && getcelldist(lf->cell, target->cell) > 1) {
// TODO: or firing! check if we have a firearm first.
o = getbestmissile(lf);
// can we attack by throwing something?
if (goingtomove) {
// TODO: or firing! check if we have a firearm first.
o = getbestmissile(lf);
if (o) {
if (db) dblog(".oO { will throw %s at my target instead of moving }", o->type->name);
// try to throw it!
if (!throwat(lf, o, target->cell)) {
// succesful
goingtomove = B_FALSE;
} else {
if (db) dblog(".oO { throw failed! }");
}
}
}
// do we have a wand we can zap?
o = aigetwand(lf);
if (o) {
if (db) dblog(".oO { will throw %s at my target instead of moving }", o->type->name);
// try to throw it!
if (!throwat(lf, o, target->cell)) {
objecttype_t *st;
cell_t *zapcell = NULL;
st = getlinkspell(o);
if (st) {
aigetspelltarget(lf, st, target, NULL, &zapcell, NULL);
} else {
// no linkspell - just zap it.
zapcell = NULL;
}
// zap it
if (db) dblog(".oO { will zap %s instead of moving }", o->type->name);
if (!operate(lf, o, zapcell)) {
// succesful
goingtomove = B_FALSE;
} else {
if (db) dblog(".oO { throw failed! }");
if (db) dblog(".oO { zap failed! }");
}
}
}
}
// do we have a valid melee attack?
@ -256,15 +388,6 @@ void aimove(lifeform_t *lf) {
}
}
/*
if (lookforobs(lf, B_COVETS)) {
if (db) dblog(".oO { found covetted object. returning. }");
return;
}
*/
// do we have a target cell?
f = hasflag(lf->flags, F_TARGETCELL);
if (f) {
@ -316,33 +439,32 @@ void aimove(lifeform_t *lf) {
// are we hostile? if so, look for a target
f = hasflag(lf->flags, F_HOSTILE);
if (f) {
int x,y;
int i;
if (db) dblog(".oO { i am hostile. looking for a target. }");
// look around for a target
// TODO: use our vis rang einstead of 10!
for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) {
for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) {
c = getcellat(lf->cell->map, x, y);
// cell exists and we can see it?
if (c && haslos(lf, c)) {
// player there?
if (c->lf && (c->lf != lf) && isplayer(c->lf)) {
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
// target them!
addtempflag(lf->flags, F_TARGET, c->lf->id, NA, NA, NULL, AI_FOLLOWTIME);
// tell the player
if (haslos(player, lf->cell)) {
makenoise(lf, N_GETANGRY);
}
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
if (curwep) {
if (!movetowards(lf, c)) return;
} else {
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
}
// look around for a target
for (i = 0; i < lf->nlos; i++) {
cell_t *c;
c = lf->los[i];
if (c->lf) {
if (isplayer(c->lf)) { // TODO: change to if isenemy ?
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
// target them!
addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME);
// tell the player
if (haslos(player, lf->cell)) {
makenoise(lf, N_GETANGRY);
}
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
if (curwep) {
if (!movetowards(lf, c)) return;
} else {
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
}
break;
}
}
}
@ -364,7 +486,7 @@ void aimove(lifeform_t *lf) {
if (c->lf && (c->lf != lf) && !isplayer(c->lf)) {
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
// target them!
addtempflag(lf->flags, F_TARGET, c->lf->id, NA, NA, NULL, AI_FOLLOWTIME);
addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME);
// then move towards them...
if (db) dblog(".oO { moving towards my new target }");
if (!movetowards(lf, c)) return;
@ -375,6 +497,13 @@ void aimove(lifeform_t *lf) {
}
// need to heal?
if ((lf->hp < lf->maxhp) ||
((lf->mp < lf->maxmp) && lfhasflag(lf, F_RESTHEALMPAMT)) ) {
if (db) dblog(".oO { resting }");
rest(lf, B_TRUE);
}
// just try to move in a random direction
if (db) dblog(".oO { default - moving randomly }");
dorandommove(lf, B_NOBADMOVES);
@ -388,54 +517,11 @@ int aipickup(lifeform_t *lf, object_t *o) {
if (isedible(o)) {
return eat(lf, o);
} else {
return pickup(lf, o, o->amt);
return pickup(lf, o, o->amt, B_TRUE);
}
return B_FALSE;
}
enum OBTYPE getattackspell(lifeform_t *lf) {
flag_t *f;
enum OBTYPE poss[MAXPILEOBS];
int nposs = 0;
int db = B_TRUE;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_CANWILL) {
poss[nposs] = f->val[0];
nposs++;
} else if (f->id == F_CANCAST) {
objecttype_t *ot;
ot = findot(f->val[0]);
if (cancast(lf, f->val[0], NULL)) {
if (db) {
dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?");
}
poss[nposs] = f->val[0];
nposs++;
} else {
if (db) {
if (ot) {
dblog(".oO { can't cast %s right now (mpcost=%d, i have %d) }",
ot ? ot->name : "?unkownspell?",
getmpcost(ot->id), lf->mp);
} else {
dblog(".oO { can't cast ?unknownspell? right now }");
}
}
}
}
}
// select a random one
if (nposs > 0) {
int sel;
sel = rnd(0,nposs-1);
return poss[sel];
}
return OT_NONE;
}
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) {
object_t *o;
@ -478,11 +564,17 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
int noids = 0;
enum FLAG wantflag[MAXPILEOBS];
int nwantflags = 0;
int db = B_TRUE;
flag_t *f;
cell_t *c;
int n;
int i;
int db = B_FALSE;
if (wantdb && lfhasflag(lf, F_DEBUG)) {
db = B_TRUE;
} else {
db = B_FALSE;
}
// construct a list of objects which we want
noids = 0;
@ -502,7 +594,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
// current cell has an object we want?
o = hasobmulti(lf->cell->obpile, oid, noids);
if (o && (canpickup(lf, o) || caneat(lf,o)) ) {
if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf,o)) ) {
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;
@ -513,7 +605,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
// has an object with a flag we want?
for (n = 0; n < nwantflags; n++) {
o = hasobwithflag(lf->cell->obpile, wantflag[n]);
if (o && (canpickup(lf, o) || caneat(lf,o)) ) {
if (o && !isdangerousob(o, lf, B_TRUE) && (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;
@ -528,7 +620,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
if (f ) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterweapon(lf, lf->cell->obpile);
if (o && canpickup(lf, o)) {
if (o && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
if (db) dblog(".oO { current cell has better weapon (%s) }",o->type->name);
// try to pick it up
if (!aipickup(lf, o)) return B_TRUE;
@ -541,7 +633,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
if (f ) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterarmour(lf, lf->cell->obpile);
if (o && canpickup(lf, o)) {
if (o && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
if (db) dblog(".oO { current cell has better armour (%s) }",o->type->name);
// try to pick it up
if (!aipickup(lf, o)) return B_TRUE;
@ -559,7 +651,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
c = lf->los[i];
if (c != lf->ignorecell) {
o = hasobmulti(c->obpile, oid, noids);
if (o && (canpickup(lf, o) || caneat(lf,o)) ) {
if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf,o)) ) {
if (db) dblog(".oO { remote cell has ob i want (%s). setting f_targetcell. }",o->type->name);
gothere = B_TRUE;
}
@ -567,7 +659,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
// has an object with a flag we want?
for (n = 0; n < nwantflags; n++) {
o = hasobwithflag(c->obpile, wantflag[n]);
if (o && (canpickup(lf, o) || caneat(lf, o)) ) {
if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf, o)) ) {
if (db) dblog(".oO { remote cell has ob with flag i want (%s) }", o->type->name);
gothere = B_TRUE;
}
@ -580,7 +672,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterweapon(lf, c->obpile);
if (o && canpickup(lf, o)) {
if (o && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
if (db) dblog(".oO { remote cell has better weapon (%s). setting f_targetcell }",o->type->name);
gothere = B_TRUE;
}
@ -594,7 +686,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
if (!covetsonly || (f->val[1] == B_COVETS)) {
o = hasbetterarmour(lf, c->obpile);
if (o && canpickup(lf, o)) {
if (o && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
if (db) dblog(".oO { remote cell has better armour (%s). setting f_targetcell }",o->type->name);
gothere = B_TRUE;
}
@ -613,6 +705,7 @@ int lookforobs(lifeform_t *lf, int covetsonly) {
}
}
}
if (db) dblog(".oO { didn't find any obs i want }");
return B_FALSE;
}

4
ai.h
View File

@ -1,8 +1,10 @@
#include "defs.h"
enum OBTYPE aigetattackspell(lifeform_t *lf);
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob);
object_t * aigetwand(lifeform_t *lf);
void aimove(lifeform_t *lf);
int aipickup(lifeform_t *lf, object_t *o);
enum OBTYPE getattackspell(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, int covetsonly);

270
attack.c
View File

@ -34,7 +34,7 @@ int attackcell(lifeform_t *lf, cell_t *c) {
}
int attacklf(lifeform_t *lf, lifeform_t *victim) {
unsigned int dam[100];
int dam[100];
enum DAMTYPE damtype[100];
int ndam = 0;
char buf[BUFLEN];
@ -50,16 +50,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
char wepname[BUFLEN];
int ev;
int i;
int willheal = B_FALSE;
int aidb = B_TRUE;
int aidb = B_FALSE;
if (aidb) {
if (isplayer(lf)) {
aidb = B_FALSE;
} else if (!haslos(player, lf->cell)) {
aidb = B_FALSE;
}
if (lfhasflag(lf, F_DEBUG)) {
aidb = B_TRUE;
}
// get names
@ -78,12 +75,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
} else if (haslos(player, lf->cell)) {
//msg("%s looks like it wants to attack!",attackername);
}
/*
if (!isplayer(lf)) {
// if ai, take some time to avoid infinite loops!
taketime(lf, getmovespeed(lf));
}
*/
if (op) killobpile(op);
return B_TRUE;
}
@ -157,26 +148,35 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
// override normal damage calculation
dam[ndam] = getdamrollfromflag(unarmedflag);
} else {
dam[ndam] = getdamroll(wep);
dam[ndam] = getdamroll(wep, victim);
}
dblog("rolled dam[%d] = %d",ndam,dam[ndam]);
if (aidb) dblog("rolled dam[%d] = %d",ndam,dam[ndam]);
// modify for strength
dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf));
if (dam[ndam] < 0) {
willheal = B_TRUE;
}
if (!willheal) {
// modify for strength
dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf));
}
// damtype?
damtype[ndam] = getdamtype(wep);
if (aidb) dblog(".oO { dealing %d %s damage }", dam[ndam], getdamname(damtype[ndam]));
ndam++;
// blessed vs undead etc?
if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) {
// a little extra damage
dam[ndam] = (int) ( (float)dam[ndam] * 1.25 );
}
if (!willheal) {
if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) {
// a little extra damage
dam[ndam] = (int) ( (float)dam[ndam] * 1.25 );
}
// determine extra damage
getextradam(wep, &dam[ndam], &damtype[ndam]);
// determine extra damage
getextradam(wep, &dam[ndam], &damtype[ndam]);
}
} else {
hit = B_FALSE;
ndam = 0;
@ -213,6 +213,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
// announce it
if (isplayer(lf)) {
char extradambuf[BUFLEN];
char *verb;
if (dam[i] == 0) {
strcpy(extradambuf, " but do no damage");
} else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) {
@ -220,11 +221,21 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
} else {
strcpy(extradambuf, "");
}
if (fatal) {
verb = getkillverb(victim, damtype[i], dam[i], victim->maxhp);
} else {
verb = getattackverb(damtype[i], dam[i], victim->maxhp);
}
warn("You %s %s%s%s",
fatal ? getkillverb(damtype[i], dam[i], victim->maxhp) : getattackverb(damtype[i], dam[i], victim->maxhp),
verb,
victimname, extradambuf,
fatal ? "!" : ".");
if (fatal && strstr(verb, "behead")) {
addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL);
}
if (fatal && !hasflag(victim->flags, F_NODEATHANNOUNCE)) {
// don't also say "the xx dies"
addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
@ -259,42 +270,64 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
}
}
// victim loses hp
// don't adjust damage - we've already done that
if (wep && !unarmedflag) {
char wepname[BUFLEN];
getobname(wep, wepname, 1);
sprintf(buf, "%s^weilding %s",attackername, wepname);
if (willheal) {
if (haslos(player, victim->cell)) {
flag_t *f;
msg("%s is healed!",victimname);
f = hasflag(wep->flags, F_BALANCE);
if (f) {
f->known = B_TRUE;
}
gainhp(victim, dam[i]);
}
} else {
strcpy(buf, attackername);
}
// check
/*
if (dam[i] >= 120) {
// potential bug
msg("DB: potential bug: huge dam=%d",dam[i]);
assert(1 == 2);
}
*/
// victim loses hp
// don't adjust damage - we've already done that
if (wep && !unarmedflag) {
char wepname[BUFLEN];
getobname(wep, wepname, 1);
sprintf(buf, "%s^weilding %s",attackername, wepname);
} else {
strcpy(buf, attackername);
}
losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE);
losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE);
// victim's armour loses hp
if (reduceamt) {
object_t *armour;
int adam;
// damage reduction goes towards armour
adam = (reduceamt / 2);
// pick a random piece of armour
armour = getrandomarmour(victim);
if (armour) {
takedamage(armour,adam, damtype[i]);
// victim's armour loses hp
if (reduceamt) {
object_t *armour;
int adam;
if (damtype[i] == DT_ACID) {
// ALL of damage reduction goes towards armour
adam = reduceamt;
} else {
// some of damage reduction goes towards armour
adam = (reduceamt / 2);
}
// pick a random piece of armour
armour = getrandomarmour(victim);
if (armour) {
takedamage(armour,adam, damtype[i]);
}
}
}
} // end foreach damtype
// special weapon effects
wepeffects(wep, victim->cell);
if (!isdead(victim)) {
if (unarmedflag) {
flag_t *f;
f = lfhasflag(lf, F_FREEZINGTOUCH);
if (f) {
// victim turns to ice for a while!
freezelf(victim, lf, rnd(5,10));
killflag(f);
}
}
}
} else { // miss!
if (aidb) dblog(".oO { i missed! }");
// announce it
@ -338,7 +371,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) {
}
int attackob(lifeform_t *lf, object_t *o) {
unsigned int dam[100];
int dam[100];
enum DAMTYPE damtype[100];
int ndam = 0;
char attackername[BUFLEN];
@ -379,7 +412,7 @@ int attackob(lifeform_t *lf, object_t *o) {
}
if (!isplayer(lf)) {
// if ai, take some time to avoid infinite loops!
taketime(lf, getmovespeed(lf));
taketime(lf, getactspeed(lf));
}
if (op) killobpile(op);
return B_TRUE;
@ -402,7 +435,7 @@ int attackob(lifeform_t *lf, object_t *o) {
// override normal damage calculation
dam[ndam] = getdamrollfromflag(unarmedflag);
} else {
dam[ndam] = getdamroll(wep);
dam[ndam] = getdamroll(wep, NULL);
}
// damtype?
@ -458,7 +491,7 @@ int attackob(lifeform_t *lf, object_t *o) {
// returns a const char *
const char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) {
char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) {
float pct;
pct = (int)(((float) dam / (float) maxhp) * 100.0);
if (damtype == DT_PROJECTILE) {
@ -502,6 +535,8 @@ const char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) {
} else if (pct <= 15) {
return "claw";
} else if (pct <= 30) {
return "tear";
} else if (pct <= 40) {
return "rake";
} else if (pct <= 50) {
return "gouge";
@ -600,7 +635,7 @@ enum DAMTYPE getdamtype(object_t *wep) {
return dt;
}
int getextradam(object_t *wep, unsigned int *dam, enum DAMTYPE *damtype) {
int getextradam(object_t *wep, int *dam, enum DAMTYPE *damtype) {
flag_t *f;
for (f = wep->flags->first ; f ; f = f->next) {
if (f->id == F_ONFIRE) {
@ -611,10 +646,14 @@ int getextradam(object_t *wep, unsigned int *dam, enum DAMTYPE *damtype) {
return *dam;
}
char *getkillverb(enum DAMTYPE damtype, int dam, int maxhp) {
char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp) {
float pct;
pct = (int)(((float) dam / (float) maxhp) * 100.0);
if ((damtype == DT_BASH) && lfhasflag(victim, F_FROZEN)) {
return "shatter";
}
if (damtype == DT_HOLY) {
return "smite";
}
@ -624,7 +663,17 @@ char *getkillverb(enum DAMTYPE damtype, int dam, int maxhp) {
if (damtype == DT_BASH) return "flatten";
if (damtype == DT_BITE) return "gore";
if (damtype == DT_CLAW) return "disembowel";
if (damtype == DT_SLASH) return "behead"; // TODO: only if they have a head! otherwise "bisect"
if (damtype == DT_SLASH) {
if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) {
return "bisect";
} else {
if (rnd(1,3)) {
return "behead";
} else {
return "bisect";
}
}
}
}
return "kill";
@ -659,9 +708,51 @@ void getdamrange(flagpile_t *fp, int *min, int *max) {
if (max) *max = maxdam;
}
void getdamrangeunarmed(flag_t *f, int *min, int *max) {
obpile_t *op;
object_t *o;
op = addobpile(NULL, NULL);
o = addob(op, f->text);
if (o) {
int ndice,nsides,mod;
flag_t *damflag;
damflag = hasflag(o->flags, F_DAM);
if (f->val[0] == NA) {
ndice = damflag->val[0];
} else {
ndice = f->val[0];
}
if (f->val[1] == NA) {
nsides = damflag->val[1];
} else {
nsides = f->val[1];
}
if (f->val[2] == NA) {
if (damflag->val[2] != NA) {
mod = damflag->val[2];
} else {
mod = 0;
}
} else {
mod = f->val[2];
}
if (min) *min = (ndice * 1) + mod;
if (max) *max = (ndice * nsides) + mod;
killob(o);
} else {
if (min) *min = 0;
if (max) *max = 0;
}
free(op);
}
// roll for damage
int getdamroll(object_t *o) {
int getdamroll(object_t *o, lifeform_t *victim) {
int dam;
flag_t *f;
f = hasflag(o->flags, F_DAM);
@ -693,6 +784,25 @@ int getdamroll(object_t *o) {
if (dam < 0) dam = 0;
// special effects ?
f = hasflag(o->flags, F_BALANCE);
if (f) {
lifeform_t *owner;
owner = o->pile->owner;
if (owner && victim) {
float ratio;
ratio = (float)owner->maxhp / (float)victim->maxhp;
if (ratio >= 1.25) {
// heals instead!
dam = -dam;
} else if (ratio <= 0.75) {
// extra dam!
dam = (int) ((float)dam * ratio);
}
}
}
return dam;
}
@ -846,7 +956,7 @@ void wepeffects(object_t *wep, cell_t *where) {
f->known = B_KNOWN;
}
}
} else if ((f->id == F_HITCONFER) && victim) {
} else if ((f->id == F_HITCONFER) && victim && !isdead(victim)) {
enum FLAG fid;
int val0,val1;
int min,max,howlong;
@ -876,6 +986,44 @@ void wepeffects(object_t *wep, cell_t *where) {
}
addtempflag(victim->flags, fid, val0, val1, NA, NULL, howlong);
}
} else if ((f->id == F_REVENGE) && victim && !isdead(victim)) {
lifeform_t *owner;
owner = wep->pile->owner;
if (owner && victim) {
float ratio;
float dampct;
int maxdam;
int extradam;
// figure out hp percentage
ratio = 1.0 - ((float)owner->hp / (float)owner->maxhp);
dampct = (ratio * 100); // ie. lower hp% = higher dampct
if (dampct >= 50) {
getdamrange(wep->flags, NULL, &maxdam);
extradam = (int)(dampct * (float)maxdam);
if (extradam > 0) {
char buf[BUFLEN];
char obname[BUFLEN];
char damstring[BUFLEN];
char victimname[BUFLEN];
getlfname(owner, buf);
getlfname(victim, victimname);
getobname(wep, obname, 1);
// announce
if (isplayer(owner)) {
msg("Your %s blasts %s!",noprefix(obname),victimname);
f->known = B_TRUE;
} else if (haslos(player, owner->cell)) {
msg("%s%s %s blasts %s!",buf, getpossessive(buf),noprefix(obname),victimname);
f->known = B_TRUE;
}
sprintf(damstring, "%s%s blast of revenge",buf, getpossessive(buf));
losehp(victim, extradam, DT_DIRECT, owner, damstring);
}
} // end if dampct > 50
}
}
}
}

View File

@ -3,14 +3,15 @@
int attackcell(lifeform_t *lf, cell_t *c);
int attacklf(lifeform_t *lf, lifeform_t *victim);
int attackob(lifeform_t *lf, object_t *o);
const char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp);
char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp);
object_t *getattackwep(lifeform_t *lf, obpile_t **unarmedpile, flag_t **unarmedflag);
enum DAMTYPE getdamtype(object_t *wep);
int getextradam(object_t *wep, unsigned int *dam, enum DAMTYPE *damtype);
char *getkillverb(enum DAMTYPE damtype, int dam, int maxhp);
int getextradam(object_t *wep, int *dam, enum DAMTYPE *damtype);
char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp);
void getdamrange(flagpile_t *fp, int *min, int *max);
void getdamrangeunarmed(flag_t *f, int *min, int *max);
float getdamreducepct(float armourrating);
int getdamroll(object_t *o);
int getdamroll(object_t *o, lifeform_t *victim);
int getdamrollfromflag(flag_t *f);
float getstrdammod(lifeform_t *lf);
obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag);

207
defs.h
View File

@ -28,7 +28,8 @@ enum ATTRIB {
enum BURDENED {
BR_NONE = 0,
BR_BURDENED = 1,
BR_OVERLOADED = 2,
BR_STRAINED = 2,
BR_OVERLOADED = 3,
};
@ -61,11 +62,15 @@ enum LFCONDITION {
#define FROMOBACTIVATE (-9868)
#define FROMMAT (-9867)
#define FROMBLESSING (-9866)
#define FROMOBMOD (-9865)
#define IFKNOWN (-9772) // used by f_xxconfer. only confer a flag if item is known.
#define IFACTIVE (-9771) // used by f_prodeuceslight. only does so if object is activated
#define IFMONSTER (-9769) // used in v2 of f_ifpct job flags
#define IFPLAYER (-9768) // used in v2 of f_ifpct job flags
#define ANYROOM (-9770)
#define TICK_INTERVAL (20)
@ -97,6 +102,7 @@ enum LFCONDITION {
#define MAXRANDOMOBCANDIDATES 100
#define MAXRANDOMLFCANDIDATES 100
#define MAXCANDIDATES 50
//#define MAX_MAPW 80
//#define MAX_MAPH 50
@ -121,7 +127,8 @@ enum LFCONDITION {
//#define DEF_SPARSENESS 14
#define DEF_SPARSENESS 20
//#define DEF_SPARSENESS 0
#define DEF_LOOPPCT 70
//#define DEF_LOOPPCT 70
#define DEF_LOOPPCT 85
//#define DEF_LOOPPCT 0
#define MINROOMS 5
#define MAXROOMS 10
@ -145,6 +152,8 @@ enum LFCONDITION {
#define AO_EQUIPPEDARMOUR 128
#define AO_WEILDABLE 256
#define AO_SPECIFIED 512
#define AO_READABLE 1024
#define AO_ARMOUR 2048
// askcoords target types
#define TT_NONE 0
@ -179,6 +188,7 @@ enum LFCONDITION {
// speed settings (lower is faster)
#define SPEED_ATTACK SP_NORMAL
#define SPEED_DEAD 50
#define SPEED_ACTION SP_NORMAL
#define SPEED_MOVE SP_NORMAL
#define SPEED_DROP SP_FAST
#define SPEED_PICKUP SP_FAST
@ -217,6 +227,7 @@ enum LFCONDITION {
// altitude directions
#define D_UP 12
#define D_DOWN 13
#define D_IN 14
@ -286,6 +297,7 @@ enum IQBRACKET {
// damage type
enum DAMTYPE {
DT_ALL = -1,
DT_PIERCE = 0,
DT_SLASH = 1,
DT_FIRE = 2,
@ -318,6 +330,7 @@ enum OBCLASS {
OC_RING,
OC_SCROLL,
OC_POTION,
OC_WAND,
OC_FOOD,
OC_CORPSE,
OC_ROCK,
@ -327,6 +340,7 @@ enum OBCLASS {
OC_ABILITY,
OC_EFFECT,
OC_DFEATURE,
OC_BOOK,
OC_NULL = -999
};
@ -358,18 +372,25 @@ enum RACE {
R_NONE, R_RANDOM,
R_HUMAN,
// monsters
R_BUGBEAR,
R_EYEBAT,
R_GIANT,
R_GNOLL,
R_GOBLIN,
R_GOBLINGUARD,
R_GOBLINCHAMP,
R_HOBGOBLIN,
R_LIZARDMAN,
R_LURKINGHORROR,
R_OGRE,
R_ORC,
R_ORK,
R_POLTERGEIST,
R_SHADOWCAT,
R_SLIME,
R_SPRITEFIRE,
R_TROLL,
R_LURKINGHORROR,
R_XAT,
// small animals
R_BAT,
R_NEWT,
@ -397,6 +418,7 @@ enum JOB {
J_COMMANDO,
J_PLUMBER,
J_PRINCE,
J_WIZARD,
};
// Object Materials
@ -437,6 +459,7 @@ enum OBTYPE {
OT_STAIRSDOWN,
OT_STAIRSUP,
OT_VENDINGMACHINE,
OT_PORTAL,
// rocks
OT_GOLD,
OT_STONE,
@ -454,6 +477,9 @@ enum OBTYPE {
OT_BREADFRESH,
OT_CHOCOLATE,
// corpses
OT_CORPSE,
OT_HEAD,
/*
OT_CORPSEEYEBAT,
OT_CORPSEBAT,
OT_CORPSEFLY,
@ -466,6 +492,7 @@ enum OBTYPE {
OT_CORPSERODENT,
OT_CORPSETROLL,
OT_CORPSEWOLF,
*/
// potions
OT_POT_ACID,
OT_POT_ACROBATICS,
@ -473,6 +500,7 @@ enum OBTYPE {
OT_POT_COMPETENCE,
OT_POT_ELEMENTENDURE,
OT_POT_ELEMENTIMMUNE,
OT_POT_ETHEREALNESS,
OT_POT_GASEOUSFORM,
OT_POT_HEALING,
OT_POT_HEALINGMIN,
@ -491,30 +519,79 @@ enum OBTYPE {
OT_SCR_CREATEMONSTER,
OT_SCR_DETECTAURA,
OT_SCR_DETECTLIFE,
OT_SCR_FIREBALL,
OT_SCR_DETECTMAGIC,
OT_SCR_FLAMEPILLAR,
OT_SCR_IDENTIFY,
OT_SCR_KNOCK,
OT_SCR_LIGHT,
OT_SCR_MAPPING,
OT_SCR_MINDSCAN,
OT_SCR_ENCHANT,
OT_SCR_FREEZEOB,
OT_SCR_REMOVECURSE,
OT_SCR_TELEPORTRND,
OT_SCR_TURNUNDEAD,
OT_SCR_WISH,
// SPELLBOOKS
// allomancy can't be learned from books
// -- death
OT_SB_INFINITEDEATH,
OT_SB_WEAKEN,
// -- divination
OT_SB_DETECTAURA,
OT_SB_DETECTLIFE,
OT_SB_IDENTIFY,
OT_SB_MAPPING,
// -- elemental
OT_SB_FIREDART,
OT_SB_CONECOLD,
OT_SB_FIREBALL,
OT_SB_FLAMEPILLAR,
// -- gravity
OT_SB_GRAVBOOST,
OT_SB_HASTE,
OT_SB_SLOW,
// -- life
OT_SB_HEALING,
OT_SB_HEALINGMIN,
OT_SB_TURNUNDEAD,
// -- mental
OT_SB_MINDSCAN,
OT_SB_TELEKINESIS,
// -- modification
OT_SB_FREEZEOB,
OT_SB_GASEOUSFORM,
OT_SB_KNOCK,
OT_SB_INSCRIBE,
OT_SB_LIGHT,
OT_SB_PASSWALL,
OT_SB_POLYMORPH,
OT_SB_POLYMORPHRND,
// -- summoning
OT_SB_CREATEMONSTER,
// -- translocation
OT_SB_BLINK,
OT_SB_DISPERSAL,
OT_SB_GATE,
OT_SB_TELEPORT,
OT_SB_TELEPORTRND,
// -- wild can't be learned from books
// spells
// -- allomancy
OT_S_ABSORBMETAL,
OT_S_ACCELMETAL,
OT_S_ANIMATEMETAL,
OT_S_DETECTMETAL,
OT_S_DETONATE,
OT_S_EXPLODEMETAL,
OT_S_PULLMETAL,
OT_S_MAGSHIELD,
OT_S_METALHEAL,
// -- death
OT_S_INFINITEDEATH,
OT_S_WEAKEN,
// -- divination
OT_S_DETECTAURA,
OT_S_DETECTLIFE,
OT_S_DETECTMAGIC,
OT_S_IDENTIFY,
OT_S_MAPPING,
// -- elemental
@ -534,28 +611,48 @@ enum OBTYPE {
OT_S_MINDSCAN,
OT_S_TELEKINESIS,
// -- modification
OT_S_ENCHANT,
OT_S_FREEZEOB,
OT_S_GASEOUSFORM,
OT_S_INSCRIBE,
OT_S_KNOCK,
OT_S_LIGHT,
OT_S_PASSWALL,
OT_S_POLYMORPH,
OT_S_POLYMORPHRND,
// -- summoning
OT_S_CREATEMONSTER,
// -- translocation
OT_S_BLINK,
OT_S_DISPERSAL,
OT_S_LEVTELEPORT,
OT_S_GATE,
OT_S_TELEPORT,
OT_S_TELEPORTRND,
// -- wild
OT_S_MANASPIKE,
OT_S_DETONATE,
OT_S_ENERGYBOLT,
OT_S_ENERGYBLAST,
OT_S_FLASH,
// -- divine powers
OT_S_WISH,
OT_S_GIFT,
// abilities
OT_A_JUMP,
OT_A_SPRINT,
OT_A_DEBUG,
OT_A_EMPLOY,
// wands
OT_WAND_COLD,
OT_WAND_DETONATION,
OT_WAND_FIRE,
OT_WAND_FIREBALL,
OT_WAND_HASTE,
OT_WAND_KNOCK,
OT_WAND_LIGHT,
OT_WAND_POLYMORPH,
OT_WAND_SLOW,
OT_WAND_WEAKNESS,
// tech/tools
OT_BLINDFOLD,
OT_POCKETWATCH,
@ -586,6 +683,7 @@ enum OBTYPE {
OT_BROKENGLASS,
OT_ICECHUNK,
OT_PUDDLEWATER,
OT_PUDDLEWATERL,
OT_SLIMEPOOL,
OT_VOMITPOOL,
OT_BLOODSTAIN,
@ -607,9 +705,12 @@ enum OBTYPE {
OT_OVERALLS,
OT_COTTONSHIRT,
OT_SILKSHIRT,
OT_ROBE,
OT_VELVETROBE,
// armour - shoulders
OT_CLOAK,
OT_VELVETROBE,
// armour - waist
OT_BELTLEATHER,
// armour - legs
OT_CLOTHTROUSERS,
OT_RIDINGTROUSERS,
@ -689,6 +790,8 @@ enum OBTYPE {
OT_RUBBERBULLET,
// holy weapons
OT_HANDOFGOD,
};
@ -701,16 +804,18 @@ enum BODYPART {
BP_SHOULDERS,
BP_BODY,
BP_HANDS,
BP_WAIST,
BP_LEGS,
BP_FEET,
BP_RIGHTHAND,
BP_LEFTHAND,
};
#define MAXBODYPARTS (11)
#define MAXBODYPARTS (12)
// empty types
#define WE_NOTSOLID 1
#define WE_EMPTY 2
#define WE_PORTAL 3
enum NOISETYPE {
N_GETANGRY,
@ -732,6 +837,7 @@ enum FLAG {
F_NONE, // dummy flag
// object flags
F_DEAD, // object will be removed
F_ENCHANTABLE, // object can get +1/-1 ect
F_STACKABLE, // can stack multiple objects togethr
F_NO_PLURAL, // this obname doesn't need an 's' for plurals (eg. gold, money)
F_NO_A, // this obname doesn't need to start with 'a' for singular (eg. gold)
@ -767,6 +873,7 @@ enum FLAG {
F_MATIMMUNE, // immune to damage from obs with material 'mat'
F_DAMAGABLE, // this ob can be damaged via takedamage()
F_TINTED, // when worn on eyes, protects against bright lights
F_HASOBMOD, // has the object mod v0 (ie. OM_FLAMESTRIKE)
F_HOLDCONFER, // gives flag v0+v1 when carried. v2 specifies if it must be id'd.
F_EQUIPCONFER, // gives flag v0+v1 when weilded/worn. v2 specifies if it must be id'd.
F_ACTIVATECONFER, // gives flag v0+v1 when activated. v2 specifies if it must be id'd.
@ -789,8 +896,9 @@ enum FLAG {
F_OPERONOFF, // operating this will just turn it on/off
F_OPERUSECHARGE, // operating this will use 1 charge
F_OPERNEEDTARGET, // need to ask for a target of type val0 when opering
// v1 is target requirements (los/lof)
// v0 is target requirements (los/lof)
// text is prompt
F_OPERNEEDDIR, // need to ask a direction when operating this. text is prompt
// what can ou do with this object?
F_EDIBLE, // you can eat this. val2 = nutrition. 100 = a meal
// -1 means "nutrition is weight x abs(val1)"
@ -804,17 +912,18 @@ enum FLAG {
F_DOOR, // this object is a door - ie. can open it
F_OPEN, // is this door open?
F_LOCKED,// door is locked
F_JAMMED, // is this door jammed?
// stairs / teleporters / portals
F_CLIMBABLE, // this is a stiarcase
F_STAIRDIR, // val0 = direcion
F_OPPOSITESTAIRS, // val0 = opposite kind of stairs
F_MAPLINK, // val0 = map to link to
F_MAPLINK, // val0 = map to link to. optional v1/v2 = x/y
F_FLAMMABLE, // object will catch alight if burnt
// object mods/effects
F_ONFIRE, // burning, also deals extra fire damage
F_HEADLESS, // for corpses
// weapon flags
F_OBATTACKSPEED, // how long weapon takes to attack
F_OBATTACKDELAY, // how long weapon takes to attack
F_DAMTYPE, // val0 = damage type
F_DAM, // val0 = ndice, val1 = nsidesondie, val2 = mod
F_ACCURACY, // 100 - val0 = penalty to tohit% (ie. higher is better)
@ -824,6 +933,8 @@ enum FLAG {
F_AMMOOB, // what object this weapon fires
F_RANGE, // range of projectile firing weapon
F_FLAMESTRIKE, // causes fires where you hit
F_BALANCE, // heals target if their maxhp < your maxhp
F_REVENGE, // causes damage based on your max hp
// tech flags
F_RNDCHARGES, // ob starts with between val0 and val1 charges
// this will cause F_CHARGES to be filled in
@ -842,6 +953,7 @@ enum FLAG {
// if no damtype specified, it will be DT_DIRECT
F_NOOBDAMTEXT, // don't anounce damage to this object
F_NOOBDIETEXT, // don't anounce destruction of this object
F_NODIECONVERTTEXT, // don't anounce when this object changes
// scroll flags
F_LINKSPELL, // val0 = spell this scroll will cast when read
// ob identification flags
@ -858,26 +970,31 @@ enum FLAG {
F_AICASTATSELF, // hints for AI to cast spells
F_AICASTANYWHERE, // hints for AI to cast spells
// lifeform flags
F_DEBUG, // debugging enabled
F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3
F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18
F_SIZE, // val0 = lf size (enum LFSIZE)
F_RESTCOUNT, // val0 = how long you've been resting for
F_RESTHEALTIME, // val0 = how long to rest before healing hp
F_RESTHEALAMT, // val0 = how many hp to gain after resting x turns
F_RESTHEALMPAMT, // val0 = how many MP to gain after resting x turns
F_AUTOCMD, // val0 = how many times to repeat this
F_LASTCMD, // text[0] = last command performed, v0/1 = x/y of cell, v2=various
F_STARTOB, // val0 = %chance of starting with it, text = ob name
// val1,2 = min/max amounts. if NA, min=max=1.
F_STARTOBDT, // val0 = %chance of starting with damtype val1
F_STARTOBCLASS, // val0 = %chance of starting with obclass val1
F_STARTJOB, // val0 = %chance of starting with it, v1 = jobid
F_STARTIQ, // val0 = start iq bracket (ie. IQ_GENIUS)
F_STARTDEX, // val0 = start dex bracket (ie. DEX_xxx)
F_STARTSTR, // val0 = start str bracket (ie. STR_STRONG)
F_CORPSETYPE, // text field specifies what corpse obtype to leave
F_NOCORPSE, // monster's body crumbles to dust after death
F_UNARMEDSPEED, // how long this race takes to attack
F_VISRANGE, // how far you can see (in the light)
F_VISRANGEMOD, // modifications to visrange
F_GUNTARGET, // current projectile weapon target
F_CASTINGSPELL, // set while the player is casting a spell
// v0 is spell id
// MONSTER AI FLAGS
F_HOSTILE, // lf will attack the player if in sight
F_FRIENDLY, // lf will attack all non-players if in sight
@ -900,7 +1017,9 @@ enum FLAG {
// eg. "shouts^a shout"
F_SPELLCASTTEXT, // text is announcement for spellcast
F_NODEATHANNOUNCE, // don't say 'the xx dies' if this lf dies
F_BEHEADED, // use special corpse drop code
F_MOVESPEED, // override default move speed
F_ACTIONSPEED, // override default action speed
F_SPELLSPEED, // override default spellcast speed (ie. movespeed)
F_RARITY, // val[0] = habitat, val[1] = rarity
F_NUMAPPEAR, // when randomly appearing, can have > 1. val[0] = min, val[1] = max
@ -908,7 +1027,7 @@ enum FLAG {
F_MPDICE, // val0: # d4 to roll for maxmp per level. val1: +xx
F_JOB, // val0 = player's class/job
F_NAME, // text = player's name
F_XPVAL, // how much xp this is worth
F_XPMOD, // add/subtract this much from calculated xpval
F_BLOODOB, // text = type of object to drop for blood
F_OBESE, // double base weight for race!
F_ORIGRACE, // original player race (if you polymorphed)
@ -923,22 +1042,29 @@ enum FLAG {
F_NOPACK, // this race cannot hold objects
F_NOSPELLS, // this race cannot cast spells
F_INDUCEFEAR, // causes fear when you attack it
F_AUTOCREATEOB, // produces obtype 'text' wherever it walks, v0=radius
// (only if ob of that type not already there)
// INTRINSICS
F_BLIND, // cannot see anything
F_CANCAST, // can cast the spell val0 (need MP)
F_CANWILL, // can cast the spell val0 without using MP
F_DETECTAURAS, // autodetect bless/curse
F_DETECTLIFE, // autodetect nearby lifeforms
F_DETECTLIFE, // autodetect nearby lifeforms in orthogonal dist v0
F_DETECTMAGIC, // autodetect magic/special objects
F_DETECTMETAL, // autodetect nearby metal
F_EXTRAINFO, // knows extra info
F_FLYING, // lf is flying
F_FASTACT, // modifier for action speed
F_FASTMOVE, // modifier for move speed
F_FOODPOISONED, // has food poisoning
F_FREEZINGTOUCH,// next thing touched turns to ice!
F_GRAVBOOSTED,// cannot walk or throw stuff
F_PARALYZED,// cannot do anything
F_FROZEN, // made of ice
F_INVULNERABLE,// immune to most damage
F_LEVITATING, // like flying but uncontrolled
F_MAGSHIELD,// magnetic shield
F_NONCORPOREAL,// can walk through walls
F_OMNIPOTENT, // knows extra info
F_PHOTOMEM, // you don't forget your surroundings
F_REGENERATES, // regenerate HP at val0 per turn
@ -949,8 +1075,12 @@ enum FLAG {
// (but not for obs in pack)
// if val2 is true, will only make light if ob
// is activated!
F_SLOWACT, // modifier for action speed
F_SLOWMOVE, // modifier for move speed
F_XRAYVIS, //val0=num of walls we can see through
F_CANSEETHROUGHMAT, //val0=kind of material you can see through
F_SPRINTING, // you are sprinting
F_TIRED, // you are too tired to sprint
// COMBAT
F_HASATTACK, // objecttype id to use when attacking unarmed
// if val0-3 are filled in, they override the object's
@ -964,6 +1094,11 @@ enum FLAG {
// nutrition
F_HUNGER, // val0 = hunger, higher = hungrier
// for jobs
F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0.
// if v2=IFMONSTER, also only add the next one for non-players
// if v2=IFPLAYER, also only add the next one for players
//
F_NULL = -1
};
@ -1063,6 +1198,8 @@ enum ERROR {
E_NOAMMO = 25,
E_GRAVBOOSTED = 26,
E_NOMP = 27,
E_AVOIDOB = 28,
E_FROZEN = 29,
};
typedef struct map_s {
@ -1160,6 +1297,9 @@ typedef struct lifeform_s {
int nlos;
cell_t **los;
// set to TRUE after lf has being created
int born;
// for ai movement - don't need to save.
struct cell_s *ignorecell;
@ -1263,6 +1403,36 @@ typedef struct object_s {
struct object_s *next, *prev;
} object_t;
enum OBMOD {
OM_BALANCE,
OM_DEXTERITY,
OM_FEEBLENESS,
OM_FLIGHT,
OM_GIANTSTRENGTH,
OM_INTELLIGENCE,
OM_KNOWLEDGE,
OM_LEVITATION,
OM_MAGRESIST,
OM_PYROMANIA,
OM_REVENGE,
OM_SLOTH,
OM_SPEED,
OM_STRENGTH,
OM_SWIFTNESS,
OM_TELEKINESIS,
OM_TELEPATHY,
OM_WEAKNESS,
};
typedef struct obmod_s {
enum OBMOD id;
char *description;
char *suffix;
flagpile_t *flags;
enum BODYPART bp;
struct obmod_s *next, *prev;
} obmod_t;
typedef struct choice_s {
char ch;
char *text;
@ -1273,8 +1443,11 @@ typedef struct choice_s {
} choice_t;
#define MAXPROMPTQUESTIONS 5
typedef struct prompt_s {
char *q1;
char *q[MAXPROMPTQUESTIONS];
int nqs;
int whichq;
void *result;
choice_t choice[MAXCHOICES];
int selection;

View File

@ -8,6 +8,7 @@ objects.c:
remember to have spelllevle
(optional) add a scroll to do the same effect, use F_LINKSPELL
(optional) add a potion to do the same effect
(optional) add a spellbook to learn it
spell.c:
implement the effects

81
flag.c
View File

@ -9,23 +9,27 @@
#include "text.h"
extern int gamestarted;
extern int needredraw;
extern int statdirty;
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text) {
return addflag_real(fp, id, val1, val2, val3, text, PERMENANT, B_KNOWN);
return addflag_real(fp, id, val1, val2, val3, text, PERMENANT, B_KNOWN, -1);
}
flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft) {
return addflag_real(fp, id, val1, val2, val3, text, timeleft, B_KNOWN);
return addflag_real(fp, id, val1, val2, val3, text, timeleft, B_KNOWN, -1);
}
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known) {
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid) {
flag_t *f;
int i;
int doredraw = B_FALSE;
// identified things mean all new flags are autmaticlaly known.
if (hasflag(fp, F_IDENTIFIED)) {
known = B_KNOWN;
}
// certain flags stack...
if (flagstacks(id)) {
f = hasflag(fp, id);
@ -58,7 +62,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
f->id = id;
f->lifetime = lifetime;
f->known = known;
f->obfrom = -1;
f->obfrom = obfromid;
// first blank values
for (i = 0; i < 3; i++) {
@ -89,12 +93,38 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
if (f->pile->owner) {
if (announceflaggain(f->pile->owner, f)) {
f->known = B_TRUE;
if (f->obfrom) { // ooooooo it's getting -1 ?!?!?!?
object_t *ob;
ob = findobbyid(f->pile->owner->pack, f->obfrom);
if (ob) {
flag_t *f2;
switch (f->lifetime) {
case FROMOBEQUIP:
f2 = hasflagval(ob->flags, F_EQUIPCONFER, f->id, NA, NA, NULL);
break;
case FROMOBHOLD:
f2 = hasflagval(ob->flags, F_HOLDCONFER, f->id, NA, NA, NULL);
break;
case FROMOBACTIVATE:
f2 = hasflagval(ob->flags, F_ACTIVATECONFER, f->id, NA, NA, NULL);
break;
}
if (f2) {
f2->known = B_TRUE;
}
}
}
}
if (isplayer(f->pile->owner)) {
switch (f->id) {
case F_BLIND:
case F_SEEINDARK:
drawscreen();
case F_SPRINTING:
case F_TIRED:
case F_FASTMOVE:
case F_SLOWMOVE:
doredraw = B_TRUE;
break;
default:
break;
@ -107,6 +137,11 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
}
}
if (gamestarted && doredraw) {
statdirty = B_TRUE;
needredraw = B_TRUE;
drawscreen();
}
return f;
}
@ -125,7 +160,7 @@ void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime) {
flag_t *f;
for (f = src->first ; f ; f = f->next) {
addflag_real(dst, f->id, f->val[0], f->val[1], f->val[2], f->text,
(lifetime == NA) ? f->lifetime : lifetime, f->known);
(lifetime == NA) ? f->lifetime : lifetime, f->known, -1);
}
}
@ -133,7 +168,6 @@ int flagstacks(enum FLAG fid) {
int res = B_FALSE;
switch (fid) {
case F_EVASION:
case F_BONUS:
res = B_TRUE;
break;
default:
@ -217,7 +251,7 @@ void killflagsofid(flagpile_t *fp, enum FLAG fid) {
void killflag(flag_t *f) {
flag_t *nextone, *lastone;
lifeform_t *lf;
int needredraw = B_FALSE;
int doredraw = B_FALSE;
lf = f->pile->owner;
@ -225,7 +259,11 @@ void killflag(flag_t *f) {
switch (f->id) {
case F_BLIND:
case F_SEEINDARK:
needredraw = B_TRUE;
case F_SPRINTING:
case F_TIRED:
case F_FASTMOVE:
case F_SLOWMOVE:
doredraw = B_TRUE;
break;
default:
break;
@ -246,6 +284,17 @@ void killflag(flag_t *f) {
lf->polyrevert = B_TRUE;
}
if (lf && (f->id == F_SPRINTING)) {
int howlong;
// you get tired when you finish sprinting
// TODO: change this based on
// constitution
// running skill
howlong = 5;
addtempflag(f->pile, F_TIRED, B_TRUE, NA, NA, NULL, howlong);
}
// free mem
// remove from list
@ -267,7 +316,9 @@ void killflag(flag_t *f) {
lastone->next = nextone;
}
if (gamestarted && needredraw) {
if (gamestarted && doredraw) {
statdirty = B_TRUE;
needredraw = B_TRUE;
drawscreen();
}
}
@ -317,6 +368,16 @@ void timeeffectsflag(flag_t *f) {
break;
}
}
} else if (f->lifetime == 2) {
if (isplayer(f->pile->owner)) {
switch (f->id) {
case F_NONCORPOREAL:
warn("You feel your body solidifying...");
break;
default:
break;
}
}
} else if (f->lifetime == 1) {
// warn about certain flags......
if (isplayer(f->pile->owner)) {

2
flag.h
View File

@ -4,7 +4,7 @@
// functions
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text);
flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft);
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known);
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid);
flagpile_t *addflagpile(lifeform_t *owner, object_t *o);
void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime);
int flagstacks(enum FLAG fid);

772
io.c

File diff suppressed because it is too large Load Diff

4
io.h
View File

@ -3,6 +3,7 @@
void addchoice(prompt_t *p, char ch, char *text, char *desc, void *data);
void addheading(prompt_t *p, char *text);
void addmsghist(char *text);
void addpromptq(prompt_t *p, char *q);
void anim(cell_t *src, cell_t *dst, char ch);
void animradial(cell_t *src, int radius, char ch);
//void announceob(enum OBTYPE oid);
@ -13,7 +14,7 @@ void announceobflagloss(object_t *o, flag_t *f);
object_t *askobject(obpile_t *op, char *title, int *count, int opts);
object_t *askobjectwithflag(obpile_t *op, char *title, int *count, int opts, enum FLAG withflag);
object_t *askobjectofclass(obpile_t *op, char *title, int *count, int opts, enum OBCLASS obclass);
object_t *doaskobject(obpile_t *op, char *title, int *count, int opts, enum OBCLASS obclass, enum FLAG withflag);
object_t *doaskobject(obpile_t *op, char *title, int *count, int opts, enum FLAG withflag, ...);
int askobjectmulti(obpile_t *op, char *prompt, int opts);
char askchar(char *prompt, char *validchars, char *def, int showchars);
cell_t *askcoords(char *prompt, int targettype);
@ -25,6 +26,7 @@ void clearmsg(void);
void real_clearmsg(int force);
void clearretobs(void);
void cls(void);
int contains(enum OBCLASS *array, int nargs, enum OBCLASS want);
void describeob(object_t *o);
void doattackcell(char dirch);
void doclose(void);

1549
lf.c

File diff suppressed because it is too large Load Diff

31
lf.h
View File

@ -4,15 +4,18 @@ lifeform_t *addlf(cell_t *cell, enum RACE rid, int level);
lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller);
job_t *addjob(enum JOB id, char *name);
race_t *addrace(enum RACE id, char *name, float weight, char glyph, enum MATERIAL mat);
void adjustdamlf(lifeform_t *lf, unsigned int *amt, enum DAMTYPE damtype);
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype);
void autotarget(lifeform_t *lf);
void autoweild(lifeform_t *lf);
int appearsrandomly(enum RACE rid);
void bleed(lifeform_t *lf);
int calcxp(lifeform_t *lf);
int calcxprace(enum RACE rid);
int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost);
int caneat(lifeform_t *lf, object_t *o);
int canhear(lifeform_t *lf, cell_t *c);
int canpickup(lifeform_t *lf, object_t *o);
int cannotmove(lifeform_t *lf);
int canpickup(lifeform_t *lf, object_t *o, int amt);
int canpush(lifeform_t *lf, object_t *o, int dir);
int canquaff(lifeform_t *lf, object_t *o);
int canrest(lifeform_t *lf);
@ -22,18 +25,22 @@ int cantakeoff(lifeform_t *lf, object_t *o);
int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell);
void die(lifeform_t *lf);
void dumplf(void);
void dumpxp(void);
int eat(lifeform_t *lf, object_t *o);
object_t *eyesshaded(lifeform_t *lf);
void fightback(lifeform_t *lf, lifeform_t *attacker);
job_t *findjob(enum JOB jobid);
job_t *findjobbyname(char *name);
lifeform_t *findlf(map_t *m, int lfid);
race_t *findrace(enum RACE id);
race_t *findracebyname(char *name);
int flee(lifeform_t *lf);
int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong);
void gainhp(lifeform_t *lf, int amt);
void gainlevel(lifeform_t *lf);
void gainmp(lifeform_t *lf, int amt);
void gainxp(lifeform_t *lf, long amt);
int getactspeed(lifeform_t *lf);
object_t *getarmour(lifeform_t *lf, enum BODYPART bp);
int getarmourrating(lifeform_t *lf);
int getattackspeed(lifeform_t *lf);
@ -68,6 +75,7 @@ float getmaxpushweight(lifeform_t *lf);
int getvisrange(lifeform_t *lf);
int getmovespeed(lifeform_t *lf);
char *getmoveverb(lifeform_t *lf);
char *getmoveverbother(lifeform_t *lf);
char *getlfname(lifeform_t *lf, char *buf);
char *getlfnamea(lifeform_t *lf, char *buf);
enum LFSIZE getlfsize(lifeform_t *lf);
@ -85,7 +93,6 @@ enum STRBRACKET getstrname(int str, char *buf);
enum DEXBRACKET getdexname(int dex, char *buf);
enum IQBRACKET getiqname(int iq, char *buf);
int getthrowspeed(int str);
int getunarmedattackspeed(lifeform_t *lf);
object_t *getweapon(lifeform_t *lf);
long getxpforlev(int level);
void givejob(lifeform_t *lf, enum JOB jobid);
@ -105,6 +112,7 @@ int hasmr(lifeform_t *lf);
void initjobs(void);
void initrace(void);
void interrupt(lifeform_t *lf);
int isairborne(lifeform_t *lf);
int isbleeding(lifeform_t *lf);
int isblind(lifeform_t *lf);
enum BURDENED isburdened(lifeform_t *lf);
@ -112,22 +120,25 @@ int isdead(lifeform_t *lf);
int isfleeing(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp);
int isgenius(lifeform_t *lf);
int isingunrange(lifeform_t *lf, cell_t *where);
int isimmobile(lifeform_t *lf);
flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt);
int isingunrange(lifeform_t *lf, cell_t *where);
int ispeaceful(lifeform_t *lf);
int isplayer(lifeform_t *lf);
int ispolymorphed(lifeform_t *lf);
flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt);
flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt);
void killjob(job_t *job);
void killlf(lifeform_t *lf);
void killrace(race_t *race);
int losehp(lifeform_t *lf, unsigned int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_real(lifeform_t *lf, unsigned int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam);
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam);
void makenoise(lifeform_t *lf, enum NOISETYPE nid);
void maycastspellschool(flagpile_t *fp, enum SPELLSCHOOL ss);
void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how);
int modattr(lifeform_t *lf, enum ATTRIB attr, int amt);
void modhunger(lifeform_t *lf, int amt);
void outfitlf(lifeform_t *lf);
int pickup(lifeform_t *lf, object_t *what, int howmany);
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground);
void precalclos(lifeform_t *lf);
int push(lifeform_t *lf, object_t *o, int dir);
void relinklf(lifeform_t *src, map_t *dst);
@ -136,7 +147,8 @@ void startresting(lifeform_t *lf);
int rolldex(enum DEXBRACKET bracket);
int rolliq(enum IQBRACKET bracket);
int rollstr(enum STRBRACKET bracket);
int savingthrow(lifeform_t *lf, enum ATTRIB attr);
int rollstat(lifeform_t *lf, enum ATTRIB attr);
int savingthrow(lifeform_t *lf, enum ATTRIB attr, int mod);
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong);
int setammo(lifeform_t *lf, object_t *o);
void setattr(lifeform_t *lf, enum ATTRIB attr, int val);
@ -147,6 +159,7 @@ int shoot(lifeform_t *lf);
void sortlf(map_t *map, lifeform_t *lf);
void stopresting(lifeform_t *lf);
void stoprunning(lifeform_t *lf);
int testammo(lifeform_t *lf, object_t *o);
int takeoff(lifeform_t *lf, object_t *o);
void taketime(lifeform_t *lf, long howlong);
int throwat(lifeform_t *thrower, object_t *o, cell_t *where);

22163
log.txt

File diff suppressed because it is too large Load Diff

51
map.c
View File

@ -33,6 +33,7 @@ cell_t *addcell(map_t *m, int x, int y) {
cell->roomid = -1;
cell->lit = B_FALSE;
cell->writing = NULL;
cell->known = B_FALSE;
return cell;
}
@ -72,9 +73,10 @@ map_t *addmap(void) {
}
lifeform_t *addmonster(cell_t *c, enum RACE raceid) {
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok) {
lifeform_t *lf = NULL;
race_t *r;
int db = B_FALSE;
// ie. don't create mosnters on closed doors!
if (!cellwalkable(NULL, c, NULL)) {
@ -88,7 +90,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid) {
}
assert(r);
dblog("adding rand lf %s to cell %d,%d",r->name,c->x,c->y);
if (db) dblog("adding rand lf %s to cell %d,%d",r->name,c->x,c->y);
if (r) {
//lf = addlf(c, r->id, getrandommonlevel(c->map->depth));
@ -96,6 +98,17 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid) {
if (lf) {
int amt;
flag_t *f;
if (jobok) {
// has a job?
f = hasflag(lf->flags, F_STARTJOB);
if (f) {
if (rnd(1,100) <= f->val[0]) {
givejob(lf, f->val[1]);
}
}
}
// appears in groups?
f = hasflag(lf->flags, F_NUMAPPEAR);
if (f) {
@ -124,13 +137,14 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid) {
void addrandomob(cell_t *c) {
char buf[BUFLEN];
int db = B_FALSE;
if (c->type->solid) {
return;
}
if (getrandomob(c->map, buf)) {
dblog("adding rand obj %s to cell %d,%d",buf,c->x,c->y);
if (db) dblog("adding rand obj %s to cell %d,%d",buf,c->x,c->y);
addob(c->obpile, buf);
}
}
@ -143,7 +157,7 @@ void addrandomthing(cell_t *c) {
addrandomob(c);
} else {
// monster
addmonster(c, R_RANDOM);
addmonster(c, R_RANDOM, B_TRUE);
}
}
@ -499,6 +513,7 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_
//int startdir,forcex,forcey,ntries;
cell_t *cell, *c;
object_t *o;
int db = B_FALSE;
// parameters
int turnpct = DEF_TURNPCT;
@ -758,7 +773,14 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_
o = addob(c->obpile, returnstairtype->name);
if (parentmap) {
addflag(o->flags, F_MAPLINK, parentmap->id, NA, NA, NULL);
cell_t *parentstairs;
objecttype_t *ot;
ot = getoppositestairs(returnstairtype);
// find stairs in parent map
parentstairs = findobinmap(parentmap, ot->id);
assert(parentstairs);
// link stairs on new map to stairs on parent map
addflag_real(o->flags, F_MAPLINK, parentmap->id, parentstairs->x, parentstairs->y, NULL, PERMENANT, B_UNKNOWN, -1);
}
// add staircase continuing on (normally this will be down)
@ -771,6 +793,7 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_
}
ot = getoppositestairs(returnstairtype);
addob(c->obpile, ot->name);
// don't add F_MAPLINK yet - this will cocur when we use the stairs
}
@ -968,7 +991,7 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_
int n;
int numpillars;
numpillars = rnd(1,maxpillars);
dblog("--> Will add %d pillars",numpillars);
if (db) dblog("--> Will add %d pillars",numpillars);
for (n = 0; n < numpillars;n++ ) {
//dblog("----> Adding pillar %d/%d",n+1,numpillars);
cell_t *c;
@ -998,7 +1021,7 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_
} else {
numobs = rnd(numobsmin,numobsmax);
}
dblog("--> Will add %d objects to room %d (of %d)",numobs,i,numrooms);
if (db) dblog("--> Will add %d objects to room %d (of %d)",numobs,i,numrooms);
for (n = 0 ; n < numobs; n++) {
int ntries = 0;
cell_t *c;
@ -1044,7 +1067,7 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_
}
}
dblog("Finished adding objects.");
if (db) dblog("Finished adding objects.");
/*
// some extra monsters in corridors
@ -1681,6 +1704,12 @@ cell_t *getrandomadjcell(cell_t *c, int wantempty) {
if (cellwalkable(NULL, new, NULL)) {
return new;
}
} else if (wantempty == WE_PORTAL) {
if (cellwalkable(NULL, new, NULL) && !hasenterableobject(new) ) {
if (!hasobwithflag(new->obpile, F_DOOR)) {
return new;
}
}
} else {
// always ok
return new;
@ -1764,6 +1793,11 @@ cell_t *getrandomroomcell(map_t *map, int roomid) {
return c;
}
object_t *hasenterableobject(cell_t *c) {
return hasobwithflag(c->obpile, F_CLIMBABLE);
}
lifeform_t *haslf(cell_t *c) {
if (c->lf && !isdead(c->lf)) {
return c->lf;
@ -1981,6 +2015,7 @@ void makelit(cell_t *c, int how) {
} else if (c->lit != B_PERM) { // don't override permenant light with temp light!
c->lit = how;
}
}
void makelitradius(cell_t *c, int radius, int how) {

3
map.h
View File

@ -2,7 +2,7 @@
cell_t *addcell(map_t *map, int x, int y);
map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE raceid);
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok);
void addrandomob(cell_t *c);
void addrandomthing(cell_t *c);
int cellhaslos(cell_t *c1, cell_t *dest);
@ -35,6 +35,7 @@ cell_t *getrandomcell(map_t *map);
cell_t *getrandomcelloftype(map_t *map, int id);
int getrandomdir(int dirtype);
cell_t *getrandomroomcell(map_t *map, int roomid);
object_t *hasenterableobject(cell_t *c);
lifeform_t *haslf(cell_t *c);
int hasobject(cell_t *c);
int isadjacent(cell_t *src, cell_t *dst);

240
move.c
View File

@ -16,6 +16,7 @@
extern lifeform_t *player;
extern int statdirty;
extern int needredraw;
extern enum ERROR reason;
extern void *rdata;
@ -47,6 +48,11 @@ int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
return B_FALSE;
}
if (isburdened(lf) >= BR_OVERLOADED) {
if (error) *error = E_TOOHEAVY;
return B_FALSE;
}
// TODO: check if we are burdened, paralyzed, etc
cell = getcellindir(lf->cell, dir);
@ -54,6 +60,47 @@ int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
}
// will populate rdata
int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
enum IQBRACKET iq;
// default
if (error) {
*error = E_OK;
rdata = NULL;
}
// check for dangerous objects
iq = getiqname(getattr(lf, A_IQ), NULL);
if (iq >= IQ_AVERAGE) {
flag_t *f;
object_t *o;
for (o = cell->obpile->first ; o ; o = o->next) {
// don't walk on sharp objects without boots
if (hasflag(o->flags, F_SHARP)) {
if (!getequippedob(lf->pack, BP_FEET)) {
if (error) {
*error = E_AVOIDOB;
rdata = o;
}
return B_TRUE;
}
}
f = hasflag(o->flags, F_WALKDAM);
if (f) {
// are we immune to this?
if (!lfhasflagval(lf, F_DTIMMUNE, f->val[1], NA, NA, NULL)) {
if (error) {
*error = E_AVOIDOB;
rdata = o;
}
return B_TRUE;
}
}
}
}
return B_FALSE;
}
int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
object_t *o;
// default
@ -61,16 +108,28 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
*error = E_OK;
rdata = NULL;
}
if (!cell || cell->type->solid) {
if (!cell) {
if (error) *error = E_WALLINWAY;
return B_FALSE;
}
if (cell->type->solid) {
if (lf && lfhasflag(lf, F_NONCORPOREAL)) {
// ok
} else {
if (error) *error = E_WALLINWAY;
return B_FALSE;
}
}
for (o = cell->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) {
if (lf) {
if ((lf->race->material->id != MT_GAS) &&
(lf->race->material->id != MT_SLIME)) {
if ((lf->race->material->id == MT_GAS) ||
(lf->race->material->id == MT_SLIME)) {
// ok
} else if (lfhasflag(lf, F_NONCORPOREAL)) {
// ok
} else {
rdata = o;
if (error) *error = E_OBINWAY;
return B_FALSE;
@ -90,8 +149,6 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
return B_TRUE;
}
void dorandommove(lifeform_t *lf, int badmovesok) {
int dir;
int tries = 0;
@ -139,6 +196,7 @@ void dorandommove(lifeform_t *lf, int badmovesok) {
}
int getdiraway(cell_t *src, cell_t *dst, int wantcheck) {
int d;
cell_t *c;
@ -280,7 +338,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
// check ground objects
if (!lfhasflag(lf, F_FLYING)) {
if (!isairborne(lf)) {
for (o = newcell->obpile->first ; o ; o = nexto ) {
nexto = o->next;
f = hasflag(o->flags, F_SHARP);
@ -341,10 +399,19 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
for (l = newcell->map->lf ; l ; l = l->next) {
if (l != lf) {
if (haslos(l, newcell)) {
interrupt(lf);
interrupt(l);
if (isplayer(l)) {
if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_RESTING)) {
char lfname2[BUFLEN];
getlfname(lf, lfname);
sprintf(lfname2, "%s",noprefix(lfname));
msg("%s %s comes into view.",isvowel(lfname2[0]) ? "An" : "A", lfname2);
}
}
}
}
}
return didmsg;
}
@ -459,6 +526,11 @@ int opendoor(lifeform_t *lf, object_t *o) {
}
return B_TRUE;
} else {
if (lf) {
taketime(lf, getactspeed(lf));
touch(lf, o);
}
// locked?
if (hasflag(o->flags, F_LOCKED)) {
if (lf && isplayer(lf)) {
@ -466,31 +538,52 @@ int opendoor(lifeform_t *lf, object_t *o) {
}
return B_TRUE;
} else {
// open it
addflag(o->flags, F_OPEN, B_TRUE, NA, NA, NULL);
f = hasflag(o->flags, F_IMPASSABLE);
if (f) killflag(f);
f = hasflag(o->flags, F_BLOCKSVIEW);
if (f) killflag(f);
if (lf) {
if (lf->controller == C_PLAYER) {
msg("You open %s.",obname);
} else {
if (haslos(player, lf->cell) && isadjacent(lf->cell, doorcell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s opens %s.",buf, obname);
} else if (haslos(player, doorcell)) {
capitalise(obname);
msg("%s opens.",obname);
}
int openit = B_TRUE;
f = hasflag(o->flags, F_JAMMED);
if (f) {
f->val[0] --;
// loosen a bit
if (lf && isplayer(lf)) {
msg("You yank on the door but it holds fast.");
}
taketime(lf, getmovespeed(lf));
touch(lf, o);
if (f->val[0] <= 0) {
killflag(f);
}
openit = B_FALSE; // don't open the door
}
if (openit) {
cell_t *where;
// open it
addflag(o->flags, F_OPEN, B_TRUE, NA, NA, NULL);
f = hasflag(o->flags, F_IMPASSABLE);
if (f) killflag(f);
f = hasflag(o->flags, F_BLOCKSVIEW);
if (f) killflag(f);
if (lf) {
if (lf->controller == C_PLAYER) {
msg("You open %s.",obname);
} else {
if (haslos(player, lf->cell) && isadjacent(lf->cell, doorcell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s opens %s.",buf, obname);
} else if (haslos(player, doorcell)) {
capitalise(obname);
msg("%s opens.",obname);
}
}
}
where = getoblocation(o);
if (player && haslos(player, where)) {
needredraw = B_TRUE;
drawscreen();
}
}
return B_FALSE;
}
}
@ -556,7 +649,7 @@ int closedoor(lifeform_t *lf, object_t *o) {
msg("%s closes.",obname);
}
}
taketime(lf, getmovespeed(lf));
taketime(lf, getactspeed(lf));
touch(lf, o);
}
}
@ -598,7 +691,7 @@ int pullnextto(lifeform_t *lf, cell_t *c) {
char buf[BUFLEN];
getlfname(lf, buf);
msg("%s %s pulled %s!", buf, isplayer(lf) ? "are" : "is",
lfhasflag(lf, F_FLYING) ? "through the air" :
isairborne(lf) ? "through the air" :
"along the ground");
}
movelf(lf, dst);
@ -610,16 +703,16 @@ int teleportto(lifeform_t *lf, cell_t *c) {
char buf[BUFLEN];
if (!isplayer(lf) && haslos(player, lf->cell)) {
getlfname(lf, buf);
msg("%s disappears in a puff of smoke!", buf);
msg("%s disappears in a cloud of smoke!", buf);
}
addob(lf->cell->obpile, "puff of smoke");
movelf(lf, c);
addob(lf->cell->obpile, "cloud of smoke");
movelf(lf, c);
// addob(lf->cell->obpile, "cloud of smoke");
if (isplayer(lf)) {
msg("Suddenly, your surroundings appear different!");
} else if (haslos(player, lf->cell)) {
getlfname(lf, buf);
msg("%s appears in a cloud of smoke!", buf);
msg("%s appears!", buf);
}
// show any objects here, just like if we moved.
// BUT don't let dolook() clear the msg bar if there are
@ -638,6 +731,31 @@ int trymove(lifeform_t *lf, int dir) {
cell = getcellindir(lf->cell, dir);
if (canandwillmove(lf, dir, &errcode)) {
object_t *o;
// check for cursed objects + animals
for (o = cell->obpile->first ; o ; o = o->next) {
if (!isplayer(lf)) {
if (o->blessed == B_CURSED) {
if (lfhasflag(lf, F_ANIMAL)) {
if (!isairborne(lf)) {
if (haslos(player, lf->cell)) {
char lfname[BUFLEN];
getlfname(lf,lfname);
getobname(o, buf, o->amt);
msg("%s shies away from %s!", lfname, buf);
o->blessknown = B_TRUE;
taketime(lf, getmovespeed(lf));
reason = E_OK;
}
return B_FALSE;
}
}
}
}
}
reason = E_OK;
moveto(lf, cell);
taketime(lf, getmovespeed(lf));
@ -697,7 +815,10 @@ int trymove(lifeform_t *lf, int dir) {
}
} else {
// try to open it
opendoor(lf, inway);
if (!opendoor(lf, inway)) {
// opening a door counts as a successful move.
reason = E_OK;
}
}
} else {
// can we push this?
@ -741,6 +862,12 @@ int trymove(lifeform_t *lf, int dir) {
taketime(lf, getmovespeed(lf));
}
break;
case E_TOOHEAVY:
if (isplayer(lf)) {
msg("Your load is too heavy to move with!");
taketime(lf, getmovespeed(lf));
}
break;
default:
break;
}
@ -756,8 +883,7 @@ int trymove(lifeform_t *lf, int dir) {
int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
object_t *o;
enum IQBRACKET iq;
//object_t *o;
// default
if (error) {
@ -766,41 +892,9 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
}
cell = getcellindir(lf->cell, dir);
// check for cursed objects + animals
for (o = cell->obpile->first ; o ; o = o->next) {
if (!isplayer(lf)) {
if (o->blessed == B_CURSED) {
if (lfhasflag(lf, F_ANIMAL)) {
if (!lfhasflag(lf, F_FLYING)) {
return B_FALSE;
}
}
}
}
if (celldangerous(lf, cell, error)) {
return B_FALSE;
}
// check for dangerous objects
iq = getiqname(getattr(lf, A_IQ), NULL);
if (iq >= IQ_AVERAGE) {
flag_t *f;
object_t *o;
for (o = cell->obpile->first ; o ; o = o->next) {
// don't walk on sharp objects without boots
if (hasflag(o->flags, F_SHARP)) {
if (!getequippedob(lf->pack, BP_FEET)) {
return B_FALSE;
}
}
f = hasflag(o->flags, F_WALKDAM);
if (f) {
// are we immune to this?
if (!lfhasflagval(lf, F_DTIMMUNE, f->val[1], NA, NA, NULL)) {
return B_FALSE;
}
}
}
}
return B_TRUE;
}

1
move.h
View File

@ -2,6 +2,7 @@
int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error);
int canmove(lifeform_t *lf, int dir, enum ERROR *error);
int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error);
int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error);
int closedoorat(lifeform_t *lf, cell_t *c);
int closedoor(lifeform_t *lf, object_t *o);

44
nexus.c
View File

@ -19,6 +19,7 @@
material_t *material = NULL,*lastmaterial = NULL;
objectclass_t *objectclass = NULL,*lastobjectclass = NULL;
objecttype_t *objecttype = NULL,*lastobjecttype = NULL;
obmod_t *firstobmod = NULL,*lastobmod = NULL;
celltype_t *firstcelltype = NULL,*lastcelltype = NULL;
race_t *firstrace = NULL,*lastrace = NULL;
job_t *firstjob = NULL,*lastjob = NULL;
@ -281,14 +282,23 @@ void checkendgame(void) {
void cleanup(void) {
fclose(logfile);
cleanupgfx();
// free maps
// free knowledge
// free obmods
// free obtypes
// free objects
// free materials
// free races
}
void donextturn(map_t *map) {
lifeform_t *who;
int db = B_FALSE;
who = map->lf;
dblog("**** donextturn for: id %d %s", who->id, who->race->name);
if (db) dblog("**** donextturn for: id %d %s", who->id, who->race->name);
turneffectslf(who);
@ -319,9 +329,8 @@ dblog("**** donextturn for: id %d %s", who->id, who->race->name);
flag_t *f;
if (donormalmove) {
// paralyzed?
f = hasflag(who->flags, F_PARALYZED);
if (f) {
// paralyzed etc?
if (cannotmove(who)) {
rest(who, B_FALSE);
donormalmove = B_FALSE;
}
@ -331,13 +340,8 @@ dblog("**** donextturn for: id %d %s", who->id, who->race->name);
if (donormalmove) {
f = hasflag(who->flags, F_RESTING);
if (f) {
if (who->hp < who->maxhp) {
rest(who, B_TRUE);
donormalmove = B_FALSE;
} else {
killflag(f);
if (isplayer(who)) msg("You finish resting.");
}
rest(who, B_TRUE);
donormalmove = B_FALSE;
}
}
@ -366,12 +370,12 @@ dblog("**** donextturn for: id %d %s", who->id, who->race->name);
// effects which happen every GAME TICK
// ie. object hp drain etc
//////////////////////////////////
timeeffectsworld(map);
// everyone else's time goes down by 1
//for (who = map->lf->next ; who ; who = who->next ){
// if (who->timespent > 0) who->timespent--;
//}
// note: can't use 'who->' below since 'who' might have died
// and been de-alloced during checkdeath() above.
timeeffectsworld(player->cell->map); // in case the player changed levels!
}
celltype_t *findcelltype(int id) {
@ -617,7 +621,7 @@ dblog("doing sort...");
void timeeffectsworld(map_t *map) {
lifeform_t *l;
int db = B_TRUE;
int db = B_FALSE;
object_t *o,*nexto;
int x,y;
long firstlftime;
@ -636,10 +640,10 @@ void timeeffectsworld(map_t *map) {
}
//if (db) dblog("timespent = %d\n", timespent);
dblog("firstlftime = %d\n", firstlftime);
if (db) dblog("firstlftime = %d\n", firstlftime);
if (firstlftime > 0) {
dblog("making firstlf timespent = 0 (currently %d):", firstlftime);
if (db) dblog("making firstlf timespent = 0 (currently %d):", firstlftime);
//dumplf();
for (l = map->lf ; l ; l = l->next) {
//dblog("shuffling id %d %s timespent=%d -> %d",l->id,l->race->name, l->timespent, l->timespent - firstlftime);
@ -653,7 +657,7 @@ void timeeffectsworld(map_t *map) {
//dblog("after shuffle:");
//dumplf();
} else {
dblog("firstlf timespent is not greater than 0. no shuffle.");
if (db) dblog("firstlf timespent is not greater than 0. no shuffle.");
}
timeleft += firstlftime;

1772
objects.c

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ material_t *addmaterial(enum MATERIAL id, char *name, float weightrating);
objectclass_t *addoc(enum OBCLASS id, char *name, char *desc, char glyph);
object_t *addob(obpile_t *where, char *name);
object_t *addobject(obpile_t *where, char *name, int canstack);
obmod_t *addobmod(enum OBMOD id, char *suffix, enum BODYPART bp);
obpile_t *addobpile(lifeform_t *owner, cell_t *where);
objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid);
void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat);
@ -28,12 +29,16 @@ void explodeob(object_t *o, flag_t *f, int bigness);
void extinguish(object_t *o);
material_t *findmaterial(int id);
objectclass_t *findoc(int id);
object_t *findobbyid(obpile_t *op, long oid);
object_t *findobl(obpile_t *op, char let); // find object by letter
obmod_t *findobmod(enum OBMOD id);
objecttype_t *findot(enum OBTYPE id);
objecttype_t *findotn(char *name); // find objecttype by name
void fragments(cell_t *centre, char *what, int speed);
void genhiddennames(void);
int getcharges(object_t *o);
int geteffecttime(int min, int max, enum BLESSTYPE isblessed);
objecttype_t *getlinkspell(object_t *o);
int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt);
int getobaccuracy(object_t *wep);
int getobvalue(object_t *o);
@ -49,7 +54,7 @@ int getfirearmspeed(object_t *o);
char getglyph(object_t *o);
char *genhiddenname(enum OBCLASS id);
char *gethiddenname(object_t *o);
int getobattackspeed(object_t *o);
int getobattackdelay(object_t *o);
int getletindex(char let);
int getmaterialvalue(enum MATERIAL mat );
int getmaxthrowrange(lifeform_t *lf, object_t *o);
@ -93,6 +98,7 @@ int isblessed(object_t *o);
int isblessknown(object_t *o);
int iscorpse(object_t *o);
int iscursed(object_t *o);
int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown);
int isdrinkable(object_t *o);
int isedible(object_t *o);
flag_t *isequipped(object_t *o);
@ -119,16 +125,18 @@ void killot(objecttype_t *ot);
lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level);
void makeknown(enum OBTYPE otid);
object_t *moveob(object_t *src, obpile_t *dst, int howmany);
object_t *newobeffects(object_t *o);
void modbonus(object_t *o, int amt);
//object_t *newobeffects(object_t *o);
void obaction(object_t *o, char *text);
object_t *obexists(enum OBTYPE obid);
void obdie(object_t *o);
int obfits(object_t *o, obpile_t *op);
enum DAMTYPE oblastdamtype(object_t *o);
int obmodappliesto(obmod_t *om, objecttype_t *ot);
flag_t *obproduceslight(object_t *o);
int obpropsmatch(object_t *a, object_t *b);
int obotpropsmatch(object_t *a, objecttype_t *b);
int operate(lifeform_t *lf, object_t *o);
int operate(lifeform_t *lf, object_t *o, cell_t *where);
int pilehasletter(obpile_t *op, char let);
void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE isblessed, int *seen);
int pour(lifeform_t *lf, object_t *o);

3
save.c
View File

@ -74,9 +74,8 @@ int loadflagpile(FILE *f, flagpile_t *fp) {
fl = addflag_real(fp, tempflag.id,
tempflag.val[0],
tempflag.val[1],
tempflag.val[2], strcmp(buf, "^^^") ? buf : NULL, tempflag.lifetime, tempflag.known);
tempflag.val[2], strcmp(buf, "^^^") ? buf : NULL, tempflag.lifetime, tempflag.known, tempflag.obfrom);
fl->obfrom = tempflag.obfrom;
if (db) {
dblog("--> added flag id=%d. v0=%d, v1=%d, v2=%d, text=%s, lifetime=%d, known=%d, obfrom=%ld\n",fl->id,

647
spell.c
View File

@ -1,4 +1,5 @@
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@ -18,6 +19,8 @@ extern lifeform_t *player;
extern WINDOW *msgwin;
extern job_t *firstjob;
int abilityeffects(lifeform_t *user, enum OBTYPE abilid) {
char username[BUFLEN];
char buf[BUFLEN];
@ -43,8 +46,20 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid) {
}
}
if (isburdened(user)) {
if (isplayer(user)) {
msg("Your load is too heavy to jump!");
}
return B_TRUE;
} else if (lfhasflag(user, F_GRAVBOOSTED)) {
if (isplayer(user)) {
msg("Gravity around you is too strong to jump in!");
}
return B_TRUE;
}
// we now have a cell - go there!
taketime(user, getmovespeed(user));
taketime(user, getactspeed(user));
origcell = user->cell;
// did you land on anyone?
@ -118,7 +133,64 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid) {
}
}
}
} else if (abilid == OT_A_SPRINT) {
int howlong;
if (lfhasflag(user, F_TIRED)) {
if (isplayer(user)) {
msg("You are too tired to sprint right now.");
}
return B_TRUE;
}
// TODO: calculate time based on:
// constitution (or max hp?)
// running speed
howlong = 3;
addtempflag(user->flags, F_SPRINTING, B_TRUE, NA, NA, NULL, howlong);
} else if (abilid == OT_A_DEBUG) {
cell_t *where;
where = askcoords("Debug who?", TT_MONSTER);
if (where) {
lifeform_t *victim;
victim = where->lf;
if (victim) {
char lfname[BUFLEN];
flag_t *f;
getlfname(victim, lfname);
f = hasflag(victim->flags, F_DEBUG);
if (f) {
killflag(f);
msg("%s - debugging is DISABLED.", lfname);
} else {
addflag(victim->flags, F_DEBUG, B_TRUE, NA, NA, NULL);
msg("%s - debugging is ON.", lfname);
}
}
}
} else if (abilid == OT_A_EMPLOY) {
cell_t *where;
where = askcoords("Assign job to who?", TT_MONSTER);
if (where && where->lf) {
char question[BUFLEN];
char lfname[BUFLEN];
char buf[BUFLEN];
job_t *j;
lifeform_t *target;
target = where->lf;
getlfname(target, lfname);
sprintf(question, "What job will you assign to %s",lfname);
askstring(question, '?', buf, BUFLEN, NULL);
j = findjobbyname(buf);
if (j) {
givejob(target, j->id);
msg("%s is now a %s.", lfname, j->name);
} else {
fizzle(user);
}
} else {
msg("There is nobody there!");
}
}
return B_FALSE;
}
@ -132,6 +204,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
getlfname(caster, castername);
// default to unseen
if (seenbyplayer) *seenbyplayer = B_FALSE;
if (spellid == OT_S_ABSORBMETAL) {
@ -163,6 +236,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
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) {
@ -194,7 +280,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (totalmass > 0) {
if (hasmr(caster)) {
if (isplayer(caster)) {
msg("You feel a surge of magic, but it quickly dampens.");
msg("You feel a surge of magic, but it quickly dampens.");
}
} else {
// heal 1 mp per kilo
@ -222,7 +308,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
return B_FALSE;
} else if (o->amt != 1) {
if (isplayer(caster)) {
msg("Your %s wobble a little.", obname);
msg("Your %s wobbles a little.", obname);
} else {
fizzle(caster);
}
@ -245,6 +331,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else {
fizzle(caster);
}
} else if (spellid == OT_S_BLINK) {
if (hasmr(caster)) {
if (isplayer(caster)) {
msg("You feel a momentary tug.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (!caster->nlos) {
// can't see anywhere
fizzle(caster);
} else {
int tries = 0,maxtries = 10;
// pick a random location
targcell = NULL;
while (!targcell || !cellwalkable(caster, targcell, NULL) || celldangerous(caster, targcell, NULL)) {
int i;
i = rnd(0,caster->nlos-1);
targcell = caster->los[i];
tries++;
if (tries >= maxtries) {
fizzle(caster);
return B_FALSE;
}
}
teleportto(caster, targcell);
}
} else if (spellid == OT_S_CONECOLD) {
char lfname[BUFLEN];
int acc;
@ -278,13 +389,36 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else if (spellid == OT_S_CREATEMONSTER) {
cell_t *where;
lifeform_t *newlf;
job_t *forcejob = NULL;
race_t *r = NULL;
int randomjobsok = B_TRUE;
// create a monster nearby
if (blessed) {
// ask what kind of monster
askstring("Create what kind of monster", '?', buf, BUFLEN, NULL);
r = findracebyname(buf);
// not found - are we asking for a job with the monster?
if (!r) {
job_t *j;
// try removing suffixes
for (j = firstjob ; j ; j = j->next) {
char *p;
char jobname[BUFLEN];
strcpy(jobname, j->name);
jobname[0] = tolower(jobname[0]);
p = strstr(buf, jobname);
if (p) {
char newbuf[BUFLEN];
strncpy(newbuf, buf, (p - buf) - 1);
r = findracebyname(newbuf);
if (r) {
forcejob = j;
break;
}
}
}
}
if (!r) {
if (caster->controller == C_PLAYER) {
nothinghappens();
@ -302,13 +436,24 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
return B_TRUE;
}
// create random monster in cell
if (forcejob) {
randomjobsok = B_FALSE;
} else {
randomjobsok = B_TRUE;
}
if (blessed) {
//newlf = addlf(where, r->id, getrandommonlevel(where->map->depth));
newlf = addmonster(where, r->id);
newlf = addmonster(where, r->id, randomjobsok);
} else {
newlf = addmonster(where, R_RANDOM);
newlf = addmonster(where, R_RANDOM, randomjobsok);
}
if (newlf) {
// assign job if required
if (forcejob) {
givejob(newlf, forcejob->id);
}
if (haslos(player, where)) {
char *newbuf;
getlfname(newlf, buf);
@ -379,55 +524,58 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else if (spellid == OT_S_DETECTLIFE) {
target = caster;
if (isplayer(caster)) {
int howlong = 15;
switch (blessed) {
case B_BLESSED:
howlong = 20; break;
case B_UNCURSED:
howlong = rnd(10,20); break;
case B_CURSED:
howlong = 2; break;
}
int howlong;
howlong = getspellduration(10,20,blessed);
addtempflag(target->flags, F_DETECTLIFE, 10, NA, NA, NULL, howlong);
} else {
// monsters can't use this
}
} else if (spellid == OT_S_DETECTMAGIC) {
target = caster;
if (isplayer(caster)) {
int howlong;
howlong = getspellduration(40,90,blessed);
addtempflag(target->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL, howlong);
} else {
// monsters can't use this
}
/*
} else if (spellid == OT_S_DETECTMETAL) {
target = caster;
if (isplayer(caster)) {
int howlong = 15;
switch (blessed) {
case B_BLESSED:
howlong = 20; break;
case B_UNCURSED:
howlong = rnd(10,20); break;
case B_CURSED:
howlong = 2; break;
}
howlong = getspellduration(10,20,blessed);
addtempflag(target->flags, F_DETECTMETAL, 10, NA, NA, NULL, howlong);
} else {
// monsters can't use this
}
*/
} else if (spellid == OT_S_DETONATE) {
// don't need line of fire!
if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, B_FALSE)) return B_TRUE;
explodecells(targcell, 20, B_TRUE, NULL, 0, B_TRUE);
if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_EXPLODEMETAL) {
float totalmass = 0;
object_t *o, *nexto;
int i;
if (!validatespellcell(caster, &targcell, TT_OBJECT, B_FALSE)) return B_TRUE;
// how much metal is there?
for (i = 0; i < caster->nlos; i++) {
cell_t *c;
c = caster->los[i];
for (o = c->obpile->first ; o ; o = nexto) {
nexto = o->next;
// destroy metal items on the ground
if (ismetal(o->material->id)) {
totalmass += getobweight(o);
removeob(o, o->amt);
}
for (o = targcell->obpile->first ; o ; o = nexto) {
nexto = o->next;
// destroy metal items on the ground
if (ismetal(o->material->id)) {
totalmass += getobweight(o);
removeob(o, o->amt);
}
}
// destroy objects right away
removedeadobs(targcell->lf->pack);
// explosion, based on size...
if (totalmass > 0) {
@ -566,27 +714,25 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
}
}
} else if (spellid == OT_S_FIREBALL) {
cell_t *where;
int failed = B_FALSE;
// ask for a target cell
sprintf(buf, "Where will you target your fireball?");
where = askcoords(buf, TT_MONSTER);
if (where && haslof(caster, where)) { // need line of FIRE for this, not just sight
if (!where->type->solid || hasflag(where->type->material->flags, F_FLAMMABLE)) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE)) return B_TRUE;
if (targcell && haslof(caster, targcell)) { // need line of FIRE for this, not just sight
if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) {
int dir;
cell_t *c;
// centre fireball here...
if (caster->controller == C_PLAYER) {
if (isplayer(caster)) {
msg("You launch an enormous ball of fire!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, caster->cell)) {
msg("%s launches an enormous ball of fire!",castername);
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, where)) {
} else if (haslos(player, targcell)) {
msg("An enormous ball of fire explodes!");
}
anim(caster->cell, where, '^');
anim(caster->cell, targcell, '^');
// add fires as follows (3 = large, 2 = medium, 1 = smell)
//
@ -596,23 +742,23 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
// 232
// 1
// add large fires to surrounding cells
addob(where->obpile, "large fire");
addob(targcell->obpile, "large fire");
for (dir = D_N; dir <= D_W; dir++) {
c = getcellindir(where, dir);
c = getcellindir(targcell, dir);
if (c && (!c->type->solid || hasflag(c->type->material->flags, F_FLAMMABLE)) ) {
addob(c->obpile, "large fire");
}
}
for (dir = DC_NE; dir <= DC_NW; dir += 2) {
cell_t *c;
c = getcellindir(where, dir);
c = getcellindir(targcell, dir);
if (c && (!c->type->solid || hasflag(c->type->material->flags, F_FLAMMABLE)) ) {
addob(c->obpile, "medium fire");
}
}
for (dir = D_N; dir <= D_W; dir++) {
cell_t *c;
c = getcellindir(where, dir);
c = getcellindir(targcell, dir);
if (c) {
c = getcellindir(c, dir);
if (c && (!c->type->solid || hasflag(c->type->material->flags, F_FLAMMABLE)) ) {
@ -665,19 +811,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
}
}
} else if (spellid == OT_S_FLAMEPILLAR) {
cell_t *where;
int failed = B_FALSE;
// ask for a target cell
sprintf(buf, "Where will you create a flame pillar?");
where = askcoords(buf, TT_MONSTER);
if (where && haslos(caster, where)) {
if (!where->type->solid || hasflag(where->type->material->flags, F_FLAMMABLE)) {
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE)) return B_TRUE;
if (targcell && haslos(caster, targcell)) {
if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) {
// create flame there
if (haslos(player, where)) {
if (haslos(player, targcell)) {
msg("A raging pillar of flame appears!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
addob(where->obpile, "large fire");
addob(targcell->obpile, "large fire");
} else {
failed = B_TRUE;
}
@ -688,6 +832,39 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (failed) {
fizzle(caster);
}
} else if (spellid == OT_S_ENCHANT) {
object_t *o;
if (targob) {
o = targob;
} else {
// ask for an object
o = askobjectwithflag(caster->pack, "Enchant which object", NULL, AO_NONE, F_ENCHANTABLE);
}
if (!o) {
fizzle(caster);
return B_TRUE;
}
if (isplayer(caster)) {
if (!hasflag(o->flags, F_ENCHANTABLE)) {
nothinghappens();
return B_TRUE;
} else {
int amt;
char obname[BUFLEN];
if (blessed == B_CURSED) {
amt = -1;
} else {
amt = 1;
}
modbonus(o, amt);
getobname(o, obname, o->amt);
msg("Your %s glows %s for a moment.", noprefix(obname), (blessed == B_CURSED) ? "black" : "green");
}
} else {
// monsters can't id things!
}
} else if (spellid == OT_S_FREEZEOB) {
object_t *o;
@ -799,9 +976,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
}
} else if (spellid == OT_S_HASTE) {
int howlong = 15;
if (!validatespelllf(caster, &target)) return B_TRUE;
if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE)) return B_TRUE;
if (!isplayer(target) && haslos(player, target->cell)) {
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_FALSE;
}
if (haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -812,17 +996,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
switch (blessed) {
case B_BLESSED:
howlong = 25;
break;
case B_UNCURSED:
howlong = rnd(5,25);
break;
case B_CURSED:
howlong = 5;
break;
}
howlong = getspellduration(5,25,blessed);
addtempflag(target->flags, F_FASTACT, 5, NA, NA, NULL, howlong);
addtempflag(target->flags, F_FASTMOVE, 5, NA, NA, NULL, howlong);
}
} else if (spellid == OT_S_HEALING) {
@ -1045,6 +1220,89 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
rv = B_FALSE;
} else if (spellid == OT_S_METALHEAL) {
int i;
float totalmass = 0;
object_t *o;
int howmuch;
// works on all metal in sight
if (isplayer(caster)) {
if (seenbyplayer) *seenbyplayer = B_FALSE;
msg("You draw health from nearby metal!");
} else if (haslos(player, caster->cell)) {
if (seenbyplayer) *seenbyplayer = B_FALSE;
msg("%s draws health from nearby metal!",castername);
}
totalmass = 0;
// destroy WORN metal objects by the caster (not CARRIED ones)
if (!hasmr(caster)) {
for (o = caster->pack->first ; o ; o = o->next) {
if (isequipped(o) && ismetal(o->material->id)) {
takedamage(o, 9999, DT_DIRECT);
if (hasflag(o->flags, F_DEAD)) {
totalmass += getobweight(o);
}
}
}
// 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) {
// 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(targcell->obpile);
if (targcell->lf && !hasmr(targcell->lf)) {
// destroy only WORN metal objects, not CARRIED ones
for (o = targcell->lf->pack->first ; o ; o = o->next) {
if (isequipped(o) && ismetal(o->material->id)) {
takedamage(o, 9999, DT_DIRECT);
if (hasflag(o->flags, F_DEAD)) {
totalmass += getobweight(o);
}
}
}
// destroy objects right away
removedeadobs(targcell->lf->pack);
}
}
if (totalmass > 0) {
if (hasmr(caster)) {
if (isplayer(caster)) {
msg("You feel momentarily healthier, but the feeling passes.");
}
} else {
// heal 2 hp per kilo
howmuch = floor(totalmass) * 2;
gainhp(caster, howmuch);
}
} else {
fizzle(caster);
}
} else if (spellid == OT_S_MINDSCAN) {
cell_t *where;
int failed = B_FALSE;
@ -1175,54 +1433,85 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
fizzle(caster);
}
}
} else if (spellid == OT_S_LEVTELEPORT) {
} else if (spellid == OT_S_GATE) {
int newdepth;
// ask which level
askstring("Teleport to which level", '?', buf, BUFLEN, NULL);
askstring("Create a portal to which level", '?', buf, BUFLEN, NULL);
newdepth = atoi(buf);
if (newdepth <= 0) {
fizzle(caster);
} else if (hasmr(caster)) {
if (isplayer(caster)) {
msg("You flicker.");
msg("You see a flicker nearby.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, caster->cell)) {
getlfname(caster, buf);
msg("%s flickers.",buf);
msg("You see a flicker near %s.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
} else {
map_t *newmap;
cell_t *newcell;
cell_t *newcell,*srccell;
object_t *srcportal,*dstportal;
// announce
// find adjacent cell for portal
srccell = getrandomadjcell(caster->cell, WE_NOTSOLID);
if (!srccell) {
fizzle(caster);
return B_FALSE;
}
// create the source portal
srcportal = addob(srccell->obpile, "magic portal");
// announce, because we might have a delay creating the level...
if (isplayer(caster)) {
msg("There is a blinding flash of light...");
wrefresh(msgwin);
}
// teleport there!
// find new map !
newmap = findmapofdepth(newdepth);
if (!newmap) {
// create new map
newmap = addmap();
createmap(newmap, newdepth, caster->cell->map->habitat, NULL, findot(OT_STAIRSUP));
}
// find a random cell there
newcell = getrandomcell(newmap);
while (!cellwalkable(caster, newcell, NULL)) {
while (!cellwalkable(caster, newcell, NULL) || hasenterableobject(newcell)) {
newcell = getrandomcell(newmap);
}
// add the dst portal
dstportal = addob(newcell->obpile, "magic portal");
// link the dst portal
addflag_real(dstportal->flags, F_MAPLINK, caster->cell->map->id, srccell->x, srccell->y, NULL, PERMENANT, B_FALSE, -1);
// announce
if (isplayer(caster)) {
msg("You find yourself on level %d.", newcell->map->depth);
// link the source portal
addflag_real(srcportal->flags, F_MAPLINK, newmap->id, newcell->x, newcell->y, NULL, PERMENANT, B_FALSE, -1);
// make both gates temporary
addflag(srcportal->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(srcportal->flags, F_OBHP, 6, 6, NA, NULL);
addflag(srcportal->flags, F_OBHPDRAIN, 1, DT_DIRECT, NA, NULL);
addflag(srcportal->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(srcportal->flags, F_DIETEXT, B_TRUE, NA, NA, "vanishes");
addflag(dstportal->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(dstportal->flags, F_OBHP, 6, 6, NA, NULL);
addflag(dstportal->flags, F_OBHPDRAIN, 1, DT_DIRECT, NA, NULL);
addflag(dstportal->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(dstportal->flags, F_DIETEXT, B_TRUE, NA, NA, "vanishes");
if (haslos(player, srccell)) {
char obname[BUFLEN];
getobname(srcportal, obname, 1);
msg("%s appears!",obname);
}
// go there!
moveto(caster, newcell);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_INSCRIBE) {
@ -1260,13 +1549,62 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else {
// monsters can't cast
}
} else if (spellid == OT_S_KNOCK) {
object_t *o;
if (!validatespellcell(caster, &targcell,TT_DOOR, B_FALSE)) return B_TRUE;
o = hasobwithflag(targcell->obpile, F_DOOR);
if (o) {
int dooropen;
isdoor(o, &dooropen); // just check whether it's open, we know it's a door
if (dooropen) {
fizzle(caster);
} else {
if (haslos(player, targcell)) {
getobname(o, buf, o->amt);
msg("%s %s!",isplayer(caster) ? "You blast" : "Something blasts", buf);
}
takedamage(o, 999, DT_DIRECT);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
fizzle(caster);
}
} else if (spellid == OT_S_LIGHT) {
lifeform_t *l;
// centre light on the caster
makelitradius(caster->cell, 10, B_PERM);
if (isplayer(caster) || haslos(player, caster->cell)) {
msg("The area is lit by a magical light!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
makelitradius(caster->cell, 10, B_PERM);
// blind anyone with nightvis who sees it
// (player last)
for (l = caster->cell->map->lf ; l ; l = l->next) {
if (!isplayer(l) && haslos(l, caster->cell)) {
if (lfhasflag(l, F_SEEINDARK)) {
// if you don't have eyes, your'e safe!
if (!lfhasflagval(l, F_NOBODYPART, BP_EYES, NA, NA, NULL)) {
// blind for 5-10 turns
addtempflag(l->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(5,10));
}
}
// undead will flee from light
if (lfhasflag(l, F_UNDEAD)) {
// runs away from caster
addtempflag(l->flags, F_FLEEFROM, caster->id, NA, NA, NULL, 20);
}
}
}
if (isplayer(caster) || haslos(player, caster->cell)) {
if (lfhasflag(player, F_SEEINDARK)) {
msg("The light burns your eyes!");
// blind for 5-10 turns
addtempflag(player->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(5,10));
}
}
} else if (spellid == OT_S_GRAVBOOST) {
// ask for target
if (!target) {
@ -1292,21 +1630,24 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
return B_FALSE;
}
switch (blessed) {
case B_BLESSED:
howlong = 10;
break;
case B_UNCURSED:
howlong = rnd(2,10);
break;
case B_CURSED:
howlong = 2;
break;
}
howlong = getspellduration(2,10,blessed);
addtempflag(target->flags, F_GRAVBOOSTED, B_TRUE, NA, NA, NULL, howlong);
} else {
fizzle(caster);
}
} else if (spellid == OT_S_PASSWALL) {
int howlong = 7;
target = caster;
if (hasmr(target)) {
if (isplayer(target)) {
msg("You feel momentarily insubstantial.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
return B_FALSE;
}
howlong = getspellduration(5,10,blessed);
addtempflag(target->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL, howlong);
} else if ((spellid == OT_S_POLYMORPHRND) || (spellid == OT_S_POLYMORPH)) {
race_t *r;
@ -1344,6 +1685,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
} else {
char buf2[BUFLEN];
char targname[BUFLEN];
getlfname(target, targname);
sprintf(buf2, "What will you transform %s into", targname);
askstring(buf2, '?', buf, BUFLEN, NULL);
}
@ -1352,7 +1694,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
// make sure race is valid:
// - can't turn into monsters which aren't randomly generated.
// - can't turn into unique monsters
if (!appearsrandomly(r->id)) {
if (r && !appearsrandomly(r->id)) {
r = NULL;
}
} else {
@ -1402,17 +1744,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
return B_FALSE;
}
switch (blessed) {
case B_BLESSED:
howlong = 5;
break;
case B_UNCURSED:
howlong = rnd(5,25);
break;
case B_CURSED:
howlong = 25;
break;
}
howlong = rnd(5,25);
addtempflag(target->flags, F_SLOWACT, 5, NA, NA, NULL, howlong);
addtempflag(target->flags, F_SLOWMOVE, 5, NA, NA, NULL, howlong);
/*
if (!isplayer(target) && haslos(player, target->cell)) {
@ -1615,76 +1948,109 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target,
if (target) {
int howlong = 30;
switch (blessed) {
case B_BLESSED:
howlong = 30;
break;
case B_UNCURSED:
howlong = rnd(10,30);
break;
case B_CURSED:
howlong = 10;
break;
}
howlong = getspellduration(10,30,blessed);
addtempflag(target->flags, F_ATTRMOD, A_STR, -6, NA, NULL, howlong);
} else {
fizzle(caster);
}
} else if (spellid == OT_S_WISH) {
} else if ((spellid == OT_S_WISH) || (spellid == OT_S_GIFT)) {
object_t *o;
if (caster->controller == C_PLAYER) {
if (isplayer(caster)) {
char lfname[BUFLEN];
char question[BUFLEN];
if (seenbyplayer) *seenbyplayer = B_TRUE;
// ask for target
if (spellid == OT_S_GIFT) {
if (!validatespelllf(caster, &target)) return B_TRUE;
} else {
target = caster;
}
getlfname(target, lfname);
// ask for an object
askstring("For what do you wish", '?', buf, BUFLEN, NULL);
o = addob(caster->cell->obpile, buf);
if (spellid == OT_S_GIFT) {
sprintf(question, "What gift will %s receive",lfname);
} else {
sprintf(question, "For what do you wish");
}
askstring(question, '?', buf, BUFLEN, NULL);
o = addob(target->cell->obpile, buf);
if (o) {
if (!hasflag(o->flags, F_IMPASSABLE) && canpickup(caster, o)) {
relinkob(o, caster->pack); // move to pack
getobname(o, buf, o->amt);
msglower("%c - %s.", o->letter, buf);
char obname[BUFLEN];
getobname(o, obname, o->amt);
if (!hasflag(o->flags, F_IMPASSABLE) && canpickup(target, o, ALL)) {
relinkob(o, target->pack); // move to pack
if (isplayer(target)) {
msglower("%c - %s.", o->letter, obname);
} else {
msg("%s is gifted with %s.", lfname, obname);
}
} else {
// couldn't pick it up - try to place on ground!
// impassable?
if (hasflag(o->flags, F_IMPASSABLE)) {
cell_t *newloc;
// if so, don't put it where the player is!
newloc = getrandomadjcell(caster->cell, WE_NOTSOLID);
newloc = getrandomadjcell(target->cell, WE_NOTSOLID);
o = relinkob(o, newloc->obpile);
}
if (o) {
if (isblind(caster)) {
youhear(caster->cell, "something hitting the ground.");
} else {
getobname(o, buf, o->amt);
msg("%s appear%s on the ground!", buf, (o->amt == 1) ? "s" : "");
msg("%s appear%s on the ground!", obname, (o->amt == 1) ? "s" : "");
}
} else {
// couldn't make it appear
msg("The air in front of you seems to ripple for a moment.");
msg("The air in front of %s seems to ripple for a while.", lfname);
}
}
} else {
// couldn't make it appear
msg("The air in front of you seems to ripple for a moment.");
// couldn't make it appear - ob doesn't exist
msg("The air in front of %s seems to ripple for a moment.", lfname);
}
} else {
// monsters can't wish
}
}
return rv;
}
void fizzle(lifeform_t *caster) {
char buf[BUFLEN];
if (isplayer(caster)) {
msg("Your spell fizzles.");
if (lfhasflag(caster, F_CASTINGSPELL)) {
msg("Your spell fizzles.");
} else {
nothinghappens();
}
/*
} else if (haslos(player, caster->cell)) {
getlfname(caster, buf);
capitalise(buf);
msg("%s's spell fizzles.", buf);
*/
}
}
// returns a number between min & max
// if blessed, always the max
// if cursed, always the min
int getspellduration(int min,int max,int blessed) {
int howlong;
switch (blessed) {
case B_BLESSED:
howlong = max; break;
case B_CURSED:
howlong = min; break;
default:
case B_UNCURSED:
howlong = rnd(min,max); break;
}
return howlong;
}
// magically propel an object into lf's hands.
// if it's too big it'll hit them!
void pullobto(object_t *o, lifeform_t *lf) {
@ -1701,7 +2067,7 @@ void pullobto(object_t *o, lifeform_t *lf) {
}
// can we pick up the object?
if (hasflag(o->flags, F_NOPICKUP) || hasflag(o->flags, F_IMPASSABLE) || !canpickup(lf, o)) {
if (hasflag(o->flags, F_NOPICKUP) || hasflag(o->flags, F_IMPASSABLE) || !canpickup(lf, o, ALL)) {
char buf[BUFLEN];
int dir;
cell_t *obloc,*newcell;
@ -1731,7 +2097,7 @@ void pullobto(object_t *o, lifeform_t *lf) {
if (isplayer(lf) || haslos(player, lf->cell)) {
msg("%s %s %s.", lfname, isplayer(lf) ? "catch" : "catches", obname);
}
pickup(lf, o, o->amt);
pickup(lf, o, o->amt, B_FALSE);
}
}
@ -1778,6 +2144,25 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, i
return *targcell;
}
// returns the amount if IQ needed to learn this spell
// required intelligence is 9 + spelllevel
// ie. spelllev1 needs 9+ intelligence
// ie. spelllev7 needs 16+ intelligence
int getiqreq(enum OBTYPE oid) {
flag_t *f;
objecttype_t *ot;
int iqreq = 0;
ot = findot(oid);
if (!ot) {
return 0;
}
f = hasflag(ot->flags, F_SPELLLEVEL);
if (f) {
iqreq = 9 + f->val[0];
}
return iqreq;
}
int getmpcost(enum OBTYPE oid) {
flag_t *f;
objecttype_t *ot;

View File

@ -5,7 +5,9 @@
int abilityeffects(lifeform_t *user, enum OBTYPE abilid);
int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer);
void fizzle(lifeform_t *caster);
int getiqreq(enum OBTYPE oid);
int getmpcost(enum OBTYPE oid);
int getspellduration(int min,int max,int blessed);
void pullobto(object_t *o, lifeform_t *lf);
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof);
lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);

14
text.c
View File

@ -16,6 +16,20 @@ char *capitalise(char *text) {
return text;
}
char *capitaliseall(char *text) {
if (strlen(text) > 0) {
char *p;
for (p = text ; *p; p++) {
if (p == text) { // first letter
*p = toupper(*p);
} else if (*(p-1) == ' ') { // first letter after a space
*p = toupper(*p);
}
}
}
return text;
}
char *getattrname(enum ATTRIB att) {
switch (att) {
case A_STR:

1
text.h
View File

@ -1,6 +1,7 @@
#include "defs.h"
char *capitalise(char *text);
char *capitaliseall(char *text);
char *getattrname(enum ATTRIB att);
char *getpossessive(char *text);
char *getsizetext(enum LFSIZE sz);