- [+] BUG: lfs are getting map flags!

- [+] Implement a* pathfinding for pets
    - [+] done
    - [+] TEST... seems okay so far.
- [+] druid spells not showing in starting list.
- [+] don't announce noise from unseen things which are attacking the
      player.
- [+] fix crash when no pet location found at start of game.
- [+] swap spell levels for warp wood and absorb wood.
- [+] only set godprayedto if you got a positive effect.
- [+] warp wood should affect wooden lifeforms.
- [+] pathfinding for player:
    - [+] only allow this to explored cells
    - [+] consider unexplored cells non-walkable.
    - [+] set f_pathfinding
    - [+] STOP if we see a monster
- [+] never let stamina exceed max.
- [+] you can now actually climb when you get the spiderclimb ability
      but don't have climbing skill
This commit is contained in:
Rob Pearce 2012-11-06 20:32:56 +00:00
parent 095fb8b7d4
commit 29483cd29f
19 changed files with 870 additions and 147 deletions

484
ai.c
View File

@ -23,8 +23,8 @@ extern int playerhasmoved;
int wantdb = B_TRUE; int wantdb = B_TRUE;
void addignorecell(lifeform_t *lf, cell_t *c) { void addignorecell(lifeform_t *lf, cell_t *c) {
if (c) { if (c && !lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) {
addflag(lf->flags, F_IGNORECELL, c->x, c->y, NA, NULL); addtempflag(lf->flags, F_IGNORECELL, c->x, c->y, NA, NULL, 20);
} }
} }
@ -97,6 +97,7 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
dblog(".oO { %s setting new target: %s }", lfname, vicname); dblog(".oO { %s setting new target: %s }", lfname, vicname);
} }
killflagsofid(lf->flags, F_AIPATH);
killflagsofid(lf->flags, F_TARGETLF); killflagsofid(lf->flags, F_TARGETLF);
killflagsofid(lf->flags, F_TARGETCELL); killflagsofid(lf->flags, F_TARGETCELL);
@ -146,6 +147,344 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
return B_FALSE; return B_FALSE;
} }
int calcheuristic(cell_t *c, cell_t *end) {
int h,xd,yd;
xd = abs(c->x - end->x);
yd = abs(c->y - end->y);
if (xd > yd) {
h = (14*yd) + 10*(xd - yd);
} else {
h = (14*xd) + 10*(yd - xd);
}
return h;
}
// inserts node 'n' into list 'list' (sorted by cost)
// returns index of insert position.
int insert(node_t *n, node_t *list, int *listcount) {
int pos,i;
// add it to open list, with parent = node[cur]
pos = -1;
for (pos = 0; pos < *listcount; pos++) {
if (n->cost <= list[pos].cost) {
// add here.
break;
}
}
// shuffle others up
for (i = *listcount; i > pos; i--) {
list[i] = list[i-1];
}
(*listcount)++;
// fill in .
list[pos] = *n;
return pos;
}
int calcg(lifeform_t *lf, cell_t *thiscell, node_t *parent, int dirfromparent) {
int fromstart;
object_t *o;
int dooropen;
enum ATTRBRACKET wis = AT_EXHIGH;
if (lf) {
wis = getattrbracket(getattr(lf, A_WIS), A_WIS, NULL);
}
if (isorthogonal(dirfromparent)) {
fromstart = parent->fromstart + 10;
} else {
fromstart = parent->fromstart + 14;
}
// closed doors count for more.
if (wis >= AT_AVERAGE) {
o = hasdoor(thiscell);
if (o && isdoor(o, &dooropen) && !dooropen) {
fromstart += 10;
}
}
// lf's wisdom will affect what is the "best" path
if (wis >= AT_GTAVERAGE) {
// avoid mud, etc
o = hasobwithflag(thiscell->obpile, F_REDUCEMOVEMENT);
if (o) {
int howmuch;
sumflags(o->flags, F_REDUCEMOVEMENT, &howmuch, NULL, NULL);
if (howmuch > 0) {
fromstart += (10*howmuch);
}
}
}
return fromstart;
}
// A* algorithm. Returns F_AIPATH flag.
flag_t *ai_createpathto(lifeform_t *lf, cell_t *targcell) {
char *pathbuf;
cell_t *pathcell[MAX_PATHFIND_STEPS];
int pathlen = 0;
int done = B_FALSE,i,n, first = B_TRUE;
node_t open[MAX_PATHFIND_ADJ];
node_t closed[MAX_PATHFIND_ADJ];
node_t *cur;
int nopen = 0,nclosed = 0;
int db = B_FALSE;
char lfname[BUFLEN];
flag_t *newf;
if (!db && lfhasflag(lf, F_DEBUG)) db = B_TRUE;
real_getlfname(lf, lfname, NULL, B_SHOWALL, B_CURRACE);
if (lf->cell->map != targcell->map) {
if (db) dblog("%s: pathfind destination on different level", lfname);
return NULL;
}
if (db) dblog("%s pathfind - finding path from %d,%d to %d,%d\n",lfname, lf->cell->x,lf->cell->y,
targcell->x,targcell->y);
// add starting cell to open list
open[0].c = lf->cell;
open[0].fromstart = 0;
open[0].heur = calcheuristic(lf->cell, targcell);
open[0].cost = open[0].fromstart + open[0].cost;
open[0].parent = NULL;
nopen = 1;
// NEED: calccosts(node, parentcell, endcell);
while (!done) {
// if open list empty?
if (!nopen) {
// if so, there is NO path. fail.
if (db) dblog("%s pathfind - open list is empty. FAILED.",lfname);
return NULL;
}
// find lowest COST in open list. this is cur.
// move node[cur] to closed list
closed[nclosed] = open[0];
cur = &closed[nclosed];
nclosed++;
for (i = 0; i < nopen-1; i++) {
open[i] = open[i+1];
}
nopen--;
//if (db) dblog("%s pathfind - lowest cost node on openlist is %d,%d",lfname,cur->c->x, cur->c->y);
// is node[cur] the target cell?
if (cur->c == targcell) {
// if so, we've found a path. now need to populate
//if (db) dblog("%s pathfind - at target cell - success!",lfname);
done = B_TRUE;
} else {
// for "adjcell" in 8 squares around it:
for (i = DC_N; i <= DC_NW; i++) {
cell_t *adjcell;
int walkable,found = B_FALSE, ok = B_FALSE;
enum ERROR whynot;
adjcell = getcellindir(cur->c, i);
if (!adjcell) continue;
//if (db) dblog("%s pathfind - checking %s",lfname, getdirnameshort(i));
// already on closed list?
for (n = 0; n < nclosed; n++) {
if (closed[n].c == adjcell) {
found = B_TRUE;
break;
}
}
if (found) {
// already on closed list. ignore.
//if (db) dblog(" %s (%d,%d): already on closed list. ignore.",getdirnameshort(i),
// adjcell->x, adjcell->y);
continue;
}
walkable = cellwalkable(lf, adjcell, &whynot);
ok = B_FALSE;
if (lfhasflagval(lf, F_IGNORECELL, adjcell->x, adjcell->y, NA, NULL)) {
ok = B_FALSE;
} else if (walkable) {
ok = B_TRUE;
} else if (celldangerous(lf, adjcell, B_TRUE, NULL) && haslos(lf, adjcell)) {
// ignore dangerous cells only if we can see them.
ok = B_FALSE;
} else {
if (whynot == E_LFINWAY) {
if (isadjacent(adjcell, lf->cell)) {
ok = B_FALSE;
} else {
ok = B_TRUE;
}
} else if (whynot == E_DOORINWAY) {
if (canopendoors(lf)) {
ok = B_TRUE;
} else {
ok = B_FALSE;
}
} else {
ok = B_FALSE;
}
}
if (ok) {
int openpos = -1;
// adjcell is walkable.
for (n = 0; n < nopen; n++) {
if (open[n].c == adjcell) {
openpos = n;
break;
}
}
if (openpos != -1) {
int newfromstart;
node_t temp;
// adjcell is already on open list
//if (db) dblog(" %s (%d,%d): on open list (position %d).",getdirnameshort(i),
// adjcell->x, adjcell->y, openpos);
// recalc fromstart of adjcell using node[cur] as a parent.
newfromstart = calcg(lf, open[openpos].c, cur, i);
if (newfromstart < open[openpos].fromstart) {
// path through node[cur] is better.
//if (db) dblog(" %s (%d,%d): better cost - recalcing.",
// getdirnameshort(i),
// adjcell->x, adjcell->y);
// change parent of adjcell to node[cur]
// and recalc new costings (and re-sort list)
temp = open[openpos];
temp.parent = cur;
assert(isadjacent(temp.c, temp.parent->c));
temp.fromstart = calcg(lf, temp.c, temp.parent, i);
temp.heur = calcheuristic(temp.c, targcell);
temp.cost = temp.fromstart + temp.heur;
// remove adjcell from open list.
for (n = openpos; n < nopen; n++) {
open[n] = open[n+1];
}
nopen--;
// re-add adjcell at correct pos;
insert(&temp, open, &nopen);
}
} else {
// not on open list
node_t temp;
//if (db) dblog(" %s (%d,%d): not on openlist. inserting.",
// getdirnameshort(i),
// adjcell->x, adjcell->y);
// calc costs
temp.c = adjcell;
temp.parent = cur;
assert(isadjacent(temp.c, temp.parent->c));
temp.fromstart = calcg(lf, temp.c, temp.parent, i);
temp.heur = calcheuristic(adjcell, targcell);
temp.cost = temp.fromstart + temp.heur;
insert(&temp, open, &nopen);
}
} else {
// !walkable - ignore it.
//if (db) dblog(" %s (%d,%d): not walkable - ignoring.",
// getdirnameshort(i),
// adjcell->x, adjcell->y);
}
}
}
}
// work backwards from node[cur] (ie. targcell) following parents.
// populate path and return
if (db) dblog("%s - found path!\n",lfname);
while (cur) {
pathcell[pathlen++] = cur->c;
if (pathlen >= MAX_PATHFIND_STEPS) {
if (db) dblog("%s pathfind - path too long (> %d). FAILED.",MAX_PATHFIND_STEPS);
return NULL;
}
cur = cur->parent;
}
pathbuf = malloc(pathlen*6*sizeof(char));
strcpy(pathbuf, "");
for (i = pathlen-1; i >= 0 ; i--) {
char smallbuf[BUFLENTINY];
// don't include starting cell
if (pathcell[i] == lf->cell) continue;
sprintf(smallbuf, "%s%d,%d",first ? "" : "-", pathcell[i]->x, pathcell[i]->y);
first = B_FALSE;
strcat(pathbuf, smallbuf);
}
if (db) dblog("* %s - path takes %d steps. ", lfname, pathlen);
if (db) dblog("* %s - pathbuf: [%s] ", lfname, pathbuf);
newf = addflag(lf->flags, F_AIPATH, targcell->x, targcell->y, NA, pathbuf);
free(pathbuf);
return newf;
}
// f is a flag of type F_AIPATH
//
// returns the next cell in the path, and removes next cell
// from the list.
//
// if there are no more cells in the path, remove the path.
cell_t *ai_getnextcellinpath(lifeform_t *lf) {
cell_t *c;
flag_t *f;
char *loctext;
char *p,buf[BUFLEN];
int x,y;
f = lfhasflag(lf, F_AIPATH);
if (!f) return NULL;
loctext = strdup(f->text);
p = loctext;
p = readuntil(buf, loctext,',');
x = atoi(buf);
p = readuntil(buf, p,'-');
y = atoi(buf);
free(loctext);
c = getcellat(lf->cell->map, x,y);
return c;
}
// returns TRUE on error
int ai_popnextcellinpath(lifeform_t *lf) {
flag_t *f;
char *loctext;
char *p,buf[BUFLEN];
f = lfhasflag(lf, F_AIPATH);
if (!f) return B_TRUE;
loctext = strdup(f->text);
p = loctext;
p = readuntil(buf, loctext,',');
p = readuntil(buf, p,'-');
if (strlen(p)) {
free(f->text);
f->text = strdup(p);
} else {
killflag(f);
}
free(loctext);
return B_FALSE;
}
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) {
flag_t *retflag[MAXCANDIDATES]; flag_t *retflag[MAXCANDIDATES];
int nretflags = 0; int nretflags = 0;
@ -304,6 +643,14 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l
if (lasty) *lasty = NA; if (lasty) *lasty = NA;
if (lastdir) *lastdir = D_NONE; if (lastdir) *lastdir = D_NONE;
// if within scent range... we 'magically' know their location.
if (getcelldist(lf->cell, target->cell) <= getsmellrange(lf)) {
if (lastx) *lastx = target->cell->x;
if (lasty) *lasty = target->cell->y;
if (lastdir) *lastdir = D_NONE;
return target->cell;
}
// do we remember the player's last known location ? // do we remember the player's last known location ?
f = ispetortarget(lf, target); f = ispetortarget(lf, target);
if (f) { if (f) {
@ -782,6 +1129,7 @@ flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int t
// kill previous target flags. // kill previous target flags.
killflagsofid(lf->flags, F_AIPATH);
killflagsofid(lf->flags, F_TARGETLF); killflagsofid(lf->flags, F_TARGETLF);
killflagsofid(lf->flags, F_TARGETCELL); killflagsofid(lf->flags, F_TARGETCELL);
@ -1488,8 +1836,7 @@ int ai_movement(lifeform_t *lf) {
} }
if (valid) { if (valid) {
aimovetotargetcell(lf, f); return aimovetotargetcell(lf, f);
return B_TRUE;
} else { } else {
killflag(f); killflag(f);
} }
@ -1788,7 +2135,6 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// try to get to our ideal range from them. // try to get to our ideal range from them.
if (db) dblog(".oO { i am at distance %d, want to be at %d-%d }", dist, wantdistmin, wantdistmax); if (db) dblog(".oO { i am at distance %d, want to be at %d-%d }", dist, wantdistmin, wantdistmax);
if (dist > wantdistmax) { if (dist > wantdistmax) {
// want to move but our race doesn't move? // want to move but our race doesn't move?
if (lfhasflag(lf, F_DOESNTMOVE)) { if (lfhasflag(lf, F_DOESNTMOVE)) {
if (db) dblog(".oO { want to move towards target but have f_doesntmove - abandoning target. }"); if (db) dblog(".oO { want to move towards target but have f_doesntmove - abandoning target. }");
@ -1796,9 +2142,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
return B_TRUE; return B_TRUE;
} }
if (db) { if (db) dblog(".oO { moving towards target. }");
dblog(".oO { moving towards target. }");
}
// do we need to sprint got catch up? // do we need to sprint got catch up?
if (lfhasflag(target, F_SPRINTING) && !lfhasflag(lf, F_SPRINTING) && cancast(lf, OT_A_SPRINT, NULL)) { if (lfhasflag(target, F_SPRINTING) && !lfhasflag(lf, F_SPRINTING) && cancast(lf, OT_A_SPRINT, NULL)) {
@ -1806,7 +2150,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
} }
if (!movetowards(lf, target->cell, DT_ORTH, B_FALSE)) { if (!movetowards(lf, target->cell, DT_ORTH, B_FALSE)) {
dblog(".oO { successfully moved towards target. }"); if (db) dblog(".oO { successfully moved towards target. }");
turntoface(lf, target->cell); turntoface(lf, target->cell);
// success // success
return B_FALSE; return B_FALSE;
@ -1948,7 +2292,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
} }
void aimovetotargetcell(lifeform_t *lf, flag_t *f) { int aimovetotargetcell(lifeform_t *lf, flag_t *f) {
int x,y; int x,y;
cell_t *c,*origc; cell_t *c,*origc;
int db = B_FALSE; int db = B_FALSE;
@ -1963,55 +2307,92 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
origc = lf->cell; origc = lf->cell;
c = getcellat(lf->cell->map, x, y); c = getcellat(lf->cell->map, x, y);
if (c) { if (c) {
// try to move towards the cell flag_t *pathf = NULL;
if (movetowards(lf, c, DT_ORTH, B_FALSE )) { if (!haslof(lf->cell, c, LOF_WALLSTOP, NULL)) {
// couldn't move towards it for some reason. // if we DONT have LOF to the target cell, use
// so stop trying. // a pathfinding algorithm.
if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }"); // do we ahv an existing path?
killflag(f); pathf = lfhasflag(lf, F_AIPATH);
// remember NOT to target this one. if (!pathf) {
addignorecell(lf, c); // if we DONT have a direct path, then pathfind.
} else { pathf = ai_createpathto(lf, c);
int turned = B_FALSE;
if (lf->cell == origc) {
if (db) dblog(".oO { turned to face f_targetcell. (still at %d,%d) }",lf->cell->x, lf->cell->y);
turned = B_TRUE;
} else {
if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y);
} }
// moved towards it.
// reset lifetime
f->lifetime = aigetchasetime(lf);
// are we there yet? if (pathf) {
if (lf->cell == c) { c = ai_getnextcellinpath(lf);
// yes. remove target cell
if (db) dblog(".oO { arrived at f_targetcell. removing. }");
if (f->val[2] == MR_LF) {
lifeform_t *targlf;
// if we were chasing someone, keep looking
// for them.
targlf = findlf(lf->cell->map, atoi(f->text));
if (targlf) {
if (db) dblog(".oO { resuming pursuit of %s }", targlf->race->name);
addflag(lf->flags, F_TARGETLF, targlf->id, NA, NA, NULL);
}
}
killflag(f);
} else { } else {
if (!turned) { // couldn't find a path there...
turntoface(lf, c); // just try to move directly towards it.
}
} }
} }
} else { // if we _DO_ have lof to the cell, we'll just walk direclty towards it.
if (db) dblog(".oO { f_targetcell doesn't exist. abandoning. }");
if (c) {
// try to move towards the cell
if (movetowards(lf, c, DT_ORTH, B_FALSE )) {
// couldn't move towards it for some reason.
// so stop trying.
if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }");
killflag(f);
// remember NOT to target this one.
addignorecell(lf, c);
c = NULL;
} else {
int turned = B_FALSE;
if (lf->cell == origc) {
if (db) dblog(".oO { turned to face f_targetcell. (still at %d,%d) }",lf->cell->x, lf->cell->y);
turned = B_TRUE;
} else {
if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y);
}
if (pathf && (lf->cell == c)) {
ai_popnextcellinpath(lf);
}
// moved towards it.
// reset lifetime
f->lifetime = aigetchasetime(lf);
// are we there yet?
if (lf->cell == c) {
// yes. remove target cell
if (db) dblog(".oO { arrived at f_targetcell. removing. }");
if (f->val[2] == MR_LF) {
lifeform_t *targlf;
// if we were chasing someone, keep looking
// for them.
targlf = findlf(lf->cell->map, atoi(f->text));
if (targlf) {
if (db) dblog(".oO { resuming pursuit of %s }", targlf->race->name);
addflag(lf->flags, F_TARGETLF, targlf->id, NA, NA, NULL);
}
}
killflag(f);
} else {
if (!turned) {
turntoface(lf, c);
}
}
}
} else {
// !c
}
}
if (!c) {
if (db) dblog(".oO { f_targetcell doesn't exist anymore. moving randomly. }");
// destination doesn't exist! // destination doesn't exist!
killflag(f); killflag(f);
// remember NOT to target this one. loseaitargets(lf);
addignorecell(lf, c);
// move randomly now.
dorandommove(lf, B_NOBADMOVES, B_TRUE, B_FALSE); // this function will call rest() if we cant move
} }
// success
return B_TRUE;
} }
int aipickup(lifeform_t *lf, object_t *o) { int aipickup(lifeform_t *lf, object_t *o) {
@ -3130,6 +3511,7 @@ int lookforobs(lifeform_t *lf) {
int loseaitargets(lifeform_t *lf) { int loseaitargets(lifeform_t *lf) {
int donesomething = B_FALSE; int donesomething = B_FALSE;
if (killflagsofid(lf->flags, F_AIPATH)) donesomething = B_TRUE;
if (killflagsofid(lf->flags, F_TARGETLF)) donesomething = B_TRUE; if (killflagsofid(lf->flags, F_TARGETLF)) donesomething = B_TRUE;
if (killflagsofid(lf->flags, F_TARGETCELL)) donesomething = B_TRUE; if (killflagsofid(lf->flags, F_TARGETCELL)) donesomething = B_TRUE;
return donesomething; return donesomething;

7
ai.h
View File

@ -2,6 +2,11 @@
void addignorecell(lifeform_t *lf, cell_t *c); void addignorecell(lifeform_t *lf, cell_t *c);
int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit); int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit);
int calcheuristic(cell_t *c, cell_t *end);
int calcg(lifeform_t *lf, cell_t *thiscell, node_t *parent, int dirfromparent);
flag_t *ai_createpathto(lifeform_t *lf, cell_t *targcell);
cell_t *ai_getnextcellinpath(lifeform_t *lf);
int ai_popnextcellinpath(lifeform_t *lf);
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim); enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim);
enum OBTYPE aigetfleespell(lifeform_t *lf); enum OBTYPE aigetfleespell(lifeform_t *lf);
int aigetchasetime(lifeform_t *lf); int aigetchasetime(lifeform_t *lf);
@ -21,7 +26,7 @@ int ai_movement(lifeform_t *lf);
int ai_premovement(lifeform_t *lf); int ai_premovement(lifeform_t *lf);
flag_t *aihastarget(lifeform_t *lf); flag_t *aihastarget(lifeform_t *lf);
int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack); int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack);
void aimovetotargetcell(lifeform_t *lf, flag_t *f); int aimovetotargetcell(lifeform_t *lf, flag_t *f);
int aipickup(lifeform_t *lf, object_t *o); int aipickup(lifeform_t *lf, object_t *o);
int aipickupok(lifeform_t *lf, object_t *o); int aipickupok(lifeform_t *lf, object_t *o);
int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target); int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target);

View File

@ -201,6 +201,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
} }
stoprunning(lf); stoprunning(lf);
stoppathfinding(lf);
// anyone there? if so just attack. // anyone there? if so just attack.
if (c->lf) { if (c->lf) {
@ -330,7 +331,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
real_getobname(priwep, wepname, priwep->amt, B_NOPREMODS, real_getobname(priwep, wepname, priwep->amt, B_NOPREMODS,
B_NOCONDITION, B_BLINDADJUST, B_NOCONDITION, B_BLINDADJUST,
B_NOBLESSINGS, B_NOUSED, B_NOSHOWALL); B_NOBLESSINGS, B_NOUSED, B_NOSHOWALL);
snprintf(buf, BUFLEN, "Attacking %s might rust your %s - proceed anyway?",victimname, wepname); snprintf(buf, BUFLEN, "Attacking %s might rust your %s - proceed anyway?",victimname, noprefix(wepname));
if (!warnabout(buf)) { if (!warnabout(buf)) {
return B_TRUE; return B_TRUE;
} }
@ -1545,7 +1546,12 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
// make noise // make noise
noise(lf->cell, lf, NC_FIGHTING, SV_SHOUT, "fighting.", NULL); // UNLESS this fighting involved the player.
// This is a hack - should really move this check into noise(), and
// implement some way to tell whether a lf is currently fighting the player.
if (!isplayer(lf) && !isplayer(victim)) {
noise(lf->cell, lf, NC_FIGHTING, SV_SHOUT, "fighting.", NULL);
}
if (backstab) { if (backstab) {
practice(lf, SK_BACKSTAB, 1); practice(lf, SK_BACKSTAB, 1);
@ -2165,6 +2171,9 @@ int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE da
int nshields,i; int nshields,i;
if (lf && !cansee(victim, lf)) return B_FALSE; if (lf && !cansee(victim, lf)) return B_FALSE;
if (lfhasflag(victim, F_STUNNED) || !hasfreeaction(victim)) {
return B_FALSE;
}
// need stamina to block // need stamina to block
if (!getstamina(victim)) return B_FALSE; if (!getstamina(victim)) return B_FALSE;

40
data.c
View File

@ -165,9 +165,11 @@ void initcommands(void) {
addcommand(CMD_TURN_SW, CH_TURN_SW, "Turn to face Southwest."); addcommand(CMD_TURN_SW, CH_TURN_SW, "Turn to face Southwest.");
addcommand(CMD_TURN_W, CH_TURN_W, "Turn to face West."); addcommand(CMD_TURN_W, CH_TURN_W, "Turn to face West.");
addcommand(CMD_TURN_NW, CH_TURN_NW, "Turn to face Northwest."); addcommand(CMD_TURN_NW, CH_TURN_NW, "Turn to face Northwest.");
// Actions
addcommand(CMD_UP, '<', "Go up stairs."); addcommand(CMD_UP, '<', "Go up stairs.");
addcommand(CMD_DOWN, '>', "Go down stairs, enter a shop/portal."); addcommand(CMD_DOWN, '>', "Go down stairs, enter a shop/portal.");
addcommand(CMD_GO, 'G', "Go to a set position (pathfind).");
// Actions
addcommand(CMD_AGAIN, 'g', "Repeat last action.");
addcommand(CMD_REST, '.', "Rest once."); addcommand(CMD_REST, '.', "Rest once.");
addcommand(CMD_PICKUP, ',', "Pick up something from the ground."); addcommand(CMD_PICKUP, ',', "Pick up something from the ground.");
addcommand(CMD_CLOSE, 'c', "Close a door."); addcommand(CMD_CLOSE, 'c', "Close a door.");
@ -4604,11 +4606,13 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
// l2 // l2
addot(OT_S_ABSORBWOOD, "absorb metal", "Destroys nearby wooden objects to boost caster's mana. Does NOT affect carried or equipped items.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_WARPWOOD, "warp wood", "Causes ^bpower^nd4 damage to all wooden creatures or objects in the target area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the maximum amount of wood which can be absorbed.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_MPCOST, 0, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_BARKSKIN, "barkskin", "Covers the caster with a skin of bark, reducing damage but making them vulnerable to fire.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_BARKSKIN, "barkskin", "Covers the caster with a skin of bark, reducing damage but making them vulnerable to fire.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
@ -4650,13 +4654,11 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL);
addot(OT_S_WARPWOOD, "warp wood", "Causes damage to all wooden objects in the target area.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_ABSORBWOOD, "absorb wood", "Destroys nearby wooden objects to boost caster's mana. Does NOT affect carried or equipped items.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the maximum amount of wood which can be absorbed.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL); addflag(lastot->flags, F_MPCOST, 0, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l3 // l3
addot(OT_S_EVAPORATE, "evaporate", "Instantly converts all water in the given area into scalding steam (including potions).", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_EVAPORATE, "evaporate", "Instantly converts all water in the given area into scalding steam (including potions).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the amount of water affected."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the amount of water affected.");
@ -5441,6 +5443,10 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_LEVELUP, "levelup", "Bestow the given xp level.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_LEVELUP, "levelup", "Bestow the given xp level.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_PATHFIND, "pathfind", "Find a path to the given cell.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_PETIFY, "petify", "Make a monster into your pet.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_S_WISH, "wish", "Grants the caster any item of their choice. Beware - casting this powerful spell will reduce the caster's hit points by 50%.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_WISH, "wish", "Grants the caster any item of their choice. Beware - casting this powerful spell will reduce the caster's hit points by 50%.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL);
@ -5547,7 +5553,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL);
addflag(lastot->flags, F_STAMCOST, 4, NA, NA, NULL); addflag(lastot->flags, F_STAMCOST, 4, NA, NA, NULL);
addot(OT_A_INSPECT, "inspect item", "Try to identify an unknown scroll, book, wand or ring from your pack.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_INSPECT, "inspect item", "Use your Lore skills to identify an unknown item from your pack.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_IRONFIST, "iron fist", "Channel all your remaining stamina into one almighty blow.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_IRONFIST, "iron fist", "Channel all your remaining stamina into one almighty blow.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
@ -6972,7 +6978,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, C_WHITE, ',', NA, NULL); addflag(lastot->flags, F_GLYPH, C_WHITE, ',', NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL);
addflag(lastot->flags, F_DIMONWALK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DIMONDISTURB, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -6980,7 +6986,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, C_YELLOW, ',', NA, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, ',', NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_DIMONWALK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DIMONDISTURB, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_PRODUCESLIGHT, 5, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 5, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -11700,6 +11706,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_SKILLED, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_SKILLED, NA, NULL);
addflag(lastrace->flags, F_STAYINROOM, NA, B_NOCHASE, NA, NULL); // stay in our starting room addflag(lastrace->flags, F_STAYINROOM, NA, B_NOCHASE, NA, NULL); // stay in our starting room
addflag(lastrace->flags, F_MORALE, 2, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 2, NA, NA, NULL);
addflag(lastrace->flags, F_GENDER, G_FEMALE, NA, NA, NULL);
addrace(R_DJINNI, "genie", 65, 'Y', C_YELLOW, MT_FLESH, RC_MAGIC, "Genies are powerful air spirits. They resemble richly dressed humans floating on a cone of whirling air."); addrace(R_DJINNI, "genie", 65, 'Y', C_YELLOW, MT_FLESH, RC_MAGIC, "Genies are powerful air spirits. They resemble richly dressed humans floating on a cone of whirling air.");
setbodytype(lastrace, BT_HUMANOID); setbodytype(lastrace, BT_HUMANOID);
@ -12174,7 +12181,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_RANDOM, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_RANDOM, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, NA, NULL);
@ -14897,7 +14904,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MAXATTACKS, 1, 2, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 1, 2, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 6, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "growls^growling"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "growls^growling");
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 6, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 6, NA, NA, NULL);
@ -19155,6 +19162,7 @@ void initskills(void) {
addskilldesc(SK_LORE_ARCANA, PR_EXPERT, "^gYou can now recognise uncommon wands.", B_TRUE); addskilldesc(SK_LORE_ARCANA, PR_EXPERT, "^gYou can now recognise uncommon wands.", B_TRUE);
addskilldesc(SK_LORE_ARCANA, PR_MASTER, "^gYou can now recognise rare wands.", B_TRUE); addskilldesc(SK_LORE_ARCANA, PR_MASTER, "^gYou can now recognise rare wands.", B_TRUE);
addskill(SK_LORE_CHEMISTRY, "Lore:Chemistry", "Allows you a chance of recognising potions.", 5); addskill(SK_LORE_CHEMISTRY, "Lore:Chemistry", "Allows you a chance of recognising potions.", 5);
free(lastskill->shortname); lastskill->shortname = strdup("Lore:Chem");
addskilldesc(SK_LORE_CHEMISTRY, PR_NOVICE, "^gYou can attempt to identify potions with the 'inspect' ability.^n", B_FALSE); addskilldesc(SK_LORE_CHEMISTRY, PR_NOVICE, "^gYou can attempt to identify potions with the 'inspect' ability.^n", B_FALSE);
addskillabil(SK_LORE_CHEMISTRY, PR_NOVICE, OT_A_INSPECT, NA, NULL, B_FALSE); addskillabil(SK_LORE_CHEMISTRY, PR_NOVICE, OT_A_INSPECT, NA, NULL, B_FALSE);
addskilldesc(SK_LORE_CHEMISTRY, PR_BEGINNER, "^gYou can now recognise very common potions.", B_TRUE); addskilldesc(SK_LORE_CHEMISTRY, PR_BEGINNER, "^gYou can now recognise very common potions.", B_TRUE);
@ -19167,7 +19175,7 @@ void initskills(void) {
addskilldesc(SK_LORE_DEMONS, PR_SKILLED, "^gEvery 50 turns you can summon demons.", B_FALSE); addskilldesc(SK_LORE_DEMONS, PR_SKILLED, "^gEvery 50 turns you can summon demons.", B_FALSE);
addskillabil(SK_LORE_DEMONS, PR_SKILLED, OT_S_SUMMONDEMON, 50, "pw:1", B_FALSE); addskillabil(SK_LORE_DEMONS, PR_SKILLED, OT_S_SUMMONDEMON, 50, "pw:1", B_FALSE);
addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.", 5); addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.", 5);
addskill(SK_LORE_LANGUAGE, "Lore:Linguistics", "Allows you a chance of recognising scrolls and books.", 5); addskill(SK_LORE_LANGUAGE, "Lore:Language", "Allows you a chance of recognising scrolls and books.", 5);
addskilldesc(SK_LORE_LANGUAGE, PR_NOVICE, "^gYou can attempt to identify scrolls/books with the 'inspect' ability.^n", B_FALSE); addskilldesc(SK_LORE_LANGUAGE, PR_NOVICE, "^gYou can attempt to identify scrolls/books with the 'inspect' ability.^n", B_FALSE);
addskillabil(SK_LORE_LANGUAGE, PR_NOVICE, OT_A_INSPECT, NA, NULL, B_FALSE); addskillabil(SK_LORE_LANGUAGE, PR_NOVICE, OT_A_INSPECT, NA, NULL, B_FALSE);
addskillabil(SK_LORE_LANGUAGE, PR_ADEPT, OT_A_STUDYSCROLL, NA, NULL, B_TRUE); addskillabil(SK_LORE_LANGUAGE, PR_ADEPT, OT_A_STUDYSCROLL, NA, NULL, B_TRUE);
@ -19318,7 +19326,7 @@ void initskills(void) {
snprintf(buf, BUFLEN, "^gYou now have common knowledge about %s.^n", rc->pluralname); snprintf(buf, BUFLEN, "^gYou now have common knowledge about %s.^n", rc->pluralname);
addskilldesc(sk->id, PR_NOVICE, buf, B_TRUE); addskilldesc(sk->id, PR_NOVICE, buf, B_TRUE);
snprintf(buf, BUFLEN, "^gYou now know about the powers/abilities of %s.^n", rc->pluralname); snprintf(buf, BUFLEN, "^gYou now know about the abilities of %s.^n", rc->pluralname);
addskilldesc(sk->id, PR_BEGINNER, buf, B_TRUE); addskilldesc(sk->id, PR_BEGINNER, buf, B_TRUE);
snprintf(buf, BUFLEN, "^gYou have now comprehensively studied %s.^n", rc->pluralname); snprintf(buf, BUFLEN, "^gYou have now comprehensively studied %s.^n", rc->pluralname);
addskilldesc(sk->id, PR_ADEPT, buf, B_TRUE); addskilldesc(sk->id, PR_ADEPT, buf, B_TRUE);

Binary file not shown.

29
defs.h
View File

@ -223,6 +223,9 @@
#define MAX_MAPW 80 #define MAX_MAPW 80
#define MAX_MAPH 30 #define MAX_MAPH 30
#define MAX_PATHFIND_ADJ (MAX_MAPW*MAX_MAPH*10)
#define MAX_PATHFIND_STEPS (MAX_MAPW*MAX_MAPH)
#define MAXPILEOBS 52 #define MAXPILEOBS 52
#define MAXRANDOMOBCANDIDATES 100 #define MAXRANDOMOBCANDIDATES 100
@ -1913,6 +1916,8 @@ enum OBTYPE {
OT_A_BLINDALL, OT_A_BLINDALL,
OT_S_CONFISCATE, OT_S_CONFISCATE,
OT_A_DEBUG, OT_A_DEBUG,
OT_A_PATHFIND,
OT_A_PETIFY,
OT_A_ENHANCE, OT_A_ENHANCE,
OT_A_LEARN, OT_A_LEARN,
OT_A_LEVELUP, OT_A_LEVELUP,
@ -2686,10 +2691,12 @@ enum FLAG {
F_CAUSESCOUGH, // being in this ob's cell will make you cough unless F_CAUSESCOUGH, // being in this ob's cell will make you cough unless
// immune to gas. // immune to gas.
// v0 = con skillcheck difficulty. // v0 = con skillcheck difficulty.
F_DIMONWALK, // when a lf walks on this ob, its f_produceslight F_DIMONDISTURB, // when a lf walks on this ob, its f_produceslight
// flag v0 reduces by one. // flag v0 reduces by one.
// if it gets to 0 (or doesnt have produceslight), // if it gets to 0 (or doesnt have produceslight),
// the object will vanish. // the object will vanish.
//
// same happens if object is removed from the ground.
F_BLOCKSVIEW, // if v0 = true, cannot see past this F_BLOCKSVIEW, // if v0 = true, cannot see past this
// if v0 > 0, reduces your vision by v0. // if v0 > 0, reduces your vision by v0.
// if v1 = true then don't block sight if you are // if v1 = true then don't block sight if you are
@ -3482,6 +3489,11 @@ enum FLAG {
// from pet's master // from pet's master
F_FEIGNFOOLEDBY, // lf shouldn't attack lf id v0 because they F_FEIGNFOOLEDBY, // lf shouldn't attack lf id v0 because they
// are feigning death // are feigning death
F_AIPATH, // text = list of coordinates for ai path,
// in form:
// x,y-x,y-x,y-x,y...
//
// v0/v1 = x/y of end cell
F_TARGETLF, // lf will attack lfid v0. lastknown x/y is v1/v2 F_TARGETLF, // lf will attack lfid v0. lastknown x/y is v1/v2
// optional text is last known movement dir. // optional text is last known movement dir.
F_IGNORECELL, // won't accept targetcells of v0=x v1=y F_IGNORECELL, // won't accept targetcells of v0=x v1=y
@ -3498,7 +3510,7 @@ enum FLAG {
// this lf run away. // this lf run away.
// TEMP FLAGS // TEMP FLAGS
F_KILLEDBYPLAYER, // did the player kill this lf? F_KILLEDBYPLAYER, // did the player (or an ally) kill this lf?
// monster noise flags // monster noise flags
F_WALKVERB, // text is verb for moving. 'walk' 'slither' F_WALKVERB, // text is verb for moving. 'walk' 'slither'
// 'bounce' 'hop' etc // 'bounce' 'hop' etc
@ -3856,6 +3868,8 @@ enum FLAG {
F_XRAYVIS, //val0=num of walls we can see through F_XRAYVIS, //val0=num of walls we can see through
F_CANSEETHROUGHMAT, //val0=kind of material you can see through F_CANSEETHROUGHMAT, //val0=kind of material you can see through
F_CANSEETHROUGHLF, // larger lifeforms don't block los for us F_CANSEETHROUGHLF, // larger lifeforms don't block los for us
F_PATHFINDING, // you are following a path via 'G'
// to coords v0,v1 on mapid v2
F_SPRINTING, // you are sprinting. F_SPRINTING, // you are sprinting.
F_WINDSHIELD,// has a windshield protecting against missiles of speed F_WINDSHIELD,// has a windshield protecting against missiles of speed
// v0 or lower. // v0 or lower.
@ -4202,6 +4216,7 @@ enum COMMAND {
CMD_TURN_W, CMD_TURN_W,
CMD_TURN_NW, CMD_TURN_NW,
// //
CMD_AGAIN,
CMD_AIM, CMD_AIM,
CMD_CLOSE, CMD_CLOSE,
CMD_COMMS, CMD_COMMS,
@ -4212,6 +4227,7 @@ enum COMMAND {
CMD_FIRE, CMD_FIRE,
CMD_FIRENEW, CMD_FIRENEW,
CMD_FORCEATTACK, CMD_FORCEATTACK,
CMD_GO,
CMD_GUNRELOAD, CMD_GUNRELOAD,
CMD_HELP, CMD_HELP,
CMD_INFOARMOUR, CMD_INFOARMOUR,
@ -5003,6 +5019,7 @@ typedef struct choice_s {
char *longdesc; // what to display once you've selected this char *longdesc; // what to display once you've selected this
void *data; void *data;
int heading; int heading;
int hilite;
int shortcutslot; // used when selecting spells/abilities int shortcutslot; // used when selecting spells/abilities
int valid; // used in askchoicestr int valid; // used in askchoicestr
} choice_t; } choice_t;
@ -5050,8 +5067,16 @@ typedef struct prompt_s {
int selection; int selection;
int nchoices; int nchoices;
int maycancel; int maycancel;
int hilite;
} prompt_t; } prompt_t;
// for a* pathfinding
typedef struct node_s {
struct cell_s *c;
struct node_s *parent;
int fromstart, heur, cost;
} node_t;
#endif #endif

14
flag.c
View File

@ -73,6 +73,10 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
known = B_KNOWN; known = B_KNOWN;
} }
if (fp->owner && (id == F_VAULTISPLAYERSTART)) {
dblog("added vaultisplayerstart");
}
if (id == F_INTERRUPTED) { if (id == F_INTERRUPTED) {
if (fp->owner == player) { if (fp->owner == player) {
dblog("player got interrupted"); dblog("player got interrupted");
@ -562,6 +566,16 @@ int countflagsofid(flagpile_t *fp, enum FLAG fid) {
return count; return count;
} }
void dumpflags(flagpile_t *fp) {
flag_t *f;
dblog("START FLAGDUMP");
for (f = fp->first ; f ; f = f->next) {
dblog("fid=%d, v0=%d v1=%d v2=%d text=[%s]",
f->id, f->val[0], f->val[1], f->val[2], f->text);
}
dblog("END FLAGDUMP");
}
// returns TRUE if knowingly gaining/losing this flag will // returns TRUE if knowingly gaining/losing this flag will
// interrupt player actions like resting, training or eating. // interrupt player actions like resting, training or eating.
int flagcausesinterrupt(flag_t *f, enum GAINORLOSS gol ) { int flagcausesinterrupt(flag_t *f, enum GAINORLOSS gol ) {

1
flag.h
View File

@ -18,6 +18,7 @@ int copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id);
void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime); void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime);
int countflags(flagpile_t *fp); int countflags(flagpile_t *fp);
int countflagsofid(flagpile_t *fp, enum FLAG fid ); int countflagsofid(flagpile_t *fp, enum FLAG fid );
void dumpflags(flagpile_t *fp);
int flagcausesinterrupt(flag_t *f, enum GAINORLOSS gol); int flagcausesinterrupt(flag_t *f, enum GAINORLOSS gol);
int flagcausesloscalc(enum FLAG fid); int flagcausesloscalc(enum FLAG fid);
int flagcausesredraw(lifeform_t *lf, enum FLAG fid); int flagcausesredraw(lifeform_t *lf, enum FLAG fid);

43
god.c
View File

@ -562,7 +562,7 @@ void dooffer(void) {
} }
// which god? // which god?
god = askgod("To whom will you sacrifice?", B_TRUE); god = askgod("To whom will you sacrifice?", B_TRUE, B_FALSE);
if (!god) { if (!god) {
msg("Cancelled."); msg("Cancelled.");
return; return;
@ -911,6 +911,9 @@ void givegodbonus(enum RACE rid, flag_t *bf) {
} }
more(); more();
// increment piety so that it doesn't keep bouncing around the border.
modpiety(rid, PIETYPRAYLOSS);
// parse regular rags // parse regular rags
parsegodbonusargs(bf, &bonuslev, &bonusid, &arg, targ); parsegodbonusargs(bf, &bonuslev, &bonusid, &arg, targ);
@ -969,31 +972,31 @@ void removegodbonus(enum RACE rid, flag_t *bf) {
// god announcement. // god announcement.
switch (rid) { switch (rid) {
case R_GODPURITY: case R_GODPURITY:
godsay(rid, B_TRUE, "I am not impressed, mortal."); godsay(rid, B_TRUE, "Your service is lacking, mortal.");
break; break;
case R_GODTHIEVES: case R_GODTHIEVES:
godsay(rid, B_TRUE, "Disloyalty deserves punishment."); godsay(rid, B_TRUE, "I expect more results, mortal.");
break; break;
case R_GODDEATH: case R_GODDEATH:
godsay(rid, B_TRUE, "Disobediant servants can easily be removed..."); godsay(rid, B_TRUE, "Lazy servants can easily be removed...");
break; break;
case R_GODFIRE: case R_GODFIRE:
godsay(rid, B_TRUE, "WRONG!"); godsay(rid, B_TRUE, "PAY ATTENTION!");
break; break;
case R_GODLIFE: case R_GODLIFE:
godsay(rid, B_TRUE, "No, no, no..."); godsay(rid, B_TRUE, "You must be more proactive, my child.");
break; break;
case R_GODMERCY: case R_GODMERCY:
godsay(rid, B_TRUE, "You disappoint me..."); godsay(rid, B_TRUE, "You lack of proactiveness is disappointing...");
break; break;
case R_GODNATURE: case R_GODNATURE:
godsay(rid, B_TRUE, "Nature will not tolerate your transgressions."); godsay(rid, B_TRUE, "Nature will not tolerate the lazy.");
break; break;
case R_GODBATTLE: case R_GODBATTLE:
godsay(rid, B_TRUE, "You have earned yourself a demotion, soldier."); godsay(rid, B_TRUE, "Your slothfulness has earned you a demotion, soldier.");
break; break;
case R_GODMAGIC: case R_GODMAGIC:
godsay(rid, B_TRUE, "One is deviating from the path!"); godsay(rid, B_TRUE, "One must always strive towards the path!");
break; break;
default: default:
break; break;
@ -1985,7 +1988,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
taketime(lf, getactspeed(lf)); taketime(lf, getactspeed(lf));
if (godblocked(god->race->id)) { if (godblocked(god->race->id)) {
msg("%s ignores you.", god->race->name); msg("%s doesn't respond.", god->race->name);
return B_TRUE; return B_TRUE;
} }
@ -1999,13 +2002,6 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
// god before // god before
piety = getpiety(god->race->id); piety = getpiety(god->race->id);
// remember that we have now prayed to this god.
// ie. player is expected to follow the god's rules.
if (!hasflag(god->flags, F_PRAYEDTO)) {
addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL);
newgod = B_TRUE;
}
if (godisangry(god->race->id)) { if (godisangry(god->race->id)) {
// get even more angry // get even more angry
angergod(god->race->id, PIETYPRAYLOSS, GA_PRAY); angergod(god->race->id, PIETYPRAYLOSS, GA_PRAY);
@ -2015,7 +2011,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
if (piety <= 99) { if (piety <= 99) {
// piety between 0 and 99 = ignored // piety between 0 and 99 = ignored
//godsay(god->race->id, "Stop pestering me!"); //godsay(god->race->id, "Stop pestering me!");
msg("%s doesn't respond.", god->race->name); msg("%s ignores you.", god->race->name);
angergod(god->race->id, 0, GA_PRAY); angergod(god->race->id, 0, GA_PRAY);
modpiety(god->race->id, -30); modpiety(god->race->id, -30);
return B_FALSE; return B_FALSE;
@ -2059,6 +2055,15 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
} }
godsay(god->race->id, B_TRUE, assisttext); godsay(god->race->id, B_TRUE, assisttext);
// at this point, remember that we have now prayed to
// this god. ie. player is expected to follow the god's rules.
if (!hasflag(god->flags, F_PRAYEDTO)) {
addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL);
newgod = B_TRUE;
}
switch (god->race->id) { switch (god->race->id) {
lifeform_t *l; lifeform_t *l;
int dist; int dist;

88
io.c
View File

@ -109,6 +109,7 @@ choice_t *addchoice(prompt_t *p, char ch, char *text, char *desc, void *data, ch
else p->choice[p->nchoices].longdesc = strdup(""); else p->choice[p->nchoices].longdesc = strdup("");
p->choice[p->nchoices].data = data; p->choice[p->nchoices].data = data;
p->choice[p->nchoices].heading = B_FALSE; p->choice[p->nchoices].heading = B_FALSE;
p->choice[p->nchoices].hilite = B_FALSE;
p->choice[p->nchoices].valid = B_TRUE; p->choice[p->nchoices].valid = B_TRUE;
p->choice[p->nchoices].shortcutslot = -1; p->choice[p->nchoices].shortcutslot = -1;
p->nchoices++; p->nchoices++;
@ -3075,7 +3076,7 @@ int confirm_injury_action(enum BODYPART bp, enum DAMTYPE dt, char *actionname) {
return B_TRUE; return B_TRUE;
} }
lifeform_t *askgod(char *prompttext, int onlyprayed) { lifeform_t *askgod(char *prompttext, int onlyprayed, int forpray) {
lifeform_t *lf = NULL; lifeform_t *lf = NULL;
int i; int i;
char *longdesc; char *longdesc;
@ -3087,6 +3088,7 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) {
for (i = 0 ; i < ngodlfs; i++) { for (i = 0 ; i < ngodlfs; i++) {
flag_t *f; flag_t *f;
choice_t *chc;
char godof[BUFLEN],buf[BUFLEN]; char godof[BUFLEN],buf[BUFLEN];
lf = godlf[i]; lf = godlf[i];
if (!lf) continue; if (!lf) continue;
@ -3094,14 +3096,28 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) {
if (onlyprayed && !lfhasflag(lf, F_PRAYEDTO)) { if (onlyprayed && !lfhasflag(lf, F_PRAYEDTO)) {
continue; continue;
} }
if (forpray && godblocked(lf->race->id)) {
continue;
}
real_getlfname(lf, buf, NULL, B_NOSHOWALL, B_REALRACE); real_getlfname(lf, buf, NULL, B_NOSHOWALL, B_REALRACE);
f = hasflag(lf->flags, F_GODOF); f = hasflag(lf->flags, F_GODOF);
snprintf(godof, BUFLEN, " (%s of %s)", (getgender(lf) == G_FEMALE) ? "goddess" : "god", f->text); snprintf(godof, BUFLEN, " (%s of %s)", (getgender(lf) == G_FEMALE) ? "goddess" : "god", f->text);
if (godblocked(lf->race->id)) {
strcat(godof, " [exiled]");
} else if (godprayedto(lf->race->id)) {
strcat(godof, " [worshipped]");
}
strcat(buf, godof); strcat(buf, godof);
makedesc_god(lf, longdesc); makedesc_god(lf, longdesc);
addchoice(&prompt, tolower(buf[0]), buf, NULL, lf, longdesc); chc = addchoice(&prompt, tolower(buf[0]), buf, NULL, lf, longdesc);
if (godblocked(lf->race->id)) {
chc->hilite = C_RED;
} else if (godprayedto(lf->race->id)) {
chc->hilite = C_GREEN;
}
} }
free(longdesc); free(longdesc);
@ -8814,7 +8830,7 @@ void dohelp(char helpmode) {
centre(mainwin,C_WHITE, 0, "GOD REFERENCE"); centre(mainwin,C_WHITE, 0, "GOD REFERENCE");
y = 2; y = 2;
god = askgod("Describe which god (ESC when done)?", B_FALSE); god = askgod("Describe which god (ESC when done)?", B_FALSE, B_FALSE);
if (!god) { if (!god) {
done = B_TRUE; done = B_TRUE;
} else { } else {
@ -9868,7 +9884,9 @@ char getchoice(prompt_t *prompt) {
mvwprintw(mainwin, y, 0, "%s", prompt->choice[i].desc); mvwprintw(mainwin, y, 0, "%s", prompt->choice[i].desc);
wattroff(mainwin, A_REVERSE); wattroff(mainwin, A_REVERSE);
} else { } else {
if (prompt->choice[i].hilite) setcol(mainwin, prompt->choice[i].hilite);
mvwprintw(mainwin, y, 0, "%s%c - %s", indenttext, prompt->choice[i].ch, prompt->choice[i].desc); mvwprintw(mainwin, y, 0, "%s%c - %s", indenttext, prompt->choice[i].ch, prompt->choice[i].desc);
if (prompt->choice[i].hilite) unsetcol(mainwin, prompt->choice[i].hilite);
} }
y++; y++;
} }
@ -10516,7 +10534,7 @@ void handleinput(void) {
} }
gotcmd = B_FALSE; gotcmd = B_FALSE;
break; break;
case 'g': // repeat last command case CMD_AGAIN: // repeat last command
f = hasflag(player->flags, F_LASTCMD); f = hasflag(player->flags, F_LASTCMD);
if (f) { if (f) {
ch = f->text[0]; ch = f->text[0];
@ -10618,12 +10636,15 @@ void handleinput(void) {
doattackcell('\0'); doattackcell('\0');
} }
break; break;
case CMD_INV: // inventory case CMD_GO: // go somewhere (pathfind)
doinventory(player->pack); startpathfind();
break; break;
case CMD_HELP: // help case CMD_HELP: // help
dohelp('?'); dohelp('?');
break; break;
case CMD_INV: // inventory
doinventory(player->pack);
break;
case CMD_INFOPLAYER: // display player stats case CMD_INFOPLAYER: // display player stats
showlfstats(player, B_FALSE); showlfstats(player, B_FALSE);
break; break;
@ -13896,6 +13917,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s do not forget your surroundings.", you(lf)); mvwprintw(mainwin, y, 0, "%s do not forget your surroundings.", you(lf));
y++; y++;
} }
f = hasflag_real(lf->flags, F_PLANTFRIEND, NA, NULL, FROMRACE);
if (f) {
mvwprintw(mainwin, y, 0, "Plants are friendly towards %s.", you(lf));
y++;
}
f = hasflag_real(lf->flags, F_POLYIMMUNE, NA, NULL, FROMRACE); f = hasflag_real(lf->flags, F_POLYIMMUNE, NA, NULL, FROMRACE);
if (f) { if (f) {
mvwprintw(mainwin, y, 0, "%s cannot be polymorphed.", you(lf)); mvwprintw(mainwin, y, 0, "%s cannot be polymorphed.", you(lf));
@ -14019,7 +14045,7 @@ void showlfstats(lifeform_t *lf, int showall) {
wattroff(mainwin, A_UNDERLINE); wattroff(mainwin, A_UNDERLINE);
y = 2; y = 2;
snprintf(line, BUFLEN, "%-30s Prayed? %-22s %s","God","Piety", "Happiness"); snprintf(line, BUFLEN, "%-29s Worship? %-22s %s","God","Piety", "Happiness");
doheading(mainwin, &y, 0, line); doheading(mainwin, &y, 0, line);
@ -14055,7 +14081,7 @@ void showlfstats(lifeform_t *lf, int showall) {
if (blocked) { if (blocked) {
col = C_RED; col = C_RED;
strcpy(happiness, "Ignored"); strcpy(happiness, "Exiled");
} else { } else {
plev = getpietylev(god->race->id, &col, happiness); plev = getpietylev(god->race->id, &col, happiness);
} }
@ -14161,6 +14187,52 @@ void showlfstats(lifeform_t *lf, int showall) {
//redraw(); //redraw();
} }
void showpath(lifeform_t *lf) {
flag_t *f;
char buf[BUFLEN];
cell_t *c;
real_getlfname(lf, buf, NULL, B_SHOWALL, B_CURRACE);
cls();
wmove(mainwin, 0, 0);
f = lfhasflag(lf, F_AIPATH);
wprintw(mainwin, "flagtext is: [%s]\n", f->text);
wprintw(mainwin, "Path for %s (%d,%d -> %d,%d) is:\n", buf,
lf->cell->x, lf->cell->y, f->val[0], f->val[1]);
c = ai_getnextcellinpath(lf);
while (c) {
wprintw(mainwin, "%d,%d ->\n", c->x, c->y);
ai_popnextcellinpath(lf);
c = ai_getnextcellinpath(lf);
}
wprintw(mainwin, "END. (press key to exit)");
getch();
restoregamewindows();
}
void startpathfind(void) {
cell_t *c = NULL;
c = askcoords("Go to where?", "Goto->", TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (!c) {
msg("Cancelled.");
return;
}
if (!c->known ||
(c->map != player->cell->map) ||
(haslos(player, c) && !cellwalkable(player, c, NULL))) {
msg("You don't know how to get there.");
return;
}
// try to find path.
if (ai_createpathto(player, c)) {
addflag(player->flags, F_PATHFINDING, c->x, c->y, player->cell->map->id, NULL);
} else {
msg("You don't know how to get there.");
}
}
void textwithcol(WINDOW *win, char *buf) { void textwithcol(WINDOW *win, char *buf) {
textwithcol_real(win, buf, B_TRUE); textwithcol_real(win, buf, B_TRUE);
} }

4
io.h
View File

@ -20,7 +20,7 @@ void announceobflagloss(object_t *o, flag_t *f);
void announcetime(int h, int m, int s, int showfull); void announcetime(int h, int m, int s, int showfull);
int confirm_badfeeling(object_t *o); int confirm_badfeeling(object_t *o);
int confirm_injury_action(enum BODYPART bp, enum DAMTYPE dt, char *actionname); int confirm_injury_action(enum BODYPART bp, enum DAMTYPE dt, char *actionname);
lifeform_t *askgod(char *prompt, int onlyprayed); lifeform_t *askgod(char *prompt, int onlyprayed, int forpray);
object_t *askobject(obpile_t *op, char *title, char *noobtext, int *count, char action, long opts); object_t *askobject(obpile_t *op, char *title, char *noobtext, int *count, char action, long opts);
object_t *askobjectwithflag(obpile_t *op, char *title, char *noobtext,int *count, char action, long opts, enum FLAG withflag); object_t *askobjectwithflag(obpile_t *op, char *title, char *noobtext,int *count, char action, long opts, enum FLAG withflag);
object_t *doaskobject(obpile_t *op, char *prompt, char *noobtext, int *count, int showlong, int forpickup, int showpoints, char action, object_t *sellshop, enum SHOPACTION sellaction, int wantmaterial, long opts, ...); object_t *doaskobject(obpile_t *op, char *prompt, char *noobtext, int *count, int showlong, int forpickup, int showpoints, char action, object_t *sellshop, enum SHOPACTION sellaction, int wantmaterial, long opts, ...);
@ -141,6 +141,8 @@ void setobcolour(WINDOW *win, object_t *o, int set);
int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname); int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname);
void showlfarmour(lifeform_t *lf); void showlfarmour(lifeform_t *lf);
void showlfstats(lifeform_t *lf, int showall); void showlfstats(lifeform_t *lf, int showall);
void showpath(lifeform_t *lf);
void startpathfind(void);
void textwithcol(WINDOW *win, char *buf); void textwithcol(WINDOW *win, char *buf);
void textwithcol_real(WINDOW *win, char *buf, int resetcolatend); void textwithcol_real(WINDOW *win, char *buf, int resetcolatend);
void tombstone(lifeform_t *lf); void tombstone(lifeform_t *lf);

54
lf.c
View File

@ -2050,8 +2050,8 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
} }
} else { } else {
if (hasflag(sp->flags, F_CASTINGTIME)) { if (hasflag(sp->flags, F_CASTINGTIME)) {
} else {
msg("%s starts casting a spell.", lfname); msg("%s starts casting a spell.", lfname);
} else {
} }
} }
} else { // player can't see them } else { // player can't see them
@ -2375,9 +2375,13 @@ int charmedaction(lifeform_t *lf, flag_t *charmflag) {
} else { } else {
if (isplayer(lf)) { if (isplayer(lf)) {
char obname[BUFLEN]; char obname[BUFLEN];
char mastername[BUFLEN];
sprintf(mastername, "your new %s",
(getgender(charmer) == G_FEMALE) ?
"mistress" : "master");
getobname(o, obname, o->amt); getobname(o, obname, o->amt);
msg("^wYou hand over your %s to %s.", noprefix(obname), msg("^wYou hand over your %s to %s.", noprefix(obname),
cansee(lf, charmer) ? charmername : "your new master"); cansee(lf, charmer) ? charmername : mastername);
} else if (cansee(player, lf)) { } else if (cansee(player, lf)) {
char lfname[BUFLEN]; char lfname[BUFLEN];
char obname[BUFLEN]; char obname[BUFLEN];
@ -4128,10 +4132,6 @@ void generatealignment(lifeform_t *lf) {
initprompt(&prompt, buf); initprompt(&prompt, buf);
if (isplayer(lf)) {
dblog("xx");
}
if (nposs == 0) { if (nposs == 0) {
if (isplayer(lf)) { if (isplayer(lf)) {
assert("Error - no possible alignment for player." == 0); assert("Error - no possible alignment for player." == 0);
@ -4764,6 +4764,8 @@ int eat(lifeform_t *lf, object_t *o) {
if (strlen(taste)) msg("%s", taste); if (strlen(taste)) msg("%s", taste);
} else if (cansee(player, lf)) { } else if (cansee(player, lf)) {
msg("%s finishes %s.", lfname, drinking ? "drinking" : "eating"); msg("%s finishes %s.", lfname, drinking ? "drinking" : "eating");
} else {
noise(lf->cell, lf, NC_OTHER, SV_TALK, drinking ? "something being quaffed." : "something being eaten.", NULL);
} }
} else { } else {
if (isplayer(lf)) { if (isplayer(lf)) {
@ -4771,6 +4773,8 @@ int eat(lifeform_t *lf, object_t *o) {
if (strlen(taste)) msg("%s", taste); if (strlen(taste)) msg("%s", taste);
} else if (cansee(player, lf)) { } else if (cansee(player, lf)) {
msg("%s %s %s.", lfname, drinking ? "drinks" : "eats", obname); msg("%s %s %s.", lfname, drinking ? "drinks" : "eats", obname);
} else {
noise(lf->cell, lf, NC_OTHER, SV_TALK, drinking ? "something being quaffed." : "something being eaten.", NULL);
} }
} }
} else { } else {
@ -4779,6 +4783,8 @@ int eat(lifeform_t *lf, object_t *o) {
msg("You continue %s.", drinking ? "drinking" : "eating"); msg("You continue %s.", drinking ? "drinking" : "eating");
} else if (cansee(player, lf)) { } else if (cansee(player, lf)) {
msg("%s continues %s.", lfname, drinking ? "drinking" : "eating"); msg("%s continues %s.", lfname, drinking ? "drinking" : "eating");
} else {
noise(lf->cell, lf, NC_OTHER, SV_TALK, drinking ? "something being quaffed." : "something being eaten.", NULL);
} }
} else { } else {
if (isplayer(lf)) { if (isplayer(lf)) {
@ -4786,6 +4792,8 @@ int eat(lifeform_t *lf, object_t *o) {
} else if (cansee(player, lf)) { } else if (cansee(player, lf)) {
msg("%s starts %s %s.", lfname, drinking ? "drinking" : "eating", obname); msg("%s starts %s %s.", lfname, drinking ? "drinking" : "eating", obname);
} else {
noise(lf->cell, lf, NC_OTHER, SV_TALK, drinking ? "something being quaffed." : "something being eaten.", NULL);
} }
} }
} }
@ -11110,7 +11118,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) {
spell = getrandomspellfromschool(SS_NATURE, 1); spell = getrandomspellfromschool(SS_NATURE, 1);
} }
// you can now cast it. // you can now cast it.
addflag(lf->flags, F_CANCAST, spell, NA, NA, NULL); addtempflag(lf->flags, F_CANCAST, spell, NA, NA, NULL, FROMJOB);
} }
// druids always worship ekrub // druids always worship ekrub
if (isplayer(lf)) { if (isplayer(lf)) {
@ -11180,7 +11188,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) {
} }
// all starting gear is blessed // all starting gear is blessed
for (o = lf->pack->first ; o ; o = o->next) { for (o = lf->pack->first ; o ; o = o->next) {
if (isequipped(o)) { if (isweapon(o) || isarmour(o) || isshield(o)) {
blessob(o); blessob(o);
} }
} }
@ -11243,7 +11251,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) {
char pwbuf[BUFLEN]; char pwbuf[BUFLEN];
pow = MINOF((gettr(lf)/2), getspellmaxpower(o->type->id)); pow = MINOF((gettr(lf)/2), getspellmaxpower(o->type->id));
sprintf(pwbuf, "pw:%d;", pow); sprintf(pwbuf, "pw:%d;", pow);
addflag(lf->flags, F_CANCAST, o->type->id, NA, NA, pwbuf); addtempflag(lf->flags, F_CANCAST, o->type->id, NA, NA, pwbuf, FROMJOB);
} }
} }
// chance of spellbook vanishing // chance of spellbook vanishing
@ -11282,6 +11290,11 @@ void givejob(lifeform_t *lf, enum JOB jobid) {
} }
*/ */
// call this again, for cases like the paladin.
if ((gamemode != GM_GAMESTARTED)) {
autoweild(lf);
}
if (isplayer(lf)) { if (isplayer(lf)) {
generatealignment(lf); generatealignment(lf);
} }
@ -11728,7 +11741,7 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) {
object_t *o = NULL; object_t *o = NULL;
flag_t *f; flag_t *f;
char buf[BUFLEN],buf2[BUFLEN]; char buf[BUFLEN],buf2[BUFLEN];
int db = B_TRUE; int db = B_FALSE;
obpile_t *op; obpile_t *op;
map_t *targmap; map_t *targmap;
enum LFSIZE maxobsize = SZ_MAX; enum LFSIZE maxobsize = SZ_MAX;
@ -13581,7 +13594,11 @@ void killlf(lifeform_t *lf) {
// shouldn't need this... // shouldn't need this...
lf->cell = NULL; lf->cell = NULL;
// remove impossible flags... // remove impossible stuff
if (getstamina(lf) > getmaxstamina(lf)) {
setstamina(lf, getmaxstamina(lf));
}
// check if anyone is targetting us. // check if anyone is targetting us.
// if so, stop targetting us now that // if so, stop targetting us now that
// we are dead. // we are dead.
@ -18544,12 +18561,12 @@ int startclimbing(lifeform_t *lf) {
} }
} else { } else {
// you need to climbing skill to climb walls // you need to climbing skill to climb walls
if (!getskill(lf, SK_CLIMBING)) { if (!getskill(lf, SK_CLIMBING) && !lfhasflag(lf, F_SPIDERCLIMB)) {
if (isplayer(lf)) { if (isplayer(lf)) {
msg("You are not sufficiently skilled to climb walls."); msg("You are not sufficiently skilled to climb walls.");
} }
return B_TRUE; return B_TRUE;
} if (skillcheck(lf, SC_CLIMB, getcellclimbdifficulty(where), 0)) { } else if (skillcheck(lf, SC_CLIMB, getcellclimbdifficulty(where), 0)) {
// announce // announce
if (isplayer(lf)) { if (isplayer(lf)) {
msg("You climb onto %s %s.", needan(where->type->name) ? "an" : "a", where->type->name); msg("You climb onto %s %s.", needan(where->type->name) ? "an" : "a", where->type->name);
@ -19932,6 +19949,7 @@ void interrupt(lifeform_t *lf) {
stopeating(lf); stopeating(lf);
stopresting(lf); stopresting(lf);
stoprunning(lf); stoprunning(lf);
stoppathfinding(lf);
killflagsofid(lf->flags, F_AUTOCMD); killflagsofid(lf->flags, F_AUTOCMD);
killflagsofid(lf->flags, F_DIGGING); killflagsofid(lf->flags, F_DIGGING);
} }
@ -20913,7 +20931,7 @@ void startlfturn(lifeform_t *lf) {
} else { } else {
msg("^wAll of your items are missing!^n"); more(); msg("^wAll of your items are missing!^n"); more();
} }
} else { } else if (cantalk(lf)) {
sayphrase(lf, SP_ROBBED, SV_SHOUT, NA, NULL, NULL); sayphrase(lf, SP_ROBBED, SV_SHOUT, NA, NULL, NULL);
} }
killflagsofid(lf->flags, F_WASROBBED); killflagsofid(lf->flags, F_WASROBBED);
@ -21160,8 +21178,12 @@ void startlfturn(lifeform_t *lf) {
// the further away from neutral you are, the less chance // the further away from neutral you are, the less chance
// piety/anger has of 'expiring' // piety/anger has of 'expiring'
if (pctchance(chance)) { if (pctchance(chance)) {
enum PIETYLEV newplev,oldplev;
// slowly move towards normal // slowly move towards normal
oldplev = getpietylev(godlf[i]->race->id, NULL, NULL);
modpiety(godlf[i]->race->id, dir); modpiety(godlf[i]->race->id, dir);
newplev = getpietylev(godlf[i]->race->id, NULL, NULL);
checkgodbonus(godlf[i]->race->id,newplev, oldplev);
} }
} }
} }
@ -22590,6 +22612,10 @@ int stopclimbing(lifeform_t *lf, int onpurpose) {
return B_FALSE; return B_FALSE;
} }
void stoppathfinding(lifeform_t *lf) {
killflagsofid(lf->flags, F_PATHFINDING);
}
void stopresting(lifeform_t *lf) { void stopresting(lifeform_t *lf) {
flag_t *f; flag_t *f;

1
lf.h
View File

@ -493,6 +493,7 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag);
int stone(lifeform_t *lf); int stone(lifeform_t *lf);
int stopclimbing(lifeform_t *lf, int onpurpose); int stopclimbing(lifeform_t *lf, int onpurpose);
void stopeating(lifeform_t *lf); void stopeating(lifeform_t *lf);
void stoppathfinding(lifeform_t *lf);
void stopresting(lifeform_t *lf); void stopresting(lifeform_t *lf);
void stoprunning(lifeform_t *lf); void stoprunning(lifeform_t *lf);
void stopsprinting(lifeform_t *lf); void stopsprinting(lifeform_t *lf);

3
map.c
View File

@ -6426,7 +6426,7 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags,
// if monster is in a vault, check its flags... // if monster is in a vault, check its flags...
v = getcellvault(lf->cell); v = getcellvault(lf->cell);
if (v) { if (v) {
copyflags(lf->flags, v->flags, F_STAYINROOM); copyflag(lf->flags, v->flags, F_STAYINROOM);
} }
if (lf->race->id == R_HYDRA) { if (lf->race->id == R_HYDRA) {
@ -6460,6 +6460,7 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags,
} }
} }
*/ */
autoskill(lf);
} }
celltype_t *findcelltype(enum CELLTYPE cid) { celltype_t *findcelltype(enum CELLTYPE cid) {

86
move.c
View File

@ -1486,7 +1486,7 @@ int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) {
} }
continue; continue;
} }
if (hasflag(o->flags, F_DIMONWALK)) { if (hasflag(o->flags, F_DIMONDISTURB)) {
f = hasflag(o->flags, F_PRODUCESLIGHT); f = hasflag(o->flags, F_PRODUCESLIGHT);
getobname(o, obname, o->amt); getobname(o, obname, o->amt);
if (f) f->val[0]--; if (f) f->val[0]--;
@ -1505,7 +1505,7 @@ int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) {
didmsg = B_TRUE; didmsg = B_TRUE;
} }
} }
} // end if dimonwalk } // end if dimondisturb
} // end if crushable } // end if crushable
if ((o->type->id == OT_VINE) && !hasjob(lf, J_DRUID)) { if ((o->type->id == OT_VINE) && !hasjob(lf, J_DRUID)) {
@ -1913,7 +1913,11 @@ int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe) {
} }
// move towards them // move towards them
dir = getdirtowards(lf->cell, dst, lf, B_TRUE, dirtype); if (isadjacent(lf->cell, dst)) {
dir = whichwayto(lf->cell, dst, lf, B_TRUE);
} else {
dir = getdirtowards(lf->cell, dst, lf, B_TRUE, dirtype);
}
if (dir != D_NONE) { if (dir != D_NONE) {
if (db) { if (db) {
dblog(".oO { dir from %d,%d -> %d,%d is %s }", lf->cell->x, lf->cell->y, dst->x, dst->y, getdirname(dir)); dblog(".oO { dir from %d,%d -> %d,%d is %s }", lf->cell->x, lf->cell->y, dst->x, dst->y, getdirname(dir));
@ -2073,6 +2077,7 @@ int opendoor(lifeform_t *lf, object_t *o) {
// trapped? // trapped?
if (lf && hasflag(o->flags, F_TRAPPED)) { if (lf && hasflag(o->flags, F_TRAPPED)) {
if (doobtraps(o, lf)) { if (doobtraps(o, lf)) {
if (isplayer(lf)) stoppathfinding(lf);
return B_TRUE; return B_TRUE;
} }
} }
@ -2095,8 +2100,9 @@ int opendoor(lifeform_t *lf, object_t *o) {
} }
} }
} }
if (isplayer(lf)) stoppathfinding(lf);
return B_TRUE; return B_TRUE;
} else {// ie. door not locked, but it might be jammed } else { // ie. door not locked, but it might be jammed
int openit = B_TRUE; int openit = B_TRUE;
f = hasflag(o->flags, F_JAMMED); f = hasflag(o->flags, F_JAMMED);
if (f && lf) { if (f && lf) {
@ -2156,6 +2162,7 @@ int opendoor(lifeform_t *lf, object_t *o) {
} }
} // end if jammedknown } // end if jammedknown
} // end if jammed } // end if jammed
if (openit) { if (openit) {
cell_t *where; cell_t *where;
// open it // open it
@ -2171,7 +2178,6 @@ int opendoor(lifeform_t *lf, object_t *o) {
if (isplayer(lf)) { if (isplayer(lf)) {
msg("You force %s open!",obname); msg("You force %s open!",obname);
} else { } else {
//if (cansee(player, lf) && isadjacent(lf->cell, doorcell)) {
if (cansee(player, lf)) { if (cansee(player, lf)) {
getlfname(lf, buf); getlfname(lf, buf);
capitalise(buf); capitalise(buf);
@ -2202,9 +2208,8 @@ int opendoor(lifeform_t *lf, object_t *o) {
noise(doorcell, NULL, NC_OTHER, SV_TALK, noisebuf, NULL); noise(doorcell, NULL, NC_OTHER, SV_TALK, noisebuf, NULL);
} }
} }
} } // end if wasjammed
} // end if lf
}
where = getoblocation(o); where = getoblocation(o);
if (player) { if (player) {
@ -2220,10 +2225,16 @@ int opendoor(lifeform_t *lf, object_t *o) {
noise(where, NULL, NC_OTHER, SV_TALK, "a door opening.", NULL); noise(where, NULL, NC_OTHER, SV_TALK, "a door opening.", NULL);
} }
} }
} else {
// !openit
if (isplayer(lf)) {
stoppathfinding(lf);
}
} }
return B_FALSE; return B_FALSE;
} // end if door locked }
}
} // end if door locked
return B_FALSE; return B_FALSE;
} }
@ -3217,7 +3228,10 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
if (isplayer(lf)) { if (isplayer(lf)) {
if (cell->known) { if (cell->known) {
// try to open it // try to open it
if (!opendoor(lf, inway)) { if (opendoor(lf, inway)) {
// failed.
if (isplayer(lf)) stoppathfinding(lf);
} else {
// opening a door counts as a successful move. // opening a door counts as a successful move.
reason = E_OK; reason = E_OK;
} }
@ -3227,6 +3241,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
snprintf(buf, BUFLEN, "%sing into a door", getmoveverb(lf)); snprintf(buf, BUFLEN, "%sing into a door", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf); losehp(lf, 1, DT_BASH, NULL, buf);
if (onpurpose || fleeing) taketime(lf, getmovespeed(lf)); if (onpurpose || fleeing) taketime(lf, getmovespeed(lf));
if (isplayer(lf)) stoppathfinding(lf);
} }
} else { } else {
if (cansee(player, lf)) { if (cansee(player, lf)) {
@ -3238,14 +3253,18 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
snprintf(buf, BUFLEN, "%sing into a door", getmoveverb(lf)); snprintf(buf, BUFLEN, "%sing into a door", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf); losehp(lf, 1, DT_BASH, NULL, buf);
if (onpurpose || fleeing) taketime(lf, getmovespeed(lf)); if (onpurpose || fleeing) taketime(lf, getmovespeed(lf));
if (isplayer(lf)) stoppathfinding(lf);
} }
} else { } else {
if (lfhasflag(lf, F_RAGE)) { if (lfhasflag(lf, F_RAGE) || !canopendoors(lf)) {
// attack it // attack it
return attackcell(lf, cell, B_FALSE); return attackcell(lf, cell, B_FALSE);
} else { } else {
// try to open it // try to open it
if (!opendoor(lf, inway)) { if (opendoor(lf, inway)) {
// fail
if (isplayer(lf)) stoppathfinding(lf);
} else {
// opening a door counts as a successful move. // opening a door counts as a successful move.
reason = E_OK; reason = E_OK;
} }
@ -3584,6 +3603,47 @@ int walkoffmap(lifeform_t *lf, int dir, int onpurpose) {
return B_FALSE; return B_FALSE;
} }
// returns direction to an adjacent cell
int whichwayto(cell_t *start, cell_t *end, lifeform_t *srclf, int wantcheck) {
int i;
cell_t *c;
for (i = DC_N; i <= DC_NW; i++) {
c = getcellindir(start, i);
if (c == end) {
int ok = B_FALSE;
enum ERROR error = E_OK;
if (wantcheck) {
if (srclf) {
if (canandwillmove(srclf, i, &error)) {
ok = B_TRUE;
} else if (error == E_DOORINWAY) {
ok = B_TRUE;
}
} else {
ok = B_TRUE;
}
} else {
if (srclf) {
if (cellwalkable(srclf, c, &error)) {
ok = B_TRUE;
} else if (error == E_DOORINWAY) {
ok = B_TRUE;
}
} else {
ok = B_TRUE;
}
}
if (ok) {
return i;
} else {
return getdirtowards(start, end, srclf, wantcheck, DT_ORTH);
}
}
}
return D_NONE;
}
int willmove(lifeform_t *lf, int dir, enum ERROR *error) { int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell; cell_t *cell;
enum ATTRBRACKET iq; enum ATTRBRACKET iq;

1
move.h
View File

@ -38,4 +38,5 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe);
int tryrun(lifeform_t *lf, int dir); int tryrun(lifeform_t *lf, int dir);
int trysneak(lifeform_t *lf, int dir); int trysneak(lifeform_t *lf, int dir);
int walkoffmap(lifeform_t *lf, int dir, int onpurpose); int walkoffmap(lifeform_t *lf, int dir, int onpurpose);
int whichwayto(cell_t *start, cell_t *end, lifeform_t *srclf, int wantcheck);
int willmove(lifeform_t *lf, int dir, enum ERROR *error); int willmove(lifeform_t *lf, int dir, enum ERROR *error);

44
nexus.c
View File

@ -418,6 +418,11 @@ int main(int argc, char **argv) {
// create pet, in view of player if possible. // create pet, in view of player if possible.
c = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, &avoidob, NULL, player, MT_NOTHING); c = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, &avoidob, NULL, player, MT_NOTHING);
if (!c) {
c = real_getrandomadjcell(player->cell, WE_SOLID, B_NOEXPAND, LOF_DONTNEED, &avoidob, NULL, player, MT_NOTHING);
assert(c);
setcelltype(c, getmapempty(player->cell->map));
}
assert(c); assert(c);
pet = addlf(c, r->id, 1); pet = addlf(c, r->id, 1);
// mark us as its master // mark us as its master
@ -1007,6 +1012,45 @@ void donextturn(map_t *map) {
} }
} }
// pathfinding?
if (donormalmove && isplayer(who)) {
if (lfhasflag(who, F_PATHFINDING)) {
cell_t *c;
// follow.....
c = ai_getnextcellinpath(who);
if (c) {
if (c->map != who->cell->map) {
msg("Destination is on different level. Aborting.");
stoppathfinding(who);
} else {
int dir,ok;
enum ERROR errcode;
donormalmove = B_FALSE;
dir = whichwayto(who->cell, c, who, B_TRUE);
ok = moveclear(who, dir, &errcode);
if (!ok && (errcode != E_DOORINWAY)) {
// something other than a door in the way?
msg("Stopped pathfinding.");
stoppathfinding(who);
} else {
if (trymove(who, dir, B_TRUE, B_FALSE)) {
msg("Can't move towards target cell.");
stoppathfinding(who);
}
if (who->cell == c) {
// success
ai_popnextcellinpath(who);
}
}
}
} else {
msg("Arrived at destination.");
stoppathfinding(who);
}
}
}
// casting a spell? // casting a spell?
if (donormalmove) { if (donormalmove) {
f = lfhasflag(who, F_CASTINGSPELL); f = lfhasflag(who, F_CASTINGSPELL);

View File

@ -475,7 +475,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum
char numstringmax[BUFLEN]; char numstringmax[BUFLEN];
int howmany = 1; int howmany = 1;
int i; int i;
int db = B_TRUE; int db = B_FALSE;
flag_t *f; flag_t *f;
char *localname = NULL; char *localname = NULL;
int wantblessed = B_UNCURSED; int wantblessed = B_UNCURSED;
@ -3964,9 +3964,6 @@ void genhiddennames(void) {
objecttype_t *ot; objecttype_t *ot;
flag_t *f; flag_t *f;
for (ot = objecttype ; ot ; ot = ot->next) { for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->obclass->id == OC_BOOK) {
dblog("xx");
}
f = hasflag(ot->flags, F_HASHIDDENNAME); f = hasflag(ot->flags, F_HASHIDDENNAME);
if (f) { if (f) {
char *thisname; char *thisname;
@ -14541,6 +14538,28 @@ void timeeffectsob(object_t *o) {
} }
} }
if (owner && !onground) {
if (hasflag(o->flags, F_DIMONDISTURB)) {
f = hasflag(o->flags, F_PRODUCESLIGHT);
getobname(o, obname, o->amt);
if (f) f->val[0]--;
if (!f || (f->val[0] <= 0)) {
if (isplayer(owner)) {
msg("Your %s dim%s and crumbles.",noprefix(obname),
(o->amt == 1) ? "s" : "");
}
removeob(o, ALL);
return;
} else {
if (isplayer(owner)) {
msg("Your %s dim%s slightly.",noprefix(obname),
(o->amt == 1) ? "s" : "");
}
}
}
}
if (location && !owner) { if (location && !owner) {
lifeform_t *who; lifeform_t *who;
who = location->lf; who = location->lf;

78
spell.c
View File

@ -2865,10 +2865,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
// ask for which god // ask for which god
initprompt(&prompt, "To whom will you pray?"); god = askgod("To whom will you pray?", B_FALSE, B_TRUE);
prompt.maycancel = B_TRUE;
god = askgod("To whom will you pray?", B_FALSE);
if (!god) { if (!god) {
msg("Cancelled."); msg("Cancelled.");
return B_TRUE; return B_TRUE;
@ -3122,6 +3119,26 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (where && where->lf) { if (where && where->lf) {
debug(where->lf); debug(where->lf);
} }
} else if (abilid == OT_A_PATHFIND) {
cell_t *where;
where = askcoords("Pathfind to where?", "Pathfind->",TT_NONE, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where) {
if (ai_createpathto(user, where)) {
msg("Success!"); more();
showpath(user);
killflagsofid(user->flags, F_AIPATH);
} else {
msg("PATHFIND FAILED.");
}
}
} else if (abilid == OT_A_PETIFY) {
cell_t *where;
where = askcoords("Petify who?", "Petify->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf) {
petify(where->lf, user);
msg("Petified %s.", where->lf->race->name);
}
} else if (abilid == OT_A_EMPLOY) { } else if (abilid == OT_A_EMPLOY) {
cell_t *where; cell_t *where;
where = askcoords("Assign job to who?", "Assignjob->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE); where = askcoords("Assign job to who?", "Assignjob->",TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
@ -12024,11 +12041,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (lfhasflag(caster, F_CONTROL)) { if (lfhasflag(caster, F_CONTROL)) {
/*
if (power < 5) { if (power < 5) {
power = 5; power = 5;
} else if (power < 8) { } else if (power < 8) {
power = 8; power = 8;
} }
*/
if (power < 8) {
power = 8;
}
} }
if ((power < 5) || !isplayer(caster)) { if ((power < 5) || !isplayer(caster)) {
@ -12847,7 +12869,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_WARPWOOD) { } else if (spellid == OT_S_WARPWOOD) {
object_t *o,*nexto; object_t *o,*nexto;
flag_t *f;
int ndone = 0; int ndone = 0;
if (!targcell) { if (!targcell) {
@ -12862,11 +12883,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if ((o->type->material->id == MT_WOOD) || (o->type->material->id == MT_DRAGONWOOD)) { if ((o->type->material->id == MT_WOOD) || (o->type->material->id == MT_DRAGONWOOD)) {
if (isequipped(o)) { if (isequipped(o)) {
int dam; int dam;
f = hasflag(o->flags, F_OBHP); dam = rolldie(power, 4);
if (f) { if (haslos(player, targcell)) {
dam = rnd(f->val[0]/2,f->val[0]); char obname[BUFLEN];
} else { getobname(o, obname, o->amt);
dam = roll("1d6"); msg("%s twist%s and writhe%s!",obname,
(o->amt == 1) ? "s" : "",
(o->amt == 1) ? "s" : "");
} }
takedamage(o, dam, DT_DECAY, caster); takedamage(o, dam, DT_DECAY, caster);
if (haslos(player, targcell)) { if (haslos(player, targcell)) {
@ -12883,12 +12906,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
nexto = o->next; nexto = o->next;
if ((o->type->material->id == MT_WOOD) || (o->type->material->id == MT_DRAGONWOOD)) { if ((o->type->material->id == MT_WOOD) || (o->type->material->id == MT_DRAGONWOOD)) {
int dam; int dam;
f = hasflag(o->flags, F_OBHP); dam = rolldie(power, 4);
if (f) { if (haslos(player, targcell)) {
dam = rnd(1,f->val[0]); char obname[BUFLEN];
} else { getobname(o, obname, o->amt);
dam = roll("1d6"); msg("%s twist%s and writhe%s!",obname,
(o->amt == 1) ? "s" : "",
(o->amt == 1) ? "s" : "");
} }
takedamage(o, dam, DT_DIRECT, caster); takedamage(o, dam, DT_DIRECT, caster);
if (haslos(player, targcell)) { if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -12896,6 +12922,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
ndone++; ndone++;
} }
} }
if (targcell->lf) {
if ((targcell->lf->material->id == MT_WOOD) ||
(targcell->lf->material->id == MT_DRAGONWOOD)) {
int dam;
char dambuf[BUFLEN];
dam = rolldie(power, 4);
if (haslos(player, targcell)) {
char lfname[BUFLEN];
getlfname(targcell->lf, lfname);
msg("%s twist%s and writhe%s!",lfname,
isplayer(targcell->lf) ? "" : "s",
isplayer(targcell->lf) ? "" : "s");
}
sprintf(dambuf, "%s%s warp wood spell", castername, getpossessive(castername));
losehp(targcell->lf, dam, DT_DIRECT, caster, dambuf);
if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
ndone++;
}
}
if (!ndone) { if (!ndone) {
fizzle(caster); fizzle(caster);
return B_TRUE; return B_TRUE;