From 290d91677e10e1682addcbbd3030b9e197e25b63 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Thu, 24 Mar 2011 05:09:31 +0000 Subject: [PATCH] * [+] backstab - [+] monsters start asleep and make spot checks ? - [+] make them start asleep - [+] then make this random - [+] sound will wake them (ie. "makenoise") - [+] when you move, make SC_STEALTH check. if you fail, you make noise! - [+] must pass LISTEN check OR have los to hear something. - [+] "the blowfly falls asleep" "the blowfly appears" when summoned. - [+] don't show 'falls asleep' while being created! * [+] don't start summoned mosnters asleep! * [+] clean up bresnham functions - [+] hearing - instead of just using distance, use distance modiied by # of walls! - [+] getcelldistsound() - each wall counts as an extra cell! - [+] add WALK/FLY noises to all monsters! - [+] don't show 'you hear xxx' when resting. - [+] extra damage for weapon skill (up to 50% extra) - [+] make broken glass crushable - [+] only interrupt rest for non-peaceful, non-friendly monsters - [+] save to fight off poison * [+] beholder is never using its BITE attack * [+] need a price for manuals!! * [+] change"dobresnham" to populate an array of cells - [+] make ai cast animate metal (if they ahve a second weapon) - [+] implement getallegiance() to clean up isfriendly / ispeaceful etc - [+] bug - f_else f_ifpct etc not working in startobs * [+] OT_S_CHARM - [+] update askcoords to show "weilding x AND Y" - [+] stop enemies from throwing firearm ammo somehow * [+] implement - [+] pacify spell - [+] make spellbooks less common - [+] detectmetal not wokring. fixed. - [+] detectobjects spell - [+] cleanup using flagcausesredraw() - [+] increase odds of weapons in rooms, and max ob count in rooms --- ai.c | 160 ++++++---- attack.c | 341 +++++++++++++-------- attack.h | 2 +- defs.h | 52 +++- doc/add_attrib.txt | 5 +- flag.c | 94 +++--- flag.h | 3 +- io.c | 148 +++++++-- lf.c | 744 ++++++++++++++++++++++++++++----------------- lf.h | 17 +- log.txt | 340 ++------------------- map.c | 57 +++- map.h | 2 +- move.c | 137 +++++++-- move.h | 4 +- nexus.c | 193 +++++++++++- nexus.h | 5 + objects.c | 162 ++++++++-- objects.h | 3 +- save.c | 2 + spell.c | 333 +++++++++++++++----- spell.h | 2 +- text.c | 23 +- text.h | 1 + 24 files changed, 1782 insertions(+), 1048 deletions(-) diff --git a/ai.c b/ai.c index 7d2fbca..415fd6f 100644 --- a/ai.c +++ b/ai.c @@ -165,6 +165,14 @@ void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victi // cast spell at the victim if (spelllf) *spelllf = victim; if (spellcell) *spellcell = victim->cell; + } else if (spelltype->id == OT_S_CHARM) { + lifeform_t *l; + l = getnearbypeaceful(lf); + if (l) { + if (spelllf) *spelllf = l; + if (spellcell) *spellcell = l->cell; + if (spellob) *spellob = NULL; + } } } } @@ -330,9 +338,17 @@ void aimove(lifeform_t *lf) { return; } + + + if (goingtomove && (getcelldist(lf->cell, target->cell) == 1)) { + } + // can we attack with spells (ie. ones which target the victim)? + // if target is adjacent, we will normally just attack rather than try a spell. spell = aigetattackspell(lf, target); - if (spell != OT_NONE) { + if ( (spell != OT_NONE) && // found a valid spell/ability to use + ((getcelldist(lf->cell, target->cell) != 1) || (rnd(1,3) == 1)) + ) { int spellfailed = B_FALSE; lifeform_t *spelllf = NULL; cell_t *spellcell = NULL; @@ -400,7 +416,7 @@ void aimove(lifeform_t *lf) { } // if not adjacent, check for guns, wands, throwing - if (goingtomove && (getcelldist(lf->cell, target->cell) > 1) && haslof(lf, target->cell)) { + if (goingtomove && (getcelldist(lf->cell, target->cell) > 1) && haslof(lf, target->cell, B_FALSE, NULL)) { // can we attack by firing something? gun = getfirearm(lf); if (goingtomove && gun && getammo(lf)) { @@ -422,8 +438,8 @@ void aimove(lifeform_t *lf) { // can we attack by throwing something? if (goingtomove) { - // TODO: or firing! check if we have a firearm first. - o = getbestmissile(lf); + // + o = getbestthrowmissile(lf); if (o) { if (db) dblog(".oO { will throw %s at my target instead of moving }", o->type->name); // try to throw it! @@ -556,63 +572,63 @@ void aimove(lifeform_t *lf) { // not attacking anyone in particular if (db) dblog(".oO { i do not have a target or can't move towards it. }"); // are we hostile? if so, look for a target - f = hasflag(lf->flags, F_HOSTILE); - if (f) { + switch (getallegiance(lf)) { int i; - if (db) dblog(".oO { i am hostile. looking for a target. }"); - - // look around for a target - for (i = 0; i < lf->nlos; i++) { - cell_t *c; - c = lf->los[i]; - - if (c->lf && cansee(lf, c->lf)) { - if (isplayer(c->lf)) { // TODO: change to if isenemy ? - if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name); - // target them! - addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME); - // tell the player - if (cansee(player, lf)) { - makenoise(lf, N_GETANGRY); - } - // then move towards them... - if (db) dblog(".oO { moving towards my new target }"); - - if (curwep) { - if (!movetowards(lf, c)) return; - } else { - if (db) dblog(".oO { won't move towards target - i have no weapon. }"); - } - break; - } - } - } - } - - // are we friendly? if so, look for a target - f = hasflag(lf->flags, F_FRIENDLY); - if (f) { int x,y; - if (db) dblog(".oO { i am friendly to the player. looking for a target. }"); - // look around for a target - // TODO: use our vis rang einstead of 10! - for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) { - for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) { - c = getcellat(lf->cell->map, x, y); - // cell exists and we can see it? - if (c && c->lf && (c->lf != lf) && cansee(lf, c->lf)) { - // player there? - if (!isplayer(c->lf)) { + case AL_HOSTILE: + if (db) dblog(".oO { i am hostile. looking for a target. }"); + + // look around for a target + for (i = 0; i < lf->nlos; i++) { + cell_t *c; + c = lf->los[i]; + + if (c->lf && cansee(lf, c->lf)) { + if (isplayer(c->lf)) { // TODO: change to if isenemy ? if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name); // target them! addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME); + // tell the player + if (cansee(player, lf)) { + makenoise(lf, N_GETANGRY); + } // then move towards them... if (db) dblog(".oO { moving towards my new target }"); - if (!movetowards(lf, c)) return; + + if (curwep) { + if (!movetowards(lf, c)) return; + } else { + if (db) dblog(".oO { won't move towards target - i have no weapon. }"); + } + break; } } } - } + break; + case AL_FRIENDLY: // are we friendly? if so, look for a target + if (db) dblog(".oO { i am friendly to the player. looking for a target. }"); + // look around for a target + // TODO: use our vis rang einstead of 10! + for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) { + for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) { + c = getcellat(lf->cell->map, x, y); + // cell exists and we can see it? + if (c && c->lf && (c->lf != lf) && cansee(lf, c->lf)) { + // player there? + if (!isplayer(c->lf)) { + if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name); + // target them! + addtempflag(lf->flags, F_TARGET, c->lf->id, c->x, c->y, NULL, AI_FOLLOWTIME); + // then move towards them... + if (db) dblog(".oO { moving towards my new target }"); + if (!movetowards(lf, c)) return; + } + } + } + } + break; + default: + break; } @@ -684,6 +700,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG int db = B_FALSE; int ok = B_FALSE; int specialcase = B_FALSE; + int specificcheckok = B_FALSE; if (lfhasflag(lf, F_DEBUG)) { db = B_TRUE; @@ -801,6 +818,10 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if (ok) break; } } + } else if (ot->id == OT_S_CHARM) { + if (getnearbypeaceful(lf)) { + ok = B_TRUE; + } } else { dblog(".oO { cant cast %s - specialcase conditions not yet coded }", ot ? ot->name : "?unkownspell?"); return B_FALSE; @@ -812,45 +833,58 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG return B_FALSE; } - // now check whether it meets spellcasting conditions + // now check whether it meets specific spell conditions + specificcheckok = B_TRUE; + if (ot->id == OT_S_ANIMATEMETAL) { + object_t *wep; + wep = getweapon(lf); + if (!wep || !ismetal(wep->material->id)) { + specificcheckok = B_TRUE; + } + } if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_HASTE) && lfhasflag(lf, F_FASTACT)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_INVISIBILITY) && lfhasflag(victim, F_INVISIBLE)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_PAIN) && lfhasflag(victim, F_PAIN)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_HEALING) && (lf->hp >= lf->maxhp)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_HEALINGMIN) && (lf->hp >= lf->maxhp)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_PARALYZE) && lfhasflag(victim, F_PARALYZED)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_SLEEP) && lfhasflag(victim, F_ASLEEP)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_SLOW) && lfhasflag(victim, F_SLOWACT)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) { - return B_FALSE; + specificcheckok = B_FALSE; } if ((ot->id == OT_S_WEAKEN)) { flag_t *lff; for (lff = lf->flags->first; lff ; lff = lff->next) { if ((lff->id == F_ATTRMOD) && (lff->val[0] == A_STR) && (lff->obfrom == OT_S_WEAKEN)) { - return B_FALSE; + specificcheckok = B_FALSE; + break; } } } + if (!specificcheckok) { + dblog(".oO { cant cast %s - specific spell check failed }", ot ? ot->name : "?unkownspell?"); + return B_FALSE; + } return B_TRUE; } diff --git a/attack.c b/attack.c index 35453c6..8dea92c 100644 --- a/attack.c +++ b/attack.c @@ -84,6 +84,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { char attackername[BUFLEN]; char victimname[BUFLEN]; int fatal = B_FALSE; + int firstisbackstab = B_FALSE; flag_t *unarmedflag = NULL; object_t *wep; obpile_t *op = NULL; @@ -109,8 +110,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { return B_TRUE; } - - // get names getlfname(lf, attackername); @@ -124,6 +123,25 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { getlfname(victim, victimname); } + if (isplayer(lf) && !areenemies(lf,victim)) { + char ch; + switch (getallegiance(victim)) { + case AL_PEACEFUL: + sprintf(buf, "Really attack the peaceful %s?",noprefix(victimname)); + break; + case AL_FRIENDLY: + sprintf(buf, "Really attack the allied %s?",noprefix(victimname)); + break; + default: + sprintf(buf, "Really attack the allied %s?",noprefix(victimname)); + break; + } + ch = askchar(buf, "yn","n", B_TRUE); + if (ch == 'n') { + // cancel. + return B_TRUE; + } + } if (aidb) dblog(".oO { trying to attack %s }", victimname); @@ -192,43 +210,65 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { // ie. if critical is 0, do this once. // if critical is 1, do this twice. // etc. - dam[ndam] = 0; + dam[0] = 0; for (n = 0; n < critical+1; n++) { if (unarmedflag) { // this mosnter's unarmed attack will // override normal damage calculation - dam[ndam] += getdamrollfromflag(unarmedflag); + dam[0] += getdamrollfromflag(unarmedflag); } else { - dam[ndam] += getdamroll(wep, victim); + dam[0] += getdamroll(wep, victim); } } - if (aidb) dblog("rolled dam[%d] = %d",ndam,dam[ndam]); + if (aidb) dblog("rolled dam[%d] = %d",0,dam[0]); - if (dam[ndam] < 0) { + if (dam[0] < 0) { willheal = B_TRUE; } + // damtype? + damtype[0] = getdamtype(wep); + if (!willheal) { + enum SKILLLEVEL slev; + skill_t *sk; + // blessed vs undead + if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) { + // a little extra damage + dam[0] = (int) ( (float)dam[0] * 1.25 ); + } // modify for strength if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { - dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf)); + dam[0] = (int)((float)dam[0] * getstrdammod(lf)); + } + // backstab? + if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon + getskill(lf, SK_BACKSTAB) && // able to backstab + !cansee(victim, lf) && // victim can't see us + !lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) && // haven't stabbed them before + !lfhasflagval(victim, F_TARGET, lf->id, NA, NA, NULL) // victim isnt attacking us + ) { + addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL); + dam[0] *= (getskill(lf, SK_BACKSTAB)*2); + firstisbackstab = B_TRUE; + } + // extra damage for being skilled? + sk = getobskill(wep); + if (sk) { + slev = getskill(lf, sk->id); + if (slev > 1) { + float pctextra; + pctextra = ((slev - 1) * 10); + dam[0] += pctof(pctextra, dam[0]); + } } } - // damtype? - damtype[ndam] = getdamtype(wep); - if (aidb) dblog(".oO { dealing %d %s damage }", dam[ndam], getdamname(damtype[ndam])); - ndam++; + if (aidb) dblog(".oO { dealing %d %s damage }", dam[0], getdamname(damtype[0])); - - // blessed vs undead etc? + ndam = 1; + // determine extra damage for flaming etc. if (!willheal) { - if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) { - // a little extra damage - dam[ndam] = (int) ( (float)dam[ndam] * 1.25 ); - } - - // determine extra damage getextradam(wep, &dam[0], &damtype[0], &ndam); } } else { @@ -243,9 +283,12 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { for (i = 0; i < ndam; i++) { int reduceamt; + int backstab = B_FALSE; + + if (firstisbackstab && (i == 0)) backstab = B_TRUE; dblog("initial dam[%d] = %d",i,dam[i]); - if (lfhasflag(lf, F_HEAVYBLOW)) { + if (lfhasflag(lf, F_HEAVYBLOW) || hasflag(wep->flags, F_HEAVYBLOW)) { dam[i] = (int)((float)dam[i] * 1.5); dblog("heavy blow makes dam[%d] = %d",i,dam[i]); } @@ -254,12 +297,14 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { adjustdamlf(victim, &dam[i], damtype[i]); dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); - // modify for defender's armour - reduceamt = getarmourdamreduction(victim, wep, dam[i], damtype[i]); + if (!backstab) { + // modify for defender's armour + reduceamt = getarmourdamreduction(victim, wep, dam[i], damtype[i]); - applyarmourdamreduction(victim, wep, reduceamt, &dam[i], damtype[i]); + applyarmourdamreduction(victim, wep, reduceamt, &dam[i], damtype[i]); - dblog("reduced by armour to dam[%d] = %d",i,dam[i]); + dblog("reduced by armour to dam[%d] = %d",i,dam[i]); + } // will this hit be fatal? if (dam[i] >= victim->hp) { @@ -278,7 +323,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { strcpy(extradambuf, ""); } - if (fatal) { + if (backstab && (i == 0)) { + verb = strdup("backstab"); + } else if (fatal) { verb = getkillverb(victim, damtype[i], dam[i], victim->maxhp); } else { verb = getattackverb(lf, wep, damtype[i], dam[i], victim->maxhp); @@ -286,7 +333,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { warn("You %s %s%s%s", verb, victimname, extradambuf, - fatal ? "!" : "."); + (fatal || backstab) ? "!" : "."); if (fatal && strstr(verb, "behead")) { addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL); @@ -296,6 +343,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { // don't also say "the xx dies" addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); } + if (!strcmp(verb, "backstab")) { + free(verb); + } } else { if (cansee(player, lf) || isplayer(victim)) { char withwep[BUFLEN]; @@ -303,7 +353,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { char nodamstr[BUFLEN]; // capitalise first letter - sprintf(buf, "%s",attackername); + strcpy(buf, attackername); capitalise(buf); if (wep && !unarmedflag && (lf->race->id != R_DANCINGWEAPON) && cansee(player, lf)) { @@ -319,11 +369,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { strcpy(nodamstr, ""); } warn("%s %s%s %s%s%s.", buf, attackverb, - attackverb[strlen(attackverb)-1] == 's' ? "es" : "s", + needses(attackverb) ? "es" : "s", victimname,withwep, nodamstr); - } else { - youhear(lf->cell, "sounds of fighting"); - } + } + noise(lf->cell, lf, "sounds of fighting.", NULL); } @@ -362,9 +411,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { } // end foreach damtype // special weapon effects - if (dam[0]) { - wepeffects(wep->flags, victim->cell); - } + wepeffects(wep->flags, victim->cell, dam[0]); if (!isdead(victim)) { if (unarmedflag) { @@ -415,9 +462,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { } // confer flags from attacker? - if (dam[0]) { - wepeffects(lf->flags, victim->cell); - } + wepeffects(lf->flags, victim->cell, dam[0]); // special lifeform-based effects if ((lf->race->id == R_COCKATRICE) && dam[0]) { @@ -464,14 +509,16 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { } if (lfhasflag(victim, F_DODGES)) { - flag_t *f; cell_t *adj; - f = addflag(victim->flags, F_NOTIME, B_TRUE, NA, NA, NULL); adj = getrandomadjcell(victim->cell, WE_NOTSOLID); - moveto(lf, adj, B_FALSE); - msg("%s dodge%s!",victimname,isplayer(victim) ? "" : "s"); - killflag(f); + if (adj) { + flag_t *f; + f = addflag(victim->flags, F_NOTIME, B_TRUE, NA, NA, NULL); + moveto(victim, adj, B_FALSE); + msg("%s dodge%s!",victimname,isplayer(victim) ? "" : "s"); + killflag(f); + } } } @@ -565,6 +612,11 @@ int attackob(lifeform_t *lf, object_t *o) { dam[ndam] = getdamroll(wep, NULL); } + // modify for strength + if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { + dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf)); + } + // damtype? damtype[ndam] = getdamtype(wep); ndam++; @@ -598,7 +650,7 @@ int attackob(lifeform_t *lf, object_t *o) { msg("%s %ss %s%s.", attackername, getattackverb(lf, wep, damtype[i],dam[i],maxhp), obname,withwep); } else { - youhear(lf->cell, "sounds of fighting"); + noise(lf->cell, NULL, "sounds of fighting.", NULL); } if ((i == 0) && unarmedflag && hasflag(o->flags, F_HARD)) { @@ -617,9 +669,7 @@ int attackob(lifeform_t *lf, object_t *o) { } // end foreach damtype // special weapon effects - if (dam[0]) { - wepeffects(wep->flags, obloc); - } + wepeffects(wep->flags, obloc, dam[0]); if (unarmedflag) { // touch effects @@ -857,6 +907,10 @@ char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp) float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); + if (victim->race->id == R_DANCINGWEAPON) { + return "defeat"; + } + if ((damtype == DT_BASH) && lfhasflag(victim, F_FROZEN)) { return "shatter"; } @@ -1189,6 +1243,11 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical) { acc -= 45; } + // victim immobile or asleep? + if (isimmobile(victim)) { + acc += 50; + } + if (critical) { if (rnd(1,20) == 20) *critical = 1; } @@ -1213,7 +1272,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical) { return gothit; } -void wepeffects(flagpile_t *fp, cell_t *where) { +void wepeffects(flagpile_t *fp, cell_t *where, int dam) { flag_t *f; lifeform_t *victim; lifeform_t *owner; @@ -1222,7 +1281,15 @@ void wepeffects(flagpile_t *fp, cell_t *where) { if (!where) return; wep = fp->ob; - owner = fp->owner; + if (wep) { + cell_t *c; + c = getoblocation(wep); + if (c && c->lf) { + owner = c->lf; + } + } else { + owner = fp->owner; + } victim = where->lf; for (f = fp->first ; f ; f = f->next) { @@ -1237,100 +1304,128 @@ void wepeffects(flagpile_t *fp, cell_t *where) { } } } else if ((f->id == F_REVENGE) && victim && !isdead(victim)) { - lifeform_t *owner; - owner = wep->pile->owner; - if (owner && victim) { - float ratio; - float dampct; - int maxdam; - int extradam; - // figure out hp percentage - ratio = 1.0 - ((float)owner->hp / (float)owner->maxhp); - dampct = (ratio * 100); // ie. lower hp% = higher dampct - - if (dampct >= 50) { - getdamrange(wep->flags, NULL, &maxdam); - extradam = (int)(dampct * (float)maxdam); - if (extradam > 0) { - char buf[BUFLEN]; - char buf2[BUFLEN]; - char obname[BUFLEN]; - char damstring[BUFLEN]; - char victimname[BUFLEN]; - getlfname(owner, buf); - real_getlfname(owner, buf2, B_FALSE); - getlfname(victim, victimname); - getobname(wep, obname, 1); + if (dam) { // only works if we did damage + lifeform_t *owner; + owner = wep->pile->owner; + if (owner && victim) { + float ratio; + float dampct; + int maxdam; + int extradam; + // figure out hp percentage + ratio = 1.0 - ((float)owner->hp / (float)owner->maxhp); + dampct = (ratio * 100); // ie. lower hp% = higher dampct + + if (dampct >= 50) { + getdamrange(wep->flags, NULL, &maxdam); + extradam = (int)(dampct * (float)maxdam); + if (extradam > 0) { + char buf[BUFLEN]; + char buf2[BUFLEN]; + char obname[BUFLEN]; + char damstring[BUFLEN]; + char victimname[BUFLEN]; + getlfname(owner, buf); + real_getlfname(owner, buf2, B_FALSE); + getlfname(victim, victimname); + getobname(wep, obname, 1); - // announce - if (isplayer(owner)) { - msg("Your %s blasts %s!",noprefix(obname),victimname); - f->known = B_TRUE; - } else if (cansee(player, owner)) { - msg("%s%s %s blasts %s!",buf, getpossessive(buf),noprefix(obname),victimname); - f->known = B_TRUE; + // announce + if (isplayer(owner)) { + msg("Your %s blasts %s!",noprefix(obname),victimname); + f->known = B_TRUE; + } else if (cansee(player, owner)) { + msg("%s%s %s blasts %s!",buf, getpossessive(buf),noprefix(obname),victimname); + f->known = B_TRUE; + } + + sprintf(damstring, "%s%s blast of revenge",buf2, getpossessive(buf2)); + losehp(victim, extradam, DT_DIRECT, owner, damstring); } - - sprintf(damstring, "%s%s blast of revenge",buf2, getpossessive(buf2)); - losehp(victim, extradam, DT_DIRECT, owner, damstring); - } - } // end if dampct > 50 + } // end if dampct > 50 + } } } else if ((f->id == F_HEAVYBLOW) && victim && owner) { int dir; // knock back victim - dir = getdirtowards(owner->cell, victim->cell, victim, B_FALSE); + dir = getdirtowards(owner->cell, victim->cell, victim, B_FALSE, DT_COMPASS); knockback(victim, dir , 2, owner); f->known = B_TRUE; } else if ((f->id == F_HITCONFER) && victim ) { - enum FLAG fid; - int min,max,howlong; - fid = f->val[0]; - if (!lfhasflag(victim, fid)) { - int passedcheck = B_FALSE; - if (!f->val[1] == NA) { - int scdiff; - if (f->val[2] == NA) { - scdiff = 20; // default - } else { - scdiff = f->val[2]; + // only works if we did damage + if (dam) { + enum FLAG fid; + int min,max,howlong; + fid = f->val[0]; + if (!lfhasflag(victim, fid)) { + int passedcheck = B_FALSE; + if (!f->val[1] == NA) { + int scdiff; + if (f->val[2] == NA) { + scdiff = 20; // default + } else { + scdiff = f->val[2]; + } + if (skillcheck(victim, f->val[1], scdiff, 0)) { + passedcheck = B_TRUE; + } } - if (skillcheck(victim, f->val[1], scdiff, 0)) { - passedcheck = B_TRUE; - } - } - if (!passedcheck) { - int val0; - val0 = f->val[1]; - if (f->text) { - char loctext[BUFLEN]; - char *word, *dummy; - strcpy(loctext,f->text); - word = strtok_r(loctext, "-", &dummy); - if (word) { - min = atoi(word); - word = strtok_r(NULL, "-", &dummy); + if (!passedcheck) { + int val0; + val0 = f->val[1]; + if (f->text) { + char loctext[BUFLEN]; + char *word, *dummy; + strcpy(loctext,f->text); + word = strtok_r(loctext, "-", &dummy); if (word) { - max = atoi(word); - howlong = rnd(min,max); + min = atoi(word); + word = strtok_r(NULL, "-", &dummy); + if (word) { + max = atoi(word); + howlong = rnd(min,max); + } else { + howlong = PERMENANT; + } } else { howlong = PERMENANT; } } else { howlong = PERMENANT; } - } else { - howlong = PERMENANT; - } - addtempflag(victim->flags, fid, val0, NA, NA, NULL, howlong); - } // end if passedcheck - } // end (if victim doesn't already have the flag) + if (fid == F_POISONED) { + // need to fill in the name of what poisoned us + char frombuf[BUFLEN]; + if (wep) { + if (owner) { + char lfname[BUFLEN]; + char wepname[BUFLEN]; + getlfnamea(owner, lfname); + getobname(wep, wepname, 1); + // ie. "a goblin's poisoned short sword" + sprintf(frombuf, "%s%s %s",lfname,getpossessive(lfname), wepname); + } else { + char wepname[BUFLEN]; + getobname(wep, wepname, 1); + // ie "a poisoned short sword" + sprintf(frombuf, "%s", wepname); + } + } else { + strcpy(frombuf, "something unknown"); + } + addtempflag(victim->flags, fid, val0, NA, NA, frombuf, howlong); + } else { + addtempflag(victim->flags, fid, val0, NA, NA, NULL, howlong); + } + } // end if passedcheck + } // end (if victim doesn't already have the flag) - // was this from a poisoned weapon? if so the poison vanishes - if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) { - killflag(f); + // was this from a poisoned weapon? if so the poison vanishes + if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) { + killflag(f); + } } } // end if (fid == hitconfer) } diff --git a/attack.h b/attack.h index e54b952..eeade8c 100644 --- a/attack.h +++ b/attack.h @@ -20,4 +20,4 @@ int getdamrollfromflag(flag_t *f); float getstrdammod(lifeform_t *lf); obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag); int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical); -void wepeffects(flagpile_t *fp, cell_t *where); +void wepeffects(flagpile_t *fp, cell_t *where, int dam); diff --git a/defs.h b/defs.h index 5e95281..578abdc 100644 --- a/defs.h +++ b/defs.h @@ -43,10 +43,12 @@ enum CHECKTYPE { ////////// SC_DODGE, SC_SLIP, + SC_LISTEN, SC_MORALE, SC_OPENLOCKS, SC_POISON, SC_RESISTMAG, + SC_STEALTH, SC_WILL, }; @@ -125,6 +127,8 @@ enum LFCONDITION { #define MAXPILEOBS 52 +#define MAXRETCELLS 80 + #define MAXCHOICES 150 #define MAXDEPTH 25 // max dungeon depth @@ -197,6 +201,14 @@ enum LFCONDITION { #define TR_NEEDLOS 1 #define TR_NEEDLOF 2 +// line of fire args +enum LOFTYPE { + LOF_DONTNEED = 0, + LOF_WALLSTOP = 2, + LOF_LFSSTOP = 4, + LOF_NEED = 6, // walls AND lfs block +}; + // CONTROLLERS #define C_AI 0 #define C_PLAYER 1 @@ -412,6 +424,8 @@ enum HABITAT { H_ALL = 999 }; +#define RARITYVARIANCE (25) + /* enum RARITY { RR_UNIQUE = 7, @@ -611,6 +625,7 @@ enum OBTYPE { OT_SCR_CREATEMONSTER, OT_SCR_DETECTAURA, OT_SCR_DETECTLIFE, + OT_SCR_DETECTOBS, OT_SCR_DETECTMAGIC, OT_SCR_FLAMEPILLAR, OT_SCR_FLAMEBURST, @@ -627,11 +642,14 @@ enum OBTYPE { OT_SCR_WISH, // BOOKS OT_MAN_ATHLETICS, + OT_MAN_BACKSTAB, OT_MAN_FIRSTAID, + OT_MAN_LISTEN, OT_MAN_LOCKPICKING, OT_MAN_MAGITEMUSAGE, OT_MAN_RESEARCH, OT_MAN_SPELLCASTING, + OT_MAN_STEALTH, OT_MAN_TECHUSAGE, // manuals of weaponry OT_MAN_AXES, @@ -667,6 +685,7 @@ enum OBTYPE { // -- divination OT_SB_DETECTAURA, OT_SB_DETECTLIFE, + OT_SB_DETECTOBS, OT_SB_IDENTIFY, OT_SB_MAPPING, // -- elemental - air @@ -695,8 +714,11 @@ enum OBTYPE { OT_SB_TURNUNDEAD, // -- mental / psionic OT_SB_MINDSCAN, + OT_SB_SLEEP, OT_SB_TELEKINESIS, + OT_SB_PACIFY, OT_SB_PSYARMOUR, + OT_SB_CHARM, // -- modification OT_SB_GASEOUSFORM, OT_SB_KNOCK, @@ -734,6 +756,7 @@ enum OBTYPE { // -- divination OT_S_DETECTAURA, OT_S_DETECTLIFE, + OT_S_DETECTOBS, OT_S_DETECTMAGIC, OT_S_IDENTIFY, OT_S_MAPPING, @@ -765,7 +788,9 @@ enum OBTYPE { OT_S_MINDSCAN, OT_S_SLEEP, OT_S_TELEKINESIS, + OT_S_PACIFY, OT_S_PSYARMOUR, + OT_S_CHARM, // -- modification OT_S_ENCHANT, OT_S_GASEOUSFORM, @@ -782,6 +807,7 @@ enum OBTYPE { OT_S_CREATEMONSTER, // -- translocation OT_S_BLINK, + OT_S_PULL, OT_S_DISPERSAL, OT_S_GATE, OT_S_TELEPORT, @@ -795,6 +821,7 @@ enum OBTYPE { OT_S_WISH, OT_S_GIFT, OT_A_DEBUG, + OT_A_ENHANCE, OT_A_LEARN, // abilities OT_A_GRAB, @@ -1022,6 +1049,8 @@ enum BODYPART { enum NOISETYPE { N_GETANGRY, + N_WALK, + N_FLY, }; enum LFSIZE { @@ -1036,6 +1065,11 @@ enum LFSIZE { SZ_MAX = 100 }; +enum ALLEGIENCE { + AL_HOSTILE, // will attack you on sight + AL_PEACEFUL, // won't attack you on sight + AL_FRIENDLY, // will help you fight +}; enum FLAG { F_NONE, // dummy flag @@ -1055,7 +1089,7 @@ enum FLAG { F_CURAMMO, // currently equipped ammo F_GOESON, // val0 = where it can be equipped. F_BONUS, // val0=bonus/penalty to damage/armour. ie. +1 sword - F_MISSILE, // weapon would make a good missle - used by AI + F_THROWMISSILE, // weapon would make a good thrown missle - used by AI F_UNIQUE, // only one may appear F_GLYPH, // override the glyph with the first char of text F_NOPICKUP, // cannot pick this up @@ -1207,9 +1241,9 @@ enum FLAG { F_MPCOST, // v0=mp cost of spell. if missing, mpcost if splev^2 F_ONGOING, // this spell has an ongoing cost //F_SPELLLETTER, // text[0] = letter to cast this spell - F_AICASTTOFLEE, // AI can cast this spell to help flee + F_AICASTTOFLEE, // AI can cast this spell to help flee/heal // v0 is who to target - F_AICASTTOATTACK, // AI can cast this spell to help flee + F_AICASTTOATTACK, // AI can cast this spell to attack // v0 is who to target F_AIBOOSTITEM, // ai will use this item to boost/buff itself. // if using this on wands, update aiobok() ! @@ -1265,6 +1299,8 @@ enum FLAG { F_NOFLEE, // lf will not run away F_TARGET, // lf will attack lfid v0. lastknown x/y is v1/v2 F_TARGETCELL, // lf will go towards this place. val0=x,val1=y + F_STABBEDBY, // lf has been stabbed by lfid v0. can't be stabbed + // by them again until they go out of sight. F_FLEEFROM, // lf will run away from this lf id // TEMP FLAGS @@ -1276,6 +1312,7 @@ enum FLAG { F_SPELLCASTTEXT, // text is announcement for spellcast F_NODEATHANNOUNCE, // don't say 'the xx dies' if this lf dies F_BEHEADED, // use special corpse drop code + F_SILENTMOVE, // lf makes no noise when walking/flying F_MOVESPEED, // override default move speed F_ACTIONSPEED, // override default action speed F_SPELLSPEED, // override default spellcast speed (ie. movespeed) @@ -1322,15 +1359,17 @@ enum FLAG { // ie. when v1 == v2, ability is ready. // text is other options, semicolon seperated: // pw:xx; cast the spell at power xx + F_CHARMEDBY,// you've been charmed by lf id v0 F_DETECTAURAS, // autodetect bless/curse F_DETECTLIFE, // autodetect nearby lifeforms in orthogonal dist v0 F_DETECTMAGIC, // autodetect magic/special objects F_DETECTMETAL, // autodetect nearby metal + F_DETECTOBS, // autodetect nearby obs in orthog dist v0 F_EXTRAINFO, // knows extra info F_FLYING, // lf is flying F_FASTACT, // modifier for action speed F_FASTMOVE, // modifier for move speed - F_POISONED, // has food poisoning + F_POISONED, // has food poisoning. text = what from.eg'a bad egg' F_FREEZINGTOUCH,// next thing touched turns to ice! F_GRABBEDBY,// you've been grabbed by lf id v0 F_GRABBING, // you are grabbing lf id v0 @@ -1369,6 +1408,7 @@ enum FLAG { F_TIRED, // you are too tired to sprint F_DODGES, // you dodge missed attacks F_NOTIME, // this lf's actions don't take time + F_PERCEPTION, // v0 = 0-20. perception level. // skills F_HASSKILL, // lf has skill v0 at level v1 // COMBAT @@ -1584,6 +1624,7 @@ typedef struct map_s { int w,h; // width/height of this map struct cell_s *cell[MAX_MAPW*MAX_MAPH]; // list of cells in this map int nextmap[MAXDIR_ORTH]; // which map is in each direction + int beingcreated; struct lifeform_s *lf,*lastlf; @@ -1730,11 +1771,14 @@ typedef struct material_s { #define SK_NONE -1 enum SKILL { SK_ATHLETICS, + SK_BACKSTAB, SK_FIRSTAID, + SK_LISTEN, SK_LOCKPICKING, SK_MAGITEMUSAGE, SK_RESEARCH, SK_SPELLCASTING, + SK_STEALTH, SK_TECHUSAGE, // weaponry SK_AXES, diff --git a/doc/add_attrib.txt b/doc/add_attrib.txt index 1a352f7..5c9d344 100644 --- a/doc/add_attrib.txt +++ b/doc/add_attrib.txt @@ -14,8 +14,7 @@ lf.c: update gainlevel() question update givejob() update modattr() - io.c: update announceflaggain() and loss() for this stat - - +text.c: + add getattrname() diff --git a/flag.c b/flag.c index addfa0f..c4d4b4e 100644 --- a/flag.c +++ b/flag.c @@ -124,31 +124,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, } } // player flags which cause a redraw - if (isplayer(f->pile->owner)) { - switch (f->id) { - case F_BLIND: - case F_SEEINDARK: - case F_SPRINTING: - case F_TIRED: - case F_FASTMOVE: - case F_SLOWMOVE: - case F_INVISIBLE: - case F_SEEINVIS: - doredraw = B_TRUE; - break; - default: - break; - } - } else if (haslos(player, f->pile->owner->cell)) { - // monster flags which cause a redraw - switch (f->id) { - case F_INVISIBLE: - doredraw = B_TRUE; - break; - default: - break; - } - } + doredraw = flagcausesredraw(f->pile->owner, f->id); } else if (f->pile->ob) { if (announceobflaggain(f->pile->ob, f)) { f->known = B_TRUE; @@ -197,6 +173,38 @@ void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime) { } } +int flagcausesredraw(lifeform_t *lf, enum FLAG fid) { + if (!lf) return B_FALSE; + + if (isplayer(lf)) { + // player + switch (fid) { + case F_BLIND: + case F_DETECTLIFE: + case F_DETECTOBS: + case F_FASTMOVE: + case F_INVISIBLE: + 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_INVISIBLE: + return B_TRUE; + default: + break; + } + // nonplayer + } + return B_FALSE; +} + int flagstacks(enum FLAG fid) { int res = B_FALSE; switch (fid) { @@ -292,34 +300,8 @@ void killflag(flag_t *f) { lf = f->pile->owner; - // player flags which cause a redraw - if (lf) { - if (isplayer(lf)) { - switch (f->id) { - case F_BLIND: - case F_SEEINDARK: - case F_SPRINTING: - case F_TIRED: - case F_FASTMOVE: - case F_SLOWMOVE: - case F_INVISIBLE: - case F_SEEINVIS: - doredraw = B_TRUE; - break; - default: - break; - } - } else if (haslos(player, lf->cell)) { - // monster flags which cause a redraw - switch (f->id) { - case F_INVISIBLE: - doredraw = B_TRUE; - break; - default: - break; - } - } - } + // flags which cause a redraw + doredraw = flagcausesredraw(f->pile->owner, f->id); // notify if ((gamemode == GM_GAMESTARTED)) { @@ -390,9 +372,9 @@ void killflagpile(flagpile_t *fp) { free(fp); } -void timeeffectsflag(flag_t *f) { +void timeeffectsflag(flag_t *f, int howlong) { if ((f->lifetime != PERMENANT) && (f->lifetime > 0)) { - f->lifetime--; + f->lifetime -= howlong; if (f->lifetime <= 0) { killflag(f); return; @@ -505,7 +487,7 @@ void timeeffectsflags(flagpile_t *fp) { flag_t *f,*nextf; for (f = fp->first ; f ; f = nextf) { nextf = f->next; - timeeffectsflag(f); + timeeffectsflag(f, 1); } } diff --git a/flag.h b/flag.h index 29f9963..f2bcf31 100644 --- a/flag.h +++ b/flag.h @@ -7,6 +7,7 @@ flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid); flagpile_t *addflagpile(lifeform_t *owner, object_t *o); void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime); +int flagcausesredraw(lifeform_t *lf, enum FLAG fid); int flagstacks(enum FLAG fid); flag_t *hasflag(flagpile_t *fp, int id); flag_t *hasflagknown(flagpile_t *fp, int id); @@ -19,5 +20,5 @@ void killflag(flag_t *f); void killflagpile(flagpile_t *fp); void makeflagknown(flagpile_t *fp); void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2); -void timeeffectsflag(flag_t *f); +void timeeffectsflag(flag_t *f, int howlong); void timeeffectsflags(flagpile_t *fp); diff --git a/io.c b/io.c index 7607f57..70b5aea 100644 --- a/io.c +++ b/io.c @@ -404,13 +404,21 @@ cell_t *askcoords(char *prompt, int targettype) { sprintf(extrainfo, "level %d, ",c->lf->level); } */ - if (isfriendly(c->lf)) { - if (strlen(extrainfo)) strcat(extrainfo, ", "); - strcat(extrainfo, "ally"); - } else if (ispeaceful(c->lf)) { - if (strlen(extrainfo)) strcat(extrainfo, ", "); - strcat(extrainfo, "peaceful"); + switch (getallegiance(c->lf)) { + case AL_FRIENDLY: + if (!isplayer(c->lf)) { + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, "ally"); + } + break; + case AL_PEACEFUL: + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, "peaceful"); + break; + case AL_HOSTILE: + break; } + if (isfleeing(c->lf)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "fleeing"); @@ -438,12 +446,30 @@ cell_t *askcoords(char *prompt, int targettype) { wep = getweapon(c->lf); if (wep) { + object_t *secwep; char obname[BUFLEN]; char buf2[BUFLEN]; getobname(wep, obname, wep->amt); sprintf(buf2, "weilding %s",obname); if (strlen(extrainfo)) strcat(extrainfo, ", "); + + secwep = getequippedob(c->lf->pack, BP_SECWEAPON); + if (secwep) { + getobname(secwep, obname, secwep->amt); + strcat(buf2, " and "); + strcat(buf2, obname); + } strcat(extrainfo, buf2); + } else { + wep = getequippedob(c->lf->pack, BP_SECWEAPON); + if (wep) { + char obname[BUFLEN]; + char buf2[BUFLEN]; + getobname(wep, obname, wep->amt); + sprintf(buf2, "weilding %s",obname); + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, buf2); + } } f = lfhasflag(c->lf, F_GRABBING); @@ -690,6 +716,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { ot = findot(f->val[0]); if (ot) { msg("You have learned the spell '%s'.", ot->name); + donesomething = B_TRUE; } } break; @@ -699,9 +726,18 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { ot = findot(f->val[0]); if (ot) { msg("You have learned the ability '%s'.", ot->name); + donesomething = B_TRUE; } } break; + case F_CHARMEDBY: + lf2 = findlf(NULL, f->val[0]); + if (lf2) { + getlfname(lf2, buf); + msg("%s %s now under %s%s power!",lfname, isplayer(lf) ? "are" : "is", buf,getpossessive(buf)); + donesomething = B_TRUE; + } + break; case F_DTIMMUNE: if (isplayer(lf)) { // don't know if monsters get it msg("You feel immune to %s!", getdamnamenoun(f->val[0])); @@ -732,6 +768,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_DETECTOBS: + if (isplayer(lf)) { // don't know if monsters get it + msg("You can now detect nearby objects."); + donesomething = B_TRUE; + } + break; case F_DETECTMAGIC: if (isplayer(lf)) { // don't know if monsters get it msg("You feel sensitive to magical enchantments."); @@ -779,7 +821,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { if (lf2) { getlfname(lf2, buf); msg("%s turn%s to flee from %s!", lfname, isplayer(lf) ? "" : "s", - cansee(player, lf2) ? buf : "something"); + (cansee(player, lf2) || isplayer(lf2)) ? buf : "something"); } break; case F_POISONED: @@ -952,7 +994,7 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { return B_FALSE; } - if (isdead(player)) return B_FALSE; + if (isdead(lf) || isdead(player)) return B_FALSE; getlfname(lf, lfname); // player can't see? @@ -1034,6 +1076,15 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { } } break; + case F_CHARMEDBY: + lf2 = findlf(NULL, f->val[0]); + if (lf2) { + char buf[BUFLEN]; + getlfname(lf2, buf); + msg("%s break%s free of %s%s control!",lfname, isplayer(lf) ? "" : "s", buf,getpossessive(buf)); + donesomething = B_TRUE; + } + break; case F_DTIMMUNE: if (isplayer(lf)) { // don't know if monsters lose it msg("You are no longer immune to %s.", getdamnamenoun(f->val[0])); @@ -1064,6 +1115,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("%s stop%s fleeing.", lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; + case F_FRIENDLY: + msg("%s no longer looks quite so friendly!", lfname); + break; case F_POISONED: if (isplayer(lf)) { // don't know if monsters lose it msg("You feel less sick now."); @@ -1107,6 +1161,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_DETECTOBS: + if (isplayer(lf)) { // don't know if monsters get it + msg("You can no longer detect nearby objects."); + donesomething = B_TRUE; + } + break; case F_DETECTMAGIC: if (isplayer(lf)) { // don't know if monsters get it msg("You can no longer detect magical enchantments."); @@ -2186,7 +2246,7 @@ void describeob(object_t *o) { } } - f = hasflag(o->flags, F_MISSILE); + f = hasflag(o->flags, F_THROWMISSILE); if (f) { if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) { int dam; @@ -2299,6 +2359,9 @@ void describeob(object_t *o) { case F_DETECTLIFE: mvwprintw(mainwin, y, 0, "%s will detect nearby lifeforms.", buf); y++; break; + case F_DETECTOBS: + mvwprintw(mainwin, y, 0, "%s will detect nearby objects.", buf); y++; + break; case F_DETECTMAGIC: mvwprintw(mainwin, y, 0, "%s will detect magical enchantemnts on objects.", buf); y++; break; @@ -3591,7 +3654,7 @@ void donextguntarget(void) { cell_t *c; c = player->los[i]; if (c->lf && (c->lf != player) && (c->lf != targ)) { - if (haslof(player, c) && isingunrange(player, c)) { + if (haslof(player, c, LOF_NEED, NULL) && isingunrange(player, c)) { // found one! setguntarget(player, c->lf); done = B_TRUE; @@ -3676,7 +3739,7 @@ void dorest(void) { } if (strchr(validchars, 'h') && strchr(validchars, 'm')) { - strcat(validchars, "b"); + strcat(validchars, "bn"); strcpy(ques, "Rest until full HP, Mana, Both or none"); ch = askchar(ques, validchars, "b", B_TRUE); if (ch == 'b') { @@ -3739,7 +3802,7 @@ void doselguntarget(void) { sprintf(buf, "Aim %s where?",gunname); where = askcoords(buf, TT_MONSTER); if (where) { - if (where->lf && haslof(player, where)) { + if (where->lf && haslof(player, where, LOF_NEED, NULL)) { setguntarget(player, where->lf); } else { setguntarget(player, NULL); @@ -3807,13 +3870,22 @@ void dothrow(obpile_t *op) { where = askcoords(buf2, TT_MONSTER); if (where) { - if (!haslof(player, where)) { - if (reason == E_NOLOS) { - msg("You can't see there!"); - } else { // ie. E_NOLOF - msg("You don't have a clear line of fire to there."); + cell_t *newwhere = NULL; + if (!haslof(player, where, LOF_WALLSTOP, &newwhere)) { + if (newwhere) { + // update destination cell. + where = newwhere; + } else { + if (reason == E_NOLOS) { + msg("You can't see there!"); + } else { // ie. E_NOLOF + msg("You don't have a clear line of fire to there."); + } + return; } - } else if (getcelldist(player->cell, where) > maxdist) { + } + + if (getcelldist(player->cell, where) > maxdist) { msg("You can't throw %s that far!",buf); } else { throwat(player, o, where); @@ -3929,7 +4001,7 @@ void drawcellwithcontents(cell_t *cell, int x, int y) { } else { void *thing; char glyph; - // scanned lf here? + // scanned lf here? if (isinscanrange(cell, &thing, NULL, &glyph) == TT_MONSTER) { //mvwprintw(gamewin, y-viewy, x-viewx, "%c", glyph); mvwprintw(gamewin, y, x, "%c", glyph); @@ -4331,9 +4403,16 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { } // fill in the name of the completed choice + /* sprintf(promptstr, "%s %s %s", prompt->q[prompt->whichq], prompt->maycancel ? "[ESC=cancel, '=next page] " : "", prompt->choice[validone].text); + */ + sprintf(promptstr, "%s [%s%s] %s", + prompt->q[prompt->whichq], + prompt->maycancel ? "ESC," : "", + showall ? "'=next page,?=toggle" : "?=list", + prompt->choice[validone].text); mvwprintw(mainwin, 0, 0, "%s", promptstr); // move the cursor back @@ -4935,6 +5014,7 @@ void nothinghappens(void) { void drawstatus(void) { char buf[BUFLEN]; char buf2[BUFLEN]; + char mpbuf[BUFLEN]; char waitbuf[BUFLEN]; char pname[BUFLEN]; char maxmpstr[BUFLEN]; @@ -5046,10 +5126,17 @@ void drawstatus(void) { sprintf(maxmpstr, "(%d)",player->maxmp); } - sprintf(buf, "HP:%d/%d MP:%d/%d%s $:%d St:%d%c Dx:%d%c Iq:%d%c Cn:%d%c DLev:%d", + if (getmaxmp(player) > 0) { + sprintf(mpbuf, "%d/%d%s", player->mp, getmaxmp(player), maxmpstr); + } else { + strcpy(mpbuf, "-"); + } + + sprintf(buf, "HP:%d/%d MP:%s $:%d AR:%d St:%d%c Dx:%d%c Iq:%d%c Cn:%d%c DLev:%d", player->hp,player->maxhp, - player->mp, getmaxmp(player), maxmpstr, + mpbuf, countmoney(player), + getarmourrating(player), str, (str == player->baseatt[A_STR]) ? ' ' : '*', dex, (dex == player->baseatt[A_DEX]) ? ' ' : '*', iq, (iq == player->baseatt[A_IQ]) ? ' ' : '*', @@ -6054,6 +6141,20 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s cannot see.", you(lf)); y++; } + f = lfhasknownflag(lf, F_CHARMEDBY); + if (f) { + lifeform_t *lf2; + char charmername[BUFLEN]; + lf2 = findlf(NULL, f->val[0]); + if (lf2) { + getlfnamea(lf2, charmername); + } else { + strcpy(charmername, "something"); + } + sprintf(buf,"%s %s been charmed by %s.",you(lf), isplayer(lf) ? "have" : "has", charmername); + mvwprintw(mainwin, y, 0, buf); + y++; + } f = lfhasknownflag(lf, F_DETECTAURAS); if (f) { mvwprintw(mainwin, y, 0, "%s automatically detect blessings or curses.", you(lf)); @@ -6074,6 +6175,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s automatically detect nearby metal.", you(lf)); y++; } + f = lfhasknownflag(lf, F_DETECTOBS); + if (f) { + mvwprintw(mainwin, y, 0, "%s automatically detect nearby objects.", you(lf)); + y++; + } f = lfhasknownflag(lf, F_EXTRAINFO); if (f && (f->known)) { mvwprintw(mainwin, y, 0, "%s receive enhanced knowledge about the world.", you(lf)); diff --git a/lf.c b/lf.c index 9f920ca..0a79d00 100644 --- a/lf.c +++ b/lf.c @@ -358,18 +358,59 @@ lifeform_t *makezombie(object_t *o) { return lf; } +int areenemies(lifeform_t *lf1, lifeform_t *lf2) { + reason = E_OK; + switch (getallegiance(lf1)) { + case AL_HOSTILE: + switch (getallegiance(lf2)) { + case AL_HOSTILE: + return B_FALSE; + case AL_PEACEFUL: + return B_FALSE; + case AL_FRIENDLY: + return B_TRUE; + } + break; + case AL_PEACEFUL: + return B_FALSE; + case AL_FRIENDLY: + switch (getallegiance(lf2)) { + case AL_HOSTILE: + return B_TRUE; + case AL_PEACEFUL: + return B_FALSE; + case AL_FRIENDLY: + return B_FALSE; + } + break; + } + return B_TRUE; +} + +int areallies(lifeform_t *lf1, lifeform_t *lf2) { + if (getallegiance(lf1) == getallegiance(lf2)) { + return B_TRUE; + } + return B_FALSE; +} + // make sure player has at least novice skill in their start weapon void autoskill(lifeform_t *lf) { object_t *wep; + skill_t *sk; wep = getweapon(lf); if (wep) { - skill_t *sk; sk = getobskill(wep); - if (sk && !getskill(lf, sk->id)) { - giveskill(lf, sk->id); - } } else { - // TODO: unarmed skill + sk = findskill(SK_UNARMED); + } + + if (sk) { + if (isplayer(lf)) { + giveskilllev(lf, sk->id, PR_NOVICE); + } else { + giveskilllev(lf, sk->id, PR_ADEPT); + } } } @@ -400,7 +441,7 @@ void autotarget(lifeform_t *lf) { if (isdead(targ)) { // clear target ? targ = NULL; - } else if (!haslof(lf, targ->cell)) { + } else if (!haslof(lf, targ->cell, B_FALSE, NULL)) { // clear target ? targ = NULL; } else { @@ -419,12 +460,10 @@ void autotarget(lifeform_t *lf) { for (i = 0; i < lf->nlos; i++) { cell_t *c; c = lf->los[i]; - if (c->lf && (c->lf != lf) && isingunrange(lf, c)) { + if (c->lf && (c->lf != lf) && cansee(lf, c->lf) && isingunrange(lf, c)) { int valid = B_TRUE; - if (isplayer(lf)) { - if (isfriendly(c->lf) || ispeaceful(c->lf)) { - valid = B_FALSE; - } + if (!areenemies(lf, c->lf)) { + valid = B_FALSE; } if (valid) { int thisdist; @@ -699,13 +738,65 @@ int caneat(lifeform_t *lf, object_t *o) { return B_TRUE; } -int canhear(lifeform_t *lf, cell_t *c) { - int hrange; - hrange = gethearingrange(lf); - if (getcelldist(lf->cell, c) <= hrange) { - return B_TRUE; +int canhear(lifeform_t *lf, cell_t *dest) { + int numpixels; + int i; + int x1,y1; + int hleft; + int x2,y2; + map_t *map; + cell_t *retcell[MAXRETCELLS]; + + if (!lf) return B_FALSE; + if (!dest) return B_FALSE; + if (!lf->cell) return B_FALSE; + + // can't hear when dead. + if (isdead(lf)) return B_FALSE; + + // can't hear on other maps + if (lf->cell->map != dest->map) return B_FALSE; + + map = dest->map; + + x1 = lf->cell->x; + y1 = lf->cell->y; + x2 = dest->x; + y2 = dest->y; + + calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels ); + + // get max hearing range + hleft = gethearingrange(lf); + if (hleft <= 0) { + return B_FALSE; } - return B_FALSE; + + for (i = 0; i < numpixels ; i++) { + cell_t *cell; + + cell = retcell[i]; + + // don't need to move out of the last one + if ((cell->x == x2) && (cell->y == y2)) { + break; + } + // you can always hear your own cell + if (i != 0) { + // solid cells decrease hearing range + if (cell->type->solid) { + hleft--; + } + + // hearing range decreases by one + hleft--; + } + + if (hleft <= 0) { + return B_FALSE; + } + } + return B_TRUE; } // @@ -806,33 +897,22 @@ int canquaff(lifeform_t *lf, object_t *o) { int canrest(lifeform_t *lf) { lifeform_t *l; reason = E_OK; - if (isplayer(lf)) { - for (l = lf->cell->map->lf ; l ; l = l->next) { - if ((l != lf) && cansee(lf, l) && !isfriendly(l)) { - reason = E_MONSTERNEARBY; - return B_FALSE; - } - } - } else if (isfriendly(lf)) { // ally - for (l = lf->cell->map->lf ; l ; l = l->next) { - if ((l != lf) && cansee(lf, l) && !isplayer(l)) { - reason = E_MONSTERNEARBY; - return B_FALSE; - } - } - } else { // monster - for (l = lf->cell->map->lf ; l ; l = l->next) { - if ((l != lf) && cansee(lf, l) && - (isplayer(l) || isfriendly(l)) ) { - reason = E_MONSTERNEARBY; - return B_FALSE; - } + + for (l = lf->cell->map->lf ; l ; l = l->next) { + if ((l != lf) && cansee(lf, l) && areenemies(lf, l) ) { + reason = E_MONSTERNEARBY; + return B_FALSE; } } return B_TRUE; } int cansee(lifeform_t *viewer, lifeform_t *viewee) { + // viewer asleep? + if (lfhasflag(viewer, F_ASLEEP)) { + return B_FALSE; + } + // no line of sight? if (!haslos(viewer, viewee->cell)) { return B_FALSE; @@ -1384,11 +1464,17 @@ int eat(lifeform_t *lf, object_t *o) { } if (isrotting(o)) { + char dambuf[BUFLEN]; // lose hp if (isplayer(lf)) { msg("That %s was bad!", drinking ? "liquid" : "food"); } // food poisoning for 20 turns + if (drinking) { + sprintf(dambuf, "%s",obname); + } else { + sprintf(dambuf, "a bad %s",noprefix(obname)); + } addtempflag(lf->flags, F_POISONED, B_TRUE, NA, NA, obname, 20); } @@ -1663,23 +1749,16 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) { scare(lf, attacker, PERMENANT); } else { lifeform_t *l; - // they will now fight back! - if (!hasflagval(lf->flags, F_TARGET, attacker->id, NA, NA, NULL)) { - addflag(lf->flags, F_TARGET, attacker->id, attacker->cell->x, attacker->cell->x, NULL); - } + + setlftarget(lf, attacker); // any nearby monsters which will help out? - for (l = lf->cell->map->lf ; l ; l = l->next) { - if (l->race->baseid == lf->race->baseid) { - if (!isdead(l) && (isfriendly(l) == isfriendly(lf))) { - if (cansee(l, attacker)) { - // make hostile - if (!isfriendly(lf)) { - addflag(l->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - } - // attack! - if (!hasflagval(l->flags, F_TARGET, attacker->id, NA, NA, NULL)) { - addflag(l->flags, F_TARGET, attacker->id, attacker->cell->x, attacker->cell->x, NULL); + if (getallegiance(lf) != AL_FRIENDLY) { + for (l = lf->cell->map->lf ; l ; l = l->next) { + if (l->race->baseid == lf->race->baseid) { + if (!isdead(l) && areallies(l,lf)) { + if (cansee(l, attacker)) { + setlftarget(l, attacker); } } } @@ -1763,6 +1842,24 @@ skill_t *findskill(enum SKILL id) { return NULL; } +skill_t *findskillbyname(char *name) { + skill_t *s; + for (s = firstskill ; s ; s = s->next) { + if (!strcasecmp(s->name, name)) return s; + } + return NULL; +} + +enum SKILLLEVEL findskilllevbyname(char *name) { + enum SKILLLEVEL slev; + for (slev = PR_INEPT; slev <= PR_MASTER; slev++) { + if (!strcasecmp(getskilllevelname(slev), name)) { + return slev; + } + } + return PR_INEPT; +} + // returns TRUE if we ran away from something int flee(lifeform_t *lf) { flag_t *f, *nextf; @@ -2022,6 +2119,26 @@ int getactspeed(lifeform_t *lf) { return speed; } +enum ALLEGIENCE getallegiance(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_CHARMEDBY); + if (f) { + lifeform_t *cb; + cb = findlf(NULL, f->val[0]); + if (cb) { + return getallegiance(cb); + } else { + killflag(f); + } + } + if (isplayer(lf) || isfriendly(lf)) { + return AL_FRIENDLY; + } else if (ispeaceful(lf)) { + return AL_PEACEFUL; + } + return AL_HOSTILE; +} + object_t *getarmour(lifeform_t *lf, enum BODYPART bp) { object_t *o; for (o = lf->pack->first ; o ; o = o->next) { @@ -2122,7 +2239,6 @@ int getattr(lifeform_t *lf, enum ATTRIB attr) { return val; } - int getevasion(lifeform_t *lf) { object_t *o; flag_t *f; @@ -2174,13 +2290,13 @@ int getevasion(lifeform_t *lf) { } -object_t *getbestmissile(lifeform_t *lf) { +object_t *getbestthrowmissile(lifeform_t *lf) { object_t *bestwep = NULL; int bestdam = -1; object_t *o; for (o = lf->pack->first ; o ; o = o->next) { - if (!isequipped(o) && (ismissile(o) || hasflag(o->flags, F_MISSILE))) { + if (!isequipped(o) && isthrowmissile(o) ) { int thisdam; // better than last one? thisdam = getthrowdam(o) + getshatterdam(o); @@ -2382,7 +2498,7 @@ int gethealtime(lifeform_t *lf) { */ int gethearingrange(lifeform_t *lf) { - int range = 15; // deafult + int range = 8; // deafult return range; } @@ -2819,6 +2935,24 @@ char *getmoveverbother(lifeform_t *lf) { return "walks"; } +lifeform_t *getnearbypeaceful(lifeform_t *lf) { + int i; + lifeform_t *poss[MAXCANDIDATES]; + lifeform_t *l; + int nposs = 0; + // peaceful enemy in los ? + for (i = 0; i < lf->nlos; i++) { + l = lf->los[i]->lf; + if (l && (getallegiance(l) == AL_PEACEFUL)) { + poss[nposs] = l; + } + } + if (nposs) { + return poss[rnd(0,nposs-1)]; + } + return NULL; +} + char *getlfname(lifeform_t *lf, char *buf) { return real_getlfname(lf, buf, B_TRUE); } @@ -3691,18 +3825,32 @@ int giveskill(lifeform_t *lf, enum SKILL id) { return B_FALSE; } +int giveskilllev(lifeform_t *lf, enum SKILL id, enum SKILLLEVEL slev) { + flag_t *f; + f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL); + if (f) { + f->val[1] = slev; + } else { + addflag(lf->flags, F_HASSKILL, id, slev, NA, NULL); + } + return B_FALSE; +} + // give start objects from a particular flagpile void givestartobs(lifeform_t *lf, flagpile_t *fp) { object_t *o; flag_t *f; char buf[BUFLEN]; int ignorenext = B_FALSE; + int ignoredprev = B_FALSE; // give start objects and id them ignorenext = B_FALSE; for (f = fp->first ; f ; f = f->next) { o = NULL; if (ignorenext) { + ignorenext = B_FALSE; + ignoredprev = B_TRUE; continue; } if (f->id == F_IFPCT) { @@ -3714,6 +3862,11 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) { } else if ((f->val[2] == IFPLAYER) && !isplayer(lf)) { ignorenext = B_TRUE; } + } else if (f->id == F_ELSE) { + if (ignoredprev) { + } else { + ignorenext = B_TRUE; + } } else { if (isplayer(lf)) { // if this is the player, DONT inherit any STARTOB* flags from race @@ -3751,6 +3904,7 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) { } } } + ignoredprev = B_FALSE; } // now remove startob flags so we don't get them again! @@ -4092,34 +4246,18 @@ int hasbp(lifeform_t *lf, enum BODYPART bp) { return B_TRUE; } -int haslof(lifeform_t *viewer, cell_t *dest) { - int deltax, deltay; +// got line of fire to dest? if lof is blocked, return last cell in 'newdest' +int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) { int numpixels; - int d; - int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2; - int xinc,yinc,dinc; int i; - int x1,y1; - int x; - int y; - //int maxvisrange; - //int lightrange; - //int xray = 0; - //int wentuphill = B_FALSE; - //int origheight; - - int x2,y2; + int x1,y1,x2,y2; map_t *map; + cell_t *retcell[MAXRETCELLS]; reason = E_OK; - // must have line of sight to fire... - /* - if (!haslos(viewer, dest)) { - reason = E_NOLOS; - return B_FALSE; - } - */ + if (!viewer) return B_FALSE; + if (!viewer->cell) return B_FALSE; if (viewer->cell->map != dest->map) { reason = E_NOLOS; @@ -4133,80 +4271,46 @@ int haslof(lifeform_t *viewer, cell_t *dest) { x2 = dest->x; y2 = dest->y; - deltax = (x2 - x1); - if (deltax < 0) deltax = -deltax; - deltay = (y2 - y1); - if (deltay < 0) deltay = -deltay; - // can always fire at your own cell - if ((deltax == 0) && (deltay == 0)) { + if ((x1 == x2) && (y1 == y2)) { return B_TRUE; } - if (deltax >= deltay) { - numpixels = deltax + 1; - d = (deltay*2) - deltax; - dinc1 = deltay << 1; - dinc2 = (deltay-deltax) << 1; - xinc1 = 1; - xinc2 = 1; - yinc1 = 0; - yinc2 = 1; - } else { - numpixels = deltay + 1; - d = (deltax*2) - deltay; - dinc1 = deltax << 1; - dinc2 = (deltax - deltay) << 1; - xinc1 = 0; - xinc2 = 1; - yinc1 = 1; - yinc2 = 1; - } + calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels); - if (x1 > x2) { - xinc1 = - xinc1; - xinc2 = - xinc2; - } - if (y1 > y2) { - yinc1 = - yinc1; - yinc2 = - yinc2; - } - x = x1; y = y1; + if (newdest) *newdest = viewer->cell; for (i = 0; i < numpixels ; i++) { cell_t *cell; object_t *blockob; - /* - // we _DO_ need to move out of last cell for line of fire. - if ((x == x2) && (y == y2)) { - break; - } - */ + cell = retcell[i]; - if (d < 0) { - xinc = xinc1; - yinc = yinc1; - dinc = dinc1; - } else { - xinc = xinc2; - yinc = yinc2; - dinc = dinc2; + // we _DO_ need to move out of last cell for line of fire. + + // if walls don't stop lof, this is now a valid cell. + if (!(loftype & LOF_WALLSTOP)) { + if (newdest) *newdest = cell; } // solid cells stop lof - cell = getcellat(map, x, y); - if (cell->type->solid) { + if ((cell->type->solid) && (loftype & LOF_WALLSTOP)) { reason = E_NOLOF; return B_FALSE; } + + // if lifeforms don't stop lof, this is now a valid cell. +// if (!(loftype & LOF_LFSSTOP)) { + if (newdest) *newdest = cell; +// } + // lifeforms block lof unless they're in our destination - if (cell->lf) { + if (cell->lf && (loftype & LOF_LFSSTOP)) { // if not in first cell... - if ((x != x1) || (y != y1)) { + if (i != 0) { // if not in last cell... - if ((x != x2) || (y != y2)) { + if (i != (numpixels-1)) { reason = E_NOLOF; return B_FALSE; } @@ -4214,7 +4318,7 @@ int haslof(lifeform_t *viewer, cell_t *dest) { } // certain objects block lof blockob = hasobwithflag(cell->obpile, F_BLOCKSTHROW); - if (blockob) { + if (blockob && (loftype & LOF_LFSSTOP)) { int blocked = B_TRUE; // default int isopen; if (isdoor(blockob, &isopen)) { @@ -4229,11 +4333,8 @@ int haslof(lifeform_t *viewer, cell_t *dest) { return B_FALSE; } } - - // move to next cell - d += dinc; - x += xinc; - y += yinc; + // cell is now valid + if (newdest) *newdest = cell; } // made it to the target cell! @@ -4241,15 +4342,9 @@ int haslof(lifeform_t *viewer, cell_t *dest) { } int haslos(lifeform_t *viewer, cell_t *dest) { - int deltax, deltay; int numpixels; - int d; - int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2; - int xinc,yinc,dinc; int i; int x1,y1; - int x; - int y; int maxvisrange; int nightvisrange; int xray = 0; @@ -4260,9 +4355,11 @@ int haslos(lifeform_t *viewer, cell_t *dest) { int x2,y2; map_t *map; object_t *o; + cell_t *retcell[MAXRETCELLS]; if (!viewer) return B_FALSE; if (!dest) return B_FALSE; + if (!viewer->cell) return B_FALSE; // let the player see when dead, otherwise the screen wil // go black when "You die" appears. @@ -4286,75 +4383,16 @@ int haslos(lifeform_t *viewer, cell_t *dest) { xray = 0; } - - deltax = (x2 - x1); - if (deltax < 0) deltax = -deltax; - deltay = (y2 - y1); - if (deltay < 0) deltay = -deltay; - - // can always see your own cell - /* - if ((deltax == 0) && (deltay == 0)) { - //if (viewer->controller == C_HUMAN) wreck->mazelev[z].maze[y2*MAZEW+x2].known = B_PERM; - return B_TRUE; - } - */ - // can't see if you're blind if (lfhasflag(viewer, F_BLIND)) { return B_FALSE; } + calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels); - /* - if (hasproplf(viewer, P_BLINDED)) { - return B_FALSE; - } - */ - - if (deltax >= deltay) { - numpixels = deltax + 1; - d = (deltay*2) - deltax; - dinc1 = deltay << 1; - dinc2 = (deltay-deltax) << 1; - xinc1 = 1; - xinc2 = 1; - yinc1 = 0; - yinc2 = 1; - } else { - numpixels = deltay + 1; - d = (deltax*2) - deltay; - dinc1 = deltax << 1; - dinc2 = (deltax - deltay) << 1; - xinc1 = 0; - xinc2 = 1; - yinc1 = 1; - yinc2 = 1; - } - - if (x1 > x2) { - xinc1 = - xinc1; - xinc2 = - xinc2; - } - if (y1 > y2) { - yinc1 = - yinc1; - yinc2 = - yinc2; - } - - x = x1; y = y1; - - //maxvisrange = getvisrange(viewer, B_LIGHTDOESNTMATTER); maxvisrange = getvisrange(viewer); nightvisrange = getnightvisrange(viewer); - /* - if (hasproplf(viewer, P_SEEINDARK) || wreck->mazelev[viewer->z].lightlevel >= 100) { - lightrange = maxvisrange; - } else { - lightrange = getvisrange(viewer, B_LIGHTMATTERS); - } - */ - //origheight = getheight(x1,y1,z); // too far away @@ -4378,22 +4416,12 @@ int haslos(lifeform_t *viewer, cell_t *dest) { for (i = 0; i < numpixels ; i++) { cell_t *cell; + cell = retcell[i]; // don't need to move out of the last one - if ((x == x2) && (y == y2)) { + if ((cell->x == x2) && (cell->y == y2)) { break; } - if (d < 0) { - xinc = xinc1; - yinc = yinc1; - dinc = dinc1; - } else { - xinc = xinc2; - yinc = yinc2; - dinc = dinc2; - } - - // you can always see your own cell if (i != 0) { // if we went uphill, stop here @@ -4412,23 +4440,11 @@ int haslos(lifeform_t *viewer, cell_t *dest) { // solid cells stop los - but if you are standing on a solid // cell you can still see out. - cell = getcellat(map, x, y); if (!cell->type->transparent) { if (xray) xray--; else return B_FALSE; } - /* - // check for smoke - if ((x != x1) || (y != y1)) { // if not in first cell - if (hasopaqueobject(viewer, x,y,z) && (getheight(x,y,z) >= origheight)) { - if (!hasproplf(viewer, P_SEEINSMOKE)) { - return B_FALSE; - } - } - } - */ - // check for objects which block view for (o = cell->obpile->first ; o ; o = o->next) { if (hasflag(o->flags, F_BLOCKSVIEW)) { @@ -4450,11 +4466,6 @@ int haslos(lifeform_t *viewer, cell_t *dest) { } */ } - - // move to next cell - d += dinc; - x += xinc; - y += yinc; } // made it to the target cell! @@ -4652,7 +4663,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_FIREDART, NA, NA, "pw:5;"); addflag(lastrace->flags, F_CANWILL, OT_S_WEAKEN, NA, NA, "pw:2;"); addflag(lastrace->flags, F_CANWILL, OT_S_SLEEP, NA, NA, "pw:2;"); - addflag(lastrace->flags, F_CANWILL, OT_S_PULLMETAL, NA, NA, "pw:2;"); + addflag(lastrace->flags, F_CANWILL, OT_S_PULL, NA, NA, "pw:2;"); addflag(lastrace->flags, F_CANWILL, OT_S_PARALYZE, NA, NA, "pw:2;"); addflag(lastrace->flags, F_HASATTACK, 2, 4, NA, "teeth"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "gazes at you"); @@ -4664,6 +4675,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addrace(R_BUGBEAR, "bugbear", 120, 'G', MT_FLESH); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -4731,6 +4743,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "0d6+5"); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addrace(R_EYEBAT, "eyebat", 5, 'e', MT_FLESH); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL); @@ -4757,6 +4770,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); addrace(R_GIANTHILL, "hill giant", 160, 'H', MT_FLESH); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 55, NA, NULL); @@ -4780,8 +4794,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_DEX, DX_CLUMSY, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_WANTS, OT_BOULDER, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); @@ -4869,6 +4883,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, DX_SWIFT, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^crackling flames."); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); addflag(lastrace->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_BURNINGWAVE, 3, 3, "pw:6;"); @@ -5185,6 +5200,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_INDUCEFEAR, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addrace(R_OGRE, "ogre", 160, 'O', MT_FLESH); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -5360,6 +5376,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); addrace(R_SHADOWCAT, "shadowcat", 5, 'f', MT_FLESH); @@ -5399,6 +5416,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, 1, 6, 5, "acidattack"); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_SEEWITHOUTEYES, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^slurping."); addflag(lastrace->flags, F_DTIMMUNE, DT_ACID, B_TRUE, NA, NULL); addflag(lastrace->flags, F_AUTOCREATEOB, 0, NA, NA, "puddle of acid"); @@ -5420,6 +5438,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, 1, 3, 0, "claws"); addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^crackling flames."); addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SS_FIRE, PR_BEGINNER, NA, NULL); @@ -5453,7 +5472,7 @@ void initrace(void) { // end monsters // animals - addrace(R_BAT, "giant bat", 1, 'B', MT_FLESH); + addrace(R_BAT, "giant bat", 3, 'B', MT_FLESH); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); @@ -5464,6 +5483,7 @@ void initrace(void) { addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, 0, 2, NA, ""); addflag(lastrace->flags, F_HASATTACK, 1, 2, 0, "teeth"); + addflag(lastrace->flags, F_HASATTACK, 1, 3, 0, "claws"); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -5473,7 +5493,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); - addrace(R_ANT, "giant worker ant", 0.1, 'a', MT_FLESH); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); + addrace(R_ANT, "giant worker ant", 4, 'a', MT_FLESH); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); @@ -5490,9 +5511,10 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, 0, 1, 4, "teeth"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); - addrace(R_ANTS, "giant soldier ant", 0.1, 'a', MT_FLESH); + addrace(R_ANTS, "giant soldier ant", 5, 'a', MT_FLESH); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); @@ -5513,6 +5535,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:1d8+3;"); addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:1d6+3;needgrab:1;"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); +/* addrace(R_HAWK, "blood hawk", 1, 'A', MT_FLESH); // 'A' for Avian addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -5534,7 +5557,8 @@ oooooooo addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); FLYBY ability ooooooooo - addrace(R_NEWT, "giant newt", 0.1, ':', MT_FLESH); +*/ + addrace(R_NEWT, "giant newt", 4, ':', MT_FLESH); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -5551,7 +5575,7 @@ ooooooooo addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL); - addrace(R_RAT, "giant rat", 0.2, 'r', MT_FLESH); + addrace(R_RAT, "giant rat", 3, 'r', MT_FLESH); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_VWEAK, NA, NULL); @@ -5573,8 +5597,8 @@ ooooooooo addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); - addrace(R_SNAKE, "brown snake", 0.2, 's', MT_FLESH); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, ""); + addrace(R_SNAKE, "brown snake", 3, 's', MT_FLESH); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, ""); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -5584,8 +5608,7 @@ ooooooooo addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, 1, 4, 0, "teeth"); - addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 20, "5-10"); - addflag(lastrace->flags, F_EVASION, 20, NA, NA, NULL); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 20, "2-5"); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); @@ -5595,6 +5618,7 @@ ooooooooo addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^hissing"); addrace(R_WOLF, "wolf", 10, 'd', MT_FLESH); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -5632,6 +5656,7 @@ ooooooooo addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addrace(R_GIANTFLY, "giant fly", 1, 'i', MT_FLESH); @@ -5654,6 +5679,7 @@ ooooooooo addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addrace(R_GIANTBLOWFLY, "giant blowfly", 2, 'i', MT_FLESH); lastrace->baseid = R_GIANTFLY; @@ -5677,6 +5703,7 @@ ooooooooo addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addrace(R_GLOWBUG, "glowbug", 1, 'i', MT_FLESH); @@ -5698,6 +5725,7 @@ ooooooooo addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); // undead addrace(R_ZOMBIE, "zombie", 50, 'Z', MT_FLESH); @@ -5721,6 +5749,7 @@ ooooooooo addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addrace(R_SKELETON, "skeleton", 20, 'Z', MT_BONE); addflag(lastrace->flags, F_UNDEAD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); @@ -5761,6 +5790,7 @@ ooooooooo addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addrace(R_GHOUL, "ghoul", 50, 'Z', MT_FLESH); addflag(lastrace->flags, F_UNDEAD, B_TRUE, NA, NA, NULL); @@ -5781,6 +5811,7 @@ ooooooooo addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); // special monsters addrace(R_GASCLOUD, "cloud of gas", 0.1, '}', MT_GAS); @@ -5806,6 +5837,7 @@ ooooooooo addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addrace(R_DANCINGWEAPON, "dancing weapon", 0, ')', MT_METAL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); @@ -5825,6 +5857,7 @@ ooooooooo addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); } int isairborne(lifeform_t *lf) { @@ -6174,7 +6207,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // if they died if (lf->hp <= 0) { //if (!fromlf || (fromlf == player)) { - if (fromlf && (isplayer(fromlf) || isfriendly(fromlf))) { + if (fromlf && (getallegiance(fromlf) == AL_FRIENDLY)) { addflag(lf->flags, F_KILLEDBYPLAYER, B_TRUE, NA, NA, NULL); } } else { @@ -6184,7 +6217,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml addtempflag(lf->flags, F_SLOWMOVE, 5, NA, NA, NULL, 10); } else if ((damtype == DT_POISONGAS) && (amt > 0)) { if (!skillcheck(lf, SC_POISON, 25, 0)) { - addtempflag(lf->flags, F_POISONED, B_TRUE, NA, NA, NULL, rnd(5,10)); + addtempflag(lf->flags, F_POISONED, B_TRUE, NA, NA, "poison gas", rnd(5,10)); } } } @@ -6228,11 +6261,22 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml return amt; } -void makefriendly(lifeform_t *lf) { - killflagsofid(lf->flags, F_HOSTILE); - if (!hasflag(lf->flags, F_FRIENDLY)) { - addflag(lf->flags, F_FRIENDLY, B_TRUE, NA, NA, NULL); +void makefriendly(lifeform_t *who, int howlong) { + char lfname[BUFLEN]; + + getlfname(who, lfname); + if (lfhasflag(who, F_DEBUG)) { + msg("Making %s friendly.",lfname); } + + if (howlong == PERMENANT) { + killflagsofid(who->flags, F_HOSTILE); + } // if not unlimited, they'll revert back. + + if (!hasflag(who->flags, F_FRIENDLY)) { + addtempflag(who->flags, F_FRIENDLY, B_TRUE, NA, NA, NULL, howlong); + } + } void makenauseated(lifeform_t *lf, int amt, int howlong) { @@ -6254,7 +6298,7 @@ void makenauseated(lifeform_t *lf, int amt, int howlong) { void makenoise(lifeform_t *lf, enum NOISETYPE nid) { flag_t *f; - char buf[BUFLEN]; + char *verb = NULL, *noun = NULL; if (lfhasflag(lf, F_FROZEN)) { // can't make noise if frozen! @@ -6264,18 +6308,49 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { f = hasflagval(lf->flags, F_NOISETEXT, nid, NA, NA, NULL); if (f) { char *dummy; - char *verb, *noun; - verb = strtok_r(f->text, "^", &dummy); - noun = strtok_r(NULL, "^", &dummy); - + char noisetext[BUFLEN]; - if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s %s.", buf, verb); + if (f->text[0] == '^') { + verb = NULL; + noun = strtok_r(f->text, "^", &dummy); } else { - youhear(lf->cell, noun); + verb = strtok_r(f->text, "^", &dummy); + noun = strtok_r(NULL, "^", &dummy); + } + + sprintf(noisetext, "%s.",noun); + noise(lf->cell, lf, noisetext, verb); + } else { + // some defaults + if (nid == N_WALK) { + char movetext[BUFLEN]; + strcpy(movetext, ""); + switch (getlfsize(lf)) { + case SZ_MINI: + case SZ_TINY: + break; + case SZ_SMALL: + noise(lf->cell, lf, "light footsteps.", NULL); + break; + case SZ_MEDIUM: + case SZ_HUMAN: + noise(lf->cell, lf, "footsteps.", NULL); + break; + case SZ_LARGE: + noise(lf->cell, lf, "heavy footsteps.", NULL); + break; + case SZ_HUGE: + case SZ_ENORMOUS: + case SZ_MAX: + noise(lf->cell, lf, "extremely loud thumping.", NULL); + break; + } + if (strlen(movetext)) { + noise(lf->cell, lf, movetext, NULL); + } } } + } void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) { @@ -6419,6 +6494,56 @@ float modifybystat(float num, lifeform_t *lf, enum ATTRIB att) { return newnum; } +void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { + lifeform_t *l; + // if anything nearby hears it, it might respond + for (l = c->map->lf; l ; l = l->next) { + if (l != noisemaker) { + //if (canhear(l, c) && haslos(l, c)) { + if (canhear(l, c) && (haslos(l, c) || skillcheck(l, SC_LISTEN, 17, 0))) { + flag_t *f; + // announce? + if (isplayer(l) && !lfhasflag(l, F_RESTING)) { + // never say "you hear xxx" if you can see the lf that caused the noise. + if (noisemaker && cansee(l, noisemaker)) { + if (seetext) { + char lfname[BUFLEN]; + getlfname(noisemaker, lfname); + msg("%s %s.", lfname, seetext); + } + } else if (text) { + msg("You hear %s", text); + } + } + // wake up a little + f = lfhasflag(l, F_ASLEEP); + if (f) { + if (f->lifetime > 0) { // ie. temporary + timeeffectsflag(f, rnd(1,10)); + } else if (f->lifetime == PERMENANT) { + // wake up! + killflag(f); + // make it temporary + //f->lifetime = rnd(1,10); + } + + // still asleep? + if (lfhasflag(l, F_ASLEEP) && cansee(player, l)) { + char lfname[BUFLEN]; + getlfname(l, lfname); + msg("%s stir%s in %s slumber...", lfname, + isplayer(l) ? "" : "s", + isplayer(l) ? "your" : "its"); + } + } else { + break; + } + } + } + } +} + + // give initial equiment / skills to a lifeform void outfitlf(lifeform_t *lf) { givestartobs(lf, lf->flags); @@ -6503,7 +6628,9 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) { o = moveob(what, lf->pack, howmany); if (o) { // if pickup was successful... if (isplayer(lf)) { - msgnocap("%c - %s.",o->letter, obname); + // refresh obname to copd with stacking + getobname(o, obname, o->amt); + msgnocap("%c - %s",o->letter, obname); } else if (cansee(player, lf)) { char buf[BUFLEN]; getlfname(lf, buf); @@ -7181,11 +7308,14 @@ void setlastdam(lifeform_t *lf, char *buf) { void initskills(void) { addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery."); + addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen."); addskill(SK_FIRSTAID, "First Aid", "Increases the rate at which you regain health."); + addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds."); addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks."); addskill(SK_MAGITEMUSAGE, "Magic Item Usage", "Lets you make better use of magical items."); addskill(SK_RESEARCH, "Research", "Allows you a chance of recognising unknown objects."); addskill(SK_SPELLCASTING, "Spellcasting", "Determines your ability to cast spells from all schools."); + addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently."); addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items."); // weaponry addskill(SK_AXES, "Axes", "Helps you use chopping weapons like axes."); @@ -7216,6 +7346,22 @@ void interrupt(lifeform_t *lf) { stoprunning(lf); killflagsofid(lf->flags, F_AUTOCMD); } +void setlftarget(lifeform_t *lf, lifeform_t *victim) { + // first remove existing targets + killflagsofid(lf->flags, F_TARGET); + killflagsofid(lf->flags, F_TARGETCELL); + + // set new target + addflag(lf->flags, F_TARGET, victim->id, victim->cell->x, victim->cell->x, NULL); + + if (!areenemies(lf, victim)) { + if (getallegiance(victim) == AL_FRIENDLY) { + if (!hasflag(lf->flags, F_HOSTILE)) { + addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } + } + } +} int shoot(lifeform_t *lf) { object_t *gun,*ammo; @@ -7296,9 +7442,15 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r // convert this to 0-20 attrib = getevasion(lf) / 5; break; + case SC_LISTEN: + attrib = (getskill(lf, SK_LISTEN)*2); + break; case SC_RESISTMAG: attrib = (getattr(lf, A_CON)/4) + (getattr(lf, A_IQ)/4) + getmr(lf); break; + case SC_STEALTH: + attrib = (getskill(lf, SK_STEALTH)*4); + break; } // level modifier @@ -7329,6 +7481,10 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r } else if (isvulnto(lf->flags, DT_POISON)) { othermod -= 10; } + } else if (ct == SC_STEALTH) { + if (isairborne(lf)) { + othermod += 5; + } } else if (ct == SC_WILL) { // level counts for more levmod *= 2; @@ -7684,16 +7840,20 @@ void timeeffectslf(lifeform_t *lf) { f = hasflag(lf->flags, F_POISONED); if (f) { - //sprintf(buf, "eating a bad %s",strchr(obname, ' ')); - // chance of losing hp - if (rnd(0,3)) { - char buf[BUFLEN]; - if (isplayer(lf)) { - msg("You vomit violently."); + // chance of fighting it off + if (skillcheck(lf, SC_POISON, (f->lifetime * 7), getskill(lf, SK_FIRSTAID))) { + killflag(f); + } else { + // chance of losing hp + if (rnd(0,3)) { + char buf[BUFLEN]; + if (isplayer(lf)) { + msg("You vomit violently."); + } + sprintf(buf, "poisoning^from %s",f->text); + losehp(lf, 2, DT_DIRECT, NULL, buf); + taketime(lf,5); } - sprintf(buf, "food poisoning^from a bad %s",noprefix(f->text)); - losehp(lf, 2, DT_DIRECT, NULL, buf); - taketime(lf,5); } } @@ -7860,7 +8020,6 @@ void turneffectslf(lifeform_t *lf) { } } - // gains/loses stench? for (l = lf->cell->map->lf ; l ; l = l->next) { if (!isdead(l) && (l != lf)) { @@ -7951,6 +8110,23 @@ void turneffectslf(lifeform_t *lf) { continue; } } + if (f->id == F_STABBEDBY) { + lifeform_t *lf2; + lf2 = findlf(NULL, f->val[0]); + // stabber can't see you anymore + if (!lf2 || !cansee(lf2, lf)) { + killflag(f); + continue; + } + } + if (f->id == F_CHARMEDBY) { + lifeform_t *cb; + cb = findlf(NULL, f->val[0]); + if (!cb) { + killflag(f); + continue; + } + } // recharge abilities if (f->id == F_CANWILL) { if (f->val[2] != NA) { @@ -7959,7 +8135,31 @@ void turneffectslf(lifeform_t *lf) { } } } - } + // remove invalid targets + if ((f->id == F_TARGET) || (f->id == F_TARGETCELL)) { + lifeform_t *targ = NULL; + if (f->id == F_TARGET) { + targ = findlf(lf->cell->map, f->val[0]); + } else if (f->id == F_TARGETCELL) { + cell_t *c; + c = getcellat(lf->cell->map, f->val[0], f->val[1]); + if (c && c->lf) { + targ = c->lf; + } + } + if (targ && areallies(lf, targ)) { + if (lfhasflag(lf, F_DEBUG)) { + char lfname[BUFLEN]; + char targname[BUFLEN]; + getlfname(lf, lfname); + getlfname(targ, targname); + msg("%s no longer targetting %s.",lfname,targname); + } + killflag(f); + continue; + } + } // end if f_target or f_targetcell + } // end loop through lf flags } @@ -8933,6 +9133,7 @@ int willflee(lifeform_t *lf) { return B_FALSE; } +/* int youhear(cell_t *c, char *text) { if (canhear(player, c)) { msg("You hear %s.", text); @@ -8940,4 +9141,5 @@ int youhear(cell_t *c, char *text) { } return B_FALSE; } +*/ diff --git a/lf.h b/lf.h index e737e75..f325c32 100644 --- a/lf.h +++ b/lf.h @@ -6,6 +6,8 @@ job_t *addjob(enum JOB id, char *name); race_t *addrace(enum RACE id, char *name, float weight, char glyph, enum MATERIAL mat); skill_t *addskill(enum SKILL id, char *name, char *desc); void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype); +int areallies(lifeform_t *lf1, lifeform_t *lf2); +int areenemies(lifeform_t *lf1, lifeform_t *lf2); void autoskill(lifeform_t *lf); void autotarget(lifeform_t *lf); void autoweild(lifeform_t *lf); @@ -40,6 +42,8 @@ lifeform_t *findlf(map_t *m, int lfid); race_t *findrace(enum RACE id); race_t *findracebyname(char *name); skill_t *findskill(enum SKILL id); +skill_t *findskillbyname(char *name); +enum SKILLLEVEL findskilllevbyname(char *name); int flee(lifeform_t *lf); int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong); void gainhp(lifeform_t *lf, int amt); @@ -47,12 +51,13 @@ void gainlevel(lifeform_t *lf); void gainmp(lifeform_t *lf, int amt); void gainxp(lifeform_t *lf, long amt); int getactspeed(lifeform_t *lf); +enum ALLEGIENCE getallegiance(lifeform_t *lf); object_t *getarmour(lifeform_t *lf, enum BODYPART bp); int getarmourrating(lifeform_t *lf); int getattackspeed(lifeform_t *lf); int getattr(lifeform_t *lf, enum ATTRIB attr); int getevasion(lifeform_t *lf); -object_t *getbestmissile(lifeform_t *lf); +object_t *getbestthrowmissile(lifeform_t *lf); object_t *getbestweapon(lifeform_t *lf); object_t *getbestfirearm(lifeform_t *lf); int getbodyparthitchance(enum BODYPART bp); @@ -85,6 +90,7 @@ int getvisrange(lifeform_t *lf); int getmovespeed(lifeform_t *lf); char *getmoveverb(lifeform_t *lf); char *getmoveverbother(lifeform_t *lf); +lifeform_t *getnearbypeaceful(lifeform_t *lf); char *getlfname(lifeform_t *lf, char *buf); char *real_getlfname(lifeform_t *lf, char *buf, int usevis); char *getlfnamea(lifeform_t *lf, char *buf); @@ -113,6 +119,7 @@ long getxpforlev(int level); void givejob(lifeform_t *lf, enum JOB jobid); void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype); int giveskill(lifeform_t *lf, enum SKILL id); +int giveskilllev(lifeform_t *lf, enum SKILL id, enum SKILLLEVEL slev); void givestartobs(lifeform_t *lf, flagpile_t *fp); void givestartskills(lifeform_t *lf, flagpile_t *fp); map_t *gotolev(lifeform_t *lf, int depth, object_t *fromstairs); @@ -125,7 +132,7 @@ flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int int lockpick(lifeform_t *lf, object_t *target, object_t *device); void loseobflags(lifeform_t *lf, object_t *o, int kind); int hasbp(lifeform_t *lf, enum BODYPART bp); -int haslof(lifeform_t *viewer, cell_t *dest); +int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest); int haslos(lifeform_t *viewer, cell_t *dest); void initjobs(void); void initrace(void); @@ -154,7 +161,7 @@ void killlf(lifeform_t *lf); void killrace(race_t *race); int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc); int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam); -void makefriendly(lifeform_t *lf); +void makefriendly(lifeform_t *lf, int howlong); void makenauseated(lifeform_t *lf, int amt, int howlong); void makenoise(lifeform_t *lf, enum NOISETYPE nid); lifeform_t *makezombie(object_t *o); @@ -162,6 +169,7 @@ void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how); int modattr(lifeform_t *lf, enum ATTRIB attr, int amt); void modhunger(lifeform_t *lf, int amt); float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); +void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext); void outfitlf(lifeform_t *lf); int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground); void precalclos(lifeform_t *lf); @@ -180,6 +188,7 @@ void setattr(lifeform_t *lf, enum ATTRIB attr, int val); void setguntarget(lifeform_t *lf, lifeform_t *targ); void setrace(lifeform_t *lf, enum RACE rid); void setlastdam(lifeform_t *lf, char *buf); +void setlftarget(lifeform_t *lf, lifeform_t *victim); int shoot(lifeform_t *lf); int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod); int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *result); @@ -203,4 +212,4 @@ int validateraces(void); int wear(lifeform_t *lf, object_t *o); int weild(lifeform_t *lf, object_t *o); int willflee(lifeform_t *lf); -int youhear(cell_t *c, char *text); +//int youhear(cell_t *c, char *text); diff --git a/log.txt b/log.txt index ee531f6..b362097 100644 --- a/log.txt +++ b/log.txt @@ -2,421 +2,117 @@ ====== NEW LOGFILE ==== -findotn(): modname is 'wooden door' -checkobnames(): got exact match: 'wooden door' xxx -findotn(): modname is 'wooden door' -checkobnames(): got exact match: 'wooden door' xxx -findotn(): modname is 'wooden door' -checkobnames(): got exact match: 'wooden door' xxx -findotn(): modname is 'wooden door' -checkobnames(): got exact match: 'wooden door' xxx -findotn(): modname is 'wooden door' -checkobnames(): got exact match: 'wooden door' xxx -findotn(): modname is 'wooden door' -checkobnames(): got exact match: 'wooden door' xxx -findotn(): modname is 'staircase going up' -checkobnames(): got exact match: 'staircase going up' -findotn(): modname is 'staircase going down' -checkobnames(): got exact match: 'staircase going down' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 2 x bolt ('bolts') -findotn(): modname is 'bolts' -checkobnames(): got match after stripping 's': 'bolt' -> 'bolts' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -adding random object with rarity value between 72 - 100 - (must have obclass = Potions) -got 8 possibilities. -random ob: 1 x potion of minor healing ('potion of minor healing') -findotn(): modname is 'potion of minor healing' -checkobnames(): got exact match: 'potion of minor healing' -findotn(): modname is 'claws' -checkobnames(): got exact match: 'claws' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -findotn(): modname is 'zapper' -checkobnames(): got exact match: 'zapper' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -adding random object with rarity value between 72 - 100 - (must have obclass = Potions) -got 8 possibilities. -random ob: 1 x potion of magic ('potion of magic') -findotn(): modname is 'potion of magic' -checkobnames(): got exact match: 'potion of magic' -findotn(): modname is 'claws' -checkobnames(): got exact match: 'claws' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x potion of oil ('potion of oil') -findotn(): modname is 'potion of oil' -checkobnames(): got exact match: 'potion of oil' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x scimitar ('scimitar') -findotn(): modname is 'scimitar' -checkobnames(): got exact match: 'scimitar' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x potion of magic ('potion of magic') -findotn(): modname is 'potion of magic' -checkobnames(): got exact match: 'potion of magic' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x apple ('apple') -findotn(): modname is 'apple' -checkobnames(): got exact match: 'apple' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 6 x nanodart ('nanodarts') -findotn(): modname is 'nanodarts' -checkobnames(): got match after stripping 's': 'nanodart' -> 'nanodarts' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x knife ('knife') -findotn(): modname is 'knife' -checkobnames(): got exact match: 'knife' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 -> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 -> possibility: giant bat, rarity=90 -> possibility: giant worker ant, rarity=85 +-> possibility: giant newt, rarity=100 -> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 +-> possibility: brown snake, rarity=85 -> possibility: giant fly, rarity=85 -> possibility: glowbug, rarity=85 got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 9 possibilities. -findotn(): modname is 'claws' -checkobnames(): got exact match: 'claws' -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 3 x bolt ('bolts') -findotn(): modname is 'bolts' -checkobnames(): got match after stripping 's': 'bolt' -> 'bolts' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x spellbook of inscribe ('spellbook of inscribe') -findotn(): modname is 'spellbook of inscribe' -checkobnames(): got exact match: 'spellbook of inscribe' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x splash of blood ('splash of blood') -findotn(): modname is 'splash of blood' -checkobnames(): got exact match: 'splash of blood' -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 9 possibilities. -findotn(): modname is 'short sword' -checkobnames(): got exact match: 'short sword' -findotn(): modname is 'claws' -checkobnames(): got exact match: 'claws' -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant newt, rarity=100 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=95 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 9 possibilities. -findotn(): modname is 'teeth' -checkobnames(): got exact match: 'teeth' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x potion of fruit juice ('potion of fruit juice') -findotn(): modname is 'potion of fruit juice' -checkobnames(): got exact match: 'potion of fruit juice' -adding random object with rarity value between 72 - 100 -got 100 possibilities. -random ob: 1 x boulder ('boulder') -findotn(): modname is 'boulder' -checkobnames(): got exact match: 'boulder' -rollhitdice() - rolling 2d4 + 2 -rollhitdice() - mod is +88% -rollhitdice() ---- die 1/2 == 4 -rollhitdice() ---- die 2/2 == 4 -TOTAL: 8 - -> modified to: 15 -findotn(): modname is 'fists' -checkobnames(): got exact match: 'fists' -givejob() starting. - -processing normal flag: 183 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 144 -processing normal flag: 145 -processing normal flag: 145 -processing normal flag: 145 -processing normal flag: 145 -processing normal flag: 145 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 210 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -processing normal flag: 209 -findotn(): modname is 'short sword' -checkobnames(): got exact match: 'short sword' -findotn(): modname is 'hand of god' -checkobnames(): got exact match: 'hand of god' -findotn(): modname is 'block of chocolate' -checkobnames(): got exact match: 'block of chocolate' -findotn(): modname is 'vial of ambrosia' -checkobnames(): got exact match: 'vial of ambrosia' -findotn(): modname is 'leather armour' -checkobnames(): got exact match: 'leather armour' -findotn(): modname is 'leather boots' -findotn(): modname is 'leather gloves' -findotn(): modname is 'graph paper' -findotn(): modname is 'digital watch' -checkobnames(): got exact match: 'digital watch' -findotn(): modname is 'scroll of create monster' -checkobnames(): got exact match: 'scroll of create monster' -findotn(): modname is 'potion of experience' -checkobnames(): got exact match: 'potion of experience' -findotn(): modname is 'ring of invulnerability' -checkobnames(): got exact match: 'ring of invulnerability' -findotn(): modname is 'fists' -checkobnames(): got exact match: 'fists' diff --git a/map.c b/map.c index b9a184f..aa37ce4 100644 --- a/map.c +++ b/map.c @@ -72,6 +72,7 @@ map_t *addmap(void) { for (i = 0; i < MAXDIR_ORTH; i++) { a->nextmap[i] = -1; } + a->beingcreated = B_TRUE; return a; } @@ -101,6 +102,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { if (lf) { flag_t *f; + lf->born = B_FALSE; if (jobok) { // has a job? f = hasflag(lf->flags, F_STARTJOB); @@ -111,6 +113,14 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { } } + if (lf->cell->map->beingcreated) { + // sometimes start off asleep in new maps + // TODO: base this on the time, and whether monster is nocturnal + if (rnd(1,2) == 1) { + addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + } + } + // appears in groups? f = hasflag(lf->flags, F_NUMAPPEAR); if (f) { @@ -130,6 +140,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { //adjcell = c; for ( ; amt > 0; amt--) { int n; + lifeform_t *newlf; // find an adjacent cell to one of the newly added monsters, // starting with the first one adjcell = NULL; @@ -141,17 +152,25 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { if (!adjcell) break; //lf = addlf(adjcell, r->id, getrandommonlevel(adjcell->map->depth)); - if (!addlf(adjcell, r->id, 1)) { + newlf = addlf(adjcell, r->id, 1); + if (!newlf) { break; } + newlf->born = B_FALSE; + + if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + + newlf->born = B_TRUE; moncell[nmoncells] = adjcell; nmoncells++; } free(moncell); } - } + lf->born = B_TRUE; + } // end if lf } + return lf; } @@ -169,10 +188,10 @@ void addrandomob(cell_t *c) { } } -void addrandomthing(cell_t *c) { +void addrandomthing(cell_t *c, int obchance) { // if there's already someone there, // then add an object. - if (c->lf || (rnd(1,2) == 1)) { + if (c->lf || (rnd(1,100) <= obchance)) { // object addrandomob(c); } else { @@ -564,6 +583,8 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_ //int db = B_TRUE; + map->beingcreated = B_TRUE; + sprintf(buf, "Map %d",map->id); map->name = strdup(buf); map->habitat = habitat; @@ -1008,7 +1029,7 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_ c = getcellat(map, x, y); if (c && isempty(c)) { if (rnd(1,100) <= getobchance(map->habitat)) { - addrandomthing(c); + addrandomthing(c, 50); } } } @@ -1047,7 +1068,8 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_ } else { */ numobsmin = 0; - numobsmax = MAXOF(roomw[i],roomh[i]) / 2; + //numobsmax = MAXOF(roomw[i],roomh[i]) / 2; + numobsmax = MAXOF(roomw[i],roomh[i]); //} @@ -1086,7 +1108,8 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_ } } else { */ - addrandomthing(c); + // slightly more chance of objects in rooms + addrandomthing(c,60); done = B_TRUE; //dblog("----> Success ob at (%d,%d).",c->x,c->y); } else { @@ -1232,7 +1255,7 @@ void createmap(map_t *map, int depth, int habitat, map_t *parentmap, objecttype_ //printf("*** Level difficulty is %0.2f\n", getmazedifficulty(curz)); - + map->beingcreated = B_FALSE; } void createroom(map_t *map, int minx, int miny, int w, int h, int roomid) { @@ -1472,7 +1495,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int msg("You see %s explosion!", (range > 0) ? "a huge" : "an"); } } else { - youhear(c, "an explosion!"); + noise(c, NULL, "an explosion!", NULL); } for (y = c->y - range ; y <= c->y + range ; y++) { @@ -1493,7 +1516,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int if (cc && (getcelldist(c, cc) <= (range+1))) { if (cc->lf && !isdead(cc->lf)) { // move away from centre of explosion - knockback(cc->lf, getdiraway(cc, c, B_FALSE), 2, NULL); + knockback(cc->lf, getdiraway(cc, c, B_FALSE, DT_COMPASS), 2, NULL); } } } @@ -1980,6 +2003,20 @@ int isinscanrange(cell_t *c, void **thing, char *desc, char *glyph) { } } } + f = lfhasflag(player, F_DETECTOBS); + if (f) { + if (getcelldistorth(player->cell, c) <= f->val[0]) { + object_t *o; + for (o = c->obpile->first ; o ; o = o->next) { + if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_DOOR)) { + *thing = o; + if (glyph) *glyph = '*'; + if (desc) sprintf(desc, "an object"); + return TT_OBJECT; + } + } + } + } return B_FALSE; } diff --git a/map.h b/map.h index d8ec934..6cbbd95 100644 --- a/map.h +++ b/map.h @@ -4,7 +4,7 @@ cell_t *addcell(map_t *map, int x, int y); map_t *addmap(void); lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt); void addrandomob(cell_t *c); -void addrandomthing(cell_t *c); +void addrandomthing(cell_t *c, int obchance); int cellhaslos(cell_t *c1, cell_t *dest); cell_t *getcellat(map_t *map, int x, int y); int getcelldist(cell_t *src, cell_t *dst); diff --git a/move.c b/move.c index 8d84dec..f07675a 100644 --- a/move.c +++ b/move.c @@ -109,7 +109,7 @@ int celldangerous(lifeform_t *lf, cell_t *cell, enum ERROR *error) { f = hasflag(o->flags, F_WALKDAM); if (f) { // are we immune to this? - if (!lfhasflagval(lf, F_DTIMMUNE, f->val[1], NA, NA, NULL)) { + if (!lfhasflagval(lf, F_DTIMMUNE, f->val[0], NA, NA, NULL)) { if (error) { *error = E_AVOIDOB; rdata = o; @@ -255,7 +255,7 @@ void dorandommove(lifeform_t *lf, int badmovesok) { // src is where something is // dst is what we are going away from // wantcheck is whether to check for dangerous things before considering a direction valid -int getdiraway(cell_t *src, cell_t *dst, int wantcheck) { +int getdiraway(cell_t *src, cell_t *dst, int wantcheck, int dirtype) { int d; cell_t *c; int maxdist=-1,bestdir=D_NONE; @@ -290,8 +290,11 @@ int getdiraway(cell_t *src, cell_t *dst, int wantcheck) { } } if (ok) { - //thisdist = getcelldistorth(c, dst); - thisdist = getcelldist(c, dst); + if (dirtype == DT_ORTH) { + thisdist = getcelldistorth(c, dst); + } else { + thisdist = getcelldist(c, dst); + } } else { thisdist = -1; } @@ -324,7 +327,7 @@ int getdiraway(cell_t *src, cell_t *dst, int wantcheck) { } -int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck) { +int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype) { int d; cell_t *c; int mindist=9999,bestdir=D_NONE; @@ -362,8 +365,11 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck) { } if (ok) { int thisdist; - //thisdist = getcelldistorth(c, dst); - thisdist = getcelldist(c, dst); + if (dirtype == DT_ORTH) { + thisdist = getcelldistorth(c, dst); + } else { + thisdist = getcelldist(c, dst); + } dist[d - DC_N] = thisdist; if (thisdist < mindist) { mindist = thisdist; @@ -449,7 +455,7 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst ) { } // move away from them - dir = getdiraway(lf->cell, dst, B_TRUE); + dir = getdiraway(lf->cell, dst, B_TRUE, DT_COMPASS); if (dir == D_NONE) { rv = B_TRUE; } else { @@ -606,15 +612,26 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if ((gamemode == GM_GAMESTARTED)) { for (l = newcell->map->lf ; l ; l = l->next) { if (l != lf) { + // cope with swapping locations with someone! if (haslos(l, newcell)) { - interrupt(l); + int dointerrupt = B_FALSE; + + if (isplayer(l)) { - if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_RESTING)) { - char lfname2[BUFLEN]; - getlfname(lf, lfname); - sprintf(lfname2, "%s",noprefix(lfname)); - msg("%s %s comes into view.",isvowel(lfname2[0]) ? "An" : "A", lfname2); + if (areenemies(lf, l)) { + if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_RESTING)) { + char lfname2[BUFLEN]; + getlfname(lf, lfname); + sprintf(lfname2, "%s",noprefix(lfname)); + msg("%s %s comes into view.",isvowel(lfname2[0]) ? "An" : "A", lfname2); + } + dointerrupt = B_TRUE; } + } else { + dointerrupt = B_TRUE; + } + if (dointerrupt) { + interrupt(l); } } } @@ -714,6 +731,29 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose) { } } } + + // make some noise + // (stealth check to avoid this) + if (!lfhasflag(lf, F_SILENTMOVE)) { + if (!skillcheck(lf, SC_STEALTH, 20, 0)) { + if (isairborne(lf)) { + makenoise(lf, N_FLY); + } else { + makenoise(lf, N_WALK); + } + } + } + + // slip on blood in new cell? + if (!isairborne(lf)) { + int slip; + object_t *slipob; + slip = getslipperyness(newcell, &slipob); + if (slip && !skillcheck(lf, SC_SLIP, slip, 0)) { + slipon(lf, slipob); + } + } + return B_FALSE; } @@ -727,7 +767,7 @@ int movetowards(lifeform_t *lf, cell_t *dst) { } // move towards them - dir = getdirtowards(lf->cell, dst, lf, B_TRUE); + dir = getdirtowards(lf->cell, dst, lf, B_TRUE, DT_COMPASS); if (dir != D_NONE) { rv = trymove(lf, dir, B_TRUE); } @@ -828,6 +868,7 @@ int opendoor(lifeform_t *lf, object_t *o) { } where = getoblocation(o); + noise(where, lf, "a door opening", NULL); if (player && haslos(player, where)) { needredraw = B_TRUE; drawscreen(); @@ -943,11 +984,12 @@ int tryrun(lifeform_t *lf, int dir) { int pullnextto(lifeform_t *lf, cell_t *c) { int dir; cell_t *dst = NULL; + cell_t *newdst = NULL; dst = c; while (dst->lf) { - dir = getdirtowards(dst, lf->cell, lf, B_FALSE); + dir = getdirtowards(dst, lf->cell, lf, B_FALSE, DT_COMPASS); if (dir == D_NONE) { return B_TRUE; } else { @@ -957,11 +999,20 @@ int pullnextto(lifeform_t *lf, cell_t *c) { } } } - // is the path clear? - if (!dst || !haslof(lf, dst)) { + if (!dst) { return B_TRUE; } + + if (!haslof(lf, dst, B_FALSE, &newdst)) { + if (newdst) { + // update destination + dst = newdst; + } else { + return B_TRUE; + } + } + if (isplayer(lf) || cansee(player, lf)) { char buf[BUFLEN]; getlfname(lf, buf); @@ -1066,17 +1117,6 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { reason = E_OK; moveto(lf, cell, onpurpose); taketime(lf, getmovespeed(lf)); - - // slip on blood in new cell? - if (!isairborne(lf)) { - slip = getslipperyness(cell, &slipob); - if (slip && !skillcheck(lf, SC_SLIP, slip, 0)) { - slipon(lf, slipob); - // don't move - reason = E_OK; - return B_FALSE; - } - } } else { object_t *inway; int door, dooropen; @@ -1173,8 +1213,37 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } break; case E_LFINWAY: - // attack! - return attacklf(lf, cell->lf); + if (areallies(lf, cell->lf)) { + // if it's the player in the way... + if (isplayer(cell->lf)) { + return attacklf(lf, cell->lf); + } else { + lifeform_t *lfinway; + cell_t *oldcell; + // otherwise swap locations. + + // make lf who is there vanish temporarily... + lfinway = cell->lf; + cell->lf = NULL; + lfinway->cell = NULL; + + // remember your cell + oldcell = lf->cell; + + // move you.. + moveto(lf, cell, onpurpose); + taketime(lf, getmovespeed(lf)); + + // move them... + lfinway->cell = oldcell; + oldcell->lf = lfinway; + reason = E_OK; + } + } else { + // attack! + return attacklf(lf, cell->lf); + } + break; case E_GRAVBOOSTED: if (isplayer(lf)) { msg("You try to move but are unable to lift your feet!"); @@ -1254,8 +1323,11 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { if (cell->lf) { if (!isplayer(lf)) { // if we are a monster // friendly monsters: don't hit other friendlies - if (isfriendly(lf) && (isfriendly(cell->lf) || isplayer(cell->lf)) ) { + if (!areenemies(lf, cell->lf)) { + // TODO: swap places instead! return B_FALSE; + } + /* } else if (ispeaceful(lf)) { // peaceful mosnters: don't hit anyone return B_FALSE; } else { // hostile/nonfriendly monsters - don't hit other monsters @@ -1263,6 +1335,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { return B_FALSE; } } + */ } } return B_TRUE; diff --git a/move.h b/move.h index 9afc772..9868e6a 100644 --- a/move.h +++ b/move.h @@ -8,8 +8,8 @@ int closedoorat(lifeform_t *lf, cell_t *c); int closedoor(lifeform_t *lf, object_t *o); int diropposite(int dir); void dorandommove(lifeform_t *lf, int badmovesok); -int getdiraway(cell_t *src, cell_t *dst, int wantcheck); -int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck); +int getdiraway(cell_t *src, cell_t *dst, int wantcheck, int dirtype); +int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype); int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher); int moveawayfrom(lifeform_t *lf, cell_t *dst); void moveeffects(lifeform_t *lf); diff --git a/nexus.c b/nexus.c index 7a7d706..48a2cd4 100644 --- a/nexus.c +++ b/nexus.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "ai.h" #include "attack.h" #include "io.h" @@ -69,16 +70,33 @@ int main(int argc, char **argv) { int newworld = B_FALSE; object_t *o; char welcomemsg[BUFLEN]; + int ch; + FILE *playerfile = NULL; atexit(cleanup); + while ((ch = getopt(argc, argv, "f:")) != -1) { + switch (ch) { + case 'f': + playerfile = fopen(optarg, "rt"); + if (!playerfile) { + fprintf(stderr, "cannot open player file: %s\n",optarg); + exit(1); + } + break; + case 'h': + case '?': + default: + usage(argv[0]); + exit(0); + } + } + // init params if (init()) { exit(1); } - - // load whatever maps are available loadall(); @@ -101,20 +119,38 @@ int main(int argc, char **argv) { if (!player) { char *user; char pname[BUFLEN]; - job_t *j; + char buf[BUFLEN]; + job_t *j = NULL; char ch; cell_t *where; - // ask for race - initprompt(&prompt, "Select your race:"); - ch = 'a'; - for (j = firstjob ; j ; j = j->next) { - addchoice(&prompt, ch++, j->name, NULL, j); + // read from input file if required + if (playerfile) { + char *p; + while (!feof(playerfile)) { + fgets(buf, BUFLEN, playerfile); + buf[strlen(buf)-1] = '\0'; + if (strstr(buf, "job:") == buf) { + p = buf + strlen("job:"); + j = findjobbyname(p); + if (j) break; + } + } + fseek(playerfile, 0, SEEK_SET); } - j = NULL; - while (!j) { - getchoice(&prompt); - j = prompt.result; + + if (!j) { + // ask for race + initprompt(&prompt, "Select your job:"); + ch = 'a'; + for (j = firstjob ; j ; j = j->next) { + addchoice(&prompt, ch++, j->name, NULL, j); + } + j = NULL; + while (!j) { + getchoice(&prompt); + j = prompt.result; + } } // find staircase @@ -135,6 +171,14 @@ int main(int argc, char **argv) { } givejob(player, j->id); + if (playerfile) { + if (parseplayerfile(playerfile, player)) { + // error! + exit(0); + } + fclose(playerfile); + } + // player needs hunger addflag(player->flags, F_HUNGER, 0, NA, NA, NULL); @@ -325,6 +369,18 @@ void cleanup(void) { // free races } +void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, int dinc2, int *xinc, int *yinc, int *dinc) { + if (d < 0) { + *xinc = xinc1; + *yinc = yinc1; + *dinc = dinc1; + } else { + *xinc = xinc2; + *yinc = yinc2; + *dinc = dinc2; + } +} + void donextturn(map_t *map) { lifeform_t *who; @@ -512,6 +568,62 @@ int init(void) { return B_FALSE; } +void calcbresnham(map_t *m, int x1, int y1, int x2, int y2, cell_t **retcell, int *numpixels) { + int xinc1,xinc2,yinc1,yinc2,dinc1,dinc2,d; + int xinc,yinc,dinc; + int i; + int x,y; + initbresnham( x1, y1, x2, y2, &xinc1, &yinc1, &dinc1, &xinc2, &yinc2, &dinc2, numpixels, &d); + x = x1; + y = y1; + for (i = 0; i < *numpixels; i++) { + retcell[i] = getcellat(m, x, y); + dobresnham(d, xinc1, yinc1, dinc1, xinc2, yinc2, dinc2, &xinc, &yinc, &dinc); + // move to next cell + d += dinc; + x += xinc; + y += yinc; + } +} + +void initbresnham(int x1, int y1, int x2, int y2, int *xinc1, int *yinc1, int *dinc1, int *xinc2, int *yinc2, int *dinc2, int *numpixels, int *d) { + int deltax,deltay; + + deltax = (x2 - x1); + if (deltax < 0) deltax = -deltax; + deltay = (y2 - y1); + if (deltay < 0) deltay = -deltay; + + if (deltax >= deltay) { + *numpixels = deltax + 1; + *d = (deltay*2) - deltax; + *dinc1 = deltay << 1; + *dinc2 = (deltay-deltax) << 1; + *xinc1 = 1; + *xinc2 = 1; + *yinc1 = 0; + *yinc2 = 1; + } else { + *numpixels = deltay + 1; + *d = (deltax*2) - deltay; + *dinc1 = deltax << 1; + *dinc2 = (deltax - deltay) << 1; + *xinc1 = 0; + *xinc2 = 1; + *yinc1 = 1; + *yinc2 = 1; + } + + if (x1 > x2) { + *xinc1 = - *xinc1; + *xinc2 = - *xinc2; + } + if (y1 > y2) { + *yinc1 = - *yinc1; + *yinc2 = - *yinc2; + } +} + void initcommands(void) { // Actions addcommand(CMD_UP, '<', "Go up stairs."); @@ -577,6 +689,57 @@ int limit(int *what, int min, int max) { return limited; } +int parseplayerfile(FILE *f, lifeform_t *lf) { + // add extra obs etc from f + char *pp; + char localbuf[BUFLEN]; + char buf[BUFLEN]; + int goterror = B_FALSE; + fgets(buf, BUFLEN, f); + while (!feof(f)) { + if (buf[strlen(buf)-1] == '\n') { + buf[strlen(buf)-1] = '\0'; + } + //dblog("got line: [%s]",buf); + if (strstr(buf, "skill:") == buf) { + skill_t *sk; + enum SKILLLEVEL slev; + strcpy(localbuf, buf + strlen("skill:")); + pp = strtok(localbuf, " "); + if (!pp) { + dblog("ERROR in playerfile. unknown skill level in this line:\n%s\n",buf); + goterror = B_TRUE; + } + slev = findskilllevbyname(pp); + + pp += (strlen(pp) + 1); + if (!pp) { + dblog("ERROR in playerfile. missing skill name in this line:\n%s\n",buf); + goterror = B_TRUE; + } + sk = findskillbyname(pp); + if (sk) { + giveskilllev(lf, sk->id, slev); + } else { + dblog("ERROR in playerfile. unknown skill (%s) in this line:\n%s\n",pp, buf); + goterror = B_TRUE; + } + } else if (strstr(buf, "ob:") == buf) { + object_t *o; + strcpy(localbuf, buf + strlen("ob:")); + o = addob(lf->pack, localbuf); + if (o) { + identify(o); + } else { + dblog("ERROR in playerfile. unknown object in this line:\n%s\n",buf); + goterror = B_TRUE; + } + } + fgets(buf, BUFLEN, f); + } + return goterror; +} + float pctof(float pct, float num) { return ((pct / 100.0) * num); } @@ -908,3 +1071,9 @@ void timeeffectsworld(map_t *map) { if (db) dblog("cur time is %ld\n",curtime); } + +void usage(char *progname) { + printf("usage: %s [ -f playerfile ]\n",progname); + printf("\t-f xx\tReads player details from file xx.\n"); +} + diff --git a/nexus.h b/nexus.h index 9caa8c6..5d83c01 100644 --- a/nexus.h +++ b/nexus.h @@ -5,14 +5,18 @@ command_t *addcommand(enum COMMAND id, char c, char *desc); void checkdeath(void); void checkendgame(void); void cleanup(void); +void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, int dinc2, int *xinc, int *yinc, int *dinc); void donextturn(map_t *map); celltype_t *findcelltype(int id); char *getdirname(int dir); void getrarity(int depth, int *min, int *max, int range); int init(void); +void calcbresnham(map_t *m, int x1, int y1, int x2, int y2, cell_t **retcell, int *numpixels); +void initbresnham(int x1, int y1, int x2, int y2, int *xinc1, int *yinc1, int *dinc1, int *xinc2, int *yinc2, int *dinc2, int *numpixels, int *d); void initcommands(void); int isplayerturn(void); int limit(int *what, int min, int max); +int parseplayerfile(FILE *f, lifeform_t *lf); float pctof(float pct, float num); int rnd(int min, int max); int roll(char *string); @@ -22,3 +26,4 @@ int rollmpdice(lifeform_t *lf); //void sortlf(map_t *map); void sortcommands(void); void timeeffectsworld(map_t *map); +void usage(char *progname); diff --git a/objects.c b/objects.c index f05430a..d68b675 100644 --- a/objects.c +++ b/objects.c @@ -1545,7 +1545,7 @@ int changemat(object_t *o, enum MATERIAL mat) { objecttype_t *checkobnames(char *haystack, char *needle) { objecttype_t *ot; char *pluralname; - int db = B_TRUE; + int db = B_FALSE; // search for exact match if (!strcmp(haystack, needle)) { @@ -1650,6 +1650,21 @@ void damageallobs(object_t *exception, obpile_t *op, int howmuch, int damtype) { } } +void dumprandomobs(int amt) { + int i; + char buf[BUFLEN]; + int min,max; + int depth; + depth = player->cell->map->depth; + getrarity(depth, &min, &max, RARITYVARIANCE); + dblog("Random object dump for depth %d (rarity %d-%d)",depth,min,max); + for (i = 0; i < amt; i++) { + getrandomob(player->cell->map, buf); + dblog(" %s",buf); + } + dblog("END RANDOM OBJECT"); +} + void explodeob(object_t *o, flag_t *f, int bigness) { cell_t *c; int dam; @@ -1776,9 +1791,13 @@ objecttype_t *findotn(char *name) { knowledge_t *k; char *modname; char *p; - int db = B_TRUE; + int db = B_FALSE; brand_t *om; + if (!strlen(name)) { + return NULL; + } + modname = strdup(name); // make some replacements @@ -2126,6 +2145,8 @@ int getobvalue(object_t *o) { } else if (o->type->obclass->id == OC_WAND) { price *= 2.25; } + } else if (f->id == F_MANUALOF) { + price *= 124; } } @@ -3107,7 +3128,7 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth int selidx; int amt; flag_t *f; - int db = B_TRUE; + int db = B_FALSE; char *pluralname; char brandname[BUFLEN]; char cursestr[BUFLEN]; @@ -3124,7 +3145,7 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth depth = rnd(1,MAXDEPTH); } - getrarity(depth, &raritymin, &raritymax, 25); + getrarity(depth, &raritymin, &raritymax, RARITYVARIANCE); while (!done) { if (db) dblog("adding random object with rarity value between %d - %d",raritymin,raritymax); @@ -3635,7 +3656,7 @@ int getthrowdam(object_t *o) { // ie. 1 tonne object does 1000 damage (car) dam = ceil((double)getobunitweight(o)); // missile objects do extra damage - if (hasflag(o->flags, F_MISSILE)) { + if (hasflag(o->flags, F_THROWMISSILE)) { dam *= 2; } // max @@ -4025,7 +4046,6 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastobjectclass->flags, F_MISSILE, B_TRUE, NA, NA, NULL); addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks.", '*'); addoc(OC_FOOD, "Food", "Yum!", '%'); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, ""); @@ -4091,7 +4111,7 @@ void initobjects(void) { // addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "50-100 stones"); @@ -4144,7 +4164,7 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addot(OT_ASH, "pile of ash", "A pile of ash", MT_STONE, 0.1, OC_ROCK); addflag(lastot->flags, F_GLYPH, B_TRUE, NA, NA, ","); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); @@ -4254,7 +4274,7 @@ void initobjects(void) { addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); addot(OT_POT_MAGIC, "potion of magic", "Fully restores the drinker's magical energy.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addot(OT_POT_ACROBATICS, "potion of acrobatics", "Allows the drinker to leap large distances.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addot(OT_POT_ELEMENTENDURE, "potion of endure elements", "Grants the imbiber temporary resistance to both fire and cold.", MT_GLASS, 1, OC_POTION); @@ -4293,7 +4313,7 @@ void initobjects(void) { addot(OT_POT_POLYMORPH, "potion of polymorph self", "Transmutes the drinker into another living race.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addot(OT_POT_INVULN, "potion of invulnerability", "Grants the drinker temporary immunity to physical harm.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 40, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); @@ -4328,6 +4348,11 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTLIFE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + addot(OT_SCR_DETECTOBS, "scroll of detect objects", "Senses objects near the caster.", MT_PAPER, 0.5, OC_SCROLL); + addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTOBS, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + + addot(OT_SCR_DETECTMAGIC, "scroll of detect magic", "Allows the reader to detect magical enchantments.", MT_PAPER, 0.5, OC_SCROLL); addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTMAGIC, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); @@ -4400,12 +4425,14 @@ void initobjects(void) { addot(OT_S_PULLMETAL, "pull metal", "Pulls metal objects to the caster.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addot(OT_S_ACCELMETAL, "accelerate metal", "Greatly accelerates a metal object thrown by the caster.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addot(OT_S_METALHEAL, "metal healing", "Uses nearby metal for accelerated healing.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); // l3 addot(OT_S_EXPLODEMETAL, "explode metal", "Causes all metal objects in a location explode.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); @@ -4417,6 +4444,7 @@ void initobjects(void) { addot(OT_S_ANIMATEMETAL, "animate metal", "Imbues a metallic weapon with temporary life, enabling it to fight on its own.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); /////////////////// // death @@ -4461,6 +4489,9 @@ void initobjects(void) { addot(OT_S_MAPPING, "sense surroundings", "Magically imbues the caster with a map of his/her surroundings.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addot(OT_S_DETECTOBS, "detect objects", "Senses objects near the caster.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); // l3 addot(OT_S_DETECTAURA, "detect aura", "Senses holiness or evil near the caster.", MT_NOTHING, 0, OC_SPELL); @@ -4599,6 +4630,14 @@ void initobjects(void) { addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); // TODO: hardcode how ai casts this + // l4 + addot(OT_S_PACIFY, "pacify", "Induces calmness in another, preventing them from attacking.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); /////////////////// // modification /////////////////// @@ -4662,6 +4701,10 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addot(OT_S_PULL, "pull", "Pulls lifeforms towards the caster.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // l4 addot(OT_S_TELEPORT, "teleportation", "Causes the caster to teleport to a new location within the same level. Becomes controlled at high power.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); @@ -4712,6 +4755,8 @@ void initobjects(void) { // divine powers addot(OT_A_DEBUG, "debug", "You can toggle debugging for a lifeform.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addot(OT_A_ENHANCE, "enhance", "Enhance a lifeform's stats.", MT_NOTHING, 0, OC_ABILITY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_LEARN, "learn", "Learn new skills.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_S_WISH, "wish", "Grants the caster any item of their choice (with some limitations).", MT_NOTHING, 0, OC_SPELL); @@ -4749,8 +4794,12 @@ void initobjects(void) { // manuals addot(OT_MAN_ATHLETICS, "manual of athletics", "Teaches you the skill 'athletics'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_ATHLETICS, NA, NA, NULL); + addot(OT_MAN_BACKSTAB, "manual of stabbing", "Teaches you the skill 'backstab'.", MT_PAPER, 3, OC_BOOK); + addflag(lastot->flags, F_MANUALOF, SK_BACKSTAB, NA, NA, NULL); addot(OT_MAN_FIRSTAID, "manual of first aid", "Teaches you the skill 'first aid'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_FIRSTAID, NA, NA, NULL); + addot(OT_MAN_LISTEN, "manual of listening", "Teaches you the skill 'listen'.", MT_PAPER, 3, OC_BOOK); + addflag(lastot->flags, F_MANUALOF, SK_LISTEN, NA, NA, NULL); addot(OT_MAN_LOCKPICKING, "manual of lockpicking", "Teaches you the skill 'lockpicking'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_LOCKPICKING, NA, NA, NULL); addot(OT_MAN_RESEARCH, "manual of research", "Teaches you the skill 'research'.", MT_PAPER, 3, OC_BOOK); @@ -4759,6 +4808,8 @@ void initobjects(void) { addflag(lastot->flags, F_MANUALOF, SK_MAGITEMUSAGE, NA, NA, NULL); addot(OT_MAN_SPELLCASTING, "manual of spellcasting", "Teaches you the skill 'spellcasting'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SPELLCASTING, NA, NA, NULL); + addot(OT_MAN_STEALTH, "manual of stealth", "Teaches you the skill 'stealth'.", MT_PAPER, 3, OC_BOOK); + addflag(lastot->flags, F_MANUALOF, SK_STEALTH, NA, NA, NULL); addot(OT_MAN_TECHUSAGE, "manual of technology", "Teaches you the skill 'technology'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_TECHUSAGE, NA, NA, NULL); // weapon manuals @@ -4820,6 +4871,8 @@ void initobjects(void) { // divination addot(OT_SB_DETECTLIFE, "spellbook of detect life", "Teaches the spell 'detect life'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTLIFE, NA, NA, NULL); + addot(OT_SB_DETECTOBS, "spellbook of detect objects", "Teaches the spell 'detect objects'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTOBS, NA, NA, NULL); addot(OT_SB_MAPPING, "spellbook of sense surroundings", "Teaches the spell 'surroundings'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_MAPPING, NA, NA, NULL); addot(OT_SB_DETECTAURA, "spellbook of detect aura", "Teaches the spell 'detect aura'.", MT_PAPER, 1.5, OC_BOOK); @@ -4867,10 +4920,16 @@ void initobjects(void) { // mental addot(OT_SB_MINDSCAN, "spellbook of mind scan", "Teaches the spell 'mind scan'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_MINDSCAN, NA, NA, NULL); + addot(OT_SB_SLEEP, "spellbook of sleep", "Teaches the spell 'sleep'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_SLEEP, NA, NA, NULL); addot(OT_SB_TELEKINESIS, "spellbook of telekinesis", "Teaches the spell 'telekinesis'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_TELEKINESIS, NA, NA, NULL); + addot(OT_SB_PACIFY, "spellbook of pacify", "Teaches the spell 'pacify'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_PACIFY, NA, NA, NULL); addot(OT_SB_PSYARMOUR, "spellbook of psychic armour", "Teaches the spell 'psychic armour'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_PSYARMOUR, NA, NA, NULL); + addot(OT_SB_CHARM, "spellbook of charm", "Teaches the spell 'charm'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_CHARM, NA, NA, NULL); // modification addot(OT_SB_INSCRIBE, "spellbook of inscribe", "Teaches the spell 'inscribe'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_INSCRIBE, NA, NA, NULL); @@ -4922,7 +4981,8 @@ void initobjects(void) { f2 = hasflag(spelltype->flags, F_SPELLLEVEL); if (f2) { int rarity; - rarity = 90 - (f2->val[0]*12); + // ie. 80 - spelllevel*12 + rarity = 80 - (f2->val[0]*12); addflag(ot->flags, F_RARITY, H_ALL, rarity, NA, NULL); } else { dblog("Spell %s has no spell level - can't determine rarity for spellbook.", spelltype->name); @@ -5112,7 +5172,7 @@ void initobjects(void) { addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, "Where will you spray?"); - addflag(lastot->flags, F_RNDCHARGES, 5, 10, NA, NULL); + addflag(lastot->flags, F_RNDCHARGES, 1, 5, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_LANTERNLED, "LED lantern", "A low-powered but efficient lantern which will last almost forever.", MT_METAL, 0.5, OC_TECH); @@ -5237,6 +5297,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, NA, NA, NA, "^"); addflag(lastot->flags, F_SHARP, 1, 2, NA, NULL); + addflag(lastot->flags, F_CRUSHABLE, SZ_MEDIUM, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addot(OT_CALTROP, "caltrop", "Connected metal spikes arranged such that one will always point upwards.", MT_METAL, 0.2, OC_MISC); addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL); @@ -5757,7 +5818,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 10, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 5, NA, NULL); // armour - shields addot(OT_BUCKLER, "buckler", "A small, unobtrusive wooden shield.", MT_WOOD, 3.00, OC_ARMOUR); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); @@ -5879,6 +5940,7 @@ void initobjects(void) { // missiles addot(OT_DART, "dart", "A small, sharp projectile weapon.", MT_WOOD, 0.5, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); @@ -5886,6 +5948,7 @@ void initobjects(void) { addot(OT_NANODART, "nanodart", "A metal dart with a laser-sharpened point.", MT_METAL, 0.5, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, ""); addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, ""); @@ -5894,6 +5957,7 @@ void initobjects(void) { addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 1.5, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_MISSILEDAM, 3, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); @@ -5941,7 +6005,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); @@ -5952,7 +6016,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); addflag(lastot->flags, F_DAM, 1, 3, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 2.5, OC_WEAPON); @@ -5988,7 +6052,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); @@ -6006,7 +6070,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMTYPE, DT_CHOP, NA, NA, NULL); addflag(lastot->flags, F_DAM, 1, 6, 1, NULL); addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addot(OT_BATTLEAXE, "battleaxe", "An axe specifically designed for combat.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); @@ -6031,7 +6095,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); addflag(lastot->flags, F_DAM, 1, 3, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); @@ -6041,7 +6105,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); addflag(lastot->flags, F_DAM, 1, 2, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); @@ -6104,7 +6168,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); - addflag(lastot->flags, F_MISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); @@ -6498,8 +6562,8 @@ int ismetal(enum MATERIAL mat) { return metal; } -int ismissile(object_t *o) { - if (hasflag(o->flags, F_MISSILE)) { +int isthrowmissile(object_t *o) { + if (hasflag(o->flags, F_THROWMISSILE)) { return B_TRUE; } // special cases... @@ -7355,13 +7419,19 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { return B_TRUE; } else { if (f->val[1] != NA) { + cell_t *newwhere = NULL; if ((f->val[1] & TR_NEEDLOS) && !haslos(lf, where)) { msg("You can't see there!"); return B_TRUE; } - if ((f->val[1] & TR_NEEDLOF) && !haslof(lf, where)) { - msg("You have no line of fire to there!"); - return B_TRUE; + if ((f->val[1] & TR_NEEDLOF) && !haslof(lf, where, B_TRUE, &newwhere)) { + if (newwhere) { + // update destination + where = newwhere; + } else { + msg("You have no line of fire to there!"); + return B_TRUE; + } } } } @@ -7545,7 +7615,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } // announce if (!seen) { - youhear(where, "something spraying."); + noise(where, NULL, "something spraying.", NULL); } } else if ((o->type->id == OT_EMPTYFLASK) || (o->type->id == OT_EMPTYVIAL)) { object_t *oo,*nextoo; @@ -8029,13 +8099,23 @@ int pour(lifeform_t *lf, object_t *o) { dst->blessknown = B_TRUE; // remove bonuses killflagsofid(dst->flags, F_BONUS); - // remove temporary flags + // remove temporary flags and modify some others for (f = dst->flags->first ; f ; f = nextf) { nextf = f->next; if (f->lifetime > 0) { killflag(f); + } else if (f->id == F_FROZEN) { + killflag(f); + } else if (f->id == F_ONFIRE) { + killflag(f); + } else if (f->id == F_POISONED) { + killflag(f); + } else if (f->id == F_OBHP) { + f->val[0] = f->val[1]; } } + // restore hp + if (!isknown(dst)) makeknown(dst->type->id); } else if (o->type->id == OT_POT_ACID) { @@ -8706,8 +8786,7 @@ int readsomething(lifeform_t *lf, object_t *o) { char obname[BUFLEN]; getlfname(lf, lfname); getobname(oo, obname,oo->amt); - msg("%s%s %s %s softly.",lfname,getpossessive(lfname),noprefix(obname), - (oo->amt == 1) ? "glows" : "glow"); + msg("A black aura breaks away from %s%s %s.",lfname,getpossessive(lfname),noprefix(obname)); seen = B_TRUE; } // uncurse it @@ -9159,6 +9238,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, int acc; int youhit; object_t *newob; + cell_t *newloc; int db = B_TRUE; reason = E_OK; @@ -9303,6 +9383,22 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, msg("%s", throwstring); } + + // adjust destination location in case something is in the way. + haslof(thrower, where, LOF_NEED, &newloc); + if (newloc) { + where = newloc; + target = where->lf; + if (target && isdead(target)) { + target = NULL; + } + if (target) { + getlfname(target, targetname); + } + } + + + //taketime(thrower, SPEED_THROW); // some obejcts will die when thrown. @@ -9406,7 +9502,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, msg("%s", buf2); } else { if (willshatter(o->material->id)) { - youhear(where, "shattering glass."); + noise(where, NULL, "shattering glass.", NULL); } } sprintf(damstring, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); @@ -9455,7 +9551,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, msg("%s shatters!",obcaps); free(obcaps); } else { - youhear(where, "shattering glass."); + noise(where, NULL, "shattering glass.", NULL); } shattered = B_TRUE; } @@ -9593,7 +9689,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (youhit && target) { if (getobweight(o) >= getlfweight(target, B_NOOBS)) { int dir; - dir = getdirtowards(srcloc, target->cell, target, B_FALSE); + dir = getdirtowards(srcloc, target->cell, target, B_FALSE, DT_COMPASS); knockback(target, dir, 1, thrower); } } @@ -10233,7 +10329,7 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob } // penalty for throwing non-missiles - if (missile && !firearm && !ismissile(missile)) { + if (missile && !firearm && !isthrowmissile(missile)) { acc -= 20; } return acc; diff --git a/objects.h b/objects.h index b9310ad..080de43 100644 --- a/objects.h +++ b/objects.h @@ -31,6 +31,7 @@ int countnames(char **list); int countobs(obpile_t *op); int curseob(object_t *o); void damageallobs(object_t *exception, obpile_t *op, int howmuch, int damtype); +void dumprandomobs(int amt); void explodeob(object_t *o, flag_t *f, int bigness); void extinguish(object_t *o); material_t *findmaterial(int id); @@ -127,7 +128,7 @@ int isknownot(objecttype_t *ot); int isidentified(object_t *o); int isimpassableob(object_t *o, lifeform_t *lf); int ismetal(enum MATERIAL mat); -int ismissile(object_t *o); +int isthrowmissile(object_t *o); int isoperable(object_t *o); int isplainob(object_t *o); int ispourable(object_t *o); diff --git a/save.c b/save.c index 909c3a7..121448b 100644 --- a/save.c +++ b/save.c @@ -277,6 +277,7 @@ map_t *loadmap(char *basefile) { fscanf(f, "%d\n",&m->nextmap[i]); // map dimensons } if (db) dblog("--> Finished map info. name='%s', dims=%d x %d\n",m->name, m->w, m->h); + fscanf(f, "beingcreated:%d\n",&m->beingcreated); fscanf(f, "id:%d\n",&m->id); // map id // load lifeforms @@ -710,6 +711,7 @@ int savemap(map_t *m) { for (i = 0; i < MAXDIR_ORTH; i++) { fprintf(f, "%d\n",m->nextmap[i] ); // map dimensons } + fprintf(f, "beingcreated:%d\n",m->beingcreated); // save all non-player lifeforms (includes their objects) fprintf(f, "lifeforms:\n"); diff --git a/spell.c b/spell.c index 090569b..107672e 100644 --- a/spell.c +++ b/spell.c @@ -400,6 +400,36 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } else { msg("There is nobody there!"); } + } else if (abilid == OT_A_ENHANCE) { + cell_t *where; + where = askcoords("Enhance stats of who?", TT_MONSTER); + if (where && where->lf) { + char ch; + enum ATTRIB att; + ch = askchar("Enhance which stat (n for none)?", "sdcin",NULL, B_TRUE); + switch (ch) { + case 's': att = A_STR; break; + case 'd': att = A_DEX; break; + case 'c': att = A_CON; break; + case 'i': att = A_IQ; break; + default: att = A_NONE; break; + } + if (att != A_NONE) { + char buf[BUFLEN]; + int val; + askstring("Set stat to what", '?', buf, BUFLEN, NULL); + val = atoi(buf); + if ((val <= 0) || (val > 18)) { + msg("Invalid value."); + } else { + setattr(where->lf, att, val); + getlfname(where->lf, buf); + msg("%s%s %s set to %d.", buf, getpossessive(buf), getattrname(att), val); + } + // + } + } + } else if (abilid == OT_A_HEAVYBLOW) { object_t *wep; char dirch; @@ -672,7 +702,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_AIRBLAST) { int dir; object_t *o,*nexto; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_NEED, spellid, power)) return B_TRUE; target = targcell->lf; if (cansee(player, caster)) { @@ -680,7 +710,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("%s emit%s a powerful blast of air!", castername, isplayer(caster) ? "" : "s"); } - dir = getdirtowards(caster->cell, targcell, target, B_FALSE); + dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); // lfs if (target) { knockback(target, dir, power, caster); @@ -704,7 +734,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ newlf = makezombie(o); if (newlf) { if (isplayer(caster) && skillcheck(caster, A_IQ, 20, power)) { - makefriendly(newlf); + makefriendly(newlf, PERMENANT); } donesomething = B_TRUE; } @@ -813,21 +843,23 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ teleportto(caster, targcell, B_TRUE); } } else if (spellid == OT_S_BURNINGWAVE) { - cell_t *c; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, spellid, power)) return B_TRUE; + cell_t *retcell[MAXRETCELLS]; + int nretcell; + int i; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_WALLSTOP, spellid, power)) return B_TRUE; if (cansee(player, caster)) { - msg("%s shoots a wave of fire!",castername); + msg("%s shoot%s a wave of fire!",castername, isplayer(caster) ? "" : "s"); } // create a line of fire towards the target cell - c = caster->cell; - while (c != targcell) { - int dir; - dir = getdirtowards(c, targcell, NULL, B_FALSE); - c = getcellindir(c, dir); - if (!c) break; - if (c->type->solid) break; + calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcell); + + // don't set caster's cell on fire! + for (i = 1; i < nretcell; i++) { + cell_t *c; + c = retcell[i]; + // set on fire addob(c->obpile, "medium fire"); if (c->lf) { @@ -841,7 +873,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_CLOUDKILL) { - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; if (targcell->type->solid) { fizzle(caster); @@ -854,10 +886,48 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("A cloud of poison gas appears!"); if (seenbyplayer) *seenbyplayer = B_TRUE; } + } else if (spellid == OT_S_CHARM) { + char targetname[BUFLEN]; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + + target = targcell->lf; + + if (!target) { + fizzle(caster); + return B_FALSE; + } + getlfname(target, targetname); + + if (getallegiance(caster) == AL_PEACEFUL) { + fizzle(caster); + return B_FALSE; + } + if (getallegiance(target) == getallegiance(caster)) { + if (isplayer(caster)) { + msg("%s is already allied with you!",targetname); + } + return B_FALSE; + } + + if (skillcheck(targcell->lf, SC_RESISTMAG, 20 + power, 0)) { + if (isplayer(caster) || cansee(player, target)) { + msg("%s resists.",targetname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } else { + int howlong; + if (isplayer(caster) || cansee(player, target)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + howlong = getspellduration(20,30,blessed) + (power*10); + + addtempflag(target->flags, F_CHARMEDBY, caster->id, NA, NA, NULL, howlong); + } } else if (spellid == OT_S_CONECOLD) { char lfname[BUFLEN]; int acc; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}'); if (isplayer(caster) || cansee(player, caster)) { @@ -1042,8 +1112,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_DETECTLIFE) { target = caster; if (isplayer(caster)) { - int howlong; + int howlong,radius; howlong = getspellduration(10,20,blessed) + (power*2); + radius = power * 10; addtempflag(target->flags, F_DETECTLIFE, 10, NA, NA, NULL, howlong); } else { // monsters can't use this @@ -1068,9 +1139,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // monsters can't use this } */ + } else if (spellid == OT_S_DETECTOBS) { + target = caster; + if (isplayer(caster)) { + int howlong,radius; + howlong = getspellduration(25,35,blessed) + (power*10); + radius = power*10; + addtempflag(target->flags, F_DETECTOBS, radius, NA, NA, NULL, howlong); + } else { + // monsters can't use this + } } else if (spellid == OT_S_DETONATE) { // don't need line of fire! - if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, B_FALSE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; explodecells(targcell, 20, B_TRUE, NULL, power / 4, B_TRUE); @@ -1081,7 +1162,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ float totalmass = 0; object_t *o, *nexto; - if (!validatespellcell(caster, &targcell, TT_OBJECT, B_FALSE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_OBJECT, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; // how much metal is there? for (o = targcell->obpile->first ; o ; o = nexto) { @@ -1194,7 +1275,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { targcell = getcellat(caster->cell->map, x,y); if (targcell && (getcelldist(caster->cell, targcell) <= range)) { - if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell)) { + if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell, B_FALSE, NULL)) { char lfname[BUFLEN]; // automatic hit getlfname(targcell->lf, lfname); @@ -1216,7 +1297,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ char numbuf[BUFLEN]; numtotext(power, numbuf); - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}'); if (isplayer(caster) || cansee(player, caster)) { @@ -1245,7 +1326,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_FIREBALL) { int failed = B_FALSE; // ask for a target cell - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; if (targcell) { if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { int dir; @@ -1312,7 +1393,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_FIREDART) { char lfname[BUFLEN]; int acc; - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}'); if (isplayer(caster) || cansee(player, caster)) { @@ -1363,7 +1444,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { targcell = getcellat(caster->cell->map, x,y); if (targcell && (getcelldistorth(caster->cell, targcell) <= range)) { - if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell)) { + if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell, B_FALSE, NULL)) { char lfname[BUFLEN]; // automatic hit getlfname(targcell->lf, lfname); @@ -1378,7 +1459,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_FLAMEPILLAR) { int failed = B_FALSE; // ask for a target cell - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_WALLSTOP, spellid, power)) return B_TRUE; if (targcell && haslos(caster, targcell)) { if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { flag_t *f; @@ -1565,7 +1646,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_HASTE) { int howlong = 15; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; target = targcell->lf; @@ -1747,7 +1828,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ char numbuf[BUFLEN]; numtotext(power, numbuf); - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}'); if (isplayer(caster) || cansee(player, caster)) { @@ -1950,7 +2031,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_WALLSTOP, spellid, power)) return B_TRUE; // 4 is the same as ST_TITANIC strength // 10 = gun speed @@ -2062,9 +2143,40 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = addtempflag(caster->flags, F_ARBOOST, power*3, NA, NA, NULL, FROMSPELL); f->obfrom = spellid; + } else if (spellid == OT_S_PULL) { + if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_WALLSTOP, spellid, power)) return B_TRUE; + + target = targcell->lf; + + if (target) { + int failed = B_FALSE; + + if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + failed = B_TRUE; + } else { + // they get pulled towards caster + failed = pullnextto(target, caster->cell); + } + + if (isplayer(target) || cansee(player, target)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + if (failed) { + if (isplayer(target) || cansee(player, target)) { + char buf[BUFLEN]; + getlfname(target, buf); + msg("%s %s pulled forward slightly.", buf, isplayer(target) ? "are" : "is"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + return B_FALSE; + } + } else { + fizzle(caster); + } } else if (spellid == OT_S_PULLMETAL) { int donesomething = B_FALSE; - if (!validatespellcell(caster, &targcell,TT_OBJECT, B_TRUE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_OBJECT, B_TRUE, LOF_WALLSTOP, spellid, power)) return B_TRUE; if (targcell->lf) { object_t *o; @@ -2282,7 +2394,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int willannounce = B_FALSE; char targname[BUFLEN]; - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_FALSE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { @@ -2305,7 +2417,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_KNOCK) { object_t *o; - if (!validatespellcell(caster, &targcell,TT_DOOR, B_FALSE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_DOOR, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; o = hasobwithflag(targcell->obpile, F_DOOR); if (o) { int dooropen; @@ -2337,7 +2449,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // at power 3, you can control where the light appears // at power 8, the light is permenant if (power >= 3) { - if (!validatespellcell(caster, &targcell,TT_NONE, B_FALSE, spellid, power)) return B_TRUE; + // TODO: this actually means we can cast it through walls!!! + if (!validatespellcell(caster, &targcell,TT_NONE, B_FALSE, LOF_DONTNEED, spellid, power)) return B_TRUE; } else { targcell = caster->cell; } @@ -2431,6 +2544,49 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = addtempflag(caster->flags, F_DTIMMUNE, DT_FALL, NA, NA, NULL, FROMSPELL); f->obfrom = spellid; + } else if (spellid == OT_S_PACIFY) { + char targetname[BUFLEN]; + if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + + target = targcell->lf; + + if (!target) { + fizzle(caster); + return B_FALSE; + } + getlfname(target, targetname); + + + if (skillcheck(targcell->lf, SC_RESISTMAG, 30 + power, 0)) { + if (isplayer(caster) || cansee(player, target)) { + msg("%s resists.",targetname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } else { + int donesomething = B_FALSE; + + // stop targetting anybody + if (killflagsofid(target->flags, F_TARGET)) { + donesomething = B_TRUE; + } + if (killflagsofid(target->flags, F_TARGETCELL)) { + donesomething = B_TRUE; + } + if (killflagsofid(target->flags, F_HOSTILE)) { + donesomething = B_TRUE; + } + + if (donesomething) { + if (cansee(player, target)) { + msg("%s calms down.",targetname); + } + } else { + if (isplayer(caster)) { + msg("%s already seems calm enough.",targetname); + } + } + return B_FALSE; + } } else if (spellid == OT_S_PASSWALL) { int howlong = 7; target = caster; @@ -2578,7 +2734,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_SPARK) { object_t *o,*nexto; int donesomething = B_FALSE; - if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, B_FALSE, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; if (haslos(player, targcell)) { msg("A small spark of flame appears."); @@ -2837,9 +2993,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ o = relinkob(o, newloc->obpile); } if (o) { - if (isblind(caster)) { - youhear(caster->cell, "something hitting the ground."); - } else { + noise(caster->cell, NULL, "something hitting the ground.", NULL); + if (!isblind(caster)) { msg("%s appear%s on the ground!", obname, (o->amt == 1) ? "s" : ""); } } else { @@ -3111,7 +3266,7 @@ void pullobto(object_t *o, lifeform_t *lf) { } // where does it end up? obloc = getoblocation(o); - dir = getdirtowards(lf->cell, obloc, NULL, B_FALSE); + dir = getdirtowards(lf->cell, obloc, NULL, B_FALSE, DT_COMPASS); newcell = getcellindir(lf->cell, dir); if (newcell) { // move next to player @@ -3205,19 +3360,68 @@ lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **targe return *target; } -cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof, enum OBTYPE spellid, int power) { +cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlos, enum LOFTYPE needlof, enum OBTYPE spellid, int power) { int maxrange = UNLIMITED; int done = B_FALSE; + cell_t *where = NULL; maxrange = getspellrange(spellid, power); while (!done) { - if (*targcell) { - done = B_TRUE; + if (where) { + cell_t *newwhere = NULL; + // validate it + if (where && needlos && !haslos(caster, where)) { + msg("You cannot see there!"); more(); + where = NULL; + } + + if (where && needlof && !haslof(caster, where, needlof, &newwhere)) { + if (newwhere) { + // warn! + int ch; + ch = askchar("Your have no clear line of fire - really target here?","yn","n", B_TRUE); + if (ch == 'y') { + where = newwhere; + } else { + where = NULL; + } + } else { + where = NULL; + } + } + if (where && (maxrange != UNLIMITED) && (getcelldist(caster->cell, where) > maxrange)) { + // out of range + msg("Too far away - max range is %d.",maxrange); more(); + where = NULL; + } + + if (where && isplayer(caster) && (where == caster->cell)) { + // warn before targetting yourself! + if (getiqname(getattr(caster, A_IQ), NULL) >= IQ_AVERAGE) { + objecttype_t *sp; + sp = findot(spellid); + if (sp) { + if (hasflagval(sp->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL) || + hasflagval(sp->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL)) { + int ch; + ch = askchar("Really target yourself","yn","n", B_TRUE); + if (ch != 'y') { + where = NULL; + } + } + } + } + } + + // still got a target? + if (where) { + *targcell = where; + done = B_TRUE; + } } else { // ask for a target cell if (isplayer(caster)) { - cell_t *where; char buf[BUFLEN]; if (maxrange == UNLIMITED) { objecttype_t *ot; @@ -3227,51 +3431,12 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, i sprintf(buf, "Where will you target your spell [max range %d]?",maxrange); } where = askcoords(buf, targtype); - - if (where) { - //if (haslos(caster, where) || (where == caster->cell)) { - if (needlof && !haslof(caster, where)) { - // no line of sight - fizzle(caster); - return NULL; - } else if ((maxrange != UNLIMITED) && (getcelldist(caster->cell, where) > maxrange)) { - // out of range - fizzle(caster); - return NULL; - } else { - *targcell = where; - done = B_TRUE; - // warn before targetting yourself! - if (isplayer(caster) && (where == caster->cell)) { - if (getiqname(getattr(caster, A_IQ), NULL) >= IQ_AVERAGE) { - objecttype_t *sp; - sp = findot(spellid); - if (sp) { - if (hasflagval(sp->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL) || - hasflagval(sp->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL)) { - int ch; - ch = askchar("Really target yourself","yn","n", B_TRUE); - if (ch != 'y') { - *targcell = NULL; - done = B_FALSE; - } - } - } - } - } - } - /* - } else { - msg("You can't see there!"); - more(); - *targcell = NULL; - done = B_FALSE; + if (!where) { + int ch; + ch = askchar("Abandon your spell?","yn","n", B_TRUE); + if (ch != 'y') { + where = NULL; } - */ - } else { - // no line of sight or invalid cell - fizzle(caster); - return NULL; } } else { // TODO: fill in monster code? diff --git a/spell.h b/spell.h index 779e9d9..ced7678 100644 --- a/spell.h +++ b/spell.h @@ -19,7 +19,7 @@ void pullobto(object_t *o, lifeform_t *lf); void stopspell(lifeform_t *caster, enum OBTYPE spellid); void stopallspells(lifeform_t *lf); lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target); -cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlof, enum OBTYPE spellid, int power); +cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlos, enum LOFTYPE needlof, enum OBTYPE spellid, int power); lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf); #endif diff --git a/text.c b/text.c index f03efb4..e897a47 100644 --- a/text.c +++ b/text.c @@ -32,16 +32,18 @@ char *capitaliseall(char *text) { char *getattrname(enum ATTRIB att) { switch (att) { + case A_NONE: + return "?attrib_none?"; case A_STR: return "strength"; case A_IQ: return "intelligence"; case A_DEX: return "dexterity"; - default: - break; + case A_CON: + return "constitution"; } - return "?unknown?"; + return "?badattrib?"; } char *getpossessive(char *text) { @@ -219,6 +221,21 @@ char *makeplural(char *text) { return newtext; } +int needses(char *text) { + if (text[strlen(text)-1] == 's') { + return B_TRUE; + } + + if (strlen(text) >= 2) { + if ((text[strlen(text)-2] == 'c') && + (text[strlen(text)-1] == 'h')) { + return B_TRUE; + } + } + + return B_FALSE; +} + char *noprefix(char *obname) { char *p; p = strchr(obname, ' '); diff --git a/text.h b/text.h index 8e83a8f..358a19c 100644 --- a/text.h +++ b/text.h @@ -10,6 +10,7 @@ char *gettimetextfuzzy(char *retbuf, int wantpm); char *getweighttext(float weight, char *buf); int isvowel(char c); char *makeplural(char *text); +int needses(char *text); char *noprefix(char *obname); char *numtotext(int num, char *buf); char *roman(int num);