#include #include #include #include "defs.h" #include "flag.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 *player; 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 *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; // identified things mean all new flags are autmaticlaly known. if (hasflag(fp, F_IDENTIFIED)) { known = B_KNOWN; } if ((id == F_POISONED) && isimmuneto(fp, DT_POISON)) { return NULL; } 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; } } } // certain flags stack... if (flagstacks(id)) { f = hasflag(fp, id); if (f) { // add values! f->val[0] += val1; f->val[1] += val2; f->val[2] += val3; // TODO: how to handle text?? return f; } } // override values sometimes /* if ((id == F_WET) && (val2 == NA)) { val2 = WETTIME; } */ if (fp->first == NULL) { fp->first = malloc(sizeof(flag_t)); f = fp->first; f->prev = NULL; } else { // go to 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; // fill in props f->id = id; f->lifetime = lifetime; f->known = known; f->obfrom = obfromid; // 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; // notify if ((gamemode == GM_GAMESTARTED)) { if (f->pile->owner) { if (announceflaggain(f->pile->owner, f)) { // don't include flags which interrupt will kill! switch (f->id) { case F_RUNNING: case F_TRAINING: case F_AUTOCMD: 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; } f->known = B_TRUE; if (f->obfrom) { object_t *ob; ob = findobbyid(f->pile->owner->pack, f->obfrom); if (ob) { flag_t *f2; switch (f->lifetime) { case FROMOBEQUIP: f2 = hasflagval(ob->flags, F_EQUIPCONFER, f->id, NA, NA, NULL); break; case FROMOBHOLD: f2 = hasflagval(ob->flags, F_HOLDCONFER, f->id, NA, NA, NULL); break; case FROMOBACTIVATE: f2 = hasflagval(ob->flags, F_ACTIVATECONFER, f->id, NA, NA, NULL); break; } if (f2) { f2->known = B_TRUE; } } } } // player flags which cause a redraw if (flagcausesredraw(f->pile->owner, f->id)) redrawscreenatend = B_TRUE; if (flagcausesstatredraw(f->pile->owner, f->id)) redrawstatatend = B_TRUE; } else if (f->pile->ob) { if (announceobflaggain(f->pile->ob, f)) { f->known = B_TRUE; } } } // special effects if (f->pile->owner) { float pct; switch (f->id) { case F_ASLEEP: stopallspells(f->pile->owner); 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 (redolight) { //dblog("CALCINGLIGHT from flag\n"); redrawscreenatend = B_TRUE; calclight(redolight); precalclos(player); } //dblog("DRAWINGSCREEN from flag\n"); if (redrawscreenatend) needredraw = B_TRUE; if (redrawstatatend) statdirty = B_TRUE; drawscreen(); } 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; return fp; } void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id) { flag_t *f; for (f = src->first ; f ; f = f->next) { if (f->id == id) { addflag_real(dst, f->id, f->val[0], f->val[1], f->val[2], f->text, f->lifetime, f->known, -1); } } } void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime) { flag_t *f; for (f = src->first ; f ; f = f->next) { addflag_real(dst, f->id, f->val[0], f->val[1], f->val[2], f->text, (lifetime == NA) ? f->lifetime : lifetime, f->known, -1); } } int countflags(flagpile_t *fp) { flag_t *f; int count = 0; for (f = fp->first ; f ; f = f->next) { count++; } return count; } 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_HIDING: case F_INVISIBLE: case F_PRODUCESLIGHT: case F_PRONE: case F_RAGE: case F_SEEINDARK: case F_SEEINVIS: case F_SPRINTING: case F_SLOWMOVE: case F_TIRED: return B_TRUE; 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_ATTRMOD: case F_BLIND: case F_EATING: case F_FASTMOVE: case F_HASNEWLEVEL: case F_HIDING: case F_INVISIBLE: case F_PARALYZED: case F_POISONED: case F_PRODUCESLIGHT: case F_PRONE: case F_RAGE: case F_SPRINTING: case F_SLOWMOVE: case F_TIRED: case F_TRAINING: return B_TRUE; default: break; } return B_FALSE; } int flagstacks(enum FLAG fid) { int res = B_FALSE; switch (fid) { case F_EVASION: res = B_TRUE; break; default: res = B_FALSE; break; } return res; } flag_t *hasflag(flagpile_t *fp, int id) { return hasflag_real(fp, id, NA, NULL); } flag_t *hasflagknown(flagpile_t *fp, int id) { return hasflag_real(fp, id, B_TRUE, NULL); } flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception) { flag_t *f; lifeform_t *owner; owner = fp->owner; for (f = fp->first ; f ; f = f->next) { 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); // 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); // 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) { flag_t *f; lifeform_t *owner; owner = fp->owner; for (f = fp->first ; f ; f = f->next) { 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; } // 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; if (f->id == fid) { killflag(f); donesomething = B_TRUE; } } return donesomething; } void killflag(flag_t *f) { flag_t *nextone, *lastone; lifeform_t *lf; map_t *redolight = NULL; int redostat = B_FALSE; int redoscreen = B_FALSE; 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; } } } // 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; // notify if ((gamemode == GM_GAMESTARTED)) { if (lf) { // special cases 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)) { // don't include flags which interrupt will kill! switch (f->id) { case F_RUNNING: case F_TRAINING: case F_AUTOCMD: 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; } } } else if (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; } } // free mem // 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; } if (gamemode == GM_GAMESTARTED) { if (redolight) { calclight(redolight); precalclos(player); } if (redoscreen || redolight) { needredraw = B_TRUE; } if (redostat) { statdirty = B_TRUE; } if (statdirty || needredraw || redolight) { drawscreen(); } } } void killflagpile(flagpile_t *fp) { while (fp->first) { killflag(fp->first); } free(fp); } void timeeffectsflag(flag_t *f, int howlong) { // special case: if (f->id == F_TRAIL) { 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; } } 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: warn("Your ability to jump is starting to run out...");; break; default: break; } break; case F_DTIMMUNE: warn("Your %s immunity is starting to run out...", getdamname(f->val[0])); break; case F_DTRESIST: warn("Your %s resistance is starting to run out...", getdamname(f->val[0])); break; case F_DTVULN: warn("You feel a little less vulnerable to %s...", getdamname(f->val[0])); break; case F_MAGSHIELD: warn("Your magnetic shield is weakening..."); break; case F_POLYMORPHED: warn("You are starting to revert to your original form..."); break; default: // no message break; } } } else if (f->lifetime == 3) { if (isplayer(f->pile->owner)) { switch (f->id) { case F_SPRINTING: if (f->val[0]) { warn("You will have to stop sprinting soon..."); } break; default: 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: warn("Your ability to jump is about to expire!");; break; default: break; } break; case F_DTIMMUNE: warn("Your %s immunity is about to expire!", getdamname(f->val[0])); break; case F_DTRESIST: warn("Your %s resistance is about to expire!", getdamname(f->val[0])); break; case F_DTVULN: warn("You feel a little less vulnerable to %s...", getdamname(f->val[0])); break; case F_MAGSHIELD: warn("Your magnetic shield is about to expire!"); break; case F_POLYMORPHED: warn("You are about to revert to your original form!"); break; default: // no message break; } } // sprinting is special if (f->id == F_SPRINTING) { if (f->val[0]) { enum SKILLLEVEL slev; lifeform_t *who; int tiredtime; who = f->pile->owner; // now you get slow // you get tired when you finish sprinting tiredtime = 15; // adjust for athletics skill. -2 per level. slev = getskill(who, SK_ATHLETICS); if (slev != PR_INEPT) { tiredtime -= (2*slev); } // adjust for constitution tiredtime = tiredtime - (int) ((float)tiredtime * (getstatmod(who, A_CON) / 100) ); // enforce minimum if (tiredtime < 1) tiredtime = 1; f->val[0] = B_FALSE; f->lifetime = tiredtime; if (isplayer(who)) { msg("You are exhausted."); } else if (cansee(player, who)) { char lfname[BUFLEN]; getlfname(who, lfname); msg("%s looks exhausted.",lfname); } needredraw = B_TRUE; statdirty = B_TRUE; } } } } if (f->id == F_BEINGSTONED) { f->val[0]--; if (f->val[0] == 0) { if (!stone(f->pile->owner)) { // lf turned to stone! return; } else { // stoning failed. stop being stoned. killflag(f); return; } } } 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] = WETTIME; // TODO: announce } } } } 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]; } 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) { 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; for (f = fp->first ; f ; f = nextf) { nextf = f->next; timeeffectsflag(f, 1); } }