From 29483cd29feacf73dc1a2bcb3747ae25f1e9918f Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Tue, 6 Nov 2012 20:32:56 +0000 Subject: [PATCH] - [+] 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 --- ai.c | 484 ++++++++++++++++++++++++++++++++++++++++++----- ai.h | 7 +- attack.c | 13 +- data.c | 40 ++-- data/hiscores.db | Bin 17408 -> 17408 bytes defs.h | 29 ++- flag.c | 14 ++ flag.h | 1 + god.c | 43 +++-- io.c | 88 ++++++++- io.h | 4 +- lf.c | 54 ++++-- lf.h | 1 + map.c | 3 +- move.c | 86 +++++++-- move.h | 1 + nexus.c | 44 +++++ objects.c | 27 ++- spell.c | 78 ++++++-- 19 files changed, 870 insertions(+), 147 deletions(-) diff --git a/ai.c b/ai.c index 03b40e5..347fcf6 100644 --- a/ai.c +++ b/ai.c @@ -23,8 +23,8 @@ extern int playerhasmoved; int wantdb = B_TRUE; void addignorecell(lifeform_t *lf, cell_t *c) { - if (c) { - addflag(lf->flags, F_IGNORECELL, c->x, c->y, NA, NULL); + if (c && !lfhasflagval(lf, 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); } + killflagsofid(lf->flags, F_AIPATH); killflagsofid(lf->flags, F_TARGETLF); killflagsofid(lf->flags, F_TARGETCELL); @@ -146,6 +147,344 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { 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) { flag_t *retflag[MAXCANDIDATES]; 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 (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 ? f = ispetortarget(lf, target); 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. + killflagsofid(lf->flags, F_AIPATH); killflagsofid(lf->flags, F_TARGETLF); killflagsofid(lf->flags, F_TARGETCELL); @@ -1488,8 +1836,7 @@ int ai_movement(lifeform_t *lf) { } if (valid) { - aimovetotargetcell(lf, f); - return B_TRUE; + return aimovetotargetcell(lf, f); } else { 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. if (db) dblog(".oO { i am at distance %d, want to be at %d-%d }", dist, wantdistmin, wantdistmax); if (dist > wantdistmax) { - // want to move but our race doesn't move? if (lfhasflag(lf, F_DOESNTMOVE)) { 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; } - if (db) { - dblog(".oO { moving towards target. }"); - } + if (db) dblog(".oO { moving towards target. }"); // do we need to sprint got catch up? 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)) { - dblog(".oO { successfully moved towards target. }"); + if (db) dblog(".oO { successfully moved towards target. }"); turntoface(lf, target->cell); // success 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; cell_t *c,*origc; int db = B_FALSE; @@ -1963,55 +2307,92 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) { origc = lf->cell; c = getcellat(lf->cell->map, x, y); 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); - } 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); + flag_t *pathf = NULL; + if (!haslof(lf->cell, c, LOF_WALLSTOP, NULL)) { + // if we DONT have LOF to the target cell, use + // a pathfinding algorithm. + // do we ahv an existing path? + pathf = lfhasflag(lf, F_AIPATH); + if (!pathf) { + // if we DONT have a direct path, then pathfind. + pathf = ai_createpathto(lf, c); } - // 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); + if (pathf) { + c = ai_getnextcellinpath(lf); } else { - if (!turned) { - turntoface(lf, c); - } + // couldn't find a path there... + // just try to move directly towards it. } } - } else { - if (db) dblog(".oO { f_targetcell doesn't exist. abandoning. }"); + // if we _DO_ have lof to the cell, we'll just walk direclty towards it. + + 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! killflag(f); - // remember NOT to target this one. - addignorecell(lf, c); + loseaitargets(lf); + + // 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) { @@ -3130,6 +3511,7 @@ int lookforobs(lifeform_t *lf) { int loseaitargets(lifeform_t *lf) { 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_TARGETCELL)) donesomething = B_TRUE; return donesomething; diff --git a/ai.h b/ai.h index 1190f71..97d1881 100644 --- a/ai.h +++ b/ai.h @@ -2,6 +2,11 @@ void addignorecell(lifeform_t *lf, cell_t *c); 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 aigetfleespell(lifeform_t *lf); int aigetchasetime(lifeform_t *lf); @@ -21,7 +26,7 @@ int ai_movement(lifeform_t *lf); int ai_premovement(lifeform_t *lf); flag_t *aihastarget(lifeform_t *lf); 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 aipickupok(lifeform_t *lf, object_t *o); int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target); diff --git a/attack.c b/attack.c index 294bcea..dcebd58 100644 --- a/attack.c +++ b/attack.c @@ -201,6 +201,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } stoprunning(lf); + stoppathfinding(lf); // anyone there? if so just attack. 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, B_NOCONDITION, B_BLINDADJUST, 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)) { return B_TRUE; } @@ -1545,7 +1546,12 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } // 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) { 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; if (lf && !cansee(victim, lf)) return B_FALSE; + if (lfhasflag(victim, F_STUNNED) || !hasfreeaction(victim)) { + return B_FALSE; + } // need stamina to block if (!getstamina(victim)) return B_FALSE; diff --git a/data.c b/data.c index 2ea756f..21666e8 100644 --- a/data.c +++ b/data.c @@ -165,9 +165,11 @@ void initcommands(void) { 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_NW, CH_TURN_NW, "Turn to face Northwest."); - // Actions addcommand(CMD_UP, '<', "Go up stairs."); 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_PICKUP, ',', "Pick up something from the ground."); 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_MAXPOWER, 1, NA, NA, NULL); // 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); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the maximum amount of wood which can be absorbed."); + 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_SPELLSCHOOL, SS_NATURE, 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); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, 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_MAXPOWER, 5, 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_SPELLLEVEL, 2, 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); + addflag(lastot->flags, F_MPCOST, 0, NA, NA, NULL); // 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); 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); 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); + 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); addflag(lastot->flags, F_SPELLLEVEL, 6, 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_AICASTTOATTACK, ST_ADJSELF, 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); 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); @@ -6972,7 +6978,7 @@ void initobjects(void) { 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_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_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_RARITY, H_DUNGEON, 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_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_STAYINROOM, NA, B_NOCHASE, NA, NULL); // stay in our starting room 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."); 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_STARTATT, A_STR, AT_AVERAGE, 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_WIS, 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_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_SEEINDARK, 5, 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_MASTER, "^gYou can now recognise rare wands.", B_TRUE); 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); 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); @@ -19167,7 +19175,7 @@ void initskills(void) { 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); 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); 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); @@ -19318,7 +19326,7 @@ void initskills(void) { snprintf(buf, BUFLEN, "^gYou now have common knowledge about %s.^n", rc->pluralname); 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); snprintf(buf, BUFLEN, "^gYou have now comprehensively studied %s.^n", rc->pluralname); addskilldesc(sk->id, PR_ADEPT, buf, B_TRUE); diff --git a/data/hiscores.db b/data/hiscores.db index fd83f0d093e569cdf45ce7935c78bc814e7e0215..fe2e7f97c3cffc2bcbd10d7a8a308324aa2acab9 100644 GIT binary patch delta 55 zcmZqZU~K4MoFL8ka-+;od&U_X3mX`D!x(@dkbz0qG@I%7N_eG-iT delta 53 zcmV-50LuS>hyj3z0gxL3+p!$^KLL@kaee^^SO5YOFMk4>ldu{d25um4XL4ba?LHWj L?HUoY=|L9)_LCC8 diff --git a/defs.h b/defs.h index bcc5b56..9e44c79 100644 --- a/defs.h +++ b/defs.h @@ -223,6 +223,9 @@ #define MAX_MAPW 80 #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 MAXRANDOMOBCANDIDATES 100 @@ -1913,6 +1916,8 @@ enum OBTYPE { OT_A_BLINDALL, OT_S_CONFISCATE, OT_A_DEBUG, + OT_A_PATHFIND, + OT_A_PETIFY, OT_A_ENHANCE, OT_A_LEARN, OT_A_LEVELUP, @@ -2686,10 +2691,12 @@ enum FLAG { F_CAUSESCOUGH, // being in this ob's cell will make you cough unless // immune to gas. // 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. // if it gets to 0 (or doesnt have produceslight), // the object will vanish. + // + // same happens if object is removed from the ground. F_BLOCKSVIEW, // if v0 = true, cannot see past this // if v0 > 0, reduces your vision by v0. // if v1 = true then don't block sight if you are @@ -3482,6 +3489,11 @@ enum FLAG { // from pet's master F_FEIGNFOOLEDBY, // lf shouldn't attack lf id v0 because they // 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 // optional text is last known movement dir. F_IGNORECELL, // won't accept targetcells of v0=x v1=y @@ -3498,7 +3510,7 @@ enum FLAG { // this lf run away. // TEMP FLAGS - F_KILLEDBYPLAYER, // did the player kill this lf? + F_KILLEDBYPLAYER, // did the player (or an ally) kill this lf? // monster noise flags F_WALKVERB, // text is verb for moving. 'walk' 'slither' // 'bounce' 'hop' etc @@ -3856,6 +3868,8 @@ enum FLAG { F_XRAYVIS, //val0=num of walls we can see through F_CANSEETHROUGHMAT, //val0=kind of material you can see through 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_WINDSHIELD,// has a windshield protecting against missiles of speed // v0 or lower. @@ -4202,6 +4216,7 @@ enum COMMAND { CMD_TURN_W, CMD_TURN_NW, // + CMD_AGAIN, CMD_AIM, CMD_CLOSE, CMD_COMMS, @@ -4212,6 +4227,7 @@ enum COMMAND { CMD_FIRE, CMD_FIRENEW, CMD_FORCEATTACK, + CMD_GO, CMD_GUNRELOAD, CMD_HELP, CMD_INFOARMOUR, @@ -5003,6 +5019,7 @@ typedef struct choice_s { char *longdesc; // what to display once you've selected this void *data; int heading; + int hilite; int shortcutslot; // used when selecting spells/abilities int valid; // used in askchoicestr } choice_t; @@ -5050,8 +5067,16 @@ typedef struct prompt_s { int selection; int nchoices; int maycancel; + int hilite; } prompt_t; +// for a* pathfinding +typedef struct node_s { + struct cell_s *c; + struct node_s *parent; + int fromstart, heur, cost; +} node_t; + #endif diff --git a/flag.c b/flag.c index 96bf6b3..892a9ea 100644 --- a/flag.c +++ b/flag.c @@ -73,6 +73,10 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, known = B_KNOWN; } + if (fp->owner && (id == F_VAULTISPLAYERSTART)) { + dblog("added vaultisplayerstart"); + } + if (id == F_INTERRUPTED) { if (fp->owner == player) { dblog("player got interrupted"); @@ -562,6 +566,16 @@ int countflagsofid(flagpile_t *fp, enum FLAG fid) { 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 // interrupt player actions like resting, training or eating. int flagcausesinterrupt(flag_t *f, enum GAINORLOSS gol ) { diff --git a/flag.h b/flag.h index 1cdb062..55db498 100644 --- a/flag.h +++ b/flag.h @@ -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); int countflags(flagpile_t *fp); int countflagsofid(flagpile_t *fp, enum FLAG fid ); +void dumpflags(flagpile_t *fp); int flagcausesinterrupt(flag_t *f, enum GAINORLOSS gol); int flagcausesloscalc(enum FLAG fid); int flagcausesredraw(lifeform_t *lf, enum FLAG fid); diff --git a/god.c b/god.c index eeff05a..ed35475 100644 --- a/god.c +++ b/god.c @@ -562,7 +562,7 @@ void dooffer(void) { } // which god? - god = askgod("To whom will you sacrifice?", B_TRUE); + god = askgod("To whom will you sacrifice?", B_TRUE, B_FALSE); if (!god) { msg("Cancelled."); return; @@ -911,6 +911,9 @@ void givegodbonus(enum RACE rid, flag_t *bf) { } more(); + // increment piety so that it doesn't keep bouncing around the border. + modpiety(rid, PIETYPRAYLOSS); + // parse regular rags parsegodbonusargs(bf, &bonuslev, &bonusid, &arg, targ); @@ -969,31 +972,31 @@ void removegodbonus(enum RACE rid, flag_t *bf) { // god announcement. switch (rid) { case R_GODPURITY: - godsay(rid, B_TRUE, "I am not impressed, mortal."); + godsay(rid, B_TRUE, "Your service is lacking, mortal."); break; case R_GODTHIEVES: - godsay(rid, B_TRUE, "Disloyalty deserves punishment."); + godsay(rid, B_TRUE, "I expect more results, mortal."); break; case R_GODDEATH: - godsay(rid, B_TRUE, "Disobediant servants can easily be removed..."); + godsay(rid, B_TRUE, "Lazy servants can easily be removed..."); break; case R_GODFIRE: - godsay(rid, B_TRUE, "WRONG!"); + godsay(rid, B_TRUE, "PAY ATTENTION!"); break; case R_GODLIFE: - godsay(rid, B_TRUE, "No, no, no..."); + godsay(rid, B_TRUE, "You must be more proactive, my child."); break; case R_GODMERCY: - godsay(rid, B_TRUE, "You disappoint me..."); + godsay(rid, B_TRUE, "You lack of proactiveness is disappointing..."); break; case R_GODNATURE: - godsay(rid, B_TRUE, "Nature will not tolerate your transgressions."); + godsay(rid, B_TRUE, "Nature will not tolerate the lazy."); break; 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; 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; default: break; @@ -1985,7 +1988,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { taketime(lf, getactspeed(lf)); if (godblocked(god->race->id)) { - msg("%s ignores you.", god->race->name); + msg("%s doesn't respond.", god->race->name); return B_TRUE; } @@ -1999,13 +2002,6 @@ int prayto(lifeform_t *lf, lifeform_t *god) { // god before 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)) { // get even more angry angergod(god->race->id, PIETYPRAYLOSS, GA_PRAY); @@ -2015,7 +2011,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { if (piety <= 99) { // piety between 0 and 99 = ignored //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); modpiety(god->race->id, -30); return B_FALSE; @@ -2059,6 +2055,15 @@ int prayto(lifeform_t *lf, lifeform_t *god) { } 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) { lifeform_t *l; int dist; diff --git a/io.c b/io.c index 5f06201..7b34614 100644 --- a/io.c +++ b/io.c @@ -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(""); p->choice[p->nchoices].data = data; 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].shortcutslot = -1; p->nchoices++; @@ -3075,7 +3076,7 @@ int confirm_injury_action(enum BODYPART bp, enum DAMTYPE dt, char *actionname) { return B_TRUE; } -lifeform_t *askgod(char *prompttext, int onlyprayed) { +lifeform_t *askgod(char *prompttext, int onlyprayed, int forpray) { lifeform_t *lf = NULL; int i; char *longdesc; @@ -3087,6 +3088,7 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) { for (i = 0 ; i < ngodlfs; i++) { flag_t *f; + choice_t *chc; char godof[BUFLEN],buf[BUFLEN]; lf = godlf[i]; if (!lf) continue; @@ -3094,14 +3096,28 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) { if (onlyprayed && !lfhasflag(lf, F_PRAYEDTO)) { continue; } + if (forpray && godblocked(lf->race->id)) { + continue; + } real_getlfname(lf, buf, NULL, B_NOSHOWALL, B_REALRACE); f = hasflag(lf->flags, F_GODOF); 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); 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); @@ -8814,7 +8830,7 @@ void dohelp(char helpmode) { centre(mainwin,C_WHITE, 0, "GOD REFERENCE"); 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) { done = B_TRUE; } else { @@ -9868,7 +9884,9 @@ char getchoice(prompt_t *prompt) { mvwprintw(mainwin, y, 0, "%s", prompt->choice[i].desc); wattroff(mainwin, A_REVERSE); } 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); + if (prompt->choice[i].hilite) unsetcol(mainwin, prompt->choice[i].hilite); } y++; } @@ -10516,7 +10534,7 @@ void handleinput(void) { } gotcmd = B_FALSE; break; - case 'g': // repeat last command + case CMD_AGAIN: // repeat last command f = hasflag(player->flags, F_LASTCMD); if (f) { ch = f->text[0]; @@ -10618,12 +10636,15 @@ void handleinput(void) { doattackcell('\0'); } break; - case CMD_INV: // inventory - doinventory(player->pack); + case CMD_GO: // go somewhere (pathfind) + startpathfind(); break; case CMD_HELP: // help dohelp('?'); break; + case CMD_INV: // inventory + doinventory(player->pack); + break; case CMD_INFOPLAYER: // display player stats showlfstats(player, B_FALSE); break; @@ -13896,6 +13917,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s do not forget your surroundings.", you(lf)); 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); if (f) { 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); 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); @@ -14055,7 +14081,7 @@ void showlfstats(lifeform_t *lf, int showall) { if (blocked) { col = C_RED; - strcpy(happiness, "Ignored"); + strcpy(happiness, "Exiled"); } else { plev = getpietylev(god->race->id, &col, happiness); } @@ -14161,6 +14187,52 @@ void showlfstats(lifeform_t *lf, int showall) { //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) { textwithcol_real(win, buf, B_TRUE); } diff --git a/io.h b/io.h index 494c7e4..fb366a7 100644 --- a/io.h +++ b/io.h @@ -20,7 +20,7 @@ void announceobflagloss(object_t *o, flag_t *f); void announcetime(int h, int m, int s, int showfull); int confirm_badfeeling(object_t *o); 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 *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, ...); @@ -141,6 +141,8 @@ void setobcolour(WINDOW *win, object_t *o, int set); int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname); void showlfarmour(lifeform_t *lf); void showlfstats(lifeform_t *lf, int showall); +void showpath(lifeform_t *lf); +void startpathfind(void); void textwithcol(WINDOW *win, char *buf); void textwithcol_real(WINDOW *win, char *buf, int resetcolatend); void tombstone(lifeform_t *lf); diff --git a/lf.c b/lf.c index 204989c..5e4621e 100644 --- a/lf.c +++ b/lf.c @@ -2050,8 +2050,8 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } } else { if (hasflag(sp->flags, F_CASTINGTIME)) { - } else { msg("%s starts casting a spell.", lfname); + } else { } } } else { // player can't see them @@ -2375,9 +2375,13 @@ int charmedaction(lifeform_t *lf, flag_t *charmflag) { } else { if (isplayer(lf)) { char obname[BUFLEN]; + char mastername[BUFLEN]; + sprintf(mastername, "your new %s", + (getgender(charmer) == G_FEMALE) ? + "mistress" : "master"); getobname(o, obname, o->amt); 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)) { char lfname[BUFLEN]; char obname[BUFLEN]; @@ -4128,10 +4132,6 @@ void generatealignment(lifeform_t *lf) { initprompt(&prompt, buf); - if (isplayer(lf)) { - dblog("xx"); - } - if (nposs == 0) { if (isplayer(lf)) { 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); } else if (cansee(player, lf)) { 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 { if (isplayer(lf)) { @@ -4771,6 +4773,8 @@ int eat(lifeform_t *lf, object_t *o) { if (strlen(taste)) msg("%s", taste); } else if (cansee(player, lf)) { 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 { @@ -4779,6 +4783,8 @@ int eat(lifeform_t *lf, object_t *o) { msg("You continue %s.", drinking ? "drinking" : "eating"); } else if (cansee(player, lf)) { 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 { if (isplayer(lf)) { @@ -4786,6 +4792,8 @@ int eat(lifeform_t *lf, object_t *o) { } else if (cansee(player, lf)) { 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); } // 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 if (isplayer(lf)) { @@ -11180,7 +11188,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) { } // all starting gear is blessed for (o = lf->pack->first ; o ; o = o->next) { - if (isequipped(o)) { + if (isweapon(o) || isarmour(o) || isshield(o)) { blessob(o); } } @@ -11243,7 +11251,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) { char pwbuf[BUFLEN]; pow = MINOF((gettr(lf)/2), getspellmaxpower(o->type->id)); 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 @@ -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)) { generatealignment(lf); } @@ -11728,7 +11741,7 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { object_t *o = NULL; flag_t *f; char buf[BUFLEN],buf2[BUFLEN]; - int db = B_TRUE; + int db = B_FALSE; obpile_t *op; map_t *targmap; enum LFSIZE maxobsize = SZ_MAX; @@ -13581,7 +13594,11 @@ void killlf(lifeform_t *lf) { // shouldn't need this... lf->cell = NULL; - // remove impossible flags... + // remove impossible stuff + if (getstamina(lf) > getmaxstamina(lf)) { + setstamina(lf, getmaxstamina(lf)); + } + // check if anyone is targetting us. // if so, stop targetting us now that // we are dead. @@ -18544,12 +18561,12 @@ int startclimbing(lifeform_t *lf) { } } else { // 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)) { msg("You are not sufficiently skilled to climb walls."); } return B_TRUE; - } if (skillcheck(lf, SC_CLIMB, getcellclimbdifficulty(where), 0)) { + } else if (skillcheck(lf, SC_CLIMB, getcellclimbdifficulty(where), 0)) { // announce if (isplayer(lf)) { 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); stopresting(lf); stoprunning(lf); + stoppathfinding(lf); killflagsofid(lf->flags, F_AUTOCMD); killflagsofid(lf->flags, F_DIGGING); } @@ -20913,7 +20931,7 @@ void startlfturn(lifeform_t *lf) { } else { msg("^wAll of your items are missing!^n"); more(); } - } else { + } else if (cantalk(lf)) { sayphrase(lf, SP_ROBBED, SV_SHOUT, NA, NULL, NULL); } killflagsofid(lf->flags, F_WASROBBED); @@ -21160,8 +21178,12 @@ void startlfturn(lifeform_t *lf) { // the further away from neutral you are, the less chance // piety/anger has of 'expiring' if (pctchance(chance)) { + enum PIETYLEV newplev,oldplev; // slowly move towards normal + oldplev = getpietylev(godlf[i]->race->id, NULL, NULL); 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; } +void stoppathfinding(lifeform_t *lf) { + killflagsofid(lf->flags, F_PATHFINDING); +} + void stopresting(lifeform_t *lf) { flag_t *f; diff --git a/lf.h b/lf.h index 1d52442..846ae89 100644 --- a/lf.h +++ b/lf.h @@ -493,6 +493,7 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag); int stone(lifeform_t *lf); int stopclimbing(lifeform_t *lf, int onpurpose); void stopeating(lifeform_t *lf); +void stoppathfinding(lifeform_t *lf); void stopresting(lifeform_t *lf); void stoprunning(lifeform_t *lf); void stopsprinting(lifeform_t *lf); diff --git a/map.c b/map.c index 2d3e1bd..b703e4d 100644 --- a/map.c +++ b/map.c @@ -6426,7 +6426,7 @@ void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags, // if monster is in a vault, check its flags... v = getcellvault(lf->cell); if (v) { - copyflags(lf->flags, v->flags, F_STAYINROOM); + copyflag(lf->flags, v->flags, F_STAYINROOM); } 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) { diff --git a/move.c b/move.c index addcb85..e7833f6 100644 --- a/move.c +++ b/move.c @@ -1486,7 +1486,7 @@ int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) { } continue; } - if (hasflag(o->flags, F_DIMONWALK)) { + if (hasflag(o->flags, F_DIMONDISTURB)) { f = hasflag(o->flags, F_PRODUCESLIGHT); getobname(o, obname, o->amt); if (f) f->val[0]--; @@ -1505,7 +1505,7 @@ int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) { didmsg = B_TRUE; } } - } // end if dimonwalk + } // end if dimondisturb } // end if crushable 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 - 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 (db) { 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? if (lf && hasflag(o->flags, F_TRAPPED)) { if (doobtraps(o, lf)) { + if (isplayer(lf)) stoppathfinding(lf); return B_TRUE; } } @@ -2095,8 +2100,9 @@ int opendoor(lifeform_t *lf, object_t *o) { } } } + if (isplayer(lf)) stoppathfinding(lf); 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; f = hasflag(o->flags, F_JAMMED); if (f && lf) { @@ -2156,6 +2162,7 @@ int opendoor(lifeform_t *lf, object_t *o) { } } // end if jammedknown } // end if jammed + if (openit) { cell_t *where; // open it @@ -2171,7 +2178,6 @@ int opendoor(lifeform_t *lf, object_t *o) { if (isplayer(lf)) { msg("You force %s open!",obname); } else { - //if (cansee(player, lf) && isadjacent(lf->cell, doorcell)) { if (cansee(player, lf)) { getlfname(lf, buf); capitalise(buf); @@ -2202,9 +2208,8 @@ int opendoor(lifeform_t *lf, object_t *o) { noise(doorcell, NULL, NC_OTHER, SV_TALK, noisebuf, NULL); } } - } - - } + } // end if wasjammed + } // end if lf where = getoblocation(o); 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); } } + } else { + // !openit + if (isplayer(lf)) { + stoppathfinding(lf); + } } return B_FALSE; - } // end if door locked - } + } + + } // end if door locked return B_FALSE; } @@ -3217,7 +3228,10 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { if (isplayer(lf)) { if (cell->known) { // 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. 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)); losehp(lf, 1, DT_BASH, NULL, buf); if (onpurpose || fleeing) taketime(lf, getmovespeed(lf)); + if (isplayer(lf)) stoppathfinding(lf); } } else { 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)); losehp(lf, 1, DT_BASH, NULL, buf); if (onpurpose || fleeing) taketime(lf, getmovespeed(lf)); + if (isplayer(lf)) stoppathfinding(lf); } } else { - if (lfhasflag(lf, F_RAGE)) { + if (lfhasflag(lf, F_RAGE) || !canopendoors(lf)) { // attack it return attackcell(lf, cell, B_FALSE); } else { // 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. reason = E_OK; } @@ -3584,6 +3603,47 @@ int walkoffmap(lifeform_t *lf, int dir, int onpurpose) { 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) { cell_t *cell; enum ATTRBRACKET iq; diff --git a/move.h b/move.h index 79d4e68..a5a5a9a 100644 --- a/move.h +++ b/move.h @@ -38,4 +38,5 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe); int tryrun(lifeform_t *lf, int dir); int trysneak(lifeform_t *lf, int dir); 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); diff --git a/nexus.c b/nexus.c index 0ead5b1..d46236f 100644 --- a/nexus.c +++ b/nexus.c @@ -418,6 +418,11 @@ int main(int argc, char **argv) { // create pet, in view of player if possible. 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); pet = addlf(c, r->id, 1); // 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? if (donormalmove) { f = lfhasflag(who, F_CASTINGSPELL); diff --git a/objects.c b/objects.c index c9a38bb..b96e77a 100644 --- a/objects.c +++ b/objects.c @@ -475,7 +475,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum char numstringmax[BUFLEN]; int howmany = 1; int i; - int db = B_TRUE; + int db = B_FALSE; flag_t *f; char *localname = NULL; int wantblessed = B_UNCURSED; @@ -3964,9 +3964,6 @@ void genhiddennames(void) { objecttype_t *ot; flag_t *f; for (ot = objecttype ; ot ; ot = ot->next) { - if (ot->obclass->id == OC_BOOK) { - dblog("xx"); - } f = hasflag(ot->flags, F_HASHIDDENNAME); if (f) { 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) { lifeform_t *who; who = location->lf; diff --git a/spell.c b/spell.c index 603912e..9e5e4ff 100644 --- a/spell.c +++ b/spell.c @@ -2865,10 +2865,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // ask for which god - initprompt(&prompt, "To whom will you pray?"); - prompt.maycancel = B_TRUE; - - god = askgod("To whom will you pray?", B_FALSE); + god = askgod("To whom will you pray?", B_FALSE, B_TRUE); if (!god) { msg("Cancelled."); return B_TRUE; @@ -3122,6 +3119,26 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (where && 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) { cell_t *where; 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 (power < 5) { power = 5; } else if (power < 8) { power = 8; } + */ + if (power < 8) { + power = 8; + } } 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) { object_t *o,*nexto; - flag_t *f; int ndone = 0; 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 (isequipped(o)) { int dam; - f = hasflag(o->flags, F_OBHP); - if (f) { - dam = rnd(f->val[0]/2,f->val[0]); - } else { - dam = roll("1d6"); + dam = rolldie(power, 4); + if (haslos(player, targcell)) { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + msg("%s twist%s and writhe%s!",obname, + (o->amt == 1) ? "s" : "", + (o->amt == 1) ? "s" : ""); } takedamage(o, dam, DT_DECAY, caster); if (haslos(player, targcell)) { @@ -12883,12 +12906,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ nexto = o->next; if ((o->type->material->id == MT_WOOD) || (o->type->material->id == MT_DRAGONWOOD)) { int dam; - f = hasflag(o->flags, F_OBHP); - if (f) { - dam = rnd(1,f->val[0]); - } else { - dam = roll("1d6"); + dam = rolldie(power, 4); + if (haslos(player, targcell)) { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + msg("%s twist%s and writhe%s!",obname, + (o->amt == 1) ? "s" : "", + (o->amt == 1) ? "s" : ""); } + takedamage(o, dam, DT_DIRECT, caster); if (haslos(player, targcell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -12896,6 +12922,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ 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) { fizzle(caster); return B_TRUE;