1513 lines
36 KiB
C
1513 lines
36 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "defs.h"
|
|
#include "flag.h"
|
|
#include "god.h"
|
|
#include "io.h"
|
|
#include "lf.h"
|
|
#include "map.h"
|
|
#include "objects.h"
|
|
#include "spell.h"
|
|
#include "text.h"
|
|
|
|
extern enum GAMEMODE gamemode;
|
|
extern int needredraw;
|
|
extern int statdirty;
|
|
|
|
extern lifeform_t *godlf[];
|
|
extern int ngodlfs;
|
|
|
|
extern lifeform_t *player;
|
|
|
|
int flagdb = B_FALSE;
|
|
|
|
altflagval_t *addaltval(flag_t *f, enum FLAG id, int val1, int val2, int val3, char *text) {
|
|
f->altval = malloc(sizeof(altflagval_t));
|
|
f->altval->id = id;
|
|
f->altval->val[0] = val1;
|
|
f->altval->val[1] = val2;
|
|
f->altval->val[2] = val3;
|
|
if (text) {
|
|
f->altval->text = strdup(text);
|
|
} else {
|
|
f->altval->text = strdup("");
|
|
}
|
|
return f->altval;
|
|
}
|
|
|
|
void addcondition(flag_t *f, enum FLAGCONDITION fc, int chance) {
|
|
f->condition = fc;
|
|
f->chance = chance;
|
|
}
|
|
|
|
flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text) {
|
|
return addflag_real(fp, id, val1, val2, val3, text, PERMENANT, B_KNOWN, -1);
|
|
}
|
|
flag_t *addflagifneeded(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text) {
|
|
if (!hasflag(fp, id)) {
|
|
return addflag_real(fp, id, val1, val2, val3, text, PERMENANT, B_KNOWN, -1);
|
|
}
|
|
return NULL;
|
|
}
|
|
flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft) {
|
|
return addflag_real(fp, id, val1, val2, val3, text, timeleft, B_KNOWN, -1);
|
|
}
|
|
|
|
flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid) {
|
|
lifeform_t *lf;
|
|
flag_t *f;
|
|
map_t *redolight = NULL;
|
|
int redrawscreenatend = B_FALSE;
|
|
int redrawstatatend = B_FALSE;
|
|
int i;
|
|
int rv;
|
|
|
|
//checkflagpile(fp);
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
|
|
// identified things mean all new flags are autmaticlaly known.
|
|
if (hasflag(fp, F_IDENTIFIED)) {
|
|
known = B_KNOWN;
|
|
}
|
|
|
|
if (id == F_INTERRUPTED) {
|
|
if (fp->owner == player) {
|
|
dblog("player got interrupted");
|
|
}
|
|
}
|
|
|
|
// impossible flags
|
|
if ((id == F_POISONED) && isimmuneto(fp, DT_POISON, B_FALSE)) return NULL;
|
|
if ((id == F_VEGETARIAN) && hasflag(fp, F_CARNIVORE)) return NULL;
|
|
if ((id == F_PARTVEGETARIAN) && hasflag(fp, F_CARNIVORE)) return NULL;
|
|
if ((id == F_CARNIVORE) && (hasflag(fp, F_VEGETARIAN) || hasflag(fp, F_PARTVEGETARIAN)) ) return NULL;
|
|
|
|
// overrite NA rarity
|
|
if ((id == F_RARITY) && (val3 == NA)) {
|
|
val3 = RR_COMMON;
|
|
}
|
|
|
|
// special case which lets us confer f_canwill. (with conferred flags, we can't
|
|
// supply val[2]).
|
|
if (id == F_CANWILL) {
|
|
if ((val3 == NA) && (val2 > 0)) {
|
|
val2 = val3;
|
|
}
|
|
}
|
|
|
|
|
|
// auto-increment order for EXTRADESC flag
|
|
if ((id == F_EXTRADESC) && (val1 == NA)) {
|
|
flag_t *retflag[MAXCANDIDATES];
|
|
int nretflags;
|
|
int nextorder = 0,i;
|
|
getflags(fp, retflag, &nretflags, F_EXTRADESC, F_NONE);
|
|
for (i = 0; i < nretflags; i++) {
|
|
int this;
|
|
this = retflag[i]->val[0];
|
|
if (this == NA) this = 0;
|
|
if (this >= nextorder) nextorder = this+1;
|
|
}
|
|
val1 = nextorder;
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
|
|
lf = fp->owner;
|
|
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
if (id == F_PRODUCESLIGHT) {
|
|
if (lf && lf->cell && (lf->cell->map == player->cell->map)) {
|
|
// someone started producing light
|
|
redolight = lf->cell->map;
|
|
} else if (fp->ob) {
|
|
cell_t *obloc;
|
|
obloc = getoblocation(fp->ob);
|
|
if (obloc && (obloc->map == player->cell->map)) {
|
|
// an object started producing light
|
|
redolight = obloc->map;
|
|
}
|
|
}
|
|
} else if (id == F_ASLEEP) {
|
|
// someone fell asleep - ie their glyph will turn upsidedown
|
|
if (lf && (isplayer(lf) || cansee(player, lf))) {
|
|
redolight = lf->cell->map;
|
|
}
|
|
}
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
|
|
////////////////////////////////
|
|
// ACTUAL FLAG ADDITION IS HERE
|
|
////////////////////////////////
|
|
|
|
if (fp->first == NULL) {
|
|
fp->first = malloc(sizeof(flag_t));
|
|
f = fp->first;
|
|
f->prev = NULL;
|
|
|
|
// also the last
|
|
fp->last = f;
|
|
f->next = NULL;
|
|
|
|
} else {
|
|
flag_t *ff;
|
|
// we will keep flags sorted.
|
|
// find correct position in list...
|
|
ff = fp->first;
|
|
while (ff && (ff->id < id)) {
|
|
ff = ff->next;
|
|
}
|
|
|
|
if (ff) {
|
|
// start or middle of list
|
|
// insert BEFORE this one
|
|
flag_t *prev;
|
|
prev = ff->prev;
|
|
|
|
// link to previous element
|
|
if (prev) {
|
|
prev->next = malloc(sizeof(flag_t));
|
|
f = prev->next;
|
|
} else {
|
|
// first one
|
|
fp->first = malloc(sizeof(flag_t));
|
|
f = fp->first;
|
|
}
|
|
f->prev = prev;
|
|
|
|
// link to next element
|
|
f->next = ff;
|
|
ff->prev = f;
|
|
} else {
|
|
// last one. insert at end of list.
|
|
f = fp->last;
|
|
f->next = malloc(sizeof(flag_t));
|
|
f->next->prev = f;
|
|
f = f->next;
|
|
fp->last = f;
|
|
f->next = NULL;
|
|
}
|
|
/*
|
|
// go to end of list
|
|
f = fp->last;
|
|
f->next = malloc(sizeof(flag_t));
|
|
f->next->prev = f;
|
|
f = f->next;
|
|
*/
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
|
|
// fill in props
|
|
f->id = id;
|
|
f->lifetime = lifetime;
|
|
f->known = known;
|
|
f->obfrom = obfromid;
|
|
|
|
f->altval = NULL;
|
|
f->condition = FC_NOCONDITION;
|
|
f->chance = 100;
|
|
|
|
// first blank values
|
|
for (i = 0; i < 3; i++) {
|
|
f->val[i] = NA;
|
|
}
|
|
|
|
f->val[0] = val1;
|
|
f->nvals = 1;
|
|
if (val2 != NA) {
|
|
f->val[1] = val2;
|
|
f->nvals++;
|
|
}
|
|
if (val3 != NA) {
|
|
f->val[2] = val3;
|
|
f->nvals++;
|
|
}
|
|
if (text) {
|
|
f->text = strdup(text);
|
|
} else {
|
|
f->text = strdup("");
|
|
}
|
|
|
|
f->pile = fp;
|
|
|
|
//checkflagpile(fp);
|
|
|
|
updatefpindex(fp);
|
|
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
|
|
// notify
|
|
if (f->pile->owner) {
|
|
if ( ((gamemode == GM_CHARGEN) && isplayer(f->pile->owner)) ||
|
|
((gamemode == GM_GAMESTARTED) && announceflaggain(f->pile->owner, f)) ) {
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
if (flagcausesinterrupt(f, GL_GAIN)) {
|
|
addflag(f->pile, F_INTERRUPTED, B_TRUE, NA, NA, NULL);
|
|
}
|
|
// only some flags will interrupt player actions
|
|
/*
|
|
switch (f->id) {
|
|
case F_RUNNING:
|
|
case F_TRAINING:
|
|
case F_AUTOCMD:
|
|
case F_PRODUCESLIGHT:
|
|
break;
|
|
case F_ASLEEP:
|
|
if (f->val[2] == NA) { // ie. sleeping, not resting
|
|
addflag(f->pile, F_INTERRUPTED, B_TRUE, NA, NA, NULL);
|
|
}
|
|
break;
|
|
default:
|
|
addflag(f->pile, F_INTERRUPTED, B_TRUE, NA, NA, NULL);
|
|
break;
|
|
}
|
|
*/
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
|
|
f->known = B_TRUE;
|
|
if (f->obfrom) {
|
|
object_t *ob;
|
|
|
|
ob = findobbyid(f->pile->owner->pack, f->obfrom);
|
|
if (ob) {
|
|
flag_t *f2 = NULL;
|
|
switch (f->lifetime) {
|
|
case FROMOBEQUIP:
|
|
f2 = hasflagval(ob->flags, F_EQUIPCONFER, f->id, NA, NA, NULL);
|
|
break;
|
|
case FROMOBHOLD:
|
|
f2 = hasflagval(ob->flags, F_HOLDCONFER, f->id, NA, NA, NULL);
|
|
break;
|
|
case FROMOBACTIVATE:
|
|
f2 = hasflagval(ob->flags, F_ACTIVATECONFER, f->id, NA, NA, NULL);
|
|
break;
|
|
}
|
|
if (f2) {
|
|
f2->known = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
}
|
|
// player flags which cause a redraw
|
|
rv = flagcausesredraw(f->pile->owner, f->id);
|
|
if (rv < redrawscreenatend) redrawscreenatend = rv;
|
|
|
|
if (flagcausesstatredraw(f->pile->owner, f->id)) redrawstatatend = B_TRUE;
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
} else if (f->pile->ob) {
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (announceobflaggain(f->pile->ob, f)) {
|
|
f->known = B_TRUE;
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
}
|
|
}
|
|
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (flagcausesloscalc(f->id)) {
|
|
cell_t *where = NULL;
|
|
// everyone who can see this cell recalcs their los
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
where = getflagpilelocation(f->pile);
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (where) {
|
|
lifeform_t *l;
|
|
for (l = where->map->lf ; l ; l = l->next) {
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (haslos(l, where)) {
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
setlosdirty(l);
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
//precalclos(l);
|
|
if (isplayer(l)) {
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (!redrawscreenatend) redrawscreenatend = B_TRUE;
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
}
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
}
|
|
|
|
// special effects
|
|
if (f->pile->owner) {
|
|
float pct;
|
|
switch (f->id) {
|
|
case F_ASLEEP:
|
|
stopallspellsexcept(f->pile->owner, OT_S_ALARM, OT_NONE);
|
|
break;
|
|
case F_NONCORPOREAL:
|
|
killflagsofid(f->pile->owner->flags, F_BEINGSTONED);
|
|
break;
|
|
case F_RAGE:
|
|
f->val[0] = f->pile->owner->hp; // remember old maxhp
|
|
f->val[1] = f->pile->owner->maxhp; // remember old maxhp
|
|
pct = (float)f->pile->owner->hp / (float)f->pile->owner->maxhp;
|
|
f->pile->owner->maxhp = (float)f->pile->owner->maxhp * 1.5;
|
|
f->pile->owner->hp = pct * (float)f->pile->owner->maxhp;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((gamemode == GM_GAMESTARTED) && (redrawscreenatend || redrawstatatend || redolight)) {
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (redolight) {
|
|
//dblog("CALCINGLIGHT from flag\n");
|
|
if (!redrawscreenatend) redrawscreenatend = B_TRUE;
|
|
calclight(redolight);
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (redolight == player->cell->map) {
|
|
setlosdirty(player);
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
//precalclos(player);
|
|
}
|
|
//dblog("DRAWINGSCREEN from flag\n");
|
|
|
|
if (redrawscreenatend) needredraw = B_TRUE;
|
|
if (redrawstatatend) statdirty = B_TRUE;
|
|
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
if (redrawscreenatend == B_FORCE) {
|
|
forceredraw();
|
|
} else {
|
|
drawscreen();
|
|
}
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
}
|
|
//checkflagpile(fp);
|
|
//if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging
|
|
return f;
|
|
}
|
|
|
|
flagpile_t *addflagpile(lifeform_t *owner, object_t *ob) {
|
|
flagpile_t *fp;
|
|
fp = malloc(sizeof(flagpile_t));
|
|
fp->first = NULL;
|
|
fp->last = NULL;
|
|
fp->owner = owner;
|
|
fp->ob = ob;
|
|
fp->nitems = 0;
|
|
|
|
return fp;
|
|
}
|
|
|
|
int canbemadepermenant(enum FLAG id) {
|
|
switch (id) {
|
|
case F_BLIND:
|
|
case F_BREATHWATER:
|
|
case F_CAFFEINATED:
|
|
case F_DEAF:
|
|
case F_DETECTAURAS:
|
|
case F_DETECTOBS:
|
|
case F_DETECTMETAL:
|
|
case F_DISEASEIMMUNE:
|
|
case F_DRUNK:
|
|
case F_ENHANCESEARCH:
|
|
case F_ENHANCESMELL:
|
|
case F_EXTRAINFO:
|
|
case F_EXTRALUCK:
|
|
case F_FLYING:
|
|
case F_PHOTOMEM:
|
|
case F_REFLECTION:
|
|
case F_SEEINDARK:
|
|
case F_SEEINVIS:
|
|
case F_STABILITY:
|
|
case F_STENCH:
|
|
case F_TREMORSENSE:
|
|
return B_TRUE;
|
|
default: break;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
void changeflagtext(flag_t *f, char *newtext) {
|
|
free(f->text);
|
|
if (newtext) {
|
|
f->text = strdup(newtext);
|
|
} else {
|
|
f->text = strdup("");
|
|
}
|
|
}
|
|
|
|
void checkmapflags(map_t *m) {
|
|
cell_t *c;
|
|
object_t *o;
|
|
int nbad = 0,x,y;
|
|
for (y = 0; y < m->h; y++) {
|
|
for (x = 0; x < m->w; x++) {
|
|
c = getcellat(m, x, y);
|
|
if (c) {
|
|
for (o = c->obpile->first ; o ; o = o->next) {
|
|
if (fpisbad(o->flags)) {
|
|
dblog("bad flagpile found in ob %s at (%d,%d)",o->type->name, c->x, c->y);
|
|
nbad++;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nbad) {
|
|
dblog("total bad flagpiles: %d", nbad);
|
|
assert("found bad flagpiles in checkmapflags!" == 0);
|
|
}
|
|
}
|
|
|
|
void checkflagpile(flagpile_t *fp) {
|
|
if (fpisbad(fp)) {
|
|
assert("flagpile is corrupt!" == 0);
|
|
}
|
|
}
|
|
|
|
int fpisbad(flagpile_t *fp) {
|
|
flag_t *f;
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
if (fp->ob && fp->owner) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
// returns # of flags copied
|
|
int copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id) {
|
|
flag_t *f;
|
|
int ndone = 0;
|
|
for (f = src->first ; f ; f = f->next) {
|
|
// gone past the requrested id's number - ie. it's not there.
|
|
if (f->id > id) break;
|
|
if (f->id == id) {
|
|
flag_t *newf;
|
|
newf = addflag_real(dst, f->id, f->val[0], f->val[1], f->val[2], f->text,
|
|
f->lifetime, f->known, -1);
|
|
newf->condition = f->condition;
|
|
newf->chance = f->chance;
|
|
if (f->altval) {
|
|
addaltval(newf, f->altval->id,
|
|
f->altval->val[0],
|
|
f->altval->val[1],
|
|
f->altval->val[2],
|
|
f->altval->text);
|
|
}
|
|
ndone++;
|
|
}
|
|
}
|
|
return ndone;
|
|
}
|
|
|
|
void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime) {
|
|
flag_t *f,*newf;
|
|
for (f = src->first ; f ; f = f->next) {
|
|
// omit certain flags
|
|
if (lifetime == FROMBRAND) {
|
|
if ((f->id == F_ONLYFOROBTYPE) ||
|
|
(f->id == F_ONLYFORDAMTYPE) ||
|
|
(f->id == F_ONLYFORWEPSKILL)) {
|
|
continue;
|
|
}
|
|
}
|
|
newf = addflag_real(dst, f->id, f->val[0], f->val[1], f->val[2], f->text,
|
|
(lifetime == NA) ? f->lifetime : lifetime, f->known, -1);
|
|
newf->condition = f->condition;
|
|
newf->chance = f->chance;
|
|
if (f->altval) {
|
|
addaltval(newf, f->altval->id,
|
|
f->altval->val[0],
|
|
f->altval->val[1],
|
|
f->altval->val[2],
|
|
f->altval->text);
|
|
}
|
|
}
|
|
}
|
|
|
|
int countflags(flagpile_t *fp) {
|
|
flag_t *f;
|
|
int count = 0;
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int countflagsofid(flagpile_t *fp, enum FLAG fid) {
|
|
flag_t *f;
|
|
int count = 0;
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
if (f->id == fid) count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// 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 ) {
|
|
switch (f->id) {
|
|
case F_ASLEEP:
|
|
if (f->val[2] == NA) { // ie. sleeping, not resting
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case F_BEINGSTONED:
|
|
case F_CONFUSED:
|
|
case F_CHARMEDBY:
|
|
case F_FEIGNINGDEATH:
|
|
case F_FLYING:
|
|
case F_LEVITATING:
|
|
case F_NONCORPOREAL:
|
|
case F_PAIN:
|
|
case F_PARALYZED:
|
|
case F_POISONED:
|
|
case F_RAGE:
|
|
case F_SPRINTING:
|
|
case F_STUNNED:
|
|
return B_TRUE;
|
|
case F_BLIND:
|
|
case F_CAFFEINATED:
|
|
case F_DRUNK:
|
|
case F_FROZEN:
|
|
case F_GRABBEDBY:
|
|
case F_HOTFEET:
|
|
case F_INJURY:
|
|
case F_INVISIBLE:
|
|
if (gol == GL_GAIN) return B_TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int flagcausesloscalc(enum FLAG fid) {
|
|
switch (fid) {
|
|
case F_ASLEEP:
|
|
case F_BLIND:
|
|
case F_BLOCKSVIEW:
|
|
case F_NIGHTVISRANGEMOD:
|
|
case F_PRONE:
|
|
case F_SEEINDARK:
|
|
case F_AWARENESS:
|
|
case F_VISRANGE:
|
|
case F_VISRANGEMOD:
|
|
return B_TRUE;
|
|
default: break;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
// eitehr returns:
|
|
// B_FALSE - gaining/losing the flag doesn't neccessitate a redraw
|
|
// B_TRUE - need to mark the game window as dirty when you see someone gaining/losing this flag
|
|
// B_FORCE - need to CLEAR the game window to force a redraw.
|
|
int flagcausesredraw(lifeform_t *lf, enum FLAG fid) {
|
|
if (!lf) return B_FALSE;
|
|
|
|
if (isplayer(lf)) {
|
|
// player
|
|
switch (fid) {
|
|
case F_ASLEEP:
|
|
case F_BLIND:
|
|
case F_DETECTLIFE:
|
|
case F_DETECTOBS:
|
|
case F_ENHANCESMELL:
|
|
case F_FASTMOVE:
|
|
case F_FEIGNINGDEATH:
|
|
case F_HIDING:
|
|
case F_INVISIBLE:
|
|
case F_PRODUCESLIGHT:
|
|
case F_PRONE:
|
|
case F_SECRET:
|
|
case F_SEEINDARK:
|
|
case F_SEEINVIS:
|
|
case F_AWARENESS:
|
|
case F_SPRINTING:
|
|
case F_SLOWMOVE:
|
|
return B_TRUE;
|
|
case F_GRABBEDBY:
|
|
case F_ATTACHEDTO:
|
|
case F_RAGE:
|
|
return B_FORCE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (haslos(player, lf->cell)) {
|
|
switch (fid) {
|
|
case F_ASLEEP:
|
|
case F_HIDING:
|
|
case F_INVISIBLE:
|
|
case F_PRODUCESLIGHT:
|
|
case F_PRONE:
|
|
return B_TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
// nonplayer
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
|
|
if (!lf || !isplayer(lf)) return B_FALSE;
|
|
|
|
switch (fid) {
|
|
case F_ASLEEP:
|
|
case F_ARBOOST:
|
|
case F_ATTRMOD:
|
|
case F_BLIND:
|
|
case F_CLIMBING:
|
|
case F_CONFUSED:
|
|
case F_DRUNK:
|
|
case F_EATING:
|
|
case F_FASTMOVE:
|
|
case F_FLYING:
|
|
case F_GRAVBOOSTED:
|
|
case F_GUNTARGET:
|
|
case F_HASNEWLEVEL:
|
|
case F_HIDING:
|
|
case F_ICESLIDE:
|
|
case F_INJURY:
|
|
case F_INVISIBLE:
|
|
case F_LEVITATING:
|
|
case F_PARALYZED:
|
|
case F_POISONED:
|
|
case F_PRODUCESLIGHT:
|
|
case F_PRONE:
|
|
case F_RAGE:
|
|
case F_SPRINTING:
|
|
case F_SLOWMOVE:
|
|
case F_STUNNED:
|
|
case F_TRAINING:
|
|
return B_TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
flag_t *hasflag(flagpile_t *fp, int id) {
|
|
return hasflag_real(fp, id, NA, NULL, NA);
|
|
}
|
|
|
|
flag_t *hasflagknown(flagpile_t *fp, int id) {
|
|
return hasflag_real(fp, id, B_TRUE, NULL, NA);
|
|
}
|
|
|
|
flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception, int lifetimeexception) {
|
|
flag_t *f,*foundflag = NULL, *searchfrom = NULL;
|
|
lifeform_t *owner;
|
|
int pos;
|
|
int l,r;
|
|
int iter = 0,subiter = 0;
|
|
int db = B_FALSE;
|
|
|
|
owner = fp->owner;
|
|
|
|
if (flagdb) db = B_TRUE;
|
|
|
|
if (db) dblog("hasflag %d in flagpile with %d entries", id, fp->nitems);
|
|
// binary search for this flag id.
|
|
l = 0;
|
|
r = fp->nitems-1;
|
|
while (!searchfrom) {
|
|
//if (db) dblog(" iter#%d: l=%d,r=%d", iter, l, r);
|
|
if (r < l) {
|
|
// NOT FOUND.
|
|
//if (db) dblog(" r < l: not found!");
|
|
break;
|
|
} else if (fp->item[l]->id > id) {
|
|
// NOT FOUND.
|
|
//if (db) dblog(" leftid %d > wantid %d. not found!",fp->item[l]->id, id);
|
|
break;
|
|
} else if (fp->item[r]->id < id) {
|
|
// NOT FOUND.
|
|
//if (db) dblog(" rightid %d > wantid %d. not found!",fp->item[r]->id, id);
|
|
break;
|
|
}
|
|
// half way inbetween l and r
|
|
pos = ((l+r)/2);
|
|
f = fp->item[pos];
|
|
//if (db) dblog(" iter#%d: pos=%d. item here is %d (looking for %d)", iter, pos, f->id, id);
|
|
|
|
if (f->id == id) {
|
|
// go back to first occurence
|
|
while (f->prev && (f->prev->id == id)) {
|
|
f = f->prev;
|
|
iter++;
|
|
}
|
|
searchfrom = f;
|
|
break;
|
|
} else if (f->id > id) {
|
|
// go left
|
|
r = pos-1;
|
|
} else {
|
|
// go right
|
|
l = pos+1;
|
|
}
|
|
iter++;
|
|
}
|
|
|
|
|
|
// now find a valid one
|
|
f = searchfrom;
|
|
while (f && (f->id == id)) {
|
|
int valid = B_TRUE;
|
|
if (f == exception) valid = B_FALSE;
|
|
if ((lifetimeexception != NA) && (f->lifetime == lifetimeexception)) valid = B_FALSE;
|
|
if ((wantknown != NA) && (f->known != wantknown)) valid = B_FALSE;
|
|
if (owner && (f->lifetime == FROMJOB) && !getjob(owner)) valid = B_FALSE;
|
|
//if (owner && (f->lifetime == FROMSKILL) && !getskill(owner, xxx)) valid = B_FALSE;
|
|
|
|
if (valid) {
|
|
foundflag = f;
|
|
break;
|
|
} else {
|
|
f = f->next;
|
|
subiter++;
|
|
}
|
|
}
|
|
|
|
if (db) dblog("finished - %s - iter=%d, subiter=%d", foundflag ? "found it" : "NOT FOUND",iter,subiter);
|
|
return foundflag;
|
|
|
|
/*
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
// gone past the requrested id's number - ie. it's not there.
|
|
if (f->id > id) break;
|
|
|
|
if ((f->id == id) && (f != exception)) {
|
|
int valid = B_TRUE;
|
|
if ((wantknown != NA) && (f->known != wantknown)) valid = B_FALSE;
|
|
if (owner && (f->lifetime == FROMJOB) && !getjob(owner)) {
|
|
valid = B_FALSE;
|
|
}
|
|
|
|
if (valid) {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
|
|
flag_t *hasflagval(flagpile_t *fp, int id, int val1, int val2, int val3, char *text) {
|
|
return hasflagval_real(fp, id, val1, val2, val3, text, B_FALSE, NA); // doesn't have to be known
|
|
}
|
|
|
|
flag_t *hasflagvalknown(flagpile_t *fp, int id, int val1, int val2, int val3, char *text) {
|
|
return hasflagval_real(fp, id, val1, val2, val3, text, B_TRUE, NA); // must be known
|
|
}
|
|
|
|
int getcounter(flagpile_t *fp) {
|
|
flag_t *f;
|
|
f = hasflag(fp, F_COUNTER);
|
|
if (f) {
|
|
return f->val[0];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, char *text, int wantknown, int lifetimeexception) {
|
|
flag_t *f,*foundflag = NULL, *searchfrom = NULL;
|
|
lifeform_t *owner;
|
|
int pos;
|
|
int l,r;
|
|
int iter = 0;
|
|
int db = B_FALSE;
|
|
owner = fp->owner;
|
|
|
|
if (flagdb) db = B_TRUE;
|
|
|
|
//if (db) dblog("hasflag %d in flagpile with %d entries", id, fp->nitems);
|
|
// binary search for this flag id.
|
|
l = 0;
|
|
r = fp->nitems-1;
|
|
while (!searchfrom) {
|
|
//if (db) dblog(" iter#%d: l=%d,r=%d", iter, l, r);
|
|
if (r < l) {
|
|
// NOT FOUND.
|
|
//if (db) dblog(" r < l: not found!");
|
|
break;
|
|
} else if (fp->item[l]->id > id) {
|
|
// NOT FOUND.
|
|
//if (db) dblog(" leftid %d > wantid %d. not found!",fp->item[l]->id, id);
|
|
break;
|
|
} else if (fp->item[r]->id < id) {
|
|
// NOT FOUND.
|
|
//if (db) dblog(" rightid %d > wantid %d. not found!",fp->item[r]->id, id);
|
|
break;
|
|
}
|
|
// half way inbetween l and r
|
|
pos = ((l+r)/2);
|
|
f = fp->item[pos];
|
|
//if (db) dblog(" iter#%d: pos=%d. item here is %d (looking for %d)", iter, pos, f->id, id);
|
|
|
|
if (f->id == id) {
|
|
// go back to first occurence
|
|
while (f->prev && (f->prev->id == id)) {
|
|
iter++;
|
|
f = f->prev;
|
|
}
|
|
searchfrom = f;
|
|
break;
|
|
} else if (f->id > id) {
|
|
// go left
|
|
r = pos-1;
|
|
} else {
|
|
// go right
|
|
l = pos+1;
|
|
}
|
|
iter++;
|
|
}
|
|
|
|
|
|
// now find a valid one
|
|
f = searchfrom;
|
|
while (f && (f->id == id)) {
|
|
if ((lifetimeexception != NA) && (f->lifetime == lifetimeexception)) {
|
|
} else if (owner && (f->lifetime == FROMJOB) && !getjob(owner)) {
|
|
// invalid
|
|
} else if ( ((val1 == NA) || (f->val[0] == val1)) &&
|
|
((val2 == NA) || (f->val[1] == val2)) &&
|
|
((val3 == NA) || (f->val[2] == val3)) &&
|
|
((text == NULL) || strstr(f->text, text))) {
|
|
if (!wantknown || f->known) {
|
|
foundflag = f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
f = f->next;
|
|
}
|
|
|
|
if (db) dblog("finished - %s - iter=%d", foundflag ? "found it" : "NOT FOUND", iter );
|
|
return foundflag;
|
|
|
|
|
|
/*
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
// gone past the requrested id's number - ie. it's not there.
|
|
if (f->id > id) break;
|
|
|
|
if (f->id == id) {
|
|
if (owner && (f->lifetime == FROMJOB) && !getjob(owner)) {
|
|
// invalid
|
|
} else {
|
|
if ( ((val1 == NA) || (f->val[0] == val1)) &&
|
|
((val2 == NA) || (f->val[1] == val2)) &&
|
|
((val3 == NA) || (f->val[2] == val3)) &&
|
|
((text == NULL) || strstr(f->text, text))) {
|
|
if (!wantknown || f->known) {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
*/
|
|
}
|
|
|
|
int istransitoryflag(flag_t *f) {
|
|
if ((f->lifetime >= FROMEXTERNAL_LOW) && (f->lifetime <= FROMEXTERNAL_HIGH)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
// returns true if we did something
|
|
int killflagsofid(flagpile_t *fp, enum FLAG fid) {
|
|
flag_t *f,*nextf;
|
|
int donesomething = B_FALSE;
|
|
for (f = fp->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
|
|
// gone past the requrested id's number - ie. it's not there.
|
|
if (f->id > fid) break;
|
|
|
|
if (f->id == fid) {
|
|
killflag(f);
|
|
donesomething = B_TRUE;
|
|
}
|
|
}
|
|
return donesomething;
|
|
}
|
|
|
|
void killflag(flag_t *f) {
|
|
flag_t *nextone, *lastone;
|
|
flagpile_t *pile;
|
|
lifeform_t *lf;
|
|
enum FLAG fid;
|
|
map_t *redolight = NULL;
|
|
cell_t *redolos = NULL;
|
|
int redostat = B_FALSE;
|
|
int redoscreen = B_FALSE;
|
|
int i,dopleasegod[MAXGODS];
|
|
|
|
//checkflagpile(f->pile);
|
|
|
|
fid = f->id;
|
|
|
|
for (i = 0; i < ngodlfs; i++) {
|
|
dopleasegod[i] = 0;
|
|
}
|
|
|
|
lf = f->pile->owner;
|
|
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
if (f->id == F_PRODUCESLIGHT) {
|
|
if (lf && lf->cell && (lf->cell->map == player->cell->map)) {
|
|
// someone stopped producing light
|
|
redolight = lf->cell->map;
|
|
} else if (f->pile->ob) {
|
|
cell_t *obloc;
|
|
obloc = getoblocation(f->pile->ob);
|
|
if (obloc && (obloc->map == player->cell->map)) {
|
|
// an object stopped producing light
|
|
redolight = obloc->map;
|
|
}
|
|
}
|
|
} else if (f->id == F_ASLEEP) {
|
|
// someone woke up - ie their glyph will turn upsidedown
|
|
if (lf && (isplayer(lf) || cansee(player, lf))) {
|
|
redolight = lf->cell->map;
|
|
}
|
|
} else if (f->id == F_FLEEFROM) {
|
|
if (lf && lf->cell) {
|
|
lifeform_t *fleefrom;
|
|
fleefrom = findlf(lf->cell->map, f->val[0]);
|
|
// ie. this lf was fleeing from the player, and
|
|
// got away.
|
|
if (isplayer(fleefrom) && !cansee(lf, fleefrom)) {
|
|
for (i = 0; i < ngodlfs; i++) {
|
|
if (godlf[i] && (godlf[i]->race->id == R_GODMERCY)) dopleasegod[i] += 5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
// flags which cause a redraw
|
|
if (flagcausesredraw(f->pile->owner, f->id)) redoscreen = B_TRUE;
|
|
if (flagcausesstatredraw(f->pile->owner, f->id)) redostat = B_TRUE;
|
|
|
|
if (flagcausesloscalc(f->id)) {
|
|
redolos = getflagpilelocation(f->pile);
|
|
}
|
|
}
|
|
|
|
// notify
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
if (lf) {
|
|
// special effects before announcement
|
|
if (f->id == F_FLEEFROM) {
|
|
// once you recover from fleeing from something,
|
|
// you don't find it scary for a little while.
|
|
if (!lfhasflagval(lf, F_NOFLEEFROM, f->val[0], NA, NA, NULL)) {
|
|
addtempflag(lf->flags, F_NOFLEEFROM, f->val[0], NA, NA, NULL, 10);
|
|
}
|
|
} else if (f->id == F_RAGE) {
|
|
if (!isdead(lf)) {
|
|
// restore original maxhp
|
|
float pct;
|
|
pct = (float)lf->hp / (float)lf->maxhp;
|
|
lf->maxhp = f->val[1];
|
|
lf->hp = pct * (float)lf->maxhp;
|
|
if (lf->hp < 1) lf->hp = 1;
|
|
}
|
|
}
|
|
|
|
// announce
|
|
if (announceflagloss(lf, f)) {
|
|
if (flagcausesinterrupt(f, GL_LOSS)) {
|
|
addflag(lf->flags, F_INTERRUPTED, B_TRUE, NA, NA, NULL);
|
|
}
|
|
/*
|
|
// don't include flags which interrupt will kill!
|
|
switch (f->id) {
|
|
case F_RUNNING:
|
|
case F_TRAINING:
|
|
case F_AUTOCMD:
|
|
case F_PRODUCESLIGHT:
|
|
break;
|
|
case F_ASLEEP:
|
|
if (f->val[2] != NA) { // ie. resting
|
|
addflag(lf->flags, F_INTERRUPTED, B_TRUE, NA, NA, NULL);
|
|
}
|
|
break;
|
|
default:
|
|
addflag(lf->flags, F_INTERRUPTED, B_TRUE, NA, NA, NULL);
|
|
break;
|
|
}
|
|
*/
|
|
}
|
|
|
|
// special effects after announcement
|
|
if (f->id == F_RAGE) {
|
|
// you are now exhausted
|
|
setstamina(lf, 0);
|
|
}
|
|
|
|
} else if (f->pile->ob && !isdeadob(f->pile->ob)) {
|
|
announceobflagloss(f->pile->ob, f);
|
|
}
|
|
|
|
// we will revert to our original form at the end of timeeffectslf().
|
|
if (lf && (f->id == F_POLYMORPHED)) {
|
|
if (lfhasflag(lf, F_ORIGRACE)) {
|
|
lf->polyrevert = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////
|
|
// now we are actually removing the flag.
|
|
/////////////////////////////////////////////
|
|
|
|
// remember the pile so that we can re-index
|
|
pile = f->pile;
|
|
|
|
// free mem
|
|
if (f->text) {
|
|
free(f->text);
|
|
f->text = NULL;
|
|
}
|
|
if (f->altval) {
|
|
if (f->altval->text) {
|
|
free(f->altval->text);
|
|
f->altval->text = NULL;
|
|
}
|
|
free(f->altval);
|
|
f->altval = NULL;
|
|
}
|
|
|
|
// remove from list
|
|
nextone = f->next;
|
|
if (nextone != NULL) {
|
|
nextone->prev = f->prev;
|
|
} else { /* last */
|
|
f->pile->last = f->prev;
|
|
}
|
|
|
|
if (f->prev == NULL) {
|
|
/* first */
|
|
nextone = f->next;
|
|
f->pile->first = nextone;
|
|
free(f);
|
|
} else {
|
|
lastone = f->prev;
|
|
free (lastone->next );
|
|
lastone->next = nextone;
|
|
}
|
|
|
|
//////////////////////////////////////////
|
|
// "f" is now gone. don't reference it
|
|
// anymore!
|
|
//////////////////////////////////////////
|
|
f = NULL;
|
|
|
|
// re-index the pile
|
|
updatefpindex(pile);
|
|
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
for (i = 0; i < ngodlfs; i++) {
|
|
if (godlf[i] && dopleasegod[i]) {
|
|
pleasegodmaybe(godlf[i]->race->id, dopleasegod[i]);
|
|
}
|
|
}
|
|
if (redolos) {
|
|
// - if this was a lf's flag, they recalc their los.
|
|
// - if it was an object flag, then everyone who can see
|
|
// its cell recalcs their los.
|
|
if (lf) {
|
|
setlosdirty(lf);
|
|
//precalclos(f->pile->owner);
|
|
if (isplayer(lf)) redoscreen = B_TRUE;
|
|
} else {
|
|
// everyone who can see this cell recalcs their los
|
|
lifeform_t *l;
|
|
for (l = redolos->map->lf ; l ; l = l->next) {
|
|
if (haslos(l, redolos)) {
|
|
setlosdirty(l);
|
|
//precalclos(l);
|
|
if (isplayer(l)) redoscreen = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (redolight) {
|
|
calclight(redolight);
|
|
setlosdirty(player);
|
|
//precalclos(player);
|
|
needredraw = B_TRUE;
|
|
}
|
|
if (redoscreen) {
|
|
needredraw = B_TRUE;
|
|
}
|
|
if (redostat) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
if (statdirty || needredraw ) {
|
|
drawscreen();
|
|
}
|
|
}
|
|
//checkflagpile(pile);
|
|
}
|
|
|
|
void killflagpile(flagpile_t *fp) {
|
|
if (fp->ob && !fp->ob->dying) {
|
|
assert(0 == "calling killflagpile on non-dying object");
|
|
}
|
|
|
|
//checkflagpile(fp);
|
|
while (fp->first) {
|
|
killflag(fp->first);
|
|
}
|
|
//checkflagpile(fp);
|
|
free(fp);
|
|
}
|
|
|
|
int killtransitoryflags(flagpile_t *fp, enum FLAG fid) {
|
|
flag_t *f,*nextf;
|
|
int nkilled = 0;
|
|
for (f = fp->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
|
|
// gone past the requrested id's number - ie. it's not there.
|
|
if (f->id > fid) break;
|
|
|
|
if (istransitoryflag(f) && (f->id == fid)) {
|
|
killflag(f);
|
|
nkilled++;
|
|
}
|
|
}
|
|
return nkilled;
|
|
}
|
|
|
|
int killtransitoryflagvals(flagpile_t *fp, enum FLAG fid, int val1, int val2, int val3, char *text) {
|
|
flag_t *f, *nextf;
|
|
int nkilled = 0;
|
|
for (f = fp->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
|
|
// gone past the requrested id's number - ie. it's not there.
|
|
if (f->id > fid) break;
|
|
|
|
if (istransitoryflag(f) && (f->id == fid)) {
|
|
if ( ((val1 == NA) || (f->val[0] == val1)) &&
|
|
((val2 == NA) || (f->val[1] == val2)) &&
|
|
((val3 == NA) || (f->val[2] == val3)) &&
|
|
((text == NULL) || strstr(f->text, text))) {
|
|
killflag(f);
|
|
nkilled++;
|
|
}
|
|
}
|
|
}
|
|
return nkilled;
|
|
}
|
|
|
|
void timeeffectsflag(flag_t *f, int howlong) {
|
|
|
|
// special case:
|
|
if (f->id == F_TRAIL) {
|
|
return;
|
|
}
|
|
|
|
// always nauseated in the sewer
|
|
if ((f->id == F_NAUSEATED) && f->pile->owner && f->pile->owner->cell && (f->pile->owner->cell->habitat->id == H_SEWER)) {
|
|
return;
|
|
}
|
|
|
|
if ((f->lifetime != PERMENANT) && (f->lifetime > 0)) {
|
|
// special case - fast metabolism speeds up poison too.
|
|
if (f->id == F_POISONED) {
|
|
int multiplier;
|
|
sumflags(f->pile, F_FASTMETAB, &multiplier, NULL, NULL);
|
|
if (multiplier > 0) {
|
|
howlong *= multiplier;
|
|
}
|
|
} else if ((f->id == F_INJURY) && hasflag(f->pile, F_ASLEEP)) {
|
|
howlong *= 2;
|
|
}
|
|
|
|
|
|
f->lifetime -= howlong;
|
|
|
|
if (f->lifetime <= 0) {
|
|
killflag(f);
|
|
return;
|
|
} else if (f->lifetime == 5) {
|
|
// warn about certain flags......
|
|
if (isplayer(f->pile->owner)) {
|
|
switch (f->id) {
|
|
case F_CANWILL:
|
|
switch (f->val[0]) {
|
|
case OT_A_JUMP:
|
|
msg("Your ability to jump is starting to run out...");;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case F_DTIMMUNE:
|
|
msg("Your %s immunity is starting to run out...", getdamname(f->val[0]));
|
|
break;
|
|
case F_DTRESIST:
|
|
msg("Your %s resistance is starting to run out...", getdamname(f->val[0]));
|
|
break;
|
|
case F_DTVULN:
|
|
msg("You feel a little less vulnerable to %s...", getdamname(f->val[0]));
|
|
break;
|
|
case F_INVISIBLE:
|
|
msg("Your body is starting to reappear...");
|
|
break;
|
|
case F_MAGSHIELD:
|
|
msg("Your magnetic shield is weakening...");
|
|
break;
|
|
case F_POLYMORPHED:
|
|
msg("You are starting to revert to your original form...");
|
|
break;
|
|
case F_LEVITATING:
|
|
msg("Your levitation is starting to expire...");
|
|
break;
|
|
case F_FLYING:
|
|
msg("Your ability to fly is starting to expire...");
|
|
break;
|
|
case F_SPIDERCLIMB:
|
|
msg("Your skin is becoming less adhesive..."); more();
|
|
break;
|
|
default: // no message
|
|
break;
|
|
}
|
|
}
|
|
} else if (f->lifetime == 2) {
|
|
if (isplayer(f->pile->owner)) {
|
|
switch (f->id) {
|
|
case F_NONCORPOREAL:
|
|
warn("You feel your body solidifying...");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else if (f->lifetime == 1) {
|
|
// warn about certain flags......
|
|
if (isplayer(f->pile->owner)) {
|
|
switch (f->id) {
|
|
case F_CANWILL:
|
|
switch (f->val[0]) {
|
|
case OT_A_JUMP:
|
|
msg("Your ability to jump is about to expire!"); more();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case F_DTIMMUNE:
|
|
msg("Your %s immunity is about to expire!", getdamname(f->val[0])); more();
|
|
break;
|
|
case F_DTRESIST:
|
|
msg("Your %s resistance is about to expire!", getdamname(f->val[0])); more();
|
|
break;
|
|
case F_DTVULN:
|
|
msg("You feel a little less vulnerable to %s...", getdamname(f->val[0]));
|
|
break;
|
|
case F_INVISIBLE:
|
|
msg("Your invisibility is about to expire!"); more();
|
|
break;
|
|
case F_MAGSHIELD:
|
|
msg("Your magnetic shield is about to expire!"); more();
|
|
break;
|
|
case F_LEVITATING:
|
|
msg("Your levitation is about to expire!"); more();
|
|
break;
|
|
case F_SPIDERCLIMB:
|
|
msg("Your skin adhesion is about to expire!"); more();
|
|
break;
|
|
case F_POLYMORPHED:
|
|
msg("You are about to revert to your original form!"); more();
|
|
break;
|
|
case F_FLYING:
|
|
msg("Your ability to fly is about to expire!"); more();
|
|
break;
|
|
default: // no message
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (f->id == F_WET) {
|
|
f->val[1]--;
|
|
if (f->val[1] <= 0) {
|
|
f->val[0]--;
|
|
if (f->val[0] <= W_DRY) {
|
|
killflag(f);
|
|
return;
|
|
} else {
|
|
// reset timer
|
|
f->val[1] = TM_WETTIME;
|
|
// TODO: announce
|
|
}
|
|
}
|
|
}
|
|
|
|
if (f->id == F_BEINGSTONED) {
|
|
f->val[0]--;
|
|
if (f->val[0] == 0) {
|
|
if (stone(f->pile->owner)) {
|
|
// stoning failed
|
|
killflag(f);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int flagtomaxhp(flag_t *f) {
|
|
int hp;
|
|
int nsides = HITDIESIDES;
|
|
if (f->val[2] > 0) {
|
|
nsides = f->val[2];
|
|
}
|
|
hp = f->val[0] * nsides;
|
|
|
|
if (f->val[1] > 0) {
|
|
hp += f->val[1];
|
|
}
|
|
return hp;
|
|
}
|
|
|
|
cell_t *getflagpilelocation(flagpile_t *fp) {
|
|
cell_t *where = NULL;
|
|
// everyone who can see this cell recalcs their los
|
|
if (fp->owner) {
|
|
where = fp->owner->cell;
|
|
} else if (fp->ob) {
|
|
where = getoblocation(fp->ob);
|
|
}
|
|
return where;
|
|
}
|
|
|
|
// populates retflag & nretflags with matching flags
|
|
int getflags(flagpile_t *fp, flag_t **retflag, int *nretflags, ... ) {
|
|
va_list flags;
|
|
enum FLAG wantflag[MAXCANDIDATES];
|
|
int nwantflags,i;
|
|
flag_t *f;
|
|
|
|
va_start(flags, nretflags);
|
|
nwantflags = 0;
|
|
wantflag[nwantflags] = va_arg(flags, enum FLAG);
|
|
while (wantflag[nwantflags] != F_NONE) {
|
|
nwantflags++;
|
|
wantflag[nwantflags] = va_arg(flags, enum FLAG);
|
|
}
|
|
va_end(flags);
|
|
|
|
assert(nwantflags < MAXCANDIDATES);
|
|
|
|
// now populate retflag[] with matches flags
|
|
*nretflags = 0;
|
|
for (i = 0; i < nwantflags; i++) {
|
|
f = hasflag(fp, wantflag[i]);
|
|
while (f && (f->id == wantflag[i])) {
|
|
retflag[(*nretflags)++] = f;
|
|
f = f->next;
|
|
}
|
|
}
|
|
return *nretflags;
|
|
}
|
|
|
|
int modcounter(flagpile_t *fp, int amt) {
|
|
flag_t *f;
|
|
f = hasflag(fp, F_COUNTER);
|
|
if (f) {
|
|
f->val[0] += amt;
|
|
} else {
|
|
f = addflag(fp, F_COUNTER, amt, NA, NA, NULL);
|
|
}
|
|
return f->val[0];
|
|
}
|
|
|
|
flag_t *modflag(flagpile_t *fp, enum FLAG fid, int val1, int val2, int val3, char *text) {
|
|
flag_t *f;
|
|
f = hasflag(fp, fid);
|
|
if (!f) {
|
|
return addflag(fp, fid, val1, val1, val3, text);
|
|
}
|
|
// make sure there is only one!
|
|
if (f->next && (f->next->id == fid)) {
|
|
if (gamemode == GM_GAMESTARTED) msg("WARNING: modflag() found multiple flag instances");
|
|
dblog("WARNING: modflag() found multiple flag instances (fid=%d)", (int)fid);
|
|
}
|
|
if (val1 != NA) f->val[0] = val1;
|
|
if (val2 != NA) f->val[1] = val2;
|
|
if (val3 != NA) f->val[2] = val3;
|
|
if (text) {
|
|
changeflagtext(f, text);
|
|
}
|
|
return f;
|
|
}
|
|
|
|
void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2) {
|
|
flag_t *f;
|
|
if (val0) *val0 = 0;
|
|
if (val1) *val1 = 0;
|
|
if (val2) *val2 = 0;
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
// gone past the requrested id's number - ie. it's not there.
|
|
if (f->id > id) break;
|
|
|
|
if (f->id == id) {
|
|
if (val0) *val0 = *val0 + f->val[0];
|
|
if (val1) *val1 = *val1 + f->val[1];
|
|
if (val2) *val2 = *val2 + f->val[2];
|
|
}
|
|
}
|
|
}
|
|
|
|
void timeeffectsflags(flagpile_t *fp) {
|
|
flag_t *f,*nextf;
|
|
|
|
//checkflagpile(fp);
|
|
|
|
for (f = fp->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
timeeffectsflag(f, 1);
|
|
}
|
|
//checkflagpile(fp);
|
|
}
|
|
|
|
// generate an index
|
|
void updatefpindex(flagpile_t *fp) {
|
|
flag_t *f;
|
|
|
|
fp->nitems = 0;
|
|
for (f = fp->first ;f ; f = f->next) {
|
|
fp->item[fp->nitems] = f;
|
|
fp->nitems++;
|
|
assert(fp->nitems < MAXFLAGS);
|
|
}
|
|
//checkflagpile(fp);
|
|
}
|