From 7099d0116459cd1bbfba46aee2258d93d63222d4 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Tue, 3 May 2011 07:34:07 +0000 Subject: [PATCH] * [+] F_prone if you're knocked down - [+] make sheilds very good against projectiles - [+] make smoke just REDUCE vision, not block it. - [+] noncorporeal should stop grabs! * [+] don't say 'a javelin is damaged' when you throw it, just apply the damge - [+] increase damage bonus with every lore level. +10% each time (ie. up to 50% at top) * [+] give accuracy + critical bonus for lore levles too - [+] typo: Enhance which skill enhance (1 left)? ['=next page,?=toggle] - [+] Show Pain on botl. * [+] more staves - [+] low hitpoint warning for pets (or make them shriek, whine, etc) - [+] CRITKNOCKDOWN * [+] FINISH GRIZZLY - [+] undead should be immune to poison!! - [+] make code to auto add flags to undead. - [+] if you ever move a door (ie. airblast), automatically open it. - [+] young wolf shouldn't be able to open a door! * [+] You throw a dart at the carpet snake. Your dart misses you.--More-- - [+] no sprinting while burdneed - [+] blood should be drawn BELOW stairs - [+] weilded torch should do 1d4 fire damage (counts as a club) * [+] The skeleton touches a leather belt then recoils in pain!The skeleton drops a blessed leather belt.The skeleton puts on a leather belt. - [+] don't show "you can cast it at power level xxx" for abilities * [+] more item randomising - [+] make grey ooze splatter into acid - [+] "the vine grabs you" if you walk onto an entangling vine. - [+] don't start monsters within player's los - [+] properly randomise sticks to snakes - [+] stirge - [+] leech (like stirge but can charge/leap, and slightly more hp / damage) - [+] treesnake - [+] constrictor - [+] cobra - [+] stickes to snakes - make caster's weapon revert. - [+] A something comes into view. - [+] is invisibility code working properly when you see someone use the invis spell? - [+] don't include cosmetic objects in 'you see xxx' * [+] monsters: don't use spells if you don't have lof. - [+] pets not following around corners if you move diagonally. fixed a little. - [+] summon small animals (2-3 x SZ_SMALL) * [+] jet of water - [+] summon medium animals (2-4 x SZ_MEDIUM, wolf etc) - [+] lightning storm (lightbning everyone within los, and more damage) - [+] summon large animals (SZ_LARGE, horse, bear etc) --- ai.c | 149 +++- ai.h | 3 +- attack.c | 88 ++- defs.h | 81 ++- flag.c | 39 + flag.h | 2 + io.c | 296 +++++--- io.h | 1 + lf.c | 2066 ++++++++++++++++++++++++++++++++++------------------- lf.h | 12 +- log.txt | 617 ++++++++++++---- map.c | 14 +- move.c | 233 ++++-- move.h | 2 +- nexus.c | 34 +- nexus.h | 3 +- objects.c | 497 ++++++++++--- objects.h | 8 +- spell.c | 646 ++++++++++++++--- spell.h | 3 +- text.c | 53 +- text.h | 4 +- 22 files changed, 3539 insertions(+), 1312 deletions(-) diff --git a/ai.c b/ai.c index b3e8e97..bfa26e0 100644 --- a/ai.c +++ b/ai.c @@ -83,13 +83,20 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { enum OBTYPE poss[MAXPILEOBS]; int nposs = 0; int db = B_FALSE; + int castok = B_TRUE; if (lfhasflag(lf, F_DEBUG)) { db = B_TRUE; } + f = lfhasflag(lf, F_NEEDOBFORSPELLS); + if (f && !hasob(lf->pack, f->val[0])) { + castok = B_FALSE; + } + for (f = lf->flags->first ; f ; f = f->next) { - if ((f->id == F_CANCAST) || (f->id == F_CANWILL)) { + if ( (castok && (f->id == F_CANCAST)) || + (f->id == F_CANWILL)) { if (aispellok(lf, f->val[0], victim, F_AICASTTOATTACK)) { poss[nposs] = f->val[0]; nposs++; @@ -100,6 +107,11 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { // select a random one if (nposs > 0) { int sel; + if (db) { + char lfname[BUFLEN]; + getlfname(lf,lfname); + dblog(".oO { %s i have %d valid spells/abils. using one. }", lfname, nposs); + } sel = rnd(0,nposs-1); return poss[sel]; } @@ -266,6 +278,15 @@ flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int t db = B_TRUE; } + + if (lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + dblog(".oO { %s cannot go to targecell %d,%d due to f_ignorecell flag }", lfname, c->x, c->y); + return NULL; + } + + if (db) { char lfname[BUFLEN]; getlfname(lf, lfname); @@ -283,8 +304,6 @@ flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int t strcpy(whybuf, ""); } - - if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) { f = addflag(lf->flags, F_TARGETCELL, c->x, c->y, why, whybuf); } else { @@ -432,6 +451,19 @@ void aiturn(lifeform_t *lf) { // healing /////////////////////////////////////////////// + // special cases + if ((lf->race->id == R_STIRGE) || (lf->race->id == R_LEECH)) { + if (ispeaceful(lf)) { + int sleepval = 18; + + if (modcounter(lf->flags, 1) >= sleepval) { + taketime(lf, getactspeed(lf)); + addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + return; + } + } + } + // need to heal? if (lf->hp < (lf->maxhp/2)) { if (!useitemwithflag(lf, F_AIHEALITEM)) { @@ -573,18 +605,20 @@ void aiturn(lifeform_t *lf) { } if (!lfhasflag(lf, F_HIDING)) { + objecttype_t *st; // 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) && // found a valid spell/ability to use - ((getcelldist(lf->cell, target->cell) != 1) || (rnd(1,3) == 1)) + st = findot(spell); + if ( (spell != OT_NONE) && // found a valid spell/ability to use + ((getcelldist(lf->cell, target->cell) != 1) || // there is distance between us and target + (st->obclass->id == OC_ABILITY) || // OR this works from adjacent + (rnd(1,3) == 1)) // OR random chance of using anyway... ) { int spellfailed = B_FALSE; lifeform_t *spelllf = NULL; cell_t *spellcell = NULL; object_t *spellob = NULL; - objecttype_t *st; - st = findot(spell); if (db) { dblog(".oO { will cast attack spell: %s }", st->name); } @@ -751,7 +785,10 @@ void aiturn(lifeform_t *lf) { // move towards their last known location instead targcell = getcellat(lf->cell->map, lastx, lasty); if (targcell) { - aigoto(lf, targcell, MR_LF, target, PERMENANT); + if (!aigoto(lf, targcell, MR_LF, target, PERMENANT)) { + + if (db) dblog(".oO { aigoto target's last known loc failed! }"); + } } else { if (db) dblog(".oO { go to target's last known loc failed! }"); } @@ -929,12 +966,35 @@ void aiturn(lifeform_t *lf) { } else { // try to move towards master's last known loc if (mf->val[1] != NA) { + flag_t *movetoflag = NULL; cell_t *newcell; newcell = getcellat(lf->cell->map, mf->val[1], mf->val[2]); - - if (db) dblog(".oO { cannot see my master - adding F_TARGETCELL for last known loc }"); - f = aigoto(lf, newcell, MR_LF, master, PERMENANT); - aimovetotargetcell(lf, f); + + if (newcell == lf->cell) { + int lastdir; + + lastdir = getownerlastdir(lf); + if (lastdir != D_NONE) { + // try going in last known dir + if (db) dblog(".oO { cannot see my master and am at last known loc. trying last known dir (%s) }",getdirname(lastdir)); + if (!trymove(lf, lastdir, B_TRUE)) { + if (db) dblog(".oO { ...successfully }"); + killflagsofid(lf->flags, F_OWNERLASTDIR); + return; + } + } + } else { + if (db) dblog(".oO { cannot see my master - adding F_TARGETCELL for last known loc }"); + movetoflag = aigoto(lf, newcell, MR_LF, master, PERMENANT); + } + + + if (movetoflag) { + aimovetotargetcell(lf, movetoflag); + } else { + if (db) dblog(".oO { cannot see my master and aigoto last known loc/dir failed. randommove. }"); + dorandommove(lf, B_NOBADMOVES); + } } else { if (db) dblog(".oO { cannot see my master and dont have a last known location. randommove. }"); dorandommove(lf, B_NOBADMOVES); @@ -970,12 +1030,23 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG int ok = B_FALSE; int specialcase = B_FALSE; int specificcheckok = B_FALSE; + int needlos = B_TRUE; + enum LOFTYPE needlof = LOF_NEED; if (lfhasflag(lf, F_DEBUG)) { db = B_TRUE; } ot = findot(spellid); + if (ot) { + flag_t *f; + f = hasflag(ot->flags, F_LOSLOF); + if (f) { + needlos = f->val[0]; + needlof = f->val[1]; + } + } + // enough mp etc? if (!cancast(lf, spellid, NULL)) { if (db) { @@ -1047,6 +1118,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if (lfhasflag(lf, F_GRABBING)) { ok = B_TRUE; } + } else if (ot->id == OT_A_SUCKBLOOD) { + // must attach first + if (lfhasflag(lf, F_ATTACHEDTO)) { + ok = B_TRUE; + } } else { ok = B_TRUE; } @@ -1061,13 +1137,30 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG specialcase = B_TRUE; break; } + + // now check for line of sight / fire + switch (f->val[0]) { + case ST_VICTIM: + case ST_ADJVICTIM: + if (needlos && (!victim || !cansee(lf, victim)) ) { + dblog(".oO { cant cast %s - no LOS to victim }", ot ? ot->name : "?unkownspell?"); + return B_FALSE; + } + if (needlof && !haslof(lf->cell, victim->cell, needlof, NULL) ) { + dblog(".oO { cant cast %s - no LOF to victim }", ot ? ot->name : "?unkownspell?"); + return B_FALSE; + } + break; + default: + break; + } + } else { // invalid spell for this purpose dblog(".oO { cant cast %s - not valid for given purpose }", ot ? ot->name : "?unkownspell?"); return B_FALSE; } - if (specialcase) { if (ot->id == OT_S_TELEKINESIS) { int i,nposs; @@ -1117,20 +1210,32 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC)) { specificcheckok = B_FALSE; } - if (ot->id == OT_A_SWOOP) { + if ((ot->id == OT_A_SWOOP) || (ot->id == OT_A_CHARGE)) { + flag_t *willflag; flag_t *srflag; int srange = 5; srflag = lfhasflag(lf, F_SWOOPRANGE); if (srflag) { srange = srflag->val[0]; } + + willflag = lfhasflagval(lf, F_CANWILL, ot->id, NA, NA, NULL); + if (willflag) { + texttospellopts(f->text, NULL, NULL, NULL, &srange); + if (!srange) srange = 5; + } + if (!haslof(lf->cell, victim->cell, LOF_NEED,NULL)) { specificcheckok = B_FALSE; - } else if (isimmobile(lf) || !lfhasflag(lf, F_FLYING)) { + } else if (isimmobile(lf)) { + specificcheckok = B_FALSE; + } else if ((ot->id == OT_A_SWOOP) && !lfhasflag(lf, F_FLYING)) { specificcheckok = B_FALSE; } else if (getcelldist(lf->cell, victim->cell) > srange) { specificcheckok = B_FALSE; + } else if (getcelldist(lf->cell, victim->cell) == 1) { // ie already adjacent + specificcheckok = B_FALSE; } } if ((ot->id == OT_S_HASTE) && (lfhasflag(victim, F_FASTACT) || lfhasflag(victim, F_FASTACTMOVE)) ) { @@ -1197,6 +1302,15 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG } +int getownerlastdir(lifeform_t *lf) { + flag_t *odflag; + odflag = lfhasflag(lf, F_OWNERLASTDIR); + if (odflag) { + return odflag->val[0]; + } + return D_NONE; +} + object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) { object_t *o; @@ -1380,8 +1494,9 @@ int lookforobs(lifeform_t *lf, int covetsonly) { if (gothere) { // start walking towards target cell - aigoto(lf, c, MR_OB, o, AI_FOLLOWTIME); - return B_TRUE; + if (aigoto(lf, c, MR_OB, o, AI_FOLLOWTIME)) { + return B_FALSE; + } } } } diff --git a/ai.h b/ai.h index 85b213e..71373de 100644 --- a/ai.h +++ b/ai.h @@ -5,13 +5,14 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit); enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim); enum OBTYPE aigetfleespell(lifeform_t *lf); void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose); -object_t * aigetwand(lifeform_t *lf, enum FLAG purpose); +object_t *aigetwand(lifeform_t *lf, enum FLAG purpose); flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int timelimit); void aimovetotargetcell(lifeform_t *lf, flag_t *f); int aipickup(lifeform_t *lf, object_t *o); int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target); int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose); void aiturn(lifeform_t *lf); +int getownerlastdir(lifeform_t *lf); object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op); object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op); int lookforobs(lifeform_t *lf, int covetsonly); diff --git a/attack.c b/attack.c index bf6b4ae..fbd09b7 100644 --- a/attack.c +++ b/attack.c @@ -397,6 +397,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (!willheal) { enum SKILLLEVEL slev; skill_t *sk; + float loremult; // blessed vs undead if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) { // a little extra damage @@ -427,12 +428,15 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) dam[0] += pctof(pctextra, dam[0]); } } + // bonus for knowledge about the other lf's race? applied LAST. - if (getlorelevel(lf, victim->race->raceclass->id) >= PR_MASTER) { - dam[0] = (int) ( (float)dam[0] * 1.5 ); - } else if (getlorelevel(lf, victim->race->raceclass->id) >= PR_SKILLED) { - dam[0] = (int) ( (float)dam[0] * 1.25 ); + slev = getlorelevel(lf, victim->race->raceclass->id); + if (slev == PR_INEPT) { + loremult = 1; + } else { + loremult = 1 + (slev * 0.1); } + dam[0] = (int) ( (float)dam[0] * loremult ); } if (aidb) dblog(".oO { dealing %d %s damage }", dam[0], getdamname(damtype[0])); @@ -463,7 +467,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) dblog("initial dam[%d] = %d",i,dam[i]); if (lfhasflag(lf, F_HEAVYBLOW) || hasflag(wep->flags, F_HEAVYBLOW)) { - dam[i] = (int)((float)dam[i] * 1.5); + dam[i] = (int)pctof(110,dam[i]); dblog("heavy blow makes dam[%d] = %d",i,dam[i]); } @@ -616,6 +620,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // special weapon effects wepeffects(wep->flags, victim->cell, damflag, dam[0]); + // other effects if (!isdead(victim)) { if (isunarmed) { f = lfhasflag(lf, F_FREEZINGTOUCH); @@ -649,7 +654,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) for (dir = DC_N; dir <= DC_NW; dir++) { c = getcellindir(victim->cell, dir); if (c && c->lf) { - if (strcasestr(c->lf->race->name, f->text)) { + if (c->lf->race->baseid == lf->race->baseid) { nmatched++; } } @@ -664,6 +669,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } + // critical hit effects + if (critical) { + if (lfhasflag(lf, F_CRITKNOCKDOWN)) { + fall(victim, lf, B_TRUE); + } + } + // confer flags from attacker? wepeffects(lf->flags, victim->cell, damflag, dam[0]); @@ -685,6 +697,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } } + } else if ((lf->race->id == R_STIRGE) || (lf->race->id == R_LEECH)) { + // automatically latch on + if (!lfhasflag(victim, F_NONCORPOREAL) && !hasflag(lf->flags, F_ATTACHEDTO)) { + addflag(lf->flags, F_ATTACHEDTO, victim->id, NA, NA, NULL); + } } } @@ -741,7 +758,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (!isdead(victim)) { if (lfhasflag(victim, F_INDUCEFEAR)) { if (cansee(lf, victim)) { - scare(lf, victim, rnd(2,3)); + scare(lf, victim, rnd(2,3), 0); } } } @@ -937,7 +954,7 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam if (pct <= 5) { return "whack"; } else if (pct <= 20) { - if (rnd(1,2) == 1) { + if (onein(2)) { return "hit"; } else { return "bash"; @@ -1037,7 +1054,7 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam } else if (damtype == DT_TOUCH) { return "touch"; } else if (damtype == DT_UNARMED) { - if (rnd(1,2) == 1) { + if (onein(2)) { return "punch"; } else { return "hit"; @@ -1190,7 +1207,7 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) { return "bisect"; } else { - if ((getlfsize(victim) >= SZ_MEDIUM) && (rnd(1,3) == 1)) { + if ((getlfsize(victim) >= SZ_MEDIUM) && onein(3)) { return "behead"; } else { return "bisect"; @@ -1356,7 +1373,14 @@ float getstrdammod(lifeform_t *lf) { // <9 = penalty // 9,10,11,12 = average // >12 = bonus - base = getattr(lf, A_STR); + + if (lfhasflag(lf, F_RAGE)) { + base = 20; + } else { + base = getattr(lf, A_STR); + } + + if ((base >= 9) && (base <= 12)) { mod = 1; } else if (base > 12) { @@ -1453,15 +1477,28 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) int acc,ev; int gothit; enum LFSIZE szlf,szvictim; + enum SKILLLEVEL slev; + int myroll; if (critical) { *critical = 0; } acc = getlfaccuracy(lf, wep); + if (isprone(victim)) { + acc += 30; + } + + // remember lore about victim... + slev = getlorelevel(lf, victim->race->raceclass->id); // modify for defender's evasion - ev = getevasion(victim); + if (isprone(victim)) { + ev = 0; + } else { + ev = getevasion(victim); + } + acc -= ev; // special case @@ -1503,15 +1540,34 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) acc += 50; } + + // base 5% critical chance if (critical) { - if (rnd(1,20) == 20) *critical = 1; + int critroll; + critroll = rnd(1,100); + + // modify for lore + if (slev != PR_INEPT) { + myroll += (slev*5); // ie. up to 30% bonus + + } + + if (critroll >= 95) *critical = 1; } if (acc < 0) acc = 0; if (acc > 100) acc = 100; + + //if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc); - if (rnd(1,100) <= acc) { + myroll = rnd(1,100); + if (slev != PR_INEPT) { + myroll += (slev*10); + } + + // modify for lore + if (myroll <= acc) { gothit = B_TRUE; } else { if (critical && *critical) { @@ -1644,13 +1700,13 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { if (cansee(player, owner)) { msg("%s trip%s %s.",lfname, isplayer(owner) ? "" : "s", victimname); } - fall(victim, B_TRUE); + fall(victim, NULL, B_TRUE); } } else if ((f->id == F_HEAVYBLOW) && victim && owner) { int dir; // knock back victim dir = getdirtowards(owner->cell, victim->cell, victim, B_FALSE, DT_COMPASS); - knockback(victim, dir , 2, owner); + knockback(victim, dir , 2, owner, 30); f->known = B_TRUE; } else if ((f->id == F_HITCONFER) && victim ) { // only works if we did damage diff --git a/defs.h b/defs.h index a377430..2776e63 100644 --- a/defs.h +++ b/defs.h @@ -131,6 +131,8 @@ enum CHECKTYPE { SC_CON, ////////// SC_DODGE, + SC_SHIELDBLOCK, + SC_FALL, SC_SLIP, SC_LISTEN, SC_MORALE, @@ -539,6 +541,7 @@ enum RARITY { */ enum RACECLASS { + RC_ANY, // not actually ever defined RC_ANIMAL, RC_DEMON, RC_HUMANOID, @@ -556,6 +559,7 @@ enum RACE { R_BEHOLDER, R_BUGBEAR, R_COCKATRICE, + R_CREEPINGCLAW, R_DARKMANTLE, R_EYEBAT, R_GIANTHILL, @@ -581,24 +585,36 @@ enum RACE { R_ORC, R_ORCWARRIOR, R_ORK, + R_PEGASUS, R_POLTERGEIST, + R_SATYR, R_SHADOWCAT, R_SPRITEFIRE, R_TROGLODYTE, R_TROLL, R_XAT, - // small animals + // animals R_ANT, R_ANTS, + R_ANTLION, R_BAT, + R_BEAR, + R_BEARGRIZZLY, + R_DOGBLINK, + R_DOGDEATH, + R_DOGWAR, R_HAWK, R_HAWKYOUNG, R_HAWKBLOOD, R_HAWKFROST, + R_LEECH, R_NEWT, R_RAT, R_SNAKE, R_SNAKECARPET, + R_SNAKECOBRA, + R_SNAKECONSTRICTOR, + R_SNAKETREE, R_SPIDER, R_SPIDERFUNNELWEB, R_SPIDERREDBACK, @@ -610,6 +626,7 @@ enum RACE { R_GLOWBUG, R_GIANTFLY, R_GIANTBLOWFLY, + R_STIRGE, // undead R_GHAST, R_GHOST, @@ -819,6 +836,7 @@ enum OBTYPE { // -- death OT_SB_ANIMATEDEAD, OT_SB_DRAINLIFE, + OT_SB_FEAR, OT_SB_PAIN, OT_SB_PARALYZE, OT_SB_POISONBOLT, @@ -837,6 +855,9 @@ enum OBTYPE { OT_SB_AIRBLAST, OT_SB_CALLLIGHTNING, OT_SB_CLOUDKILL, + OT_SB_GUSTOFWIND, + OT_SB_LIGHTNINGSTORM, + OT_SB_WINDSHIELD, // -- elemental - fire OT_SB_SPARK, OT_SB_FIREDART, @@ -900,6 +921,7 @@ enum OBTYPE { // -- death OT_S_ANIMATEDEAD, OT_S_DRAINLIFE, + OT_S_FEAR, OT_S_PAIN, OT_S_PARALYZE, OT_S_INFINITEDEATH, @@ -919,6 +941,7 @@ enum OBTYPE { // -- elemental - air OT_S_AIRBLAST, OT_S_CLOUDKILL, + OT_S_GUSTOFWIND, OT_S_WINDSHIELD, // -- elemental - fire OT_S_SPARK, @@ -975,6 +998,7 @@ enum OBTYPE { OT_S_ENDUREELEMENTS, OT_S_ENTANGLE, OT_S_HAILSTORM, + OT_S_LIGHTNINGSTORM, OT_S_PURIFYFOOD, OT_S_QUENCH, OT_S_LESSENPOISON, @@ -982,7 +1006,11 @@ enum OBTYPE { OT_S_SLEETSTORM, OT_S_SOFTENEARTH, OT_S_STICKTOSNAKE, + OT_S_SUMMONANIMALSSM, + OT_S_SUMMONANIMALSMD, + OT_S_SUMMONANIMALSLG, OT_S_WARPWOOD, + OT_S_WATERJET, // -- summoning OT_S_CREATEMONSTER, // -- translocation @@ -1005,10 +1033,12 @@ enum OBTYPE { OT_A_LEARN, OT_A_LEVELUP, // abilities + OT_A_SUCKBLOOD, OT_A_GRAB, OT_A_CHARGE, OT_A_CRUSH, OT_A_JUMP, + OT_A_RAGE, OT_A_SPRINT, OT_A_STINGACID, // need to define dam in f_canwill OT_A_SWOOP, @@ -1044,6 +1074,7 @@ enum OBTYPE { OT_LAMPOIL, OT_LANTERNOIL, OT_LOCKPICK, + OT_PANPIPES, OT_PICKAXE, OT_TORCH, // tech @@ -1076,6 +1107,7 @@ enum OBTYPE { OT_SPLASHWATER, OT_PUDDLEWATER, OT_PUDDLEWATERL, + OT_ACIDSPLASH, OT_ACIDPUDDLE, OT_ACIDPOOL, OT_SLIMEPOOL, @@ -1174,6 +1206,8 @@ enum OBTYPE { OT_FISTS, OT_HOOKHAND, // for pirate OT_STING, + OT_BUTT, + OT_HOOF, OT_TAIL, OT_TEETH, OT_TEETHSM, @@ -1225,6 +1259,9 @@ enum OBTYPE { OT_TRIDENT, // staves OT_QUARTERSTAFF, + OT_BAMBOOSTAFF, + OT_IRONSTAFF, + OT_BLADEDSTAFF, // clubs OT_CLUB, OT_FLAIL, @@ -1277,9 +1314,11 @@ enum NOISETYPE { N_WALK, N_FLY, N_WARCRY, + N_LOWHP, }; enum LFSIZE { + SZ_ANY = -1, SZ_MINI = 0, // ie. fly SZ_TINY = 1, // ie. mouse SZ_SMALL = 2, // ie. cat @@ -1329,10 +1368,12 @@ enum FLAG { F_UNIQUE, // only one may appear F_GLYPH, // override the glyph with the first char of text. // v0 is either NA (white) or colourid (C_xxx). + F_COSMETIC, // this object is mostly cosmetic, don't say 'you see xx' F_NOPICKUP, // cannot pick this up F_IMPASSABLE, // cannot walk past this if your size if v0 or smaller F_CRUSHABLE, // if you are bigger than size v0, walking on this crushes it - F_BLOCKSVIEW, // cannot see past this + F_BLOCKSVIEW, // if v0 = true, cannot see past this + // if v0 > 0, reduces your vision by v0. F_BLOCKSTHROW, // cannot throw past this F_THEREISHERE, // announce "there is xx here!", not "you see xx here" // text[0] is punctuation to use. @@ -1361,6 +1402,7 @@ enum FLAG { F_EQUIPCONFER, // gives flag v0+v1 when weilded/worn. v2 specifies if it must be id'd. F_ACTIVATECONFER, // gives flag v0+v1 when activated. v2 specifies if it must be id'd. + F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit F_HITCONFER, // hitting with this gives flagid=v0 // unless you pass a val1 skillcheck, diff val2 // with timeleft = text ("min-max") @@ -1460,7 +1502,7 @@ enum FLAG { F_USESSKILL, // weapon needs skill sk_v0 F_CANHAVEOBMOD, // weapon can have obmod om_v0 applied // optional: v1 is chance of randomly having it - F_ATTREQ, // requires attrib v0 to be at least bracket v1 + F_ATTREQ, // requires attrib v0 to be at least v1 //F_DAMTYPE, // val0 = damage type //F_DAM, // val0 = ndice, val1 = nsidesondie, val2 = mod F_DAM, // v0 = damtype, text = 1d1+1 @@ -1542,6 +1584,7 @@ enum FLAG { F_DONEDARKMSG, // tells the game not to say 'it is very dark here' F_DONELISTEN, // supress further 'you hear xx' messages this turn. // lifeform flags / lf flags + F_COUNTER, // generic counter flag for race abilities. F_DEBUG, // debugging enabled F_ACCURACYMOD, // modify your accuracy by val0 F_VEGETARIAN, // this lf will not eat meat. @@ -1584,14 +1627,23 @@ enum FLAG { F_FAILEDINSPECT, // lf has failed an inspect check for item id v0 F_BOOSTSPELL, // v0 is active boost spell, v1 is ongoing mpcost, v2 is power F_SWOOPRANGE, // v0 = how far a flying creature can swoop + F_LOSLOF, // v0 = whether this spell needs line of sight + // v1 = whether this spell needs line of fire // MONSTER AI FLAGS F_XPVAL, // force xp val for killing this lf to v0 // ...OR if applied to an ability... // monsters with this abil/spell are worth // v0 more xp. F_XPMULTIPLY, // multiply xp val for killing this lf by v0 + F_LASTDIR, // this is the last direction we moved. + F_OWNERLASTDIR, // for pets, this it the last dir our owner moved + // when we could see them. F_PETOF, // this lf is a pet of lfid v0 // v1/2 = last known location of my owner. + F_SUMMONEDBY, // this lf was summoned by lfid v0. if they die, we + // vanish. + // v1 is lifetime left. this decrements each turn. + // when at zero, lf vanishes. F_HOSTILE, // lf will attack the player if in sight F_FRIENDLY, // lf will attack all non-players if in sight F_WANTS, // lf will try to pick up object type val0. if @@ -1637,6 +1689,10 @@ enum FLAG { F_NAME, // text = player's name F_XPMOD, // add/subtract this much from calculated xpval F_BLOODOB, // text = type of object to drop for blood + F_DIESPLATTER, // this lf will splatter objcets of type 'text' + // when it dies. + // v0 = max distance to splatter (or UNLIMITED) + // text = type of object to splatter F_OBESE, // double base weight for race! F_ORIGRACE, // original player race (if you polymorphed) F_ORIGJOB, // original player job (if you polymorphed) @@ -1647,7 +1703,6 @@ enum FLAG { // for monsters F_HUMANOID, // this race can wear armour / use weapons F_INSECT, // this race is classed as an insect - F_ANIMAL, // this race is classed as an animal F_UNDEAD, // this race is classed as undead F_COLDBLOOD, // this race is coldblooded F_NOBODYPART, // this race doesn't have bodypart val0 @@ -1658,8 +1713,8 @@ enum FLAG { F_AUTOCREATEOB, // produces obtype 'text' wherever it walks, v0=radius // (only if ob of that type not already there) F_PACKATTACK, // deal v0 extra damage of type v1 if there are - // v2 or more monsters matching f->text next - // to the victim + // v2 or more monsters of the same baseid + // next to the attacker F_PHALANX, // gain v0 AR if v2 or more adj monsters matching f->text F_MORALE, // gain +v0 in morale checks. F_SPOTTED, // you have spotted hiding lf id v0 @@ -1668,12 +1723,16 @@ enum FLAG { // ie 'magic armour', 'force field' // v0 is power left. F_ASLEEP, // is asleep + F_ATTACHEDTO, // you are attached to lf id v0, and will move with it F_BEINGSTONED,// turn to stone when v0 drops to zero. (drops 1/turn) F_BLIND, // cannot see anything F_DEAF, // cannot hear + F_NEEDOBFORSPELLS, // lf can only cast spells if it has object v0 F_CANCAST, // can cast the spell val0 (need MP) F_CANHEARLF, // you can hear lifeform id v0 (show their glyph) // this flag does not get announced. + F_BLEEDABIL, // will automatically use the ability v0 when + // this lf starts bleeding. F_CANWILL, // can cast the spell/ability val0 without using MP // v1 is counter untiluse // v2 is what you need to use it @@ -1682,6 +1741,7 @@ enum FLAG { // pw:xx; cast the spell at power xx // dam:xdy+b; damage // needgrab:xx; do you need to grab first? + // range:xx; F_CHARMEDBY,// you've been charmed by lf id v0 F_CONTROL,// you control polymorphs, teleports and createmonsters F_DETECTAURAS, // autodetect bless/curse @@ -1721,16 +1781,20 @@ enum FLAG { F_PAIN, // take damage if you walk. v0=damtype,text is damage (xdy+z). // if text not set, default dam is 1d2 F_PARALYZED,// cannot do anything + F_PRONE, // lying on the ground F_FROZEN, // made of ice F_LEVITATING, // like flying but uncontrolled F_MAGSHIELD,// magnetic shield F_NAUSEATED, // lf has a stench penalty of v0 (-v0*10 to hit). F_NONCORPOREAL,// can walk through walls + // when this comes from the passwall spell, 'obfrom' + // be set to the ot_s_passwall. F_OMNIPOTENT, // knows extra info F_PHOTOMEM, // you don't forget your surroundings F_REGENERATES, // regenerate HP at val0 per turn F_RESISTMAG, // immunity to magic effects. v0=amt (1-20) F_MPREGEN, // regenerate MP at val0 per turn + F_RAGE, // you are enraged. v0/v1 will be set to player's old hp/maxhp F_RISEASGHOST, // become a ghost when you die. F_SEEINDARK, // nightvis range is val0 F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0 @@ -1747,7 +1811,7 @@ enum FLAG { F_XRAYVIS, //val0=num of walls we can see through F_CANSEETHROUGHMAT, //val0=kind of material you can see through F_SPRINTING, // v0=true: you are sprinting. false=you are tired - F_TIRED, // you are too tired to sprint + F_TIRED, // you are too tired to sprint, rage, etc F_WINDSHIELD,// has a windshield protecting against missiles of speed // v0 or lower. F_DODGES, // you dodge missed attacks @@ -1954,6 +2018,7 @@ enum ERROR { // E_NOBP = 48, E_VEGETARIAN = 49, + E_NOOB = 50, }; @@ -2043,7 +2108,7 @@ typedef struct cell_s { } cell_t; typedef struct glyph_s { - char ch; + int ch; int colour; } glyph_t; diff --git a/flag.c b/flag.c index 86c5a9d..f54206e 100644 --- a/flag.c +++ b/flag.c @@ -141,6 +141,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, // special effects if (f->pile->owner) { + float pct; switch (f->id) { case F_ASLEEP: stopallspells(f->pile->owner); @@ -148,6 +149,13 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, case F_NONCORPOREAL: killflagsofid(f->pile->owner->flags, F_BEINGSTONED); break; + case F_RAGE: + f->val[0] = f->pile->owner->hp; // remember old maxhp + f->val[1] = f->pile->owner->maxhp; // remember old maxhp + pct = (float)f->pile->owner->hp / (float)f->pile->owner->maxhp; + f->pile->owner->maxhp = (float)f->pile->owner->maxhp * 1.5; + f->pile->owner->hp = pct * (float)f->pile->owner->maxhp; + break; default: break; } @@ -202,6 +210,7 @@ int flagcausesredraw(lifeform_t *lf, enum FLAG fid) { case F_FASTMOVE: case F_HIDING: case F_INVISIBLE: + case F_RAGE: case F_SEEINDARK: case F_SEEINVIS: case F_SPRINTING: @@ -274,6 +283,15 @@ flag_t *hasflagvalknown(flagpile_t *fp, int id, int val1, int val2, int val3, ch return hasflagval_real(fp, id, val1, val2, val3, text, B_TRUE); // must be known } +int getcounter(flagpile_t *fp) { + flag_t *f; + f = hasflag(fp, F_COUNTER); + if (f) { + return f->val[0]; + } + return 0; +} + flag_t *hasflagval_real(flagpile_t *fp, int id, int val1, int val2, int val3, char *text, int wantknown) { flag_t *f; lifeform_t *owner; @@ -331,6 +349,15 @@ void killflag(flag_t *f) { if (!lfhasflagval(lf, F_NOFLEEFROM, f->val[0], NA, NA, NULL)) { addtempflag(lf->flags, F_NOFLEEFROM, f->val[0], NA, NA, NULL, 10); } + } else if (f->id == F_RAGE) { + if (!isdead(lf)) { + // restore original maxhp + float pct; + pct = (float)lf->hp / (float)lf->maxhp; + lf->maxhp = f->val[1]; + lf->hp = pct * (float)lf->maxhp; + if (lf->hp < 1) lf->hp = 1; + } } // announce @@ -562,6 +589,18 @@ void timeeffectsflag(flag_t *f, int howlong) { } } +int modcounter(flagpile_t *fp, int amt) { + flag_t *f; + f = hasflag(fp, F_COUNTER); + if (f) { + f->val[0] += amt; + } else { + f = addflag(fp, F_COUNTER, amt, NA, NA, NULL); + } + return f->val[0]; +} + + void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2) { flag_t *f; if (val0) *val0 = 0; diff --git a/flag.h b/flag.h index 1c1a687..1af65aa 100644 --- a/flag.h +++ b/flag.h @@ -10,6 +10,7 @@ void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id); void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime); int flagcausesredraw(lifeform_t *lf, enum FLAG fid); int flagstacks(enum FLAG fid); +int modcounter(flagpile_t *fp, int amt); flag_t *hasflag(flagpile_t *fp, int id); flag_t *hasflagknown(flagpile_t *fp, int id); flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception); @@ -20,6 +21,7 @@ int killflagsofid(flagpile_t *fp, enum FLAG fid); void killflag(flag_t *f); void killflagpile(flagpile_t *fp); void makeflagknown(flagpile_t *fp); +int modcounter(flagpile_t *fp, int amt); void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2); void timeeffectsflag(flag_t *f, int howlong); void timeeffectsflags(flagpile_t *fp); diff --git a/io.c b/io.c index ce58795..9e0415e 100644 --- a/io.c +++ b/io.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -119,6 +120,7 @@ void addpromptq(prompt_t *p, char *q) { p->nqs++; } + void anim(cell_t *src, cell_t *dst, char ch, int colour) { int deltax, deltay; int numpixels; @@ -305,6 +307,38 @@ void animradialorth(cell_t *src, int radius, char ch,int colour) { curs_set(1); } + +// bolt from the sky +void animsky(cell_t *src, char ch, int colour) { + glyph_t gl; + int y; + + if (!haslos(player, src)) { + return; + } + + gl.ch = ch; + gl.colour = colour; + // hide cursor + curs_set(0); + + // update viewpoint + updateviewfor(src); + + drawlevelfor(player); + + // draw bolt coming down + for (y = 0; y <= src->y - viewy; y++) { + drawglyph(&gl, src->x - viewx, y); + } + wrefresh(gamewin); + usleep(ANIMDELAY); + + // show cursor + curs_set(1); + +} + char askchar(char *prompt, char *validchars, char *def, int showchars) { char buf[BUFLEN]; char *p; @@ -460,7 +494,7 @@ cell_t *askcoords(char *prompt, int targettype) { if (!isplayer(c->lf)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); if (lfhasflagval(c->lf, F_PETOF, player->id, NA, NA, NULL)) { - if (lfhasflag(c->lf, F_ANIMAL)) { + if (getraceclass(c->lf) == RC_ANIMAL) { strcat(extrainfo, "pet"); } else { strcat(extrainfo, "ally"); @@ -482,6 +516,10 @@ cell_t *askcoords(char *prompt, int targettype) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "fleeing"); } + if (lfhasflag(c->lf, F_PRONE)) { + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, "prone"); + } if (lfhasflag(c->lf, F_RESTING)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "resting"); @@ -490,6 +528,19 @@ cell_t *askcoords(char *prompt, int targettype) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "asleep"); } + f = lfhasflag(c->lf, F_ATTACHEDTO); + if (lfhasflag(c->lf, F_ATTACHEDTO)) { + lifeform_t *alf; + alf = findlf(c->map, f->val[0]); + if (alf) { + char alfname[BUFLEN]; + char buf2[BUFLEN]; + getlfname(alf, alfname); + if (strlen(extrainfo)) strcat(extrainfo, ", "); + sprintf(buf2, "attached to %s",alfname); + strcat(extrainfo, buf2); + } + } if ((getallegiance(c->lf) == AL_HOSTILE) && (getlorelevel(player, c->lf->race->raceclass->id) >= PR_ADEPT)) { @@ -517,7 +568,7 @@ cell_t *askcoords(char *prompt, int targettype) { strcat(extrainfo, dangerbuf); } - o = hasobwithflag(c->obpile, F_RESTRICTMOVEMENT); + o = isstuck(c->lf); if (o) { char buf2[BUFLEN]; char obname[BUFLEN]; @@ -547,6 +598,11 @@ cell_t *askcoords(char *prompt, int targettype) { } + if (lfhasflag(c->lf, F_RAGE)) { + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, "enraged"); + } + wep = getweapon(c->lf); if (wep && (c->lf->race->id != R_DANCINGWEAPON)) { object_t *secwep; @@ -806,6 +862,14 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; + case F_ATTACHEDTO: + lf2 = findlf(NULL, f->val[0]); + if (lf2) { + getlfname(lf2, buf); + msg("%s %s on to %s!",lfname, isplayer(lf) ? "latch" : "latches", buf); + donesomething = B_TRUE; + } + break; case F_BEINGSTONED: msg("%s begin%s to turn to stone!",lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; @@ -852,7 +916,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { 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)); + msg("%s %s now under %s%s power!",lfname, is(lf), buf,getpossessive(buf)); donesomething = B_TRUE; } break; @@ -1035,7 +1099,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { break; // don't announce grabbing. case F_GRAVBOOSTED: - msg("%s %s stuck to the floor!",lfname, isplayer(lf) ? "are" : "is"); + msg("%s %s incredibly heavy all of a sudden!",lfname, isplayer(lf) ? "feel" : "looks"); donesomething = B_TRUE; break; case F_LEVITATING: @@ -1043,7 +1107,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; break; case F_MAGSHIELD: - msg("%s %s surrounded by a magnetic shield!",lfname, isplayer(lf) ? "are" : "is"); + msg("%s %s surrounded by a magnetic shield!",lfname, is(lf)); donesomething = B_TRUE; break; case F_NAUSEATED: @@ -1078,6 +1142,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s start%s producing light!", lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; + case F_RAGE: + msg("%s enter%s a berzerker rage!", lfname, isplayer(lf) ? "" : "s"); + donesomething = B_TRUE; + break; case F_REGENERATES: if (isplayer(lf)) { // don't know if monsters get it msg("Your body's healing rate is enhanced!"); @@ -1250,6 +1318,15 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("%s%s %s vanishes.",lfname,getpossessive(lfname), f->text); donesomething = B_TRUE; break; + case F_ATTACHEDTO: + lf2 = findlf(NULL, f->val[0]); + if (lf2) { + char buf[BUFLEN]; + getlfname(lf2, buf); + msg("%s %s %s!",lfname, isplayer(lf) ? "release" : "releases", buf); + donesomething = B_TRUE; + } + break; case F_ASLEEP: msg("%s wake%s up.",lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; @@ -1458,7 +1535,7 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { } break; case F_GRAVBOOSTED: - msg("%s %s no longer stuck to the floor.",lfname, isplayer(lf) ? "are" : "is"); + msg("%s %s no longer stuck to the floor.",lfname, is(lf)); donesomething = B_TRUE; break; case F_LEVITATING: @@ -1500,7 +1577,11 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { } break; case F_PRODUCESLIGHT: - msg("%s %s no longer producing light.", lfname, isplayer(lf) ? "are" : "is"); + msg("%s %s no longer producing light.", lfname, is(lf)); + donesomething = B_TRUE; + break; + case F_RAGE: + msg("%s %s less angry now.", lfname, isplayer(lf) ? "feel" : "seems"); donesomething = B_TRUE; break; case F_REGENERATES: @@ -1655,7 +1736,7 @@ int announceobflaggain(object_t *o, flag_t *f) { wantpremods = B_FALSE; } - real_getobname(o, obname, o->amt, wantpremods, B_FALSE, B_TRUE, B_TRUE); + real_getobname(o, obname, o->amt, wantpremods, B_FALSE, B_TRUE, B_TRUE, B_FALSE); if (o->pile->owner) { if (isplayer(o->pile->owner)) { @@ -1699,7 +1780,7 @@ void announceobflagloss(object_t *o, flag_t *f) { if (!haslos(player, loc)) { return; } - real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE); + real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); if (o->pile->owner) { if (isplayer(o->pile->owner)) { @@ -2802,6 +2883,9 @@ void describeob(object_t *o) { case F_PRODUCESLIGHT: mvwprintw(mainwin, y, 0, "%s produces light.", buf); y++; break; + case F_RAGE: + mvwprintw(mainwin, y, 0, "%s makes you enraged.", buf); y++; + break; case F_REGENERATES: if (f->val[1] == 1) { strcpy(buf2, ""); @@ -2978,8 +3062,14 @@ void describespell(objecttype_t *ot) { wprintw(mainwin, "\n"); - power = getspellpower(player, ot->id); - wprintw(mainwin, "You can cast it at power level %d (maximum %d).\n",power, getspellmaxpower(ot->id)); + if (ot->obclass->id == OC_SPELL) { + power = getspellpower(player, ot->id); + if (power > 0) { + wprintw(mainwin, "You can cast it at power level %d (maximum %d).\n",power, getspellmaxpower(ot->id)); + } else { + wprintw(mainwin, "It is too powerful for you to cast (maximum power %d).\n",power, getspellmaxpower(ot->id)); + } + } wrefresh(mainwin); @@ -3602,10 +3692,13 @@ void dolook(cell_t *where) { // doens't matter if you're blind getobname(o, buf, o->amt); msg("There is %s here%c", buf, f->text[0]); + interrupt(player); seensomething = B_TRUE; } else { - if (!numobs) firstob = o; - numobs++; + if (!hasflag(o->flags, F_COSMETIC)) { + if (!numobs) firstob = o; + numobs++; + } } } @@ -4620,58 +4713,15 @@ void drawunviscell(cell_t *cell, int x, int y) { void drawglyph(glyph_t *g, int x, int y) { int col; - col = g->colour; - setcol(gamewin, g->colour); - mvwprintw(gamewin, y, x, "%c", g->ch); - unsetcol(gamewin, g->colour); -} - -/* -void drawcell(cell_t *cell, int x, int y) { - drawglyph(&cell->type->glyph, x, y); -} -*/ - -// draw a cell that we have LOS to. -/* -void drawcellwithcontents(cell_t *cell, int x, int y) { - if (cell->lf && cansee(player, cell->lf)) { // lifeform here that we can see - glyph_t *gl; - // draw the lf's race glyph - gl = getlfglyph(cell->lf); - drawglyph(gl, x, y); - return; + if ((gamemode == GM_GAMESTARTED) && lfhasflag(player, F_RAGE)) { + col = C_RED; } else { - void *thing; - glyph_t glyph; - // scanned lf here? - if (isinscanrange(cell, &thing, NULL, &glyph) == TT_MONSTER) { - //mvwprintw(gamewin, y-viewy, x-viewx, "%c", glyph); - drawglyph(&glyph, x, y); - return; - } - } - - if ((countobs(cell->obpile) > 0)) { - object_t *o; - - // draw highest object in sort order - o = gettopobject(cell); - if (o) { - drawglyph(getglyph(o), x, y); - } else { - // should never happen. if it does, just show the - // first object - dblog("Warn: sorted object glyph drawing matching nothing!"); - //mvwprintw(gamewin, y, x, "%c", cell->obpile->first->type->obclass->glyph); - drawglyph(&cell->obpile->first->type->obclass->glyph, x, y); - } - } else { - // draw cell normally - drawcell(cell, x, y); + col = g->colour; } + setcol(gamewin, col); + mvwprintw(gamewin, y, x, "%lc", g->ch); + unsetcol(gamewin, col); } -*/ void drawcursor(void) { // move cursor to player position @@ -4736,6 +4786,9 @@ void doheading(WINDOW *win, int *y, int x, char *what) { void initgfx(void) { int msgwinh = 2; int statwinh = 2; + + setlocale(LC_CTYPE, ""); + mainwin = initscr(); // colour setup @@ -5776,6 +5829,12 @@ void drawstatus(void) { unsetcol(statwin, C_RED); } + if (lfhasflag(player, F_RAGE)) { + setcol(statwin, C_RED); + wprintw(statwin, " Enraged"); + unsetcol(statwin, C_RED); + } + // paralysed somehow? if (isimmobile(player)) { setcol(statwin, C_RED); @@ -5853,6 +5912,12 @@ void drawstatus(void) { } + if (lfhasflag(player, F_PAIN)) { + setcol(statwin, C_YELLOW); + wprintw(statwin, " Pain"); + unsetcol(statwin, C_YELLOW); + } + // show certain flags f = isdrunk(player); if (f) { @@ -6418,7 +6483,7 @@ void showlfstats(lifeform_t *lf, int showall) { } else if (accmod > 0) { sprintf(buf, "%d (%s, +%d%% bonus)",dex, buf2, accmod ); } else { // ie. accmod < 0 - sprintf(buf, "%d (%s, %d%% bonus)",dex, buf2, accmod ); + sprintf(buf, "%d (%s, %d%% penalty)",dex, buf2, accmod ); } if (dex != lf->baseatt[A_DEX]) strcat(buf, "*"); @@ -6714,6 +6779,11 @@ void showlfstats(lifeform_t *lf, int showall) { } if (strlen(knowstring)) { + char dambonusstr[BUFLEN]; + // append dam bonus + sprintf(dambonusstr, " (+%d%% bonus)",(lorelev*10)); + strcat(knowstring, dambonusstr); + // print it setcol(mainwin, lorecol); mvwprintw(mainwin, y, 0, "%s", knowstring); unsetcol(mainwin, lorecol); @@ -6754,18 +6824,37 @@ void showlfstats(lifeform_t *lf, int showall) { // obvious physical effects here. f = lfhasknownflag(lf, F_ASLEEP); if (f) { - mvwprintw(mainwin, y, 0, "%s %s sleeping.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s sleeping.", you(lf), is(lf)); + y++; + } + f = lfhasknownflag(lf, F_ATTACHEDTO); + if (f && (f->known)) { + lifeform_t *lf2; + char grabeename[BUFLEN]; + lf2 = findlf(NULL, f->val[0]); + if (lf2) { + getlfname(lf2, grabeename); + } else { + strcpy(grabeename, "something"); + } + sprintf(buf,"%s %s attached to %s.",you(lf), is(lf), grabeename); + mvwprintw(mainwin, y, 0, buf); y++; } f = lfhasknownflag(lf, F_FLYING); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s flying.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s flying.", you(lf), is(lf)); + y++; + } + f = lfhasknownflag(lf, F_PRONE); + if (f && (f->known)) { + mvwprintw(mainwin, y, 0, "%s %s lying on the ground.", you(lf), is(lf)); y++; } f = lfhasflag(lf, F_FROZEN); if (f && (f->known)) { mvwprintw(mainwin, y, 0, "%s %s been turned to ice, and %s slowly melting.", you(lf), isplayer(lf) ? "have" : "has", - isplayer(lf) ? "are" : "is"); + is(lf)); y++; } f = lfhasknownflag(lf, F_GRABBEDBY); @@ -6778,7 +6867,7 @@ void showlfstats(lifeform_t *lf, int showall) { } else { strcpy(grabbername, "something"); } - sprintf(buf,"%s %s being held by %s.",you(lf), isplayer(lf) ? "are" : "is", grabbername); + sprintf(buf,"%s %s being held by %s.",you(lf), is(lf), grabbername); mvwprintw(mainwin, y, 0, buf); y++; } @@ -6792,28 +6881,28 @@ void showlfstats(lifeform_t *lf, int showall) { } else { strcpy(grabeename, "something"); } - sprintf(buf,"%s %s holding on to %s.",you(lf), isplayer(lf) ? "are" : "is", grabeename); + sprintf(buf,"%s %s holding on to %s.",you(lf), is(lf), grabeename); mvwprintw(mainwin, y, 0, buf); y++; } f = lfhasknownflag(lf, F_HIDING); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s hiding.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s hiding.", you(lf), is(lf)); y++; } f = lfhasknownflag(lf, F_INVISIBLE); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s invisible.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s invisible.", you(lf), is(lf)); y++; } f = lfhasknownflag(lf, F_LEVITATING); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s levitating.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s levitating.", you(lf), is(lf)); y++; } f = lfhasflag(lf, F_NONCORPOREAL); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s noncorporeal and can walk through walls.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s noncorporeal and can walk through walls.", you(lf), is(lf)); y++; } f = lfhasflag(lf, F_PRODUCESLIGHT); @@ -6824,10 +6913,10 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasknownflag(lf, F_SPRINTING); if (f) { if (f->val[0]) { - mvwprintw(mainwin, y, 0, "%s %s sprinting.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s sprinting.", you(lf), is(lf)); y++; } else { - mvwprintw(mainwin, y, 0, "%s %s exhausted.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s exhausted.", you(lf), is(lf)); y++; } } @@ -6836,7 +6925,7 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasknownflag(lf, F_UNDEAD); if (f) { - mvwprintw(mainwin, y, 0, "%s %s undead.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s undead.", you(lf), is(lf)); y++; } @@ -6913,7 +7002,7 @@ void showlfstats(lifeform_t *lf, int showall) { if (lf2) { getlfname(lf2, buf); mvwprintw(mainwin, y, 0, "%s %s fleeing from %s.", - you(lf), isplayer(lf) ? "are" : "is", buf); + you(lf), is(lf), buf); y++; } } @@ -6922,7 +7011,7 @@ void showlfstats(lifeform_t *lf, int showall) { // diff materials? if (lf->race->material->id != MT_FLESH) { - mvwprintw(mainwin, y, 0, "%s %s made out of %s.",you(lf), isplayer(lf) ? "are" : "is", lf->race->material->name); + mvwprintw(mainwin, y, 0, "%s %s made out of %s.",you(lf), is(lf), lf->race->material->name); y++; } @@ -6931,14 +7020,14 @@ void showlfstats(lifeform_t *lf, int showall) { strcpy(buf, ""); f = lfhasflagval(lf, F_DTRESIST, DT_ALL, NA, NA, NULL); if (f && (showall || f->known)) { - sprintf(buf, "%s %s resistant to %s", you(lf), isplayer(lf) ? "are" : "is", getdamname(DT_ALL)); + sprintf(buf, "%s %s resistant to %s", you(lf), is(lf), getdamname(DT_ALL)); } else { first = B_TRUE; for (i = 0; i < MAXDAMTYPE; i++) { f = isresistantto(lf->flags, i); if (f && (showall || f->known)) { if (first) { - sprintf(buf2, "%s %s resistant to: %s", you(lf), isplayer(lf) ? "are" : "is",getdamnamenoun(i)); + sprintf(buf2, "%s %s resistant to: %s", you(lf), is(lf),getdamnamenoun(i)); first = B_FALSE; } else { sprintf(buf2, ", %s", getdamnamenoun(i)); @@ -6966,14 +7055,14 @@ void showlfstats(lifeform_t *lf, int showall) { strcpy(buf, ""); f = lfhasflagval(lf, F_DTIMMUNE, DT_ALL, NA, NA, NULL); if (f && (showall || f->known)) { - sprintf(buf, "%s %s immune to %s", you(lf), isplayer(lf) ? "are" : "is", getdamname(DT_ALL)); + sprintf(buf, "%s %s immune to %s", you(lf), is(lf), getdamname(DT_ALL)); } else { first = B_TRUE; for (i = 0; i < MAXDAMTYPE; i++) { f = isimmuneto(lf->flags, i); if (f && (showall || f->known)) { if (first) { - sprintf(buf2, "%s %s immune to: %s", you(lf), isplayer(lf) ? "are" : "is", getdamname(i)); + sprintf(buf2, "%s %s immune to: %s", you(lf), is(lf), getdamname(i)); first = B_FALSE; } else { sprintf(buf2, ", %s", getdamname(i)); @@ -6993,14 +7082,14 @@ void showlfstats(lifeform_t *lf, int showall) { strcpy(buf, ""); f = lfhasflagval(lf, F_DTVULN, DT_ALL, NA, NA, NULL); if (f && (showall || f->known)) { - sprintf(buf, "%s %s vulnerable to %s", you(lf), isplayer(lf) ? "are" : "is", getdamname(DT_ALL)); + sprintf(buf, "%s %s vulnerable to %s", you(lf), is(lf), getdamname(DT_ALL)); } else { first = B_TRUE; for (i = 0; i < MAXDAMTYPE; i++) { f = isvulnto(lf->flags, i); if (f && (showall || f->known)) { if (first) { - sprintf(buf2, "%s %s vulnerable to: %s", you(lf), isplayer(lf) ? "are" : "is", getdamnamenoun(i)); + sprintf(buf2, "%s %s vulnerable to: %s", you(lf), is(lf), getdamnamenoun(i)); first = B_FALSE; } else { sprintf(buf2, ", %s", getdamnamenoun(i)); @@ -7039,6 +7128,7 @@ void showlfstats(lifeform_t *lf, int showall) { char expirebuf[BUFLEN]; char eb2[BUFLEN]; int needgrab = B_FALSE; + int range; if (f->val[2] == NA) { sprintf(expirebuf, "at will"); @@ -7048,10 +7138,15 @@ void showlfstats(lifeform_t *lf, int showall) { } // extra options? - texttospellopts(f->text, NULL, NULL, &needgrab); + texttospellopts(f->text, NULL, NULL, &needgrab, &range); if (needgrab) { strcat(expirebuf, ",after grab"); } + if (range) { + char rbuf[BUFLEN]; + sprintf(rbuf, ",range:%d",range); + strcat(expirebuf, rbuf); + } if (strlen(expirebuf)) { sprintf(eb2,"(%s)",expirebuf); @@ -7235,7 +7330,7 @@ void showlfstats(lifeform_t *lf, int showall) { // obvious physical effects first. f = lfhasknownflag(lf, F_BEINGSTONED); if (f) { - mvwprintw(mainwin, y, 0, "%s %s being turning to stone.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s being turning to stone.", you(lf), is(lf)); y++; } @@ -7249,13 +7344,13 @@ void showlfstats(lifeform_t *lf, int showall) { if (hasjob(lf, J_PIRATE)) { mvwprintw(mainwin, y, 0, "%s can hold %s liquor well.", you(lf), isplayer(lf) ? "your" : "its"); y++; - mvwprintw(mainwin, y, 0, "%s %s missing one eye.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s missing one eye.", you(lf), is(lf)); y++; } // flags which aren't really intrinsics if (lfhasflag(lf, F_VEGETARIAN)) { - mvwprintw(mainwin, y, 0, "%s %s a vegetarian.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s a vegetarian.", you(lf), is(lf)); y++; } @@ -7275,7 +7370,7 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasknownflag(lf, F_MAGICARMOUR); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s protected by %s %s", you(lf), isplayer(lf) ? "are" : "is", + mvwprintw(mainwin, y, 0, "%s %s protected by %s %s", you(lf), is(lf), needan(f->text) ? "an" : "a", f->text); if (isplayer(lf)) { wprintw(mainwin, " (+%d AR).",f->val[0]); @@ -7353,7 +7448,7 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasknownflag(lf, F_DRUNK); if (f) { mvwprintw(mainwin, y, 0, "%s %s %s.", you(lf), - isplayer(lf) ? "are" : "is", getdrunktext(f)); + is(lf), getdrunktext(f)); y++; } @@ -7425,7 +7520,7 @@ void showlfstats(lifeform_t *lf, int showall) { } } - sprintf(buf, "%s %s sick with %s%s.", you(lf), isplayer(lf) ? "are" : "is", + sprintf(buf, "%s %s sick with %s%s.", you(lf), is(lf), getpoisonname(f->val[0]), knownfatal ? ", potentially fatally" : ""); if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT) || @@ -7441,7 +7536,7 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasflag(lf, F_NAUSEATED); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s nauseated.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s nauseated.", you(lf), is(lf)); y++; } f = lfhasknownflag(lf, F_PACKATTACK); @@ -7498,23 +7593,23 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasflag(lf, F_MAGSHIELD); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s surrounded by a magnetic shield.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s surrounded by a magnetic shield.", you(lf), is(lf)); y++; } f = lfhasflag(lf, F_PAIN); if (f && (f->known)) { if (isdrunk(lf)) { - mvwprintw(mainwin, y, 0, "%s %s in extreme pain, somewhat mitigated by %s inebriation.", you(lf), isplayer(lf) ? "are" : "is", isplayer(lf) ? "your" : "its"); + mvwprintw(mainwin, y, 0, "%s %s in extreme pain, somewhat mitigated by %s inebriation.", you(lf), is(lf), isplayer(lf) ? "your" : "its"); } else { - mvwprintw(mainwin, y, 0, "%s %s in extreme pain, and movement will cause %s damage.", you(lf), isplayer(lf) ? "are" : "is", isplayer(lf) ? "you" : "it"); + mvwprintw(mainwin, y, 0, "%s %s in extreme pain, and movement will cause %s damage.", you(lf), is(lf), isplayer(lf) ? "you" : "it"); } y++; } f = lfhasflag(lf, F_PARALYZED); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s paralyzed.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s paralyzed.", you(lf), is(lf)); y++; } f = lfhasflag(lf, F_PHOTOMEM); @@ -7522,6 +7617,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s do not forget your surroundings.", you(lf)); y++; } + f = lfhasflag(lf, F_RAGE); + if (f && (f->known)) { + mvwprintw(mainwin, y, 0, "%s %s enraged.", you(lf), is(lf)); + y++; + } f = lfhasknownflag(lf, F_REGENERATES); if (f) { char regenspeed[BUFLEN]; @@ -7553,7 +7653,7 @@ void showlfstats(lifeform_t *lf, int showall) { } else { // ie. 21 upwards strcpy(adjective, "incredibly"); } - mvwprintw(mainwin, y, 0, "%s %s %s resistant to magic.", you(lf), isplayer(lf) ? "are" : "is", adjective); + mvwprintw(mainwin, y, 0, "%s %s %s resistant to magic.", you(lf), is(lf), adjective); y++; } f = lfhasknownflag(lf, F_TREMORSENSE); @@ -7563,7 +7663,7 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasknownflag(lf, F_WINDSHIELD); if (f) { - mvwprintw(mainwin, y, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), is(lf)); if (isplayer(lf)) { wprintw(mainwin, " (power %d).",roman(f->val[0])); @@ -7574,7 +7674,7 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasknownflag(lf, F_TIRED); if (f) { - mvwprintw(mainwin, y, 0, "%s %s tired.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s tired.", you(lf), is(lf)); y++; } diff --git a/io.h b/io.h index 5ca47ff..3bb26b7 100644 --- a/io.h +++ b/io.h @@ -7,6 +7,7 @@ void addpromptq(prompt_t *p, char *q); void anim(cell_t *src, cell_t *dst, char ch, int colour); void animradial(cell_t *src, int radius, char ch, int colour); void animradialorth(cell_t *src, int radius, char ch, int colour); +void animsky(cell_t *src, char ch, int colour); //void announceob(enum OBTYPE oid); int announceflaggain(lifeform_t *lf, flag_t *f); int announceflagloss(lifeform_t *lf, flag_t *f); diff --git a/lf.c b/lf.c index e941e1d..6678463 100644 --- a/lf.c +++ b/lf.c @@ -52,579 +52,6 @@ race_t **raceposs; int *xpposs; int xplistlen; -job_t *addjob(enum JOB id, char *name) { - job_t *a; - - // add to the end of the list - if (firstjob == NULL) { - firstjob = malloc(sizeof(job_t)); - a = firstjob; - a->prev = NULL; - } else { - // go to end of list - a = lastjob; - a->next = malloc(sizeof(job_t)); - a->next->prev = a; - a = a->next; - } - lastjob = a; - a->next = NULL; - - // props - a->id = id; - a->name = strdup(name); - - a->flags = addflagpile(NULL, NULL); - return a; -} - -lifeform_t *addlf(cell_t *cell, enum RACE rid, int level) { - return real_addlf(cell, rid, level, C_AI); -} - -lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { - map_t *m; - lifeform_t *a; - int i; - - assert(cell); - if (cell->type != (celltype_t *) DUMMYCELLTYPE) { - assert(!cell->type->solid); - } - - m = cell->map; - - // add to the end of the list - if (m->lf == NULL) { - m->lf = malloc(sizeof(lifeform_t)); - a = m->lf; - a->prev = NULL; - } else { - // go to end of list - a = m->lastlf; - a->next = malloc(sizeof(lifeform_t)); - a->next->prev = a; - a = a->next; - } - - if (controller == C_PLAYER) { - player = a; - } - - m->lastlf = a; - a->next = NULL; - - a->born = B_FALSE; // will set this back to true later - - // props - a->id = nextlfid; nextlfid++; - a->controller = controller; - a->level = level; - a->newlevel = level; - a->xp = getxpforlev(a->level); - a->skillpoints = 0; - a->cell = cell; - a->alive = B_TRUE; - a->lastdam = strdup("nothing"); - a->lastdamtype = DT_NONE; - if ((gamemode == GM_GAMESTARTED) && a->prev) { - a->timespent = a->prev->timespent + 1; - } else { - a->timespent = 0; - } - a->sorted = B_FALSE; - a->forgettimer = 0; - - a->polyrevert = B_FALSE; - - // for precalcing line of sight - a->nlos = 0; - a->los = NULL; - - // for ai - - // avoid messages when equipping initial obs - a->created = B_FALSE; - - a->pack = addobpile(a, NOLOC); - - // clear laoding variables - for (i = 0; i < MAXPILEOBS; i++) { - a->oblist[i] = -1; - } - a->x = -1; - a->y = -1; - - // defaults - a->hp = 1; - a->maxhp = a->hp; - a->mp = 0; - a->maxmp = a->mp; - - // init flags - a->flags = addflagpile(a, NULL); - - // set race - this will inherit race flags - a->race = NULL; - setrace(a, rid, B_FALSE); - - // update other things - cell->lf = a; - - // give start objetcs - if ((gamemode != GM_LOADING) && (gamemode != GM_VALIDATION)) { - outfitlf(a); - } - a->created = B_TRUE; - a->born = B_TRUE; // now finished creating it. - return a; -} - - - -race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass) { - race_t *a; - - assert(!findrace(id)); - - // add to the end of the list - if (firstrace == NULL) { - firstrace = malloc(sizeof(race_t)); - a = firstrace; - a->prev = NULL; - } else { - // go to end of list - a = lastrace; - a->next = malloc(sizeof(race_t)); - a->next->prev = a; - a = a->next; - } - lastrace = a; - a->next = NULL; - - - // props - a->id = id; - a->baseid = id; // default - a->raceclass = findraceclass(raceclass); - - a->material = findmaterial(mat); - assert(a->material); - a->name = strdup(name); - a->weight = weight; - a->glyph.ch = glyph; - a->glyph.colour = glyphcolour; - - a->flags = addflagpile(NULL, NULL); - return a; -} - -raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill) { - raceclass_t *a; - - assert(!findraceclass(id)); - - // add to the end of the list - if (firstraceclass == NULL) { - firstraceclass = malloc(sizeof(raceclass_t)); - a = firstraceclass; - a->prev = NULL; - } else { - // go to end of list - a = lastraceclass; - a->next = malloc(sizeof(raceclass_t)); - a->next->prev = a; - a = a->next; - } - lastraceclass = a; - a->next = NULL; - - - // props - a->id = id; - a->name = strdup(name); - a->pluralname = strdup(pluralname); - a->skill = skill; - - return a; -} - -skill_t *addskill(enum SKILL id, char *name, char *desc) { - skill_t *a; - - assert(!findskill(id)); - - // add to the end of the list - if (firstskill == NULL) { - firstskill = malloc(sizeof(skill_t)); - a = firstskill; - a->prev = NULL; - } else { - // go to end of list - a = lastskill; - a->next = malloc(sizeof(skill_t)); - a->next->prev = a; - a = a->next; - } - lastskill = a; - a->next = NULL; - - - // props - a->id = id; - a->name = strdup(name); - a->desc = strdup(desc); - - return a; -} - -void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { - flag_t *f; - if (isimmuneto(lf->flags, damtype)) { - *amt = 0; - return; - } - - if ((damtype == DT_MAGIC) && getmr(lf) && skillcheck(lf, SC_RESISTMAG, 10 + (*amt * 2), 0)) { - *amt = 0; - return; - } - - // water normally doesn't hurt. - if ((damtype == DT_WATER) && !isvulnto(lf->flags, damtype)) { - *amt = 0; - return; - } - - if (lfhasflag(lf, F_INVULNERABLE)) { - switch (damtype) { - case DT_DIRECT: - case DT_NONE: - break; - default: - *amt = 0; - break; - } - return; - } - - if ((damtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { - (*amt) *= 2; - } - - if (isresistantto(lf->flags, damtype)) { - (*amt) /= 2; - } - f = isvulnto(lf->flags, damtype); - if (f) { - if ((*amt == 0) && strlen(f->text)) { - int ndice,nsides,bonus; - texttodice(f->text, &ndice,&nsides,&bonus); - *amt = rolldie(ndice,nsides) + bonus; - } else { - (*amt) *= 2; - } - } - - - // adjust for lifeform material - //adjustdammaterial(amt, damtype, getlfmaterial(lf)); - - if (*amt < 0) *amt = 0; -} - -void makepeaceful(lifeform_t *who) { - char lfname[BUFLEN]; - - getlfname(who, lfname); - if (lfhasflag(who, F_DEBUG)) { - msg("Making %s friendly.",lfname); - } - - if (lfhasflag(who, F_HOSTILE)) { - if (cansee(player, who)) { - char lfname[BUFLEN]; - getlfname(who, lfname); - msg("%s calms down.", lfname); - } - } - - killflagsofid(who->flags, F_HOSTILE); - killflagsofid(who->flags, F_TARGET); // stop targetting anyone - -} - -lifeform_t *makezombie(object_t *o) { - flag_t *f; - race_t *r; - lifeform_t *lf; - cell_t *where; - char obname[BUFLEN]; - - if (o->type->id != OT_CORPSE) return NULL; - - f = hasflag(o->flags, F_CORPSEOF); - if (!f) return NULL; - - r = findrace(f->val[0]); - if (!r) return NULL; - - where = getoblocation(o); - getobname(o, obname, 1); - - lf = addlf(where, r->id, 1); - - addflag(lf->flags, F_LFSUFFIX, B_TRUE, NA, NA, "zombie"); - addflag(lf->flags, F_GLYPH, C_GREY, NA, NA, "Z"); - addflag(lf->flags, F_UNDEAD, B_TRUE, NA, NA, NULL); - addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); - addflag(lf->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lf->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); - addflag(lf->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); - addflag(lf->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); - addflag(lf->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); - - if (hasflag(o->flags, F_HEADLESS)) { - // remove the head - addflag(lf->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL); - // remove the eyes (this will make the creature blind) - addflag(lf->flags, F_NOBODYPART, BP_EYES, NA, NA, NULL); - // need HEADLESS too to show that this monster normally - // _does_ have a head. this will cause getlfname - // to add "headless " to the description. - addflag(lf->flags, F_HEADLESS, B_TRUE, NA, NA, NULL); - } - - killflagsofid(lf->flags, F_WANTSBETTERWEP); - killflagsofid(lf->flags, F_WANTSBETTERARM); - killflagsofid(lf->flags, F_WANTSOBFLAG); - killflagsofid(lf->flags, F_WANTS); - killflagsofid(lf->flags, F_NOISETEXT); - killflagsofid(lf->flags, F_SEEINDARK); - killflagsofid(lf->flags, F_TREMORSENSE); - - killflagsofid(lf->flags, F_MOVESPEED); - addflag(lf->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); - killflagsofid(lf->flags, F_ACTIONSPEED); - addflag(lf->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); - lf->baseatt[A_IQ] = rolliq(IQ_MINDLESS); - lf->att[A_IQ] = lf->baseatt[A_IQ]; - - // no magic - lf->maxmp = 0; - lf->mp = 0; - - // no objects - while (lf->pack->first) { - killob(lf->pack->first); - } - - // no abilities - killflagsofid(lf->flags, F_CANCAST); - killflagsofid(lf->flags, F_CANWILL); - - // remove the object - removeob(o,o->amt); - - // redraw & announce - if (haslos(player, where)) { - needredraw = B_TRUE; - drawscreen(); - msg("%s rises from the dead!", obname); - } - - 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; -} - -void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) { - flag_t *fromlfflag; - lifeform_t *fromlf = NULL; - char damstring[BUFLEN],buf[BUFLEN]; - - getobname(o, buf, o->amt); - - fromlfflag = hasflag(o->flags, F_CREATEDBY); - if (fromlfflag) { - sprintf(damstring, "%s^created by %s",buf, fromlfflag->text); - } else { - strcpy(damstring, buf); - } - - dam = losehp(lf, dam, damtype, fromlf, damstring); - if (dam > 0) { - if (damtype == DT_POISONGAS) { - if (isplayer(lf) || cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s choke%s on %s!", lfname, isplayer(lf) ? "" : "s", buf); - } - } else { - if (isplayer(lf)) { - msg("%s %ss you!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp)); - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s %ss %s!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname); - } - } - } -} - -int areallies(lifeform_t *lf1, lifeform_t *lf2) { - if (getallegiance(lf1) == getallegiance(lf2)) { - if (isplayer(lf1) || isplayer(lf2)) { - // if one of them is the player - return B_TRUE; - } else { - if (lf1->race->baseid == lf2->race->baseid) { - return B_TRUE; - } - } - } - return B_FALSE; -} - -// make sure player has at least novice skill in all their start weapons/armour -void autoskill(lifeform_t *lf) { - skill_t *sk; - object_t *o; - enum SKILLLEVEL slev; - int nweps = 0; - - if (isplayer(lf)) { - slev = PR_NOVICE; - } else { - slev = PR_ADEPT; - } - - if (lf == player) { - dblog("test"); - } - - for (o = lf->pack->first ; o ; o = o->next) { - if (isweapon(o) && canweild(lf, o)) { - sk = getobskill(o); - if (sk && !getskill(lf, sk->id)) { - giveskilllev(lf, sk->id, slev); - } - nweps++; - } - if (isarmour(o) && canwear(lf, o, BP_NONE)) { - flag_t *f; - // evasion penalty? - f = hasflag(o->flags, F_EVASION); - if (f && (f->val[0] < 0)) { - giveskilllev(lf, SK_ARMOUR, PR_NOVICE); - } - } - if (isshield(o) && canwear(lf, o, BP_NONE)) { - giveskilllev(lf, SK_SHIELDS, PR_NOVICE); - } - } - - // monsters must get unarmed skill! - if (!nweps && !isplayer(lf)) { - giveskilllev(lf, SK_UNARMED, slev); - } - -} - -void autotarget(lifeform_t *lf) { - object_t *gun; - lifeform_t *targ,*newtarg; - int closest; - int i; - int gunrange; - int targid; - - gun = getfirearm(lf); - if (!gun) return; - - if (!getammo(lf)) return; - - gunrange = getfirearmrange(gun); - - // already got a target? - targid = getguntargetid(lf); - - if (targid == -1) { - targ = NULL; - } else { - targ = findlf(NULL, targid); - if (targ) { - // dead? remove target and keep going. - if (isdead(targ)) { - // clear target ? - targ = NULL; - } else if (!haslof(lf->cell, targ->cell, B_FALSE, NULL)) { - // clear target ? - targ = NULL; - } else { - // already got a valid target. return. - return; - } - } else { - // target no longer exists? - // clear target ? - } - } - - // find new target - newtarg = NULL; - closest = 9999; - for (i = 0; i < lf->nlos; i++) { - cell_t *c; - c = lf->los[i]; - if (c->lf && (c->lf != lf) && cansee(lf, c->lf) && isingunrange(lf, c)) { - int valid = B_TRUE; - if (!areenemies(lf, c->lf)) { - valid = B_FALSE; - } - if (valid) { - int thisdist; - thisdist = getcelldist(lf->cell, c); - if (thisdist < closest) { - newtarg = c->lf; - closest = thisdist; - } - } - } - } - - - if (newtarg && (newtarg != targ)) { - setguntarget(lf, newtarg); - } -} void autoweild(lifeform_t *lf) { object_t *bestwep,*bestfirearm; @@ -707,6 +134,33 @@ void bleed(lifeform_t *lf) { } } +void breakallgrabs(lifeform_t *lf) { + flag_t *f; + lifeform_t *alf; + f = lfhasflag(lf, F_GRABBING); + if (f) { + lifeform_t *grabee; + grabee = findlf(NULL, f->val[0]); + assert(grabee); + killflagsofid(grabee->flags, F_GRABBEDBY); + killflagsofid(lf->flags, F_GRABBING); + } + f = lfhasflag(lf, F_GRABBEDBY); + if (f) { + lifeform_t *graber; + graber = findlf(NULL, f->val[0]); + assert(graber); + killflagsofid(graber->flags, F_GRABBING); + killflagsofid(lf->flags, F_GRABBEDBY); + } + + for (alf = lf->cell->map->lf ; alf ; alf = alf->next) { + f = lfhasflagval(alf, F_ATTACHEDTO, lf->id, NA, NA, NULL); + if (f) { + killflag(f); + } + } +} // figure out how much xp a race is worth int calcxp(lifeform_t *lf) { float multiplier = 1; @@ -826,7 +280,7 @@ int calcxp(lifeform_t *lf) { break; } // get dam from text - texttospellopts(f->text, NULL, damstr, &needgrab); + texttospellopts(f->text, NULL, damstr, &needgrab, NULL); if (strlen(damstr)) { int dice,sides,mod,min,max; float thisavg; @@ -928,8 +382,7 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { int needgrab = B_FALSE; // get canwill opts - texttospellopts(f->text, NULL, NULL, &needgrab); - + texttospellopts(f->text, NULL, NULL, &needgrab, NULL); // no mp cost. if (mpcost) *mpcost = 0; @@ -1020,8 +473,10 @@ int caneat(lifeform_t *lf, object_t *o) { r = findrace(f->val[0]); // same race? if ((r->id == lf->race->id) || (r->baseid == lf->race->baseid)) { + enum RACECLASS rc; + rc = getraceclass(lf); // race which doens't eat its own? - if (hasflag(lf->flags, F_ANIMAL) || (lf->race->id == R_HUMAN)) { + if ((rc == RC_ANIMAL) || (rc == RC_HUMANOID)) { // no cannibulism! reason = E_NOCANNIBUL; return B_FALSE; @@ -1256,7 +711,10 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) { } // viewer asleep? if (lfhasflag(viewer, F_ASLEEP)) { - return B_FALSE; + // can only 'see' yourself + if (viewee != viewer) { + return B_FALSE; + } } // no line of sight? @@ -1483,6 +941,19 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar willflag = lfhasflagval(lf, F_CANWILL, sid, NA, NA, NULL); + // special case + if (!willflag) { + f = lfhasflag(lf, F_NEEDOBFORSPELLS); + if (f && !hasob(lf->pack, f->val[0])) { + objecttype_t *ot; + ot = findot(f->val[0]); + if (isplayer(lf)) { + msg("You can't cast spells without %s %s.",needan(ot->name) ? "an" : "a", ot->name); + } + return B_TRUE; + } + } + power = getspellpower(lf, sid); sp = findot(sid); @@ -1536,6 +1007,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar if (!isplayer(lf) && cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); + // special case f = lfhasflag(lf,F_SPELLCASTTEXT); if (f) { if (strlen(f->text)) { @@ -1815,15 +1287,15 @@ void die(lifeform_t *lf) { if (vaporised) { switch (rnd(1,2)) { case 1: - fragments(lf->cell, "chunk of flesh", 2); + fragments(lf->cell, "chunk of flesh", 2, UNLIMITED); break; case 2: - fragments(lf->cell, "pool of blood", 2); + fragments(lf->cell, "pool of blood", 2, UNLIMITED); break; } } else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { // shattered - fragments(lf->cell, "chunk of ice", 2); + fragments(lf->cell, "chunk of ice", 2, UNLIMITED); } else { if (lfhasflag(lf, F_NOCORPSE)) { if (lfhasflag(lf, F_UNDEAD) && cansee(player, lf)) { @@ -1902,6 +1374,15 @@ void die(lifeform_t *lf) { } } + // splatter + if (!vaporised) { + flag_t *f; + f = lfhasflag(lf, F_DIESPLATTER); + if (f) { + fragments(lf->cell, f->text, 1, f->val[0]); + } + } + if (willbecomeghost) { flag_t *f, *nextf; @@ -2002,7 +1483,7 @@ void dumpxp(void) { // dump dblog("%-10s%-30s%s","XP", "Race", "Rarity"); for (i = 0; i < xplistlen; i++) { - dblog("%-10d%-30s%d",xpposs[i], raceposs[i]->name,getracerarity(raceposs[i]->id)); + dblog("%-10d%-30s%d",xpposs[i], raceposs[i]->name,getracerarity(NULL, raceposs[i]->id)); } // free mem @@ -2030,8 +1511,8 @@ void dumplev(void) { // NOTE: this code copied from getrandomrace(), which is used by addmonster(). for (i = 1; i <= 25; i++) { int min,max,prevmin,prevmax; - getrarity(i-1, &prevmin, &prevmax, RARITYVARIANCELF); - getrarity(i, &min, &max, RARITYVARIANCELF); + getrarity(i-1, &prevmin, &prevmax, RARITYVARIANCELF, B_FALSE); + getrarity(i, &min, &max, RARITYVARIANCELF, B_FALSE); fprintf(logfile, "Dlev %d (rar >= %d): ",i,min); for (r = firstrace ; r; r = r->next) { int rarity = 0; @@ -2067,8 +1548,8 @@ void dumplev(void) { // NOTE: this code copied from getrandomrace(), which is used by addmonster(). for (i = 1; i <= 25; i++) { int min,max,prevmin,prevmax; - getrarity(i-1, &prevmin, &prevmax, RARITYVARIANCEOB); - getrarity(i, &min, &max, RARITYVARIANCEOB); + getrarity(i-1, &prevmin, &prevmax, RARITYVARIANCEOB, B_FALSE); + getrarity(i, &min, &max, RARITYVARIANCEOB, B_FALSE); fprintf(logfile, "Dlev %d (rar >= %d): ",i,min); for (ot = objecttype ; ot; ot = ot->next) { int rarity = 0; @@ -2402,7 +1883,7 @@ void enhanceskills(lifeform_t *lf) { // any skills to get? if (skillstoenhance) { char ques[BUFLEN]; - sprintf(ques, "Enhance which skill enhance (%d left)?", lf->skillpoints); + sprintf(ques, "Enhance which skill (%d left)?", lf->skillpoints); initprompt(&prompt, ques); ch = 'a'; @@ -2544,7 +2025,7 @@ object_t *eyesshaded(lifeform_t *lf) { return NULL; } -int fall(lifeform_t *lf, int announce) { +int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) { char lfname[BUFLEN]; getlfname(lf,lfname); @@ -2553,24 +2034,40 @@ int fall(lifeform_t *lf, int announce) { } if (announce) { if (isplayer(lf) || cansee(player, lf)) { - msg("%s fall%s to the ground.",lfname, isplayer(lf) ? "" : "s"); + if (fromlf) { + char fromlfname[BUFLEN]; + getlfname(fromlf, fromlfname); + msg("%s knock%s %s to the ground!",fromlfname, isplayer(fromlf) ? "" : "s", lfname); + } else { + msg("%s fall%s to the ground.",lfname, isplayer(lf) ? "" : "s"); + } } } - taketime(lf, getactspeed(lf)*2); + taketime(lf, getactspeed(lf)); + addflag(lf->flags, F_PRONE, B_TRUE, NA, NA, NULL); loseconcentration(lf); return B_FALSE; } // make 'lf' respond to damage void fightback(lifeform_t *lf, lifeform_t *attacker) { + + // special cases + if ((lf->race->id == R_STIRGE) || (lf->race->id == R_LEECH)) { + if (ispeaceful(lf)) { + // rest our sated counter + killflagsofid(lf->flags, F_COUNTER); + } + } + if (attacker && !isdead(lf)) { // wake up killflagsofid(lf->flags, F_ASLEEP); // monsters might flee, fight back, etc if (!isplayer(lf)) { if (willflee(lf)) { - scare(lf, attacker, PERMENANT); + scare(lf, attacker, PERMENANT, 0); } else { lifeform_t *l; @@ -2667,6 +2164,7 @@ race_t *findracebyname(char *name) { return NULL; } + raceclass_t *findraceclass(enum RACECLASS id) { raceclass_t *r; for (r = firstraceclass; r ; r = r->next) { @@ -3071,6 +2569,29 @@ enum ALLEGIENCE getallegiance(lifeform_t *lf) { return AL_HOSTILE; } +int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs) { + object_t *o; + enum BODYPART bp; + *nobs = 0; + for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) { + o = getouterequippedob(lf, bp); + if (o) { + int n,found = B_FALSE; + // already got htis one? + for (n = 0; n < *nobs; n++) { + if (ob[n]->id == o->id) { + found = B_TRUE; + } + } + if (!found) { + ob[*nobs] = o; + (*nobs)++; + } + } + } + return *nobs; +} + object_t *getarmour(lifeform_t *lf, enum BODYPART bp) { object_t *o; for (o = lf->pack->first ; o ; o = o->next) { @@ -3361,6 +2882,17 @@ int getavgdam(lifeform_t *lf, int forxp) { return (int)avgdam; } +float getequippedweight(lifeform_t *lf) { + object_t *o; + float total = 0; + for (o = lf->pack->first ; o ; o = o->next) { + if (isequipped(o) && isarmour(o)) { + total += getobweight(o); + } + } + return total; +} + int getevasion(lifeform_t *lf) { object_t *o; flag_t *f; @@ -3736,6 +3268,15 @@ job_t *getjob(lifeform_t *lf) { return NULL; } +int getlastdir(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_LASTDIR); + if (f) { + return f->val[0]; + } + return D_NONE; +} + int getlfaccuracy(lifeform_t *lf, object_t *wep) { flag_t *f; @@ -3756,13 +3297,22 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { // modify for weilder's level acc += (lf->level * 2); - // modify with dexterity - acc += getstatmod(lf, A_DEX); + if (lfhasflag(lf, F_RAGE)) { + // assume maximum dex + acc += 50; + } else { + // modify with dexterity + acc += getstatmod(lf, A_DEX); + } // modify for blindness if (isblind(lf)) { acc -= 50; } + // modify for being on the ground + if (isprone(lf)) { + acc -= 30; + } // modify for drunkenness f = isdrunk(lf); @@ -4232,7 +3782,7 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) { wep = getweapon(lf); if (wep) { char obname[BUFLEN]; - real_getobname(wep, obname, 1, B_TRUE, B_FALSE, B_FALSE, B_FALSE); + real_getobname(wep, obname, 1, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_FALSE); sprintf(buf, "%s %s%s",the,descstring,noprefix(obname)); } else { sprintf(buf, "%s %s%s%s",the,descstring,lf->race->name,jobstring); @@ -4405,18 +3955,30 @@ int getraceclass(lifeform_t *lf) { return lf->race->raceclass->id; } -int getracerarity(enum RACE rid) { +int getracerarity(map_t *map, enum RACE rid) { race_t *r; int rarity = -1; r = findrace(rid); if (r) { flag_t *f; - f = hasflag(r->flags, F_RARITY); + + f = hasflagval(r->flags, F_RARITY, H_ALL, NA, NA, NULL); + if (!f) { + if (map) { + f = hasflagval(r->flags, F_RARITY, map->habitat, NA, NA, NULL); + } else { + f = hasflagval(r->flags, F_RARITY, NA, NA, NA, NULL); + } + } + if (f) { // ignore habitat for now! rarity = f->val[1]; } } + + + return rarity; } @@ -4503,7 +4065,7 @@ race_t *getrandomrace(map_t *map, int forcedepth) { } } - getrarity(depth, &raritymin, &raritymax, RARITYVARIANCELF); + getrarity(depth, &raritymin, &raritymax, RARITYVARIANCELF, B_TRUE); if (db) dblog("finding random lf with rarity val %d-%d\n",raritymin,raritymax); @@ -5259,8 +4821,6 @@ int giveskill(lifeform_t *lf, enum SKILL id) { // announce. if (f->val[1] >= PR_MASTER) { msg("You now know everything there is to know about %s.", rc->pluralname); - } else if (f->val[1] >= PR_EXPERT) { - msg("You now deal extra damage to %s.", rc->pluralname); } else if (f->val[1] >= PR_SKILLED) { msg("You can now anticipate how %s will react.", rc->pluralname); } else if (f->val[1] >= PR_ADEPT) { @@ -5784,7 +5344,7 @@ int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) { // } // lifeforms block lof unless they're in our destination - if (cell->lf && (loftype & LOF_LFSSTOP)) { + if (cell->lf && (!isprone(cell->lf)) && (loftype & LOF_LFSSTOP)) { // if not in first cell... if (i != 0) { // if not in last cell... @@ -5833,6 +5393,7 @@ int haslos(lifeform_t *viewer, cell_t *dest) { int x2,y2; map_t *map; object_t *o; + int currange; cell_t *retcell[MAXRETCELLS]; if (!viewer) return B_FALSE; @@ -5890,6 +5451,7 @@ int haslos(lifeform_t *viewer, cell_t *dest) { } //shopwall = B_FALSE; + currange = 0; for (i = 0; i < numpixels ; i++) { cell_t *cell; @@ -5902,6 +5464,10 @@ int haslos(lifeform_t *viewer, cell_t *dest) { // you can always see your own cell if (i != 0) { + currange++; + if (currange > maxvisrange) { + return B_FALSE; + } // if we went uphill, stop here /* if (wentuphill) { @@ -5925,10 +5491,18 @@ int haslos(lifeform_t *viewer, cell_t *dest) { // check for objects which block view for (o = cell->obpile->first ; o ; o = o->next) { - if (hasflag(o->flags, F_BLOCKSVIEW)) { + f = hasflag(o->flags, F_BLOCKSVIEW); + if (f) { if (!lfhasflagval(viewer, F_CANSEETHROUGHMAT, o->material->id, NA, NA, NULL)) { - if (xray) xray--; - else return B_FALSE; + if (xray) { + xray--; + } else { + if (f->val[0] == B_TRUE) { + return B_FALSE; + } else { + currange += f->val[0]; + } + } } } } @@ -5989,6 +5563,8 @@ void initjobs(void) { mayusespellschool(lastjob->flags, i, F_CANCAST); } } + addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); + addjob(J_ADVENTURER, "Adventurer"); addflag(lastjob->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); @@ -6062,8 +5638,10 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); - addflag(lastjob->flags, F_LEVABIL, 4, OT_A_CHARGE, 3, NULL); - addflag(lastjob->flags, F_LEVABIL, 7, OT_A_WARCRY, NA, NULL); + addflag(lastjob->flags, F_LEVABIL, 3, OT_A_HEAVYBLOW, 3, NULL); + addflag(lastjob->flags, F_LEVABIL, 4, OT_A_WARCRY, 4, NULL); + addflag(lastjob->flags, F_LEVABIL, 5, OT_A_CHARGE, 5, NULL); + addflag(lastjob->flags, F_LEVABIL, 6, OT_A_RAGE, 50, NULL); addflag(lastjob->flags, F_LEVABIL, 10, OT_A_HURRICANESTRIKE, 5, NULL); addjob(J_COMMANDO, "Commando"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "combat knife"); @@ -6096,7 +5674,6 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "quarterstaff"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of sandals"); - addflag(lastjob->flags, F_HITDICE, 1, 1, NA, NULL); // low hp addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); @@ -6107,6 +5684,8 @@ void initjobs(void) { // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); // gained skills addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL); addflag(lastjob->flags, F_LEVFLAG, 7, F_DETECTAURAS, B_TRUE, NULL); @@ -6284,9 +5863,10 @@ void initjobs(void) { void initrace(void) { // race classes + addraceclass(RC_OTHER, "miscellaneous creature", "miscellaneous creatures", SK_NONE); addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE); - addraceclass(RC_DEMON, "demon", "animals", SK_LORE_DEMONS); - addraceclass(RC_HUMANOID, "humanoid", "humanoid creates", SK_LORE_HUMANOID); + addraceclass(RC_DEMON, "demon", "demons", SK_LORE_DEMONS); + addraceclass(RC_HUMANOID, "humanoid", "humanoid creatures", SK_LORE_HUMANOID); addraceclass(RC_INSECT, "insect", "insects and animals", SK_LORE_NATURE); addraceclass(RC_SLIME, "slime", "slimes", SK_NONE); addraceclass(RC_MAGIC, "magical creature", "magical creatures", SK_LORE_ARCANA); @@ -6386,6 +5966,30 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); // special attack handled in attack.c + addrace(R_CREEPINGCLAW, "creeping claw", 3, 'x', C_YELLOW, MT_FLESH, RC_MAGIC); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, ""); + addflag(lastrace->flags, F_HITDICE, 1, -2, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); + addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + 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_EYES, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_BODY, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:1d6;"); + addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); + addrace(R_DARKMANTLE, "darkmantle", 70, 'Q', C_BLUE, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_STARTHIDDENPCT, 80, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -6421,6 +6025,7 @@ void initrace(void) { addrace(R_EYEBAT, "eyebat", 5, 'e', C_BLUE, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, ST_VWEAK, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); @@ -6591,7 +6196,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 5, NA, 2, "gnoll"); + addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addrace(R_GNOLLHM, "gnoll huntmaster", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); @@ -6616,7 +6221,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-40 gold coins"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 5, NA, 2, "gnoll"); + addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6641,7 +6246,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_QUICKBITE, 1, 6, 2, NULL); - addflag(lastrace->flags, F_PACKATTACK, 5, NA, 2, "gnoll"); + addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6666,7 +6271,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); //addflag(lastrace->flags, F_STARTJOB, 25, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, "goblin"); + addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6691,7 +6296,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, "goblin"); + addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6717,7 +6322,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, "goblin"); + addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_MINIONS, 70, 1, 2, "goblin"); addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); addflag(lastrace->flags, F_STARTHIDDENPCT, 75, NA, NA, NULL); @@ -6742,7 +6347,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, "goblin"); + addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_MPDICE, 0, 10, NA, NULL); addflag(lastrace->flags, F_MPREGEN, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_BLINDNESS, NA, NA, NULL); @@ -7082,6 +6687,30 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addrace(R_PEGASUS, "pegasus", 130, 'H', C_GREY, MT_FLESH, RC_MAGIC); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 57, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, 6, NA, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_HOOF, NA, NA, "1d8"); + addflag(lastrace->flags, F_HASATTACK, OT_HOOF, NA, NA, "1d8"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); + addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL); + 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); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 2, 2, NULL); + addflag(lastrace->flags, F_SWOOPRANGE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screams in pain^screams of pain"); + addflag(lastrace->flags, F_RESISTMAG, 5, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 25, NA, NA, NULL); + addrace(R_POLTERGEIST, "poltergeist", 50, 'p', C_GREEN, MT_FLESH, RC_UNDEAD); // sPirit addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); @@ -7110,11 +6739,35 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL); addflag(lastrace->flags, F_UNDEAD, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); - addflag(lastrace->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); + + addrace(R_SATYR, "satyr", 80, 'h', C_GREEN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4"); + addflag(lastrace->flags, F_STARTOBDT, 50, DT_SLASH, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "panpipes"); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "bow"); + addflag(lastrace->flags, F_STARTOB, 75, NA, NA, "1-10 arrows"); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-30 gold coins"); + addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "plays its pipes"); + addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MPDICE, 0, 16, NA, NULL); + addflag(lastrace->flags, F_MPREGEN, 8, NA, NA, NULL); + addflag(lastrace->flags, F_NEEDOBFORSPELLS, OT_PANPIPES, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_FEAR, NA, NA, NULL); + addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_HASSKILL, SK_SS_MENTAL, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTHIDDENPCT, 60, NA, NA, NULL); addrace(R_SHADOWCAT, "shadowcat", 5, 'f', C_BLUE, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -7154,9 +6807,10 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_ACIDATTACK, NA, NA, "1d6+5"); addflag(lastrace->flags, F_TREMORSENSE, 5, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^slurping."); + 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"); + addflag(lastrace->flags, F_DIESPLATTER, 3, NA, NA, "splash of acid"); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); @@ -7179,7 +6833,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); 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_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); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -7223,7 +6877,6 @@ void initrace(void) { addrace(R_BAT, "giant bat", 3, 'B', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, ""); @@ -7242,11 +6895,10 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); - addrace(R_ANT, "giant worker ant", 4, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); + addrace(R_ANT, "giant worker ant", 20, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL); @@ -7264,11 +6916,48 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1+4"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); - addrace(R_ANTS, "giant soldier ant", 5, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); + addrace(R_BEAR, "black bear", 150, 'b', C_BLUE, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 3, 3, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6"); + addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "roars^a roars"); + addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d4;"); + addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'b', C_BROWN, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 52, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 5, 5, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d8"); + addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "roars^a roars"); + addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); + addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_BLEEDABIL, OT_A_RAGE, NA, NA, NULL); + addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_HITDICE, 4, 4, NA, NULL); @@ -7288,11 +6977,101 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "giant worker ant"); + addrace(R_ANTLION, "giant antlion", 30, 'a', C_YELLOW, MT_FLESH, RC_ANIMAL); + lastrace->baseid = R_ANT; + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 6, 0, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); + 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_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_HASATTACK, OT_TEETH, NA, NA, "5d4"); + addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:2d4;"); + addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "roars^a roars"); + addrace(R_DOGBLINK, "blink dog", 35, 'd', C_YELLOW, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 77, NA, ""); + addflag(lastrace->flags, F_HITDICE, 4, 0, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6"); + addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + 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); + 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_VEGETARIAN, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_BLINK, 2, 2, "pw:1;"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addrace(R_DOGDEATH, "death hound", 40, 'd', C_BLUE, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, ""); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, ""); + addflag(lastrace->flags, F_HITDICE, 2, 1, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d10"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d10"); + addflag(lastrace->flags, F_MAXATTACKS, 2, NA, NA, NULL); + addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL); + 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); + addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); + 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_SEEINDARK, 5, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 24, "10-15"); + addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL); + addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); + addrace(R_DOGWAR, "war hound", 40, 'd', C_BROWN, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 4, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 83, NA, ""); + addflag(lastrace->flags, F_HITDICE, 2, 2, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "2d4"); + addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); + 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); + 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_SEEINDARK, 5, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, ""); - 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_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, IQ_AVERAGE, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); @@ -7312,12 +7091,12 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL); addflag(lastrace->flags, F_SWOOPRANGE, 2, NA, NA, NULL); addflag(lastrace->flags, F_LEVRACE, 4, R_HAWK, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); addrace(R_HAWK, "hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); @@ -7338,12 +7117,12 @@ void initrace(void) { addflag(lastrace->flags, F_SWOOPRANGE, 3, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_LEVRACE, 8, R_HAWKBLOOD, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); addrace(R_HAWKBLOOD, "blood hawk", 1, 'A', C_RED, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); @@ -7363,10 +7142,10 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL); addflag(lastrace->flags, F_SWOOPRANGE, 5, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 7, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); addrace(R_HAWKFROST, "frost hawk", 1, 'A', C_CYAN, MT_FLESH, RC_ANIMAL); // 'A' for Avian addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); @@ -7388,11 +7167,32 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_COLDBURST, 2, 2, "pw:2;"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "screeches"); addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); + addrace(R_LEECH, "giant leech", 10, 'j', C_MAGENTA, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 81, NA, ""); + addflag(lastrace->flags, F_HITDICE, 3, 1, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); + 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); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, 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_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:4;"); + addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:0d1+4;"); addrace(R_NEWT, "giant newt", 4, ':', C_BROWN, MT_FLESH, RC_ANIMAL); 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); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); @@ -7407,19 +7207,17 @@ void initrace(void) { addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addrace(R_RAT, "giant rat", 3, 'r', C_BROWN, MT_FLESH, RC_ANIMAL); - 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); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, ""); addflag(lastrace->flags, F_HITDICE, 0, 1, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); - addflag(lastrace->flags, F_EVASION, 20, NA, NA, NULL); 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); @@ -7431,7 +7229,6 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addrace(R_SNAKE, "brown snake", 3, 's', C_BROWN, MT_FLESH, RC_ANIMAL); 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); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -7450,11 +7247,33 @@ 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_DTVULN, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addrace(R_SNAKECARPET, "carpet snake", 3, 's', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 88, 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); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, 1, NA, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3+1"); + 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); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_FEET, 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_DTVULN, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addrace(R_SNAKETREE, "tree snake", 3, 's', C_GREEN, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -7473,9 +7292,58 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 2, 2, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addrace(R_SNAKECOBRA, "giant cobra", 3, 's', C_BLUE, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, ""); + addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, 3, NA, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3+1"); + 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); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_FEET, 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_DTVULN, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "spits"); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_POISONBOLT, 4, 4, "pw:3;"); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addrace(R_SNAKECONSTRICTOR, "constrictor", 3, 's', C_MAGENTA, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, ""); + addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, 4, 3, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1"); + 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); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_FEET, 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_DTVULN, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addrace(R_SPIDER, "giant spider", 5, 'S', C_GREEN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, ""); - 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_DEX, DX_DEXTROUS, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -7498,7 +7366,6 @@ void initrace(void) { addrace(R_SPIDERFUNNELWEB, "giant funnelweb", 5, 'S', C_MAGENTA, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_SPIDER; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, ""); - 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_DEX, DX_DEXTROUS, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -7523,7 +7390,6 @@ void initrace(void) { addrace(R_SPIDERREDBACK, "giant redback", 5, 'S', C_RED, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_SPIDER; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, ""); - 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_DEX, DX_DEXTROUS, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -7545,15 +7411,14 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); - addrace(R_WOLFYOUNG, "young wolf", 5, 'd', C_BROWN, MT_FLESH, RC_ANIMAL); + addrace(R_WOLFYOUNG, "young wolf", 5, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, ""); - addflag(lastrace->flags, F_HITDICE, 2, 0, NA, ""); + addflag(lastrace->flags, F_HITDICE, 2, 2, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); @@ -7566,14 +7431,14 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 8, 8, NULL); addflag(lastrace->flags, F_LEVRACE, 5, R_WOLF, NA, NULL); - addrace(R_WOLF, "wolf", 10, 'd', C_BROWN, MT_FLESH, RC_ANIMAL); - addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addrace(R_WOLF, "wolf", 10, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); - addflag(lastrace->flags, F_HITDICE, 2, 4, NA, ""); + addflag(lastrace->flags, F_HITDICE, 3, 3, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d5"); addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); @@ -7587,6 +7452,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); // insects addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_GREEN, MT_FLESH, RC_ANIMAL); @@ -7619,7 +7485,7 @@ void initrace(void) { addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, ""); addflag(lastrace->flags, F_HITDICE, 1, 0, NA, ""); - addflag(lastrace->flags, F_EVASION, 50, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2"); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -7642,7 +7508,7 @@ void initrace(void) { addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, 1, NA, ""); - addflag(lastrace->flags, F_EVASION, 40, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -7655,6 +7521,30 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addrace(R_STIRGE, "stirge", 10, 'i', C_BROWN, MT_FLESH, RC_INSECT); + addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, ""); + addflag(lastrace->flags, F_HITDICE, 1, 1, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); + 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); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, 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_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); + addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:1d4;"); addrace(R_CENTIPEDE, "giant centipede", 3, 'c', C_GREEN, MT_FLESH, RC_INSECT); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); @@ -7718,11 +7608,6 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5"); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); - addflag(lastrace->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -7735,19 +7620,14 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, 2, 4, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5"); addflag(lastrace->flags, F_STARTOBDT, 50, DT_CHOP, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); - addflag(lastrace->flags, F_DTRESIST, DT_SLASH, NA, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 25, DT_CHOP, NA, "buckler"); addflag(lastrace->flags, F_DTVULN, DT_BASH, NA, NA, NULL); - addflag(lastrace->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -7765,11 +7645,6 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE2, NA, NA, "0d1+0"); - addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, 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_LEVITATING, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); @@ -7787,11 +7662,6 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, 4, 2, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); - addflag(lastrace->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); addflag(lastrace->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_XRAYVIS, 3, NA, NA, NULL); @@ -7816,11 +7686,6 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5+3"); addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE, NA, NA, "0d1+0"); - addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); - addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, 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); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); @@ -7891,7 +7756,7 @@ int isbleeding(lifeform_t *lf) { float hppct; hppct = ((float)lf->hp / (float) lf->maxhp) * 100; - if (hppct <= 30) return B_TRUE; + if (hppct <= 40) return B_TRUE; return B_FALSE; } @@ -7973,6 +7838,8 @@ void killlf(lifeform_t *lf) { for (l = m->lf ; l ; l = l->next) { f = lfhasflagval(l, F_TARGET, lf->id, NA, NA, NULL); if (f) killflag(f); + f = lfhasflagval(l, F_ATTACHEDTO, lf->id, NA, NA, NULL); + if (f) killflag(f); f = lfhasflagval(l, F_GRABBEDBY, lf->id, NA, NA, NULL); if (f) killflag(f); f = lfhasflagval(l, F_GRABBING, lf->id, NA, NA, NULL); @@ -8174,6 +8041,13 @@ int ispolymorphed(lifeform_t *lf) { } } +int isprone(lifeform_t *lf) { + if (lfhasflag(lf, F_PRONE)) { + return B_TRUE; + } + return B_FALSE; +} + flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt) { flag_t *f; f = hasflagval(fp, F_DTRESIST, dt, NA, NA, NULL); @@ -8193,6 +8067,593 @@ flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt) { return NULL; } +object_t *isstuck(lifeform_t *lf) { + object_t *o; + + for (o = lf->cell->obpile->first ; o ; o = o->next) { + if ((o->type->id == OT_WEB) && (lf->race->baseid == R_SPIDER)) { + continue; + } + if (hasflag(o->flags, F_RESTRICTMOVEMENT)) { + return o; + } + } + return NULL; +} + +job_t *addjob(enum JOB id, char *name) { + job_t *a; + + // add to the end of the list + if (firstjob == NULL) { + firstjob = malloc(sizeof(job_t)); + a = firstjob; + a->prev = NULL; + } else { + // go to end of list + a = lastjob; + a->next = malloc(sizeof(job_t)); + a->next->prev = a; + a = a->next; + } + lastjob = a; + a->next = NULL; + + // props + a->id = id; + a->name = strdup(name); + + a->flags = addflagpile(NULL, NULL); + return a; +} + +lifeform_t *addlf(cell_t *cell, enum RACE rid, int level) { + return real_addlf(cell, rid, level, C_AI); +} + +lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { + map_t *m; + lifeform_t *a; + int i; + + assert(cell); + if (cell->type != (celltype_t *) DUMMYCELLTYPE) { + assert(!cell->type->solid); + } + + m = cell->map; + + // add to the end of the list + if (m->lf == NULL) { + m->lf = malloc(sizeof(lifeform_t)); + a = m->lf; + a->prev = NULL; + } else { + // go to end of list + a = m->lastlf; + a->next = malloc(sizeof(lifeform_t)); + a->next->prev = a; + a = a->next; + } + + if (controller == C_PLAYER) { + player = a; + } + + m->lastlf = a; + a->next = NULL; + + a->born = B_FALSE; // will set this back to true later + + // props + a->id = nextlfid; nextlfid++; + a->controller = controller; + a->level = level; + a->newlevel = level; + a->xp = getxpforlev(a->level); + a->skillpoints = 0; + a->cell = cell; + a->alive = B_TRUE; + a->lastdam = strdup("nothing"); + a->lastdamtype = DT_NONE; + if ((gamemode == GM_GAMESTARTED) && a->prev) { + a->timespent = a->prev->timespent + 1; + } else { + a->timespent = 0; + } + a->sorted = B_FALSE; + a->forgettimer = 0; + + a->polyrevert = B_FALSE; + + // for precalcing line of sight + a->nlos = 0; + a->los = NULL; + + // for ai + + // avoid messages when equipping initial obs + a->created = B_FALSE; + + a->pack = addobpile(a, NOLOC); + + // clear laoding variables + for (i = 0; i < MAXPILEOBS; i++) { + a->oblist[i] = -1; + } + a->x = -1; + a->y = -1; + + // defaults + a->hp = 1; + a->maxhp = a->hp; + a->mp = 0; + a->maxmp = a->mp; + + // init flags + a->flags = addflagpile(a, NULL); + + // set race - this will inherit race flags + a->race = NULL; + setrace(a, rid, B_FALSE); + + // update other things + cell->lf = a; + + // give start objetcs + if ((gamemode != GM_LOADING) && (gamemode != GM_VALIDATION)) { + outfitlf(a); + } + a->created = B_TRUE; + a->born = B_TRUE; // now finished creating it. + return a; +} + + + +race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass) { + race_t *a; + + assert(!findrace(id)); + + // add to the end of the list + if (firstrace == NULL) { + firstrace = malloc(sizeof(race_t)); + a = firstrace; + a->prev = NULL; + } else { + // go to end of list + a = lastrace; + a->next = malloc(sizeof(race_t)); + a->next->prev = a; + a = a->next; + } + lastrace = a; + a->next = NULL; + + + // props + a->id = id; + a->baseid = id; // default + a->raceclass = findraceclass(raceclass); + + a->material = findmaterial(mat); + assert(a->material); + a->name = strdup(name); + a->weight = weight; + a->glyph.ch = glyph; + a->glyph.colour = glyphcolour; + + a->flags = addflagpile(NULL, NULL); + return a; +} + +raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill) { + raceclass_t *a; + + assert(!findraceclass(id)); + + // add to the end of the list + if (firstraceclass == NULL) { + firstraceclass = malloc(sizeof(raceclass_t)); + a = firstraceclass; + a->prev = NULL; + } else { + // go to end of list + a = lastraceclass; + a->next = malloc(sizeof(raceclass_t)); + a->next->prev = a; + a = a->next; + } + lastraceclass = a; + a->next = NULL; + + + // props + a->id = id; + a->name = strdup(name); + a->pluralname = strdup(pluralname); + a->skill = skill; + + return a; +} + +skill_t *addskill(enum SKILL id, char *name, char *desc) { + skill_t *a; + + assert(!findskill(id)); + + // add to the end of the list + if (firstskill == NULL) { + firstskill = malloc(sizeof(skill_t)); + a = firstskill; + a->prev = NULL; + } else { + // go to end of list + a = lastskill; + a->next = malloc(sizeof(skill_t)); + a->next->prev = a; + a = a->next; + } + lastskill = a; + a->next = NULL; + + + // props + a->id = id; + a->name = strdup(name); + a->desc = strdup(desc); + + return a; +} + +void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { + flag_t *f; + if (isimmuneto(lf->flags, damtype)) { + *amt = 0; + return; + } + + if ((damtype == DT_MAGIC) && getmr(lf) && skillcheck(lf, SC_RESISTMAG, 10 + (*amt * 2), 0)) { + *amt = 0; + return; + } + + // water normally doesn't hurt. + if ((damtype == DT_WATER) && !isvulnto(lf->flags, damtype)) { + *amt = 0; + return; + } + + if (lfhasflag(lf, F_INVULNERABLE)) { + switch (damtype) { + case DT_DIRECT: + case DT_NONE: + break; + default: + *amt = 0; + break; + } + return; + } + + if ((damtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { + (*amt) *= 2; + } + + if (isresistantto(lf->flags, damtype)) { + (*amt) /= 2; + } + f = isvulnto(lf->flags, damtype); + if (f) { + if ((*amt == 0) && strlen(f->text)) { + int ndice,nsides,bonus; + texttodice(f->text, &ndice,&nsides,&bonus); + *amt = rolldie(ndice,nsides) + bonus; + } else { + (*amt) *= 2; + } + } + + + // adjust for lifeform material + //adjustdammaterial(amt, damtype, getlfmaterial(lf)); + + if (*amt < 0) *amt = 0; +} + +void makepeaceful(lifeform_t *who) { + char lfname[BUFLEN]; + + getlfname(who, lfname); + if (lfhasflag(who, F_DEBUG)) { + msg("Making %s friendly.",lfname); + } + + if (lfhasflag(who, F_HOSTILE)) { + if (cansee(player, who)) { + char lfname[BUFLEN]; + getlfname(who, lfname); + msg("%s calms down.", lfname); + } + } + + killflagsofid(who->flags, F_HOSTILE); + killflagsofid(who->flags, F_TARGET); // stop targetting anyone + +} + +lifeform_t *makezombie(object_t *o) { + flag_t *f; + race_t *r; + lifeform_t *lf; + cell_t *where; + char obname[BUFLEN]; + + if (o->type->id != OT_CORPSE) return NULL; + + f = hasflag(o->flags, F_CORPSEOF); + if (!f) return NULL; + + r = findrace(f->val[0]); + if (!r) return NULL; + + where = getoblocation(o); + getobname(o, obname, 1); + + lf = addlf(where, r->id, 1); + + addflag(lf->flags, F_LFSUFFIX, B_TRUE, NA, NA, "zombie"); + addflag(lf->flags, F_GLYPH, C_GREY, NA, NA, "Z"); + addflag(lf->flags, F_UNDEAD, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); + addflag(lf->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); + addflag(lf->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); + addflag(lf->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); + addflag(lf->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); + + if (hasflag(o->flags, F_HEADLESS)) { + // remove the head + addflag(lf->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL); + // remove the eyes (this will make the creature blind) + addflag(lf->flags, F_NOBODYPART, BP_EYES, NA, NA, NULL); + // need HEADLESS too to show that this monster normally + // _does_ have a head. this will cause getlfname + // to add "headless " to the description. + addflag(lf->flags, F_HEADLESS, B_TRUE, NA, NA, NULL); + } + + killflagsofid(lf->flags, F_WANTSBETTERWEP); + killflagsofid(lf->flags, F_WANTSBETTERARM); + killflagsofid(lf->flags, F_WANTSOBFLAG); + killflagsofid(lf->flags, F_WANTS); + killflagsofid(lf->flags, F_NOISETEXT); + killflagsofid(lf->flags, F_SEEINDARK); + killflagsofid(lf->flags, F_TREMORSENSE); + + killflagsofid(lf->flags, F_MOVESPEED); + addflag(lf->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); + killflagsofid(lf->flags, F_ACTIONSPEED); + addflag(lf->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); + lf->baseatt[A_IQ] = rolliq(IQ_MINDLESS); + lf->att[A_IQ] = lf->baseatt[A_IQ]; + + // no magic + lf->maxmp = 0; + lf->mp = 0; + + // no objects + while (lf->pack->first) { + killob(lf->pack->first); + } + + // no abilities + killflagsofid(lf->flags, F_CANCAST); + killflagsofid(lf->flags, F_CANWILL); + + // remove the object + removeob(o,o->amt); + + // redraw & announce + if (haslos(player, where)) { + needredraw = B_TRUE; + drawscreen(); + msg("%s rises from the dead!", obname); + } + + 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; +} + +void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) { + flag_t *fromlfflag; + lifeform_t *fromlf = NULL; + char damstring[BUFLEN],buf[BUFLEN]; + + getobname(o, buf, o->amt); + + fromlfflag = hasflag(o->flags, F_CREATEDBY); + if (fromlfflag) { + sprintf(damstring, "%s^created by %s",buf, fromlfflag->text); + } else { + strcpy(damstring, buf); + } + + dam = losehp(lf, dam, damtype, fromlf, damstring); + if (dam > 0) { + if (damtype == DT_POISONGAS) { + if (isplayer(lf) || cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s choke%s on %s!", lfname, isplayer(lf) ? "" : "s", buf); + } + } else { + if (isplayer(lf)) { + msg("%s %ss you!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp)); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s %ss %s!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname); + } + } + } +} + +int areallies(lifeform_t *lf1, lifeform_t *lf2) { + if (getallegiance(lf1) == getallegiance(lf2)) { + if (isplayer(lf1) || isplayer(lf2)) { + // if one of them is the player + return B_TRUE; + } else { + if (lf1->race->baseid == lf2->race->baseid) { + return B_TRUE; + } + } + } + return B_FALSE; +} + +// make sure player has at least novice skill in all their start weapons/armour +void autoskill(lifeform_t *lf) { + skill_t *sk; + object_t *o; + enum SKILLLEVEL slev; + int nweps = 0; + + if (isplayer(lf)) { + slev = PR_NOVICE; + } else { + slev = PR_ADEPT; + } + + if (lf == player) { + dblog("test"); + } + + for (o = lf->pack->first ; o ; o = o->next) { + if (isweapon(o) && canweild(lf, o)) { + sk = getobskill(o); + if (sk && !getskill(lf, sk->id)) { + giveskilllev(lf, sk->id, slev); + } + nweps++; + } + if (isarmour(o) && canwear(lf, o, BP_NONE)) { + flag_t *f; + // evasion penalty? + f = hasflag(o->flags, F_EVASION); + if (f && (f->val[0] < 0)) { + giveskilllev(lf, SK_ARMOUR, PR_NOVICE); + } + } + if (isshield(o) && canwear(lf, o, BP_NONE)) { + giveskilllev(lf, SK_SHIELDS, PR_NOVICE); + } + } + + // monsters must get unarmed skill! + if (!nweps && !isplayer(lf)) { + giveskilllev(lf, SK_UNARMED, slev); + } + +} + +void autotarget(lifeform_t *lf) { + object_t *gun; + lifeform_t *targ,*newtarg; + int closest; + int i; + int gunrange; + int targid; + + gun = getfirearm(lf); + if (!gun) return; + + if (!getammo(lf)) return; + + gunrange = getfirearmrange(gun); + + // already got a target? + targid = getguntargetid(lf); + + if (targid == -1) { + targ = NULL; + } else { + targ = findlf(NULL, targid); + if (targ) { + // dead? remove target and keep going. + if (isdead(targ)) { + // clear target ? + targ = NULL; + } else if (!haslof(lf->cell, targ->cell, B_FALSE, NULL)) { + // clear target ? + targ = NULL; + } else { + // already got a valid target. return. + return; + } + } else { + // target no longer exists? + // clear target ? + } + } + + // find new target + newtarg = NULL; + closest = 9999; + for (i = 0; i < lf->nlos; i++) { + cell_t *c; + c = lf->los[i]; + if (c->lf && (c->lf != lf) && cansee(lf, c->lf) && isingunrange(lf, c)) { + int valid = B_TRUE; + if (!areenemies(lf, c->lf)) { + valid = B_FALSE; + } + if (valid) { + int thisdist; + thisdist = getcelldist(lf->cell, c); + if (thisdist < closest) { + newtarg = c->lf; + closest = thisdist; + } + } + } + } + + + if (newtarg && (newtarg != targ)) { + setguntarget(lf, newtarg); + } +} flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt) { flag_t *f; @@ -8314,6 +8775,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml char buf[BUFLEN]; char buf2[BUFLEN]; char lfname[BUFLEN]; + int prebleed = B_FALSE,postbleed = B_FALSE; flag_t *f; getlfname(lf, lfname); @@ -8322,6 +8784,10 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml statdirty = B_TRUE; } + if (isbleeding(lf)) { + prebleed = B_TRUE; + } + // check for psychic armour etc if (amt > 0) { if (isphysicaldam(damtype)) { @@ -8379,7 +8845,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // occasionally drop blood if ((damtype != DT_POISON) && (damtype != DT_POISONGAS)) { - if (rnd(1,3) == 1) { + if (onein(3)) { bleed(lf); } } @@ -8411,7 +8877,10 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } } } - + + if (isbleeding(lf)) { + postbleed = B_TRUE; + } // replace 'the' at start of damsrc with 'a' if (strstr(damsrc, "the ") == damsrc) { @@ -8427,28 +8896,46 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml setlastdam(lf, buf); - // fight back if required - if (fromlf) { - fightback(lf, fromlf); - } + // further effects if not dead... + if (!isdead(lf)) { + // fight back if required + if (fromlf) { + fightback(lf, fromlf); + } - // player low hitpoint warning - if (lf->hp > 0) { - int warnthresh; - warnthresh = (int)((float)0.25 * (float)lf->maxhp); - if (lf->hp <= warnthresh) { - if (isplayer(lf)) { + // low hitpoint warning + if (isplayer(lf)) { + int warnthresh; + warnthresh = (int)((float)0.25 * (float)lf->maxhp); + if (lf->hp <= warnthresh) { warn("*** LOW HITPOINT WARNING ***"); more(); - } else if (ispetof(lf, player)) { + } + } else if (prebleed != postbleed) { + if (ispetof(lf, player) && !canhear(player, lf->cell)) { warn("You feel worried about your %s.", noprefix(lfname)); + } else { + makenoise(lf, N_LOWHP); + } + if (ispetof(lf, player)) { more(); } } - } + // you wake up if you were hit! + killflagsofid(lf->flags, F_ASLEEP); - // you wake up if you were hit! - killflagsofid(lf->flags, F_ASLEEP); + + // automatic onbleed abilities? + if (postbleed && !prebleed) { + f = lfhasflag(lf, F_BLEEDABIL); + if (f) { + flag_t *notime; + notime = addflag(lf->flags, F_NOTIME, B_TRUE, NA, NA, NULL); + abilityeffects(lf, f->val[0], lf->cell, lf, NULL); + killflag(notime); + } + } + } // update screen drawstatus(); @@ -8555,6 +9042,8 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { case SZ_MAX: noise(lf->cell, lf, "extremely loud thumping.", NULL); break; + default: + break; } if (strlen(movetext)) { noise(lf->cell, lf, movetext, NULL); @@ -8593,47 +9082,41 @@ void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) { // if you don't meet it, return why not in 'reason' int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o) { enum ATTRIB att; - int brackneeded; - int myatt; - int mybrack; + int valneeded; + int myval; att = f->val[0]; - brackneeded = f->val[1]; - - reason = E_OK; + valneeded = f->val[1]; // modify for masterwork if (o) { if (hasflag(o->flags, F_MASTERWORK)) { - brackneeded--; - if (brackneeded < 0) brackneeded = 0; + valneeded -= 3; + if (valneeded < 0) valneeded = 0; } } - myatt = getattr(lf, att); + myval = getattr(lf, att); - switch (att) { - case A_DEX: - mybrack = getdexname(myatt, NULL); - reason = E_LOWDEX; - break; - case A_CON: - mybrack = getconname(myatt, NULL); - reason = E_LOWCON; - break; - case A_IQ: - mybrack = getiqname(myatt, NULL); - reason = E_LOWIQ; - break; - case A_STR: - mybrack = getstrname(myatt, NULL); - reason = E_LOWSTR; - break; - case A_NONE: - break; - } - if (mybrack < brackneeded) { + if (myval < valneeded) { + switch (att) { + case A_DEX: + reason = E_LOWDEX; + break; + case A_CON: + reason = E_LOWCON; + break; + case A_IQ: + reason = E_LOWIQ; + break; + case A_STR: + reason = E_LOWSTR; + break; + case A_NONE: + break; + } return B_FALSE; } + reason = E_OK; return B_TRUE; } @@ -8818,7 +9301,7 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { if (canhear(l, c) && (haslos(l, c) || skillcheck(l, SC_LISTEN, 17, 0))) { flag_t *f; // announce? - if (isplayer(l) && !lfhasflag(l, F_RESTING)) { + if (isplayer(l) && !lfhasflag(l, F_RESTING) && !lfhasflag(l, F_ASLEEP)) { // never say "you hear xxx" if you can see the lf that caused the noise. if (noisemaker && cansee(l, noisemaker)) { if (seetext) { @@ -9541,7 +10024,7 @@ int safetorest(lifeform_t *lf) { // returns TRUE if something happened -int scare(lifeform_t *lf, lifeform_t *scarer, int howlong) { +int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus) { int nfailures = 0; int i; int penalty = 0; @@ -9551,6 +10034,9 @@ int scare(lifeform_t *lf, lifeform_t *scarer, int howlong) { if (lfhasflag(lf, F_UNDEAD)) { return B_FALSE; } + if (lfhasflag(lf, F_ASLEEP)) { + return B_FALSE; + } // not intelligent enough to be scared? if (getiqname(getattr(scarer, A_IQ), NULL) <= IQ_VEGETABLE) { return B_FALSE; @@ -9562,14 +10048,14 @@ int scare(lifeform_t *lf, lifeform_t *scarer, int howlong) { } if (lfhasflag(lf, F_HUMANOID)) { object_t *o; - for (o = lf->pack->first ; o; o = o->next) { + for (o = scarer->pack->first ; o; o = o->next) { flag_t *f; f = isequipped(o); // ie. equipped, but not primary or secondary weapon if (f && (f->val[0] > BP_SECWEAPON)) { f = hasflag(o->flags, F_SCARY); if (f) { - penalty += f->val[0]; + scarerbonus += f->val[0]; } } } @@ -9579,7 +10065,7 @@ int scare(lifeform_t *lf, lifeform_t *scarer, int howlong) { // three checks nfailures = 0; for (i = 0; i < 3; i++) { - if (!skillcheckvs(lf, SC_MORALE, penalty, scarer, SC_MORALE, 0)) { + if (!skillcheckvs(lf, SC_MORALE, -penalty, scarer, SC_MORALE, scarerbonus)) { nfailures++; } } @@ -9891,7 +10377,7 @@ void initskills(void) { addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently."); addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items."); // knowledge - addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising unknown objects."); + addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising magical objects and creatures."); addskill(SK_LORE_DEMONS, "Lore:Demonology", "Determines your knowledge about demons."); addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures."); addskill(SK_LORE_NATURE, "Lore:Nature", "Determines your knowledge of plants, animals and insects."); @@ -10025,8 +10511,12 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r if (f) attrib += f->val[0]; break; case SC_SLIP: + case SC_FALL: attrib = getattr(lf, A_DEX); break; + case SC_SHIELDBLOCK: + attrib = (getattr(lf, A_DEX) / 4); + break; case SC_POISON: attrib = getattr(lf, A_CON); break; @@ -10060,6 +10550,22 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) { othermod += 20; } + } else if (ct == SC_FALL) { + if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) { + othermod += 10; + } + } else if (ct == SC_SHIELDBLOCK) { + switch (getskill(lf, SK_SHIELDS)) { + case PR_NOVICE: othermod = 4; break; + case PR_BEGINNER: othermod = 7; break; + case PR_ADEPT: othermod = 10; break; + case PR_SKILLED: othermod = 13; break; + case PR_EXPERT: othermod = 16; break; + case PR_MASTER: othermod = 20; break; + default: + othermod = 0; + break; + } } else if (ct == SC_OPENLOCKS) { enum SKILLLEVEL slev; slev = getskill(lf, SK_LOCKPICKING); @@ -10179,7 +10685,6 @@ int slipon(lifeform_t *lf, object_t *o) { char obname[BUFLEN]; char lfname[BUFLEN]; - if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET) || lfhasflag(lf, F_NONCORPOREAL) || isairborne(lf)) { return B_TRUE; @@ -10194,7 +10699,9 @@ int slipon(lifeform_t *lf, object_t *o) { sprintf(damstring, "slipping on %s",obname); losehp(lf, 1, DT_FALL, NULL, damstring); } - taketime(lf, getactspeed(lf)*2); + + fall(lf, NULL, B_FALSE); + // object gets damaged? if (hasflag(o->flags, F_DAMAGABLE)) { takedamage(o, 1, DT_DIRECT); @@ -10570,6 +11077,7 @@ void turneffectslf(lifeform_t *lf) { char buf[BUFLEN]; lifeform_t *l; int i; + int willvanish = B_FALSE; map = lf->cell->map; @@ -10795,6 +11303,49 @@ void turneffectslf(lifeform_t *lf) { } } + // summoned creatures + f = hasflag(lf->flags, F_SUMMONEDBY); + if (f) { + lifeform_t *creator; + creator = findlf(NULL, f->val[0]); + if (!creator) { + willvanish = B_TRUE; + } else { + if (f->val[1] > 0) { + f->val[1]--; + if (f->val[1] <= 0) { + willvanish = B_TRUE; + } + } + } + + if (willvanish) { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s%s vanishes.", + (creator == player) ? "Your " : "", + (creator == player) ? noprefix(lfname) : lfname + ); + } + + // all objects vanish + while (lf->pack->first) { + killob(lf->pack->first); + } + + // lf dies. + lf->hp = 0; + addflag(lf->flags, F_DEAD, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + + // puff + addob(lf->cell->obpile, "puff of smoke"); + } + } + if (isdead(lf)) return; + // IMPORTANT: any potentially damaging effects have to go after here... f = hasflag(lf->flags, F_POISONED); @@ -10829,7 +11380,7 @@ void turneffectslf(lifeform_t *lf) { f = hasflag(lf->flags, F_NAUSEATED); if (f) { // chance of being delayed - if (rnd(0,3) == 0) { + if (onein(4)) { if (isplayer(lf)) { msg("You %s!", rnd(0,1) ? "retch" : "gag"); } else if (cansee(player, lf)) { @@ -10910,6 +11461,24 @@ void turneffectslf(lifeform_t *lf) { for (f = lf->flags->first ; f ; f = nextf) { nextf = f->next; // remove impossible flags + if ((f->id == F_BOOSTSPELL) && (f->val[0] == OT_S_PASSWALL)) { + if (!lfhasflag(lf, F_NONCORPOREAL)) { + killflag(f); + continue; + } + } + + if (f->id == F_ATTACHEDTO) { + lifeform_t *lf2; + lf2 = findlf(NULL, f->val[0]); + if (!lf2) { + killflag(f); + continue; + } else if (getcelldist(lf2->cell, lf->cell) != 1) { + killflag(f); + continue; + } + } if (f->id == F_GRABBEDBY) { lifeform_t *lf2; lf2 = findlf(NULL, f->val[0]); @@ -11050,7 +11619,7 @@ int touch(lifeform_t *lf, object_t *o) { o->blessknown = B_TRUE; } // use real name here... - real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_FALSE, B_TRUE); + real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_FALSE, B_TRUE, B_FALSE); sprintf(buf, "touching %s",obname); losehp(lf, 2, DT_HOLY, NULL, buf); // drop the object if we're holding it @@ -11324,7 +11893,11 @@ int usestairs(lifeform_t *lf, object_t *o) { } // move player to new map moveto(lf, newcell, B_TRUE, B_TRUE); - taketime(lf, getmovespeed(lf)); + if ((dir == D_UP) && !isairborne(lf)) { + taketime(lf, getmovespeed(lf)*2); // takes longer to climb + } else { + taketime(lf, getmovespeed(lf)); + } // move adjacent allies/monsters too for (n = 0; n < nadjallies; n++) { @@ -11333,7 +11906,11 @@ int usestairs(lifeform_t *lf, object_t *o) { if (c) { if (!initiatemove(adjally[n], NULL, NULL)) { movelf(adjally[n], c); - taketime(adjally[n], getmovespeed(adjally[n])); + if ((dir == D_UP) && !isairborne(adjally[n])) { + taketime(adjally[n], getmovespeed(adjally[n])*2); // takes longer to climb + } else { + taketime(adjally[n], getmovespeed(adjally[n])); + } } } } @@ -11395,7 +11972,19 @@ int validateraces(void) { cell_t fakecell; map_t fakemap; - // first generate xp list + // add undead flags + for (r = firstrace ; r ; r = r->next) { + if (r->raceclass->id == RC_UNDEAD) { + addflag(r->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); + addflag(r->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(r->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); + addflag(r->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); + addflag(r->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); + addflag(r->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); + } + } + + // generate xp list genxplist(); @@ -11872,7 +12461,12 @@ int wear(lifeform_t *lf, object_t *o) { } // end while !canwear // some checks first... - touch(lf, o); + if (touch(lf, o)) { + taketime(lf, getactspeed(lf)); + return B_TRUE; + } + + // probably don't need this now... if (hasflag(o->flags, F_DEAD)) { taketime(lf, getactspeed(lf)); return B_TRUE; diff --git a/lf.h b/lf.h index 020a463..a5824ec 100644 --- a/lf.h +++ b/lf.h @@ -15,6 +15,7 @@ void autotarget(lifeform_t *lf); void autoweild(lifeform_t *lf); int appearsrandomly(enum RACE rid); void bleed(lifeform_t *lf); +void breakallgrabs(lifeform_t *lf); int calcxp(lifeform_t *lf); int calcxprace(enum RACE rid); int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost); @@ -43,7 +44,7 @@ void dumpxp(void); int eat(lifeform_t *lf, object_t *o); void enhanceskills(lifeform_t *lf); object_t *eyesshaded(lifeform_t *lf); -int fall(lifeform_t *lf, int announce); +int fall(lifeform_t *lf, lifeform_t *fromlf, int announce); void fightback(lifeform_t *lf, lifeform_t *attacker); job_t *findjob(enum JOB jobid); job_t *findjobbyname(char *name); @@ -64,6 +65,7 @@ void gainxp(lifeform_t *lf, long amt); void genxplist(void); int getactspeed(lifeform_t *lf); enum ALLEGIENCE getallegiance(lifeform_t *lf); +int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs); object_t *getarmour(lifeform_t *lf, enum BODYPART bp); int getarmourrating(lifeform_t *lf); int getattackspeed(lifeform_t *lf); @@ -71,6 +73,7 @@ int getattpoints(lifeform_t *lf); int getattr(lifeform_t *lf, enum ATTRIB attr); int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset); int getavgdam(lifeform_t *lf, int forxp); +float getequippedweight(lifeform_t *lf); int getevasion(lifeform_t *lf); object_t *getbestthrowmissile(lifeform_t *lf); object_t *getbestweapon(lifeform_t *lf); @@ -91,6 +94,7 @@ enum HUNGER gethungerlevel(int hunger); char * gethungername(enum HUNGER hunger, char *buf); int gethungerval(lifeform_t *lf); job_t *getjob(lifeform_t *lf); +int getlastdir(lifeform_t *lf); int getlfaccuracy(lifeform_t *lf, object_t *wep); enum LFCONDITION getlfcondition(lifeform_t *lf); int getnightvisrange(lifeform_t *lf); @@ -124,7 +128,7 @@ int getpoisondamchance(enum POISONTYPE ptype); char *getpoisondamverb(enum POISONTYPE ptype); char *getpoisonname(enum POISONTYPE ptype); int getraceclass(lifeform_t *lf); -int getracerarity(enum RACE rid); +int getracerarity(map_t *map, enum RACE rid); object_t *getrandomarmour(lifeform_t *lf); //int getrandommonlevel(int depth); race_t *getrandomrace(map_t *map, int forcedepth); @@ -187,7 +191,9 @@ int ispetof(lifeform_t *lf, lifeform_t *owner); int isplayer(lifeform_t *lf); flag_t *ispoisoned(lifeform_t *lf); int ispolymorphed(lifeform_t *lf); +int isprone(lifeform_t *lf); flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt); +object_t *isstuck(lifeform_t *lf); flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); void killjob(job_t *job); void killlf(lifeform_t *lf); @@ -227,7 +233,7 @@ int rolliq(enum IQBRACKET bracket); int rollstr(enum STRBRACKET bracket); int rollstat(lifeform_t *lf, enum ATTRIB attr); int safetorest(lifeform_t *lf); -int scare(lifeform_t *lf, lifeform_t *scarer, int howlong); +int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus); int setammo(lifeform_t *lf, object_t *o); void setattr(lifeform_t *lf, enum ATTRIB attr, int val); void setguntarget(lifeform_t *lf, lifeform_t *targ); diff --git a/log.txt b/log.txt index 09efb40..682f75b 100644 --- a/log.txt +++ b/log.txt @@ -12,88 +12,6 @@ xxx xxx xxx xxx -xxx -xxx -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. finding random lf with rarity val 92-100 -> possibility: kobold, rarity=95 @@ -215,70 +133,481 @@ finding random lf with rarity val 92-100 -> possibility: giant rat, rarity=95 got 5 possibilities. rollhitdice() - rolling 2d4 + 2 -rollhitdice() - mod is +54% -rollhitdice() ---- die 1/2 == 5 -rollhitdice() ---- die 2/2 == 3 +rollhitdice() - mod is +44% +rollhitdice() ---- die 1/2 == 4 +rollhitdice() ---- die 2/2 == 4 TOTAL: 8 - -> modified to: 12 + -> modified to: 11 test givejob() starting. -processing normal flag: 171 -processing normal flag: 171 -processing normal flag: 171 -processing normal flag: 220 -processing normal flag: 221 -processing normal flag: 176 -processing normal flag: 176 -processing normal flag: 176 -processing normal flag: 172 -processing normal flag: 172 -processing normal flag: 170 -processing normal flag: 170 -processing normal flag: 337 -processing normal flag: 337 -processing normal flag: 337 -processing normal flag: 172 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 251 -processing normal flag: 326 -processing normal flag: 158 +processing normal flag: 228 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 174 +processing normal flag: 175 +processing normal flag: 175 +processing normal flag: 175 +processing normal flag: 175 +processing normal flag: 175 +processing normal flag: 175 +processing normal flag: 175 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 173 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 263 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 175 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 260 +processing normal flag: 338 test -rollhitdice() - rolling 1d4 + 1 -rollhitdice() - mod is +54% -rollhitdice() ---- die 1/1 == 4 -TOTAL: 4 - -> modified to: 6 +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { cannot see my master - adding F_TARGETCELL for last known loc } +.oO { something going to targecell: 1, 2 } +.oO { walking from 1,4 towards f_targetcell (1,2) ... } +.oO { successfully walked towards f_targetcell. arrived at 1,3 } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving randomly } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { cannot see my master - adding F_TARGETCELL for last known loc } +.oO { your young wolf going to targecell: 1, 1 } +.oO { walking from 1,3 towards f_targetcell (1,1) ... } +.oO { successfully walked towards f_targetcell. arrived at 1,2 } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { didn't find any obs i want } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving randomly } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { cannot see my master - adding F_TARGETCELL for last known loc } +.oO { something going to targecell: 1, 1 } +.oO { walking from 3,1 towards f_targetcell (1,1) ... } +.oO { successfully walked towards f_targetcell. arrived at 2,1 } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { didn't find any obs i want } +.oO { walking from 2,1 towards f_targetcell (1,1) ... } +.oO { successfully walked towards f_targetcell. arrived at 1,1 } +.oO { arrived at f_targetcell. removing. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { i can see my master - moving towards them } +.oO { success. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { cannot see my master - adding F_TARGETCELL for last known loc } +.oO { something going to targecell: 1, 13 } +.oO { walking from 1,10 towards f_targetcell (1,13) ... } +.oO { successfully walked towards f_targetcell. arrived at 1,11 } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { didn't find any obs i want } +.oO { walking from 1,11 towards f_targetcell (1,13) ... } +.oO { successfully walked towards f_targetcell. arrived at 1,12 } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { didn't find any obs i want } +.oO { walking from 1,12 towards f_targetcell (1,13) ... } +.oO { successfully walked towards f_targetcell. arrived at 1,13 } +.oO { arrived at f_targetcell. removing. } +AIMOVE: your young wolf +.oO { looking for covetted objects... } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { looking for any ob which i want. } +.oO { no targetcell, so looking for remote objects } +.oO { didn't find any obs i want } +.oO { i do not have a target or can't move towards it. } +.oO { i am friendly to the player. looking for a target. } +.oO { cannot see my master and am at last known loc. trying last known dir (Southeast) } +.oO { ...successfully } diff --git a/map.c b/map.c index 3a64742..2200062 100644 --- a/map.c +++ b/map.c @@ -408,6 +408,9 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) { if (c->lf && cansee(viewer, c->lf)) { // lifeform here which we can see // draw the lf's race glyph *g = *(getlfglyph(c->lf)); + if (isprone(c->lf)) { + g->ch = flip(g->ch); + } return; } else { // we can see the floor here void *thing; @@ -1676,11 +1679,13 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int for (y = c->y - range-1 ; y <= c->y + range+1 ; y++) { for (x = c->x - range-1 ; x <= c->x + range+1 ; x++) { cell_t *cc; + int mydist; cc = getcellat(c->map, x,y); - if (cc && (getcelldist(c, cc) <= (range+1))) { + mydist = getcelldist(c,cc); + if (cc && (mydist <= (range+1))) { if (cc->lf && !isdead(cc->lf)) { // move away from centre of explosion - knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS), 2, NULL); + knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS), 2, NULL, 40-(mydist*10)); } } } @@ -1974,7 +1979,10 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum OB for (y = c->y - radius ; y <= c->y + radius ; y++) { for (x = c->x - radius ; x <= c->x + radius ; x++) { new = getcellat(c->map, x, y); - if (new && (getcelldist(c,new) == radius) && haslof(c, new, LOF_WALLSTOP, NULL)) { + if (new && + (new != c) && + (getcelldist(c,new) == radius) && + haslof(c, new, LOF_WALLSTOP, NULL)) { enum OBTYPE *badoid; int ok = B_FALSE; numwithlof++; diff --git a/move.c b/move.c index 39621e5..300b447 100644 --- a/move.c +++ b/move.c @@ -11,6 +11,7 @@ #include "move.h" #include "nexus.h" #include "objects.h" +#include "spell.h" #include "text.h" extern lifeform_t *player; @@ -177,9 +178,11 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) { if (cell->type->solid) { // mover is noncorporeal? if (lf && lfhasflag(lf, F_NONCORPOREAL)) { + if (error) *error = E_WALLINWAY; // ok but still set reason // ok } else if (cell->lf && (cell->lf != lf)) { // someone (else) in the wall? - // ok + if (error) *error = E_LFINWAY; // ok but still set reason + return B_FALSE; } else { if (error) *error = E_WALLINWAY; return B_FALSE; @@ -200,7 +203,8 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) { (lf->race->material->id == MT_SLIME)) { // ok } else if (lfhasflag(lf, F_NONCORPOREAL)) { - // ok + // ok but still set error + *error = E_OBINWAY; } else { rdata = o; if (error) { @@ -480,10 +484,11 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, in return bestdir; } -int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher) { +int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff) { int i; char lfname[BUFLEN]; int seen; + int hitwall = B_FALSE; getlfname(lf,lfname); if (cansee(player, lf)) { @@ -505,7 +510,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher) { for (i = 0; i < howfar; i++) { if (canmove(lf, dir, &reason)) { if ((i == 0) && seen) { - msg("%s %s knocked backwards!",lfname,isplayer(lf) ? "are" : "is"); + msg("%s %s knocked backwards!",lfname,is(lf)); } trymove(lf, dir, B_FALSE); } @@ -516,6 +521,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher) { case E_OFFMAP: msg("%s slam%s into a wall!",lfname,isplayer(lf) ? "" : "s"); losehp(lf, rnd(1,6), DT_BASH, pusher, "slamming into a wall"); + hitwall = B_TRUE; // stop moving i = howfar; break; @@ -524,6 +530,20 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher) { } } } + + // if you ran into a wall, it will prevent you from falling back. + if (!hitwall) { + int diff; + if (fallcheckdiff) { + diff = fallcheckdiff; + } else { + diff = howfar*10; + } + // save to avoid falling + if (!skillcheck(lf, SC_FALL, howfar*10, 0)) { + fall(lf, NULL, B_TRUE); + } + } return B_FALSE; } @@ -644,7 +664,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { killflagsofid(lf->flags, F_HIDING); - // remove grabs + // remove grabs (but not attached things) f = lfhasflag(lf, F_GRABBING); if (f) { lifeform_t *grabee; @@ -654,6 +674,20 @@ int movelf(lifeform_t *lf, cell_t *newcell) { killflagsofid(lf->flags, F_GRABBING); } + // passwall ends when you walk onto a non-solid cell. + f = lfhasflag(lf, F_NONCORPOREAL); + if (f && (f->obfrom == OT_S_PASSWALL)) { + enum ERROR err; + cellwalkable(lf, lf->cell, &err); + if (err == E_OK) { + stopspell(lf, OT_S_PASSWALL); + killflag(f); + if (isplayer(lf)) { + didmsg = B_TRUE; + } + } + } + // check ground objects if (!isairborne(lf)) { @@ -710,8 +744,19 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } // kill object removeob(o, o->amt); + continue; } } // end if crushable + + if (o->type->id == OT_VINE) { + char obname[BUFLEN]; + getobname(o,obname,o->amt); + if (isplayer(lf)) { + msg("%s grab%s you!",obname,(o->amt == 1) ? "s" : ""); + } else if (cansee(player, lf)) { + msg("%s grab%s %s!",obname, (o->amt == 1) ? "s" : "", lfname); + } + } } // end foreach object in cell } // end if !flying @@ -752,6 +797,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } } + // does anyone else see you? if ((gamemode == GM_GAMESTARTED)) { for (l = newcell->map->lf ; l ; l = l->next) { @@ -760,7 +806,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { int dointerrupt = B_FALSE; if (isplayer(l)) { - if (areenemies(lf, l)) { + if (cansee(l, lf) && areenemies(lf, l)) { if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_RESTING)) { char lfname2[BUFLEN]; getlfname(lf, lfname); @@ -800,6 +846,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { // does other game things like telling the player // what is here. int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { + object_t *o; char lfname[BUFLEN]; int didmsg; int predark = B_FALSE,postdark = B_FALSE; @@ -849,7 +896,6 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { if (!isdead(lf)) { // some lifeforms can go through things if (lf->race->material->id == MT_GAS) { - object_t *o; char obname[BUFLEN]; for (o = newcell->obpile->first ; o ; o = o->next) { if (isimpassableob(o, lf)) { @@ -862,7 +908,6 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { } } } else if (lf->race->material->id == MT_SLIME) { - object_t *o; char obname[BUFLEN]; for (o = newcell->obpile->first ; o ; o = o->next) { if (isimpassableob(o, lf)) { @@ -889,6 +934,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { } } + // make some noise // (stealth check to avoid this) if (!lfhasflag(lf, F_SILENTMOVE)) { @@ -1123,7 +1169,7 @@ int closedoor(lifeform_t *lf, object_t *o) { } else { // close it killflag(f); - addflag(o->flags, F_IMPASSABLE, B_TRUE, NA, NA, NULL); + addflag(o->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL); addflag(o->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); if (lf) { @@ -1190,7 +1236,7 @@ int pullnextto(lifeform_t *lf, cell_t *c) { if (isplayer(lf) || cansee(player, lf)) { char buf[BUFLEN]; getlfname(lf, buf); - msg("%s %s pulled %s!", buf, isplayer(lf) ? "are" : "is", + msg("%s %s pulled %s!", buf, is(lf), isairborne(lf) ? "through the air" : "along the ground"); } @@ -1207,49 +1253,22 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) { char buf[BUFLEN]; flag_t *f; - // check for cursed objects in new cell + animals - // do this AFTER checking if we will move, so that - // they will actually try the move and fail (this lets - // the player find out about the cursed object). - // - // note however that if a monster is chasing a player (ie - // has F_TARGET,player) then they will simply avoid the cursed - // object rather than failing the movement. - if (cell) { - for (o = cell->obpile->first ; o ; o = nexto) { - nexto = o->next; - if (!isplayer(lf)) { - if ((o->blessed == B_CURSED) && lfhasflag(lf, F_ANIMAL) && !isairborne(lf)) { - if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf,lfname); - getobname(o, buf, o->amt); - msg("%s %s away from %s!", lfname, isplayer(lf) ? "shy" : "shies", buf); - o->blessknown = B_TRUE; - if (didmsg) *didmsg = B_TRUE; - } - taketime(lf, getmovespeed(lf)); - reason = E_OK; - // avoid this object in future - sprintf(buf, "%ld",o->id); - addflag(lf->flags, F_AVOIDCURSEDOB, NA, NA, NA, buf); - return B_TRUE; - } - } - } - } // gravboosted if (lfhasflag(lf, F_GRAVBOOSTED)) { // make a saving throw to move if (!skillcheck(lf, SC_STR, 25, 0)) { if (isplayer(lf)) { - msg("You try to move but are unable to lift your feet!"); + msg("You try to %s but are unable to %s!", + isprone(lf) ? "stand" : "move", + isprone(lf) ? "lift your arms" : "lift your feet"); if (didmsg) *didmsg = B_TRUE; } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("%s tries to move but is unable to lift its feet!",lfname); + msg("%s tries to %s but is unable to %s!", lfname, + isprone(lf) ? "stand" : "move", + isprone(lf) ? "get up" : "lift its feet"); if (didmsg) *didmsg = B_TRUE; } reason = E_OK; @@ -1258,7 +1277,6 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) { } } - // sticky objects in current cell? for (o = lf->cell->obpile->first ; o ; o = nexto) { nexto = o->next; @@ -1319,6 +1337,31 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) { } } + // are we on the ground? + if (isprone(lf)) { + int howlong; + float quartermax; + int units; + if (isplayer(lf)) { + msg("You stand up."); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s stands up.",lfname); + } + killflagsofid(lf->flags, F_PRONE); + // time to get up depends on armour + // 1*movespeed for every 1/4 of maxcarryweight being worn. + quartermax = getmaxcarryweight(lf) / 4; + units = (getequippedweight(lf) / quartermax)+1; + howlong = getmovespeed(lf)*units; + taketime(lf, howlong); + + reason = E_OK; + return B_TRUE; + } + + // slipping on something before moving? if (!isairborne(lf)) { int slip; @@ -1332,6 +1375,38 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) { return B_TRUE; } } + + // check for cursed objects in new cell + animals + // do this AFTER checking if we will move, so that + // they will actually try the move and fail (this lets + // the player find out about the cursed object). + // + // note however that if a monster is chasing a player (ie + // has F_TARGET,player) then they will simply avoid the cursed + // object rather than failing the movement. + if (cell) { + for (o = cell->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (!isplayer(lf)) { + if ((o->blessed == B_CURSED) && (getraceclass(lf) == RC_ANIMAL) && !isairborne(lf)) { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf,lfname); + getobname(o, buf, o->amt); + msg("%s %s away from %s!", lfname, isplayer(lf) ? "shy" : "shies", buf); + o->blessknown = B_TRUE; + if (didmsg) *didmsg = B_TRUE; + } + taketime(lf, getmovespeed(lf)); + reason = E_OK; + // avoid this object in future + sprintf(buf, "%ld",o->id); + addflag(lf->flags, F_AVOIDCURSEDOB, NA, NA, NA, buf); + return B_TRUE; + } + } + } + } return B_FALSE; } @@ -1388,6 +1463,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { enum ERROR errcode; char buf[BUFLEN]; int dontclearmsg = B_FALSE; + int moveok; flag_t *f; f = isdrunk(lf); @@ -1401,15 +1477,64 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } cell = getcellindir(lf->cell, dir); - if (canandwillmove(lf, dir, &errcode)) { + + moveok = B_FALSE; + if (onpurpose) { + if (canandwillmove(lf, dir, &errcode)) { + moveok = B_TRUE; + } + } else { + if (canmove(lf, dir, &errcode)) { + moveok = B_TRUE; + } + } + + if (moveok) { + lifeform_t *alf; if (initiatemove(lf, cell, &dontclearmsg)) { // failed? return B_FALSE; } // move to new cell reason = E_OK; + + // remember last dir we walked + killflagsofid(lf->flags, F_LASTDIR); + addflag(lf->flags, F_LASTDIR, dir, NA, NA, NULL); + + // do your pets see you move? + if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) { + lifeform_t *l; + for (l = lf->cell->map->lf ; l ; l = l->next) { + if (ispetof(l,lf) && cansee(l, lf)) { + killflagsofid(l->flags, F_OWNERLASTDIR); + addflag(l->flags, F_OWNERLASTDIR, dir, NA, NA, NULL); + } + } + } + moveto(lf, cell, onpurpose, dontclearmsg); - taketime(lf, getmovespeed(lf)); + if (onpurpose) { + taketime(lf, getmovespeed(lf)); + } + + // attached things will move the same direction if they can + for (alf = cell->map->lf ; alf ; alf = alf->next) { + if (lfhasflagval(alf, F_ATTACHEDTO, lf->id, NA, NA, NULL)) { + // if the lifeform we were attached to just moved away from us, + // try to stay with them. + if (getcelldist(alf->cell,lf->cell) > 1) { + int newdir; + newdir = getdirtowards(alf->cell, lf->cell, alf, B_FALSE, DT_ORTH); + // do a manual canmove check here first, to avoid 'the stirge flies into a wall' + // if the move fails. + if ((newdir != D_NONE) && canmove(alf, newdir, NULL)) { + trymove(alf, newdir, B_FALSE); + } + + } + } + } } else { object_t *inway = NULL; int door, dooropen; @@ -1439,12 +1564,12 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { losehp(lf, 1, DT_BASH, NULL, buf); // we now know there is a wall there. cell->known = B_TRUE; - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); } } else { sprintf(buf, "%sing into a wall", getmoveverb(lf)); losehp(lf, 1, DT_BASH, NULL, buf); - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); } } break; @@ -1463,7 +1588,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { cell->known = B_TRUE; sprintf(buf, "%sing into a door", getmoveverb(lf)); losehp(lf, 1, DT_BASH, NULL, buf); - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); } } else { if (cansee(player, lf)) { @@ -1472,7 +1597,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } sprintf(buf, "%sing into a door", getmoveverb(lf)); losehp(lf, 1, DT_BASH, NULL, buf); - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); } } else { // try to open it @@ -1531,7 +1656,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { // move you.. moveto(lf, cell, onpurpose, B_FALSE); - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); // move them... lfinway->cell = oldcell; @@ -1551,7 +1676,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { if (isplayer(lf)) { msg("You cannot move!"); } - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); break; case E_GRABBEDBY: if (rdata) { @@ -1576,13 +1701,13 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { msg("You cannot get away from whatever is holding you!"); } } - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); break; case E_TOOHEAVY: if (isplayer(lf)) { msg("Your load is too heavy to move with!"); } - taketime(lf, getmovespeed(lf)); + if (onpurpose) taketime(lf, getmovespeed(lf)); break; default: break; diff --git a/move.h b/move.h index 7acbba3..79d5369 100644 --- a/move.h +++ b/move.h @@ -11,7 +11,7 @@ int diropposite(int dir); void dorandommove(lifeform_t *lf, int badmovesok); int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, 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 knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff); int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype); int moveeffects(lifeform_t *lf); int movelf(lifeform_t *lf, cell_t *newcell); diff --git a/nexus.c b/nexus.c index 9572495..34afc17 100644 --- a/nexus.c +++ b/nexus.c @@ -78,6 +78,8 @@ int main(int argc, char **argv) { char welcomemsg[BUFLEN]; int ch; FILE *playerfile = NULL; + int x,y; + cell_t *c; atexit(cleanup); @@ -242,6 +244,7 @@ int main(int argc, char **argv) { sprintf(welcomemsg, "Greetings %s, welcome to %snexus!", pname, newworld ? "the new " : ""); // 00:00 - 23:59 curtime = rnd(0,86399); + } else { sprintf(welcomemsg, "Welcome back!"); } @@ -256,6 +259,18 @@ int main(int argc, char **argv) { // pre-calc line-of-sight for player precalclos(player); + // don't want any mosnters starting within los of player + for (y = 0; y < player->cell->map->h; y++) { + for (x = 0; x < player->cell->map->w; x++) { + c = getcellat(player->cell->map, x, y); + if (c && c->lf && haslos(player, c)) { + if (!isplayer(c->lf) && !ispetof(c->lf, player)) { + killlf(c->lf); + } + } + } + } + // show level drawscreen(); @@ -592,8 +607,20 @@ enum COLOUR getpctcol(float num, float max) { return C_ORANGE; } -void getrarity(int depth, int *min, int *max, int range) { +void getrarity(int depth, int *min, int *max, int range, int oodok) { int mid; + int num; + + // adjust depth for out-of-depth things + if (oodok && (onein(6))) { + // repeated 1/3 chances of incing level + num = rnd(1,6) - 4; + while (num > 0) { + depth += num; + num = rnd(1,6) - 4; + } + } + mid = 100 - (depth * 3); *min = mid - range; if (*min < 0) *min = 0; //*max = mid + range; if (*max > 100) *max = 100; @@ -766,6 +793,11 @@ int limit(int *what, int min, int max) { return limited; } +int onein(int howmany) { + if (rnd(1,howmany) == 1) return B_TRUE; + return B_FALSE; +} + int parseplayerfile(FILE *f, lifeform_t *lf) { // add extra obs etc from f char *pp; diff --git a/nexus.h b/nexus.h index eaf5509..7b5205c 100644 --- a/nexus.h +++ b/nexus.h @@ -9,13 +9,14 @@ void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, in void donextturn(map_t *map); char *getdirname(int dir); enum COLOUR getpctcol(float num, float max); -void getrarity(int depth, int *min, int *max, int range); +void getrarity(int depth, int *min, int *max, int range, int oodok); 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 onein(int howmany); int parseplayerfile(FILE *f, lifeform_t *lf); float pctof(float pct, float num); int rnd(int min, int max); diff --git a/objects.c b/objects.c index db30c19..53f113a 100644 --- a/objects.c +++ b/objects.c @@ -68,8 +68,8 @@ enum OBCLASS sortorder[] = { OC_TOOLS, OC_BOOK, OC_ROCK, - OC_MISC, OC_DFEATURE, + OC_MISC, // omitting OC_SPELL and OC_JUMP because it shouldn't ever be displayed OC_NULL }; @@ -486,6 +486,9 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { if (db) dblog("DB: ob is blessed (%s)",p); wantblessed = B_BLESSED; //canstack = B_FALSE; + } else if (strstr(p, "uncursed")) { + if (db) dblog("DB: ob is uncursed (%s)",p); + wantblessed = B_UNCURSED; } else if (strstr(p, "cursed") || strstr(p, "incompetence")) { if (db) dblog("DB: ob is cursed (%s)",p); wantblessed = B_CURSED; @@ -1163,7 +1166,7 @@ void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int all } } -objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid) { +objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid) { objecttype_t *a, *ot; //flag_t *f; @@ -1188,6 +1191,10 @@ objecttype_t *addot(int id, char *name, char *description, int material, float w // props a->id = id; + if (a->id == OT_BERRY) { + int a; + a = 2; + } a->name = strdup(name); a->desc = strdup(description); a->material = findmaterial(material); @@ -1353,7 +1360,7 @@ void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) { // adjust damage if (o->blessed == B_BLESSED) { // chance of no hp loss - if (rnd(1,2) == 1) { + if (onein(2)) { lifeform_t *owner; owner = o->pile->owner; if (owner && isplayer(owner)) { @@ -1370,7 +1377,7 @@ void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) { } } else if (o->blessed == B_CURSED) { // chance of double damage! - if (rnd(1,2) == 1) { + if (onein(2)) { lifeform_t *owner; (*dam) *= 2; owner = o->pile->owner; @@ -2047,6 +2054,7 @@ objecttype_t *findotn(char *name) { modname = strrep(modname, "puddles ", "puddle ", NULL); modname = strrep(modname, "rings ", "ring ", NULL); modname = strrep(modname, "scrolls ", "scroll ", NULL); + modname = strrep(modname, "sets ", "set ", NULL); modname = strrep(modname, "splashes ", "splash ", NULL); modname = strrep(modname, "suits ", "suit ", NULL); modname = strrep(modname, "vials ", "vial ", NULL); @@ -2199,13 +2207,14 @@ glyph_t *getglyph(object_t *o) { return &tempglyph; } -void fragments(cell_t *centre, char *what, int speed) { +void fragments(cell_t *centre, char *what, int speed, int howfar) { cell_t *c,*dst; int n; int dir; + for (dir = DC_N; dir <= DC_NW; dir++) { - int maxdist = 0; int wantdist = 0; + int maxdist = 0; int done = B_FALSE; // get max distance c = centre; @@ -2218,11 +2227,12 @@ void fragments(cell_t *centre, char *what, int speed) { done = B_TRUE; } } + // pick random distance if (maxdist == 0) { wantdist = 0; } else { - wantdist = rnd(1,maxdist); + wantdist = rnd(1,(howfar > maxdist) ? maxdist : howfar); } // go that far dst = centre; @@ -2353,12 +2363,19 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder) { // modify for weilder's skill sk = getobskill(wep); if (sk) { - switch (getskill(weilder, sk->id)) { + enum SKILLLEVEL slev; + + slev = getskill(weilder, sk->id); + if (hasflag(wep->flags, F_MASTERWORK)) { + if (slev < PR_ADEPT) slev++; + } + + switch (slev) { case PR_INEPT: - acc -= 45; + acc -= 30; break; case PR_NOVICE: - acc -= 25; + acc -= 10; break; case PR_BEGINNER: acc -= 5; @@ -3010,11 +3027,15 @@ cell_t *getoblocation(object_t *o) { } char *getobname(object_t *o, char *buf, int count) { - return real_getobname(o, buf, count, B_TRUE, B_TRUE, B_TRUE, B_TRUE); + return real_getobname(o, buf, count, B_TRUE, B_TRUE, B_TRUE, B_TRUE, B_FALSE); +} + +char *getobnametrue(object_t *o, char *buf, int count) { + return real_getobname(o, buf, count, B_TRUE, B_TRUE, B_FALSE, B_TRUE, B_TRUE); } // buf must already be allocated -char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse) { +char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse, int showall) { char *pluralname; char prefix[BUFLEN]; char basename[BUFLEN]; @@ -3036,12 +3057,16 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan where = getoblocation(o); if (shopitem) { + showall = B_TRUE; + } + + if (showall) { strcpy(basename,o->type->name); } else { strcpy(basename,gethiddenname(o)); } - if (!shopitem) { + if (!showall) { if ((gamemode == GM_GAMESTARTED) && adjustforblind && !haslos(player, where) ) { // override with obclass names switch (o->type->obclass->id) { @@ -3129,7 +3154,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan // blessed status if (!hasflag(o->flags, F_NOBLESS) && wantblesscurse) { - if (shopitem || isblessknown(o)) { + if (showall || isblessknown(o)) { switch (o->blessed) { case B_BLESSED: // blessed water is known as "holy water" @@ -3196,7 +3221,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan // include enchantments (ie. a blessed +5 sword) f = hasflag(o->flags, F_BONUS); - if (f && (f->known || shopitem)) { + if (f && (f->known || showall)) { char buf2[BUFLENSMALL]; int bonus; bonus = f->val[0]; @@ -3242,7 +3267,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan for (brf = br->flags->first ; brf ; brf = brf->next) { for (f = o->flags->first; f ; f = f->next) { if ((f->id == brf->id) && (f->lifetime == FROMBRAND)) { - if (f->known || shopitem) { + if (f->known || showall) { } else { ok = B_FALSE; hasunknownmod = B_TRUE; @@ -3492,7 +3517,7 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth depth = rnd(1,MAXDEPTH); } - getrarity(depth, &raritymin, &raritymax, RARITYVARIANCEOB); + getrarity(depth, &raritymin, &raritymax, RARITYVARIANCEOB, B_TRUE); while (!done) { if (db) dblog("adding random object with rarity value between %d - %d",raritymin,raritymax); @@ -4707,9 +4732,11 @@ void initobjects(void) { 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); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, 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); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_WALLSTOP, 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); @@ -4718,6 +4745,7 @@ void initobjects(void) { 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); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_MAGSHIELD, "magnetic shield", "Surrounds the caster with magnetic force, repelling metal objects and attacks.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ALLOMANCY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -4734,17 +4762,25 @@ void initobjects(void) { addot(OT_S_BLINDNESS, "blindness", "Temporarily blinds the target.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addot(OT_S_FEAR, "cause fear", "Causes intense fear in the target.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l3 addot(OT_S_POISONBOLT, "poison bolt", "Fires a glob of venom at the target.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); addot(OT_S_DRAINLIFE, "drain life", "Draws life force from the victim in order to heal the caster.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); addot(OT_S_PAIN, "pain", "Causes extreme pain in the target whenever they move.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -4772,6 +4808,7 @@ void initobjects(void) { addot(OT_S_POSSESSION, "possession", "Completely possess an enemy, moving your consciousness into their body.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 7, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l8 addot(OT_S_INFINITEDEATH, "infinite death", "Annihilates all nearby life, including the caster!", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); @@ -4812,15 +4849,18 @@ void initobjects(void) { // elemental - air /////////////////// // l2 - addot(OT_S_AIRBLAST, "airblast", "Knocks enemies back with a powerful blast of air.", MT_NOTHING, 0, OC_SPELL); + addot(OT_S_GUSTOFWIND, "gust of wind", "Causes a gust of wind to blow the target's objects away.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); // l3 - addot(OT_S_CLOUDKILL, "cloudkill", "Creates a cloud of poisonous gas.", MT_NOTHING, 0, OC_SPELL); + addot(OT_S_AIRBLAST, "airblast", "Knocks enemies back with a powerful blast of air.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); addot(OT_S_WINDSHIELD, "cyclonic shield", "Surrounds the caster with a whirling cyclone to repel missiles.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); @@ -4828,6 +4868,11 @@ void initobjects(void) { addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + // l4 + addot(OT_S_CLOUDKILL, "cloudkill", "Creates a cloud of poisonous gas.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); /////////////////// // elemental - fire /////////////////// @@ -4836,11 +4881,13 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l2 addot(OT_S_FIREDART, "flame dart", "Fires a medium-sized dart of fire, dealing 2-6 fire damage.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); // l3 addot(OT_S_FLAMEBURST, "flame burst", "Creates a radial blast of fire out from the caster.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); @@ -4852,6 +4899,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); // l5 addot(OT_S_BURNINGWAVE, "burning wave", "Fire bursts from the ground in a line towards the target.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); @@ -4859,10 +4907,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); addot(OT_S_FIREBALL, "fireball", "Creates a huge ball of fire.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // TODO: should be "near victim" + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); /////////////////// // elemental - ice /////////////////// @@ -4871,6 +4921,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ICE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); addot(OT_S_FREEZEOB, "freezing touch", "Permenantly changes the next object touched into solid ice.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -4911,11 +4962,13 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_LESSENPOISON, "lessen poison", "Reduces the effects of poison within the caster's bloodstream.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_REPELINSECTS, "repel insects", "Surrounds the caster with an insect-repelling smell.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); @@ -4925,35 +4978,47 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_SUMMONANIMALSSM, "summon small animals", "Summons 2-3 small animals.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); addot(OT_S_WARPWOOD, "warp wood", "Causes damage to all wooden object in the target area.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l3 addot(OT_S_CALLLIGHTNING, "call lightning", "Blasts a single enemy with a bolt of lightning from the sky.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_ENDUREELEMENTS, "endure elements", "Provides resistance to fire and cold.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_QUENCH, "quench", "Extinguishes all fires within the given area.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_SLEETSTORM, "sleet storm", "Creates an cloud of sleet, hampering vision and movement.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_WEB, "web", "Slows down pursuers with a burst of sticky spider web.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); // l4 addot(OT_S_DIG, "dig", "Blasts away earth to create passages.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); @@ -4963,7 +5028,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); - // l4 + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_CALMINGSCENT, "calming scent", "Automatically calms any nearby animals.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); @@ -4974,12 +5039,36 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_HAILSTORM, "hail storm", "Creates an intense storm of hail, causing damage to all within.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_SUMMONANIMALSMD, "summon medium animals", "Summons 2-3 medium animals.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + addot(OT_S_WATERJET, "water spray", "Fires a high pressure blast of water from the caster's hands.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); + // l5 + addot(OT_S_LIGHTNINGSTORM, "lightning storm", "Blasts all visible enemies bolts of lightning from the sky.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + // l6 + addot(OT_S_SUMMONANIMALSLG, "summon large animals", "Summons 2-3 large animals.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); /////////////////// // gravity /////////////////// @@ -5013,6 +5102,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // life /////////////////// @@ -5022,6 +5112,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_TURNUNDEAD, "turn undead", "Instills fear in undead creatures. Power depends on caster's skill.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -5031,6 +5122,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // mental/psionic /////////////////// @@ -5059,10 +5151,12 @@ void initobjects(void) { 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); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, 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); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // modification /////////////////// @@ -5073,11 +5167,13 @@ void initobjects(void) { addot(OT_S_KNOCK, "knock", "Magically opens doors or other such barriers.\nAt Power VII, this spell will also knock back living creatures.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_LIGHT, "light", "Creates a temporary light source centred on the caster.\nAt Power III, you can control where the light appears.\nAt Power VIII, the light becomes permenant.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); addot(OT_S_DARKNESS, "darkness", "Permenantly darkens the area around the caster.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -5093,9 +5189,11 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_XPVAL, 50, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_PASSWALL, "passwall", "Allows the caster to temporarily walk through walls.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); // l6 addot(OT_S_PETRIFY, "petrify", "Causes the target mosnter to turn into stone.", MT_NOTHING, 0, OC_SPELL); @@ -5124,6 +5222,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // translocation /////////////////// @@ -5137,6 +5236,7 @@ void initobjects(void) { 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); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); // l4 addot(OT_S_TELEPORT, "teleportation", "Teleports the caster (and Power-1 adjacent allies) to a new location within the same level.\nBecomes semi-controlled at Power V, and fully controlled at Power VII.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); @@ -5162,12 +5262,14 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); // l2 addot(OT_S_ENERGYBOLT, "energy bolt", "Fires a medium-sized bolt of wild magic, dealing 1d4 damage per power level.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); // l3 addot(OT_S_ENERGYBLAST, "energy blast", "Causes a ring of energy to expand from the caster, causing 2-6 damage to anything in sight.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); @@ -5204,6 +5306,9 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); // abilities + addot(OT_A_CHARGE, "charge", "You can quickly charge into close quarters for battle.", MT_NOTHING, 0, OC_ABILITY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addot(OT_A_CRUSH, "crush", "You can crush enemies after grabbing them.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); @@ -5228,13 +5333,19 @@ void initobjects(void) { addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL); + addot(OT_A_RAGE, "rage", "Enter a state of berzerker rage, gaining attack and defence bonuses.", MT_NOTHING, 0, OC_ABILITY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL); addot(OT_A_SPRINT, "sprint", "You can run at high speed over short distances.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addot(OT_A_STINGACID, "sting (acid)", "You can sting your enemies.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL); + addot(OT_A_SUCKBLOOD, "suck blood", "You can suck the blood from enemies after attaching to them.", MT_NOTHING, 0, OC_ABILITY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addot(OT_A_SWOOP, "swoop", "You can attack an enemy while flying past them.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); @@ -5329,6 +5440,8 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_ANIMATEDEAD, NA, NA, NULL); addot(OT_SB_DRAINLIFE, "spellbook of drain life", "Teaches the spell 'drain life'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_DRAINLIFE, NA, NA, NULL); + addot(OT_SB_FEAR, "spellbook of cause fear", "Teaches the spell 'cause fear'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_FEAR, NA, NA, NULL); addot(OT_SB_FEEBLEMIND, "spellbook of feeblemind", "Teaches the spell 'feeblemind'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_FEEBLEMIND, NA, NA, NULL); addot(OT_SB_PAIN, "spellbook of pain", "Teaches the spell 'pain'.", MT_PAPER, 1.5, OC_BOOK); @@ -5363,6 +5476,12 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_CALLLIGHTNING, NA, NA, NULL); addot(OT_SB_CLOUDKILL, "spellbook of cloudkill", "Teaches the spell 'cloudkill'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_CLOUDKILL, NA, NA, NULL); + addot(OT_SB_GUSTOFWIND, "spellbook of gust of wind", "Teaches the spell 'gust of wind'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_GUSTOFWIND, NA, NA, NULL); + addot(OT_SB_LIGHTNINGSTORM, "spellbook of lightning storm", "Teaches the spell 'lightning storm'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_LIGHTNINGSTORM, NA, NA, NULL); + addot(OT_SB_WINDSHIELD, "spellbook of cyclonic shield", "Teaches the spell 'cyclonic shield'.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_LINKSPELL, OT_S_WINDSHIELD, NA, NA, NULL); // elemental - fire addot(OT_SB_SPARK, "spellbook of spark", "Teaches the spell 'spark'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_SPARK, NA, NA, NULL); @@ -5426,6 +5545,7 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_COLDBURST, NA, NA, NULL); addot(OT_SB_DIG, "spellbook of dig", "Teaches the spell 'dig'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_DIG, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); addot(OT_SB_GASEOUSFORM, "spellbook of gaseous form", "Teaches the spell 'gaseous form'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_GASEOUSFORM, NA, NA, NULL); @@ -5552,6 +5672,7 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_DETONATE, NA, NA, NULL); addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER|TT_DOOR, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_WAND_POLYMORPH, "wand of polymorph", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_LINKSPELL, OT_S_POLYMORPH, NA, NA, NULL); @@ -5628,6 +5749,10 @@ void initobjects(void) { addflag(lastot->flags, F_PICKLOCKS, 10, B_DIEONFAIL, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addot(OT_PANPIPES, "set of panpipes", "A set of musical pipes.", MT_METAL, 0.5, OC_TOOLS); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addot(OT_PICKAXE, "pickaxe", "A heavy tool for breaking rock.", MT_METAL, 8, OC_TOOLS); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); @@ -5642,6 +5767,10 @@ void initobjects(void) { addflag(lastot->flags, F_RNDCHARGES, 50, 100, NA, NULL); addflag(lastot->flags, F_REFILLWITH, OT_POT_OIL, NA, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_FIRE, NA, NA, "1d4"); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); // tech - l0 addot(OT_CREDITCARD, "credit card", "A rectangular plastic card.", MT_PLASTIC, 0.01, OC_TECH); @@ -5893,6 +6022,20 @@ void initobjects(void) { addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL); + addot(OT_ACIDSPLASH, "splash of acid", "A splash corrosive acid.", MT_ACID, 0, OC_MISC); + addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); + addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates"); + addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); + addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); + addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_ACID, FALLTHRU, "1d2"); + addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL); + addot(OT_SLIMEPOOL, "pool of slime", "A disgusting mass of sticky slime.", MT_WATER, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); @@ -5936,6 +6079,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); addflag(lastot->flags, F_REDUCEMOVEMENT, 2, NA, NA, NULL); + addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); //addflag(lastot->flags, F_WALKDAM, DT_WATER, NA, NA, "0d1+1"); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+1"); @@ -5970,6 +6114,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, ","); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL); addot(OT_BLOODCSPLASH, "splash of cockatrice blood", "A small pool of cockatrice blood.", MT_BLOOD, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -6000,6 +6145,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LINKOB, OT_POT_BLOOD, NA, NA, NULL); + addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL); addot(OT_BLOODPOOL, "pool of blood", "A large pool of blood.", MT_BLOOD, 0, OC_MISC); @@ -6085,6 +6231,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, 3, NA, NA, NULL); addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "1d2"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -6095,6 +6242,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, 1, NA, NA, NULL); addflag(lastot->flags, F_WALKDAM, DT_FIRE, NA, NA, "1d1+1"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -6106,7 +6254,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, 3, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_REDUCEMOVEMENT, 2, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); @@ -6135,6 +6283,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, 4, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "."); addot(OT_POISONCLOUD, "cloud of poison gas", "A thick cloud of poisonous gas.", MT_GAS, 0, OC_EFFECT); @@ -6147,6 +6296,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_WALKDAM, DT_POISONGAS, NA, NA, "1d4"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); + addflag(lastot->flags, F_BLOCKSVIEW, 2, NA, NA, NULL); addot(OT_POISONPUFF, "puff of poison gas", "A small puff of poisonous gas.", MT_GAS, 0, OC_EFFECT); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "{"); @@ -6163,6 +6313,7 @@ void initobjects(void) { addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, 5, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -6186,9 +6337,10 @@ void initobjects(void) { addot(OT_VINE, "entangling vine", "A living vine which grasps nearby creature", MT_SILK, 0.1, OC_EFFECT); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 82, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "^"); - addflag(lastot->flags, F_RESTRICTMOVEMENT, 25, B_FALSE, NA, NULL);// the value here will be filled in by the spell. + addflag(lastot->flags, F_RESTRICTMOVEMENT, 30, B_FALSE, NA, NULL);// the value here will be filled in by the spell. addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); @@ -6199,7 +6351,7 @@ void initobjects(void) { addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 86, NA, NULL); addflag(lastot->flags, F_RESTRICTMOVEMENT, 25, B_TRUE, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -6446,28 +6598,28 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR); addflag(lastot->flags, F_RARITY, H_ALL, 76, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addot(OT_SHIELDLARGE, "large shield", "A large (if somewhat cumbersome) shield.", MT_METAL, 6.00, OC_ARMOUR); addflag(lastot->flags, F_RARITY, H_ALL, 78, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 8, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 20, NA, NULL); - addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR); addflag(lastot->flags, F_RARITY, H_ALL, 65, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 12, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 30, NA, NULL); - addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); + addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); // rings addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING); @@ -6576,6 +6728,20 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); + addot(OT_HOOF, "hooves", "hoof object", MT_BONE, 0, OC_WEAPON); + addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d2"); + addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "kick"); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); + addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); + + addot(OT_BUTT, "headbutt", "headbutt object", MT_BONE, 0, OC_WEAPON); + addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d2"); + addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "butt"); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); + addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); + addot(OT_STING, "sting", "sting object", MT_BONE, 0, OC_WEAPON); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "sting"); addflag(lastot->flags, F_DAM, DT_ACID, NA, NA, "1d2"); @@ -6643,7 +6809,7 @@ void initobjects(void) { 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, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); @@ -6700,7 +6866,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 9, 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); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); @@ -6708,7 +6874,7 @@ void initobjects(void) { addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 8, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); @@ -6716,7 +6882,7 @@ void initobjects(void) { addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_MIGHTY, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL); addot(OT_HANDAXE, "hand axe", "A fast one-handed axe made for combat.", MT_METAL, 2, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); @@ -6724,7 +6890,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); // short blades addot(OT_COMBATKNIFE, "combat knife", "A sharp knife designed for military use.", MT_METAL, 1, OC_WEAPON); @@ -6773,20 +6939,20 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d8"); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL); addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4"); addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_DEX, DX_DEXTROUS, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 10, NA, NULL); addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 2.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL); addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 0.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d6"); @@ -6808,7 +6974,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+3"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_GREATSWORD, "greatsword", "A massive two-handed sword.", MT_METAL, 10, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 55, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); @@ -6816,14 +6982,14 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d8+4"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL); addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 2, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL); @@ -6837,13 +7003,13 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d8+2"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL); addot(OT_CUTLASS, "cutlass", "An accuracte, light-weight pirate blade.", MT_METAL, 1, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d7"); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 8, NA, NULL); // polearms addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 4, OC_WEAPON); @@ -6853,7 +7019,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_GUISARME, "guisarme", "A hooked polearm, made by attaching a hook to a spear shaft.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL); addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL); @@ -6862,8 +7028,8 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4"); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_DEX, DX_AWKWARD, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); addot(OT_HALBERD, "halberd", "A spiked axe blade mounted on a long shaft, with a hook on the back.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 71, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); @@ -6872,8 +7038,8 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_DEX, DX_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL); addot(OT_LANCE, "lance", "A pole weapon designed for use while mounted.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -6881,7 +7047,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d8+2"); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 1, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, NULL); addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); @@ -6890,15 +7056,15 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "2d4"); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_DEX, DX_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL); addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4"); addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addot(OT_SPEAR, "spear", "A long pole with a sharpened head.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -6909,14 +7075,14 @@ void initobjects(void) { 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); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d10"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); // staves addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 2, OC_WEAPON); @@ -6926,9 +7092,41 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + addot(OT_BAMBOOSTAFF, "bamboo staff", "A long hard pole made from bamboo.", MT_WOOD, 1.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4"); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 6, NA, NULL); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + + addot(OT_BLADEDSTAFF, "bladed staff", "A long wooden pole with blades on either end.", MT_WOOD, 2, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "2d4+3"); + addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 9, NA, NULL); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + + addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 4, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 135, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "3d4+1"); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); + addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + + // clubs (bashing) addot(OT_CLUB, "club", "A heavy, blunt wooden instrument to hit things with.", MT_WOOD, 1.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); @@ -6936,21 +7134,21 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 6, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d4"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addot(OT_FLAILHEAVY, "heavy flail", "A flexible chain attached to a very heavy weight.", MT_METAL, 12, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 155, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "2d6"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); @@ -6958,14 +7156,14 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_MIGHTY, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL); addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d7+1"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 3.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); @@ -6973,7 +7171,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 1.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); @@ -6981,7 +7179,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d6+1"); addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_DEX, DX_DEXTROUS, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 10, NA, NULL); addot(OT_SPANNER, "spanner", "A long, heavy metal wrench.", MT_METAL, 1, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); @@ -7008,7 +7206,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 5, OC_WEAPON); @@ -7019,7 +7217,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_CROSSBOWHAND, "hand crossbow", "A small one-handed crossbow. Lightweight, but less powerful than a full-sized one.", MT_WOOD, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); @@ -7038,7 +7236,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_REVOLVER, "revolver", "Basic one-handed firearm.", MT_METAL, 1, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); @@ -8037,6 +8235,15 @@ object_t *moveob(object_t *src, obpile_t *dst, int howmany) { if (dst->owner && isplayer(dst->owner) && isblessknown(o)) { o->blessknown = B_TRUE; } + + if (hasflag(o->flags, F_DOOR)) { + killflagsofid(o->flags, F_LOCKED); + killflagsofid(o->flags, F_JAMMED); + killflagsofid(o->flags, F_SECRETDOOR); + if (!hasflag(o->flags, F_OPEN)) { + addflag(o->flags, F_OPEN, B_TRUE, NA, NA, NULL); + } + } } if (dst->where && !dst->where->lf && haslos(player, dst->where)) { @@ -8133,7 +8340,7 @@ void obdie(object_t *o) { char desc[BUFLEN]; if (!hasflag(o->flags, F_NODIECONVERTTEXT)) { // announce the change - real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE); + real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); f2 = NULL; if (o->amt > 1) { @@ -8182,7 +8389,7 @@ void obdie(object_t *o) { } else { char desc[BUFLEN]; - real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE); + real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); if (!hasflag(o->flags, F_NOOBDIETEXT)) { // announce the death f = hasflag(o->flags, F_OBDIETEXT); @@ -8588,7 +8795,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { // random power power = rnd(1,10); // 1 in 3 chance of targetting yourself - if (rnd(1,3) == 1) { + if (onein(3)) { where = lf->cell; } @@ -8677,7 +8884,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { o->blessknown = B_TRUE; } if (isplayer(lf)) { - real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_TRUE); // don't adjust for blindness + real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_TRUE, B_FALSE); // don't adjust for blindness msg("This is %s!",obname); } } @@ -8894,6 +9101,13 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { return B_TRUE; } } + } else if (o->type->id == OT_PANPIPES) { + // announce + if (isplayer(lf)) { + msg("You play a few notes on your panpipes."); + } else { + noise(lf->cell, lf, "the sound of panpipes.", "plays a tune on its panpipes."); + } } else if (o->type->id == OT_PICKAXE) { int ch,dir; cell_t *c; @@ -9341,7 +9555,7 @@ void quaff(lifeform_t *lf, object_t *o) { if (!isknown(o) && willid) { // id the potion makeknown(o->type->id); - real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE); // don't adjust for blindness + real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness if (isplayer(lf)) { // tell the player msg("This is %s!",obname); @@ -9874,7 +10088,7 @@ int readsomething(lifeform_t *lf, object_t *o) { if (!isknown(o) && willid) { // id the scroll makeknown(o->type->id); - real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE); // don't adjust for blindness + real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness if (isplayer(lf)) { // tell the player msg("This is %s!",obname); @@ -10194,7 +10408,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { if (shatterdam && !isdead(target)) { // extra glass damage if (seen) { - msg("%s %s showered in %s shards!", targetname, isplayer(target) ? "are" : "is", + msg("%s %s showered in %s shards!", targetname, is(target), o->material->name); } losehp(target, shatterdam, DT_SLASH, fromlf, damstring); @@ -10233,7 +10447,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { if (target) { if (seen) { msg("%s %s splashed with acid!", targetname, - isplayer(target) ? "are" : "is"); + is(target)); } losehp(target, rnd(1,5)*o->amt, DT_ACID, fromlf, "a splash of acid"); } else { @@ -10250,7 +10464,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { if (target) { if (seen) { msg("%s %s splashed with blood.", targetname, - isplayer(target) ? "are" : "is"); + is(target)); } } else { // announce @@ -10285,7 +10499,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { case OT_POT_OIL: if (seen) { makeknown(o->type->id); - msg("%s %s covered with oil!", targetname, isplayer(target) ? "are" : "is"); + msg("%s %s covered with oil!", targetname, is(target)); } // target is temporarily vulnerable to fire. addtempflag(target->flags, F_DTVULN, DT_FIRE, NA, NA, "1d6", rnd(5,10)); @@ -10295,7 +10509,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { if (target) { if (seen) { msg("%s %s splashed with water.", targetname, - isplayer(target) ? "are" : "is"); + is(target)); } if (hasflag(target->flags, F_UNDEAD) && isblessed(o)) { @@ -10423,9 +10637,13 @@ object_t *splitob(object_t *o) { } return newob; } - // returns amount of damage taken int takedamage(object_t *o, unsigned int howmuch, int damtype) { + return real_takedamage(o, howmuch, damtype, B_TRUE); +} + +// returns amount of damage taken +int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantannounce) { char predamname[BUFLEN],postdamname[BUFLEN]; char obname[BUFLEN]; flag_t *hpflag, *f; @@ -10527,7 +10745,7 @@ int takedamage(object_t *o, unsigned int howmuch, int damtype) { - real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE); + real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); getobconditionname(o, predamname); hpflag = hasflag(o->flags, F_OBHP); if (hpflag) { @@ -10570,7 +10788,6 @@ int takedamage(object_t *o, unsigned int howmuch, int damtype) { // object was just damaged getobconditionname(o, postdamname); - // was it enough to change the status if (!hasflag(o->flags, F_NOOBDAMTEXT) && strcmp(predamname, postdamname)) { // if it was melting, drop some water here @@ -10584,20 +10801,24 @@ int takedamage(object_t *o, unsigned int howmuch, int damtype) { } if (o->pile->owner) { - if (isplayer(o->pile->owner)) { - msg("Your %s %s!",noprefix(obname), getobhurtname(o, damtype)); - } else if (cansee(player, o->pile->owner)) { - // don't announce decay damage for object you aren't holding - if (damtype != DT_DECAY) { - char monname[BUFLEN]; - getlfname(o->pile->owner, monname); - msg("%s's %s %s!",monname, noprefix(obname), getobhurtname(o, damtype)); + if (wantannounce) { + if (isplayer(o->pile->owner)) { + msg("Your %s %s!",noprefix(obname), getobhurtname(o, damtype)); + } else if (cansee(player, o->pile->owner)) { + // don't announce decay damage for object you aren't holding + if (damtype != DT_DECAY) { + char monname[BUFLEN]; + getlfname(o->pile->owner, monname); + msg("%s's %s %s!",monname, noprefix(obname), getobhurtname(o, damtype)); + } } } } else if (haslos(player, o->pile->where)) { - // don't announce decay damage for object you aren't holding - if (damtype != DT_DECAY) { - msg("%s %s!", obname, getobhurtname(o, damtype)); + if (wantannounce) { + // don't announce decay damage for object you aren't holding + if (damtype != DT_DECAY) { + msg("%s %s!", obname, getobhurtname(o, damtype)); + } } // if you see a secret door get damaged, it's not secret anymore. killflagsofid(o->flags, F_SECRETDOOR); @@ -10722,13 +10943,16 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (target && isdead(target)) { target = NULL; } - if (thrower && target) { - getlfname(target, targetname); + if (thrower && target && !isprone(target)) { if (areallies(thrower, target) && !firearm) { willcatch = B_TRUE; } } + if (target) { + getlfname(target, targetname); + } + // touch effects if (thrower && !firearm) { if (o->pile == thrower->pack) { @@ -10770,7 +10994,14 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, msg("Something %ss %s.",throwverbpres, obname); } */ - sprintf(throwstring, "%s %s through the air", obname, (amt == 1) ? "flies" : "fly"); + if (o->pile->owner && cansee(player, o->pile->owner)) { + char ownername[BUFLEN]; + getlfname(o->pile->owner, ownername); + sprintf(throwstring, "%s%s %s %s through the air", ownername, getpossessive(ownername), + noprefix(obname), (amt == 1) ? "flies" : "fly"); + } else { + sprintf(throwstring, "%s %s through the air", obname, (amt == 1) ? "flies" : "fly"); + } if (target && haslos(player, where)) { strcat(throwstring, " toward "); strcat(throwstring, targetname); @@ -10781,7 +11012,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // adjust destination location in case something is in the way. - haslof(thrower->cell, where, LOF_NEED, &newloc); + haslof(srcloc, where, LOF_NEED, &newloc); if (newloc) { where = newloc; target = where->lf; @@ -10882,9 +11113,10 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, youhit = B_TRUE; } - // cyclone shield? if (youhit && target) { flag_t *f; + object_t *shield; + // cyclone shield? f = lfhasflag(target, F_WINDSHIELD); if (f) { if (speed <= f->val[0]) { @@ -10895,10 +11127,38 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, youhit = B_FALSE; } } + // an actual physical shield? + shield = getequippedob(target->pack, BP_SECWEAPON); + if (shield && isshield(shield)) { + // block chance based on shield skill + // ie. ST_AVERAGE = speed3 = 18 + // ie. gun = speed10 = 60 = basically impossible + if (skillcheck(target, SC_SHIELDBLOCK, speed*6, 0)) { + int throwdam,dam; + if (seen) { + char shname[BUFLEN]; + getobname(shield, shname, 1); + if (isplayer(target)) { + msg("You block %s with your %s.", obname, noprefix(shname)); + } else { + msg("%s blocks %s with %s.", targetname, obname, shname); + } + announcedmiss = B_TRUE; + } + // damage shield + throwdam = getthrowdam(o); + dam = throwdam * speed; + takedamage(shield, dam, DT_PROJECTILE); + + youhit = B_FALSE; + + } + } } + // saving throws - if (youhit && !willcatch) { + if (youhit && !willcatch && !isprone(target)) { // can the victim see the thrower? if (thrower && cansee(target, thrower)) { // first check to see if you can catch it @@ -11013,12 +11273,10 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if ((getobunitweight(o)*amt) >= getlfweight(target, B_NOOBS)) { int dir; dir = getdirtowards(srcloc, target->cell, target, B_FALSE, DT_COMPASS); - knockback(target, dir, 1, thrower); + knockback(target, dir, 1, thrower, 0); } } - - // move the object to the cell then take dam or kill it. newob = moveob(o, where->obpile, amt); // fake its birth time so that it can be damaged @@ -11028,7 +11286,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, sprintf(dambuf, "%s (%s by %s)",obname,throwverbpast, realthrowernamea); shatter(newob, youhit, dambuf, thrower); } else { - takedamage(newob, speed, DT_BASH); + // don't announce damage to the thrown object + real_takedamage(newob, speed, DT_BASH, B_FALSE); } return B_FALSE; @@ -11154,11 +11413,6 @@ void timeeffectsob(object_t *o) { lifeform_t *creator; int willvanish = B_FALSE; - // noone there? - if (!location->lf) { - willvanish = B_TRUE; - } - // creator no longer has los? f = hasflag(o->flags, F_CREATEDBY); if (f) { @@ -11166,15 +11420,20 @@ void timeeffectsob(object_t *o) { if (!creator || !haslos(creator, location)) { willvanish = B_TRUE; } - } - if (willvanish) { - // vanish. - if (haslos(player, location)) { - msg("%s vanish%s.", obname, (o->amt == 1) ? "es" : ""); + // noone there? + if (!location->lf) { + willvanish = B_TRUE; + } + + if (willvanish) { + // vanish. + if (haslos(player, location)) { + msg("%s vanish%s.", obname, (o->amt == 1) ? "es" : ""); + } + killob(o); + return; } - killob(o); - return; } } } @@ -11266,7 +11525,7 @@ void timeeffectsob(object_t *o) { needredraw = B_TRUE; return; } else if (f2->val[0] <= 50) { - if (rnd(1,6) == 1) { + if (onein(6)) { mf = hasflag(o->flags, F_CHARGELOWMSG); if (mf) obaction(o, mf->text); } @@ -11809,11 +12068,15 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob if (missile && !firearm && !isthrowmissile(missile)) { acc -= 20; } + // modify for prone throwers + if (isprone(thrower)) { + acc -= 50; + } else { + // modify for prone defenders + if (where->lf && isprone(where->lf)) { + acc -= 30; + } + } return acc; } - - - - - diff --git a/objects.h b/objects.h index b5596b3..4f71e2d 100644 --- a/objects.h +++ b/objects.h @@ -14,7 +14,7 @@ int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fr obmod_t *addobmod(enum OBMOD id, char *prefix); obpile_t *addobpile(lifeform_t *owner, cell_t *where); void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes); -objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid); +objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid); void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat); void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype); int adjustarmourpenalty(lifeform_t *lf, float amt); @@ -46,7 +46,7 @@ brand_t *findbrand(enum BRAND id); obmod_t *findobmod(enum OBMOD id); objecttype_t *findot(enum OBTYPE id); objecttype_t *findotn(char *name); // find objecttype by name -void fragments(cell_t *centre, char *what, int speed); +void fragments(cell_t *centre, char *what, int speed, int howfar); void genhiddennames(void); int getcharges(object_t *o); int geteffecttime(int min, int max, enum BLESSTYPE isblessed); @@ -84,7 +84,8 @@ char *getobequipinfo(object_t *o, char *buf); char *getobextrainfo(object_t *o, char *buf); cell_t *getoblocation(object_t *o); char *getobname(object_t *o, char *buf, int count); -char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse); +char *getobnametrue(object_t *o, char *buf, int count); +char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse, int showall); float getobpileweight(obpile_t *op); char *getobconditionname(object_t *o, char *buf); char *getobhurtname(object_t *o, enum DAMTYPE damtype); @@ -193,6 +194,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf); void shufflehiddennames(void); object_t *splitob(object_t *o); int takedamage(object_t *o, unsigned int howmuch, int damtype); +int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantannounce); int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm); void timeeffectsob(object_t *o); void turnoff(lifeform_t *lf, object_t *o); diff --git a/spell.c b/spell.c index 80e0cf0..bf0018d 100644 --- a/spell.c +++ b/spell.c @@ -18,6 +18,7 @@ extern lifeform_t *player; extern skill_t *firstskill, *lastskill; +extern race_t *firstrace, *lastrace; extern int needredraw; @@ -34,10 +35,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef char killername[BUFLEN]; char targetname[BUFLEN]; char buf[BUFLEN]; - int power = 0,needgrab = B_FALSE; + int power = 0,needgrab = B_FALSE, range = 0; char damstr[BUFLEN]; objecttype_t *ot; - flag_t *f; getlfname(user, username); @@ -49,7 +49,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef needgrab = B_FALSE; if (cwflag && strlen(cwflag->text)) { - texttospellopts(cwflag->text, &power, damstr, &needgrab); + texttospellopts(cwflag->text, &power, damstr, &needgrab, &range); } // get more options from ablity itself... @@ -70,6 +70,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef return B_TRUE; } } + if (target) { getlfname(target, targetname); } @@ -81,24 +82,25 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int i; cell_t *retcell[MAXRETCELLS]; int nretcell; - int crange = 3; // default if (isimmobile(user)) { if (isplayer(user)) msg("You can't move!"); return B_TRUE; } - // get max range - based on speed. - crange = (int) (((float)SP_NORMAL / (float)getmovespeed(user)) * 2.5); - if (crange <= 1) { - if (isplayer(user)) msg("You are too slow to charge!"); - return B_TRUE; + if (!range) { + // get max range - based on speed. + range = (int) (((float)SP_NORMAL / (float)getmovespeed(user)) * 2.5); + if (range <= 1) { + if (isplayer(user)) msg("You are too slow to charge!"); + return B_TRUE; + } } if (!targcell) { if (isplayer(user)) { - sprintf(buf, "Charge who (max range %d)?",crange); + sprintf(buf, "Charge who (max range %d)?",range); // TODO: ask for direction targcell = askcoords(buf, TT_MONSTER); if (!targcell) { @@ -110,7 +112,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } - if (getcelldist(user->cell, targcell) > crange) { + if (getcelldist(user->cell, targcell) > range) { if (isplayer(user)) msg("You can't charge that far!"); return B_TRUE; } @@ -151,7 +153,19 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // teleport next to them movelf(user, adjcell); if (haslos(player, adjcell)) { - msg("%s charge%s towards %s!",username,isplayer(user) ? "" : "s",targetname); + char verb[BUFLEN]; + // special case: sometimes we call this a 'leap' + switch (user->race->id) { + case R_CREEPINGCLAW: + case R_LEECH: + case R_SNAKETREE: + strcpy(verb, "leap"); + break; + default: + strcpy(verb, "charge"); + break; + } + msg("%s %s%s towards %s!",username,verb, isplayer(user) ? "" : "s",targetname); needredraw = B_TRUE; drawlevelfor(player); redraw(); @@ -161,8 +175,15 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef //} } - // attack - attackcell(user, targcell); + // special cases.... + if (user->race->id == R_CREEPINGCLAW) { + // creeping claw automatically grabs target + addflag(user->flags, F_GRABBING, target->id, NA, NA, NULL); + addflag(target->flags, F_GRABBEDBY, user->id, NA, NA, NULL); + } else { + // attack + attackcell(user, targcell); + } } else if (abilid == OT_A_GRAB) { char dirch; flag_t *f; @@ -202,12 +223,26 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef return B_TRUE; } + taketime(user, getactspeed(user)); + getlfname(target, targetname); + if (lfhasflag(target, F_NONCORPOREAL)) { + if (isplayer(user)) { + msg("You grab at %s%s insubstantial body.", targetname, getpossessive(targetname)); + } else if (cansee(player, user)) { + msg("%s grabs at %s%s insubstantial body.", + username, targetname, getpossessive(targetname)); + } + return B_TRUE; + } + // victim gets a skilcheck to avoid being grabbed if (skillcheck(target, SC_DODGE, getattr(user, A_DEX)+11, 0)) { - msg("%s evade%s %s%s grasp.", targetname, isplayer(target) ? "" : "s", - username, getpossessive(username)); + if (cansee(player, user)) { + msg("%s evade%s %s%s grasp.", targetname, isplayer(target) ? "" : "s", + username, getpossessive(username)); + } } else { addflag(user->flags, F_GRABBING, target->id, NA, NA, NULL); addflag(target->flags, F_GRABBEDBY, user->id, NA, NA, NULL); @@ -216,7 +251,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef losehp(target, roll(damstr), DT_CRUSH, user, killername); } } - taketime(user, getactspeed(user)); } else if (abilid == OT_A_CRUSH) { int dam = 0; @@ -260,7 +294,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // announce if (cansee(player, target)) { - msg("%s %s being crushed!", targetname, isplayer(target) ? "are" : "is"); + msg("%s %s being crushed!", targetname, is(target)); } losehp(target, dam, DT_CRUSH, user, killername); @@ -379,6 +413,23 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } } + } else if (abilid == OT_A_RAGE) { + int howlong; + f = lfhasflag(user, F_RAGE); + if (f) { + if (isplayer(user)) { + msg("You are already enraged!"); + } + return B_TRUE; + } + if (lfhasflag(user, F_TIRED)) { + if (isplayer(user)) { + msg("You are too tired to enter a rage right now."); + } + return B_TRUE; + } + howlong = 10; + addtempflag(user->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong); } else if (abilid == OT_A_SPRINT) { int howlong; int slev; @@ -403,6 +454,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } return B_TRUE; } + if (isburdened(user)) { + if (isplayer(user)) { + msg("You cannot sprint while burdened."); + } + return B_TRUE; + } howlong = 2; // +2 for each athletics skill level @@ -435,6 +492,59 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // cause ongoing pain for 2 turns addtempflag(target->flags, F_PAIN, DT_ACID, NA, NA, damstr, 2); taketime(user, getactspeed(user)); + } else if (abilid == OT_A_SUCKBLOOD) { + int dam = 0; + + f = lfhasflag(user, F_ATTACHEDTO); + if (!f) { + if (isplayer(user)) msg("You need to attach to someone before using this ability."); + return B_TRUE; + } + + // announce + if (cansee(player, target)) { + msg("%s suck%s blood from %s!", username, isplayer(user) ? "" : "s", targetname); + } + + // fixed damage? + if (strlen(damstr)) { + dam = roll(damstr); + } else { + dam = 1; + } + losehp(target, dam, DT_DIRECT, user, killername); + + taketime(user, getactspeed(user)); + + // special case + if (!isplayer(user)) { + if ((user->race->id == R_STIRGE) || (user->race->id == R_LEECH)) { + int satedat = 8; + int num; + num = modcounter(user->flags, dam); + + switch (user->race->id) { + default: + case R_STIRGE: + satedat = 8; + break; + case R_LEECH: + satedat = 12; + break; + } + + if (num >= satedat) { + // sated. + killflagsofid(user->flags, F_ATTACHEDTO); + makepeaceful(user); + addflag(user->flags, F_FLEEONDAM, B_TRUE, NA, NA, NULL); + addflag(user->flags, F_DIESPLATTER, 3, NA, NA, "splash of blood"); + // counter will keep ticking up. + // once it gets past next threshold, monster will go to sleep. + modcounter(user->flags, rnd(1,4)); + } + } + } } else if (abilid == OT_A_SWOOP) { cell_t *adjcell = NULL,*origcell; char targetname[BUFLEN]; @@ -711,7 +821,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef for (target = user->cell->map->lf ; target ; target = target->next) { if ((target != user) && cansee(target, user) && areenemies(target, user)) { if (canhear(target, user->cell)) { - scare(target, user, rnd(5,10)); + scare(target, user, rnd(5,10), 0); } } } @@ -863,7 +973,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ char castername[BUFLEN]; int rv = B_FALSE; objecttype_t *sp; - + sp = findot(spellid); getlfname(caster, castername); @@ -979,7 +1089,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, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; if (cansee(player, caster)) { @@ -990,12 +1100,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); // lfs if (target) { - knockback(target, dir, power, caster); - } - // objects - for (o = targcell->obpile->first ;o ; o = nexto) { - nexto = o->next; - if (!hasflag(o->flags, F_NOPICKUP)) knockbackob(o, dir, power, power, caster); + knockback(target, dir, power, caster, 0); + } else { + // objects + for (o = targcell->obpile->first ;o ; o = nexto) { + nexto = o->next; + if (!hasflag(o->flags, F_NOPICKUP)) knockbackob(o, dir, power, power, caster); + } } } else if (spellid == OT_S_ANIMATEDEAD) { int i; @@ -1133,7 +1244,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ cell_t *retcell[MAXRETCELLS]; int nretcell; int i; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_WALLSTOP, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; if (cansee(player, caster)) { msg("%s shoot%s a wave of fire!",castername, isplayer(caster) ? "" : "s"); @@ -1174,7 +1285,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_CALLLIGHTNING) { int failed = B_FALSE; // ask for a target cell - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; if (target) { @@ -1183,7 +1294,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(target, targname); if (haslos(player, targcell)) { - msg("%s is struck by a bolt of lightning!",targname); + animsky(targcell, '}', C_CYAN); + msg("%s %s struck by a bolt of lightning!",targname,is(target)); if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -1226,14 +1338,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("A relaxing aroma surrounds you."); } } else if (spellid == OT_S_CLOUDKILL) { - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + int radius; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; if (targcell->type->solid) { fizzle(caster); return B_FALSE; } + radius = power/3; + if (radius < 1) radius = 1; - addobburst(targcell, (power/3), DT_COMPASS, "cloud of gas", caster); + addobburst(targcell, radius, DT_COMPASS, "cloud of gas", caster); if (haslos(player, targcell)) { msg("A cloud of poison gas appears!"); @@ -1241,7 +1356,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_CHARM) { char targetname[BUFLEN]; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; @@ -1252,7 +1367,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(target, targetname); // only animals/humanoids - if (!lfhasflag(target, F_ANIMAL) && !lfhasflag(target, F_HUMANOID)) { + if (getraceclass(target) != getraceclass(caster)) { if (isplayer(caster)) { msg("%s%s mind is too alien for you to charm.",targetname,getpossessive(targetname)); } @@ -1313,7 +1428,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_CHARMANIMAL) { char targetname[BUFLEN]; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; @@ -1323,8 +1438,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } getlfname(target, targetname); - // only animals/humanoids - if (!lfhasflag(target, F_ANIMAL)) { + // only animals + if (getraceclass(target) != RC_ANIMAL) { fizzle(caster); return B_FALSE; } @@ -1406,7 +1521,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // automatic hit getlfname(targcell->lf, lfname); if (haslos(caster, targcell)) { - msg("%s %s chilled!",lfname,isplayer(targcell->lf) ? "are" : "is"); + msg("%s %s chilled!",lfname,is(targcell->lf)); } losehp(targcell->lf, rolldie(1,8)+3, DT_COLD, caster, "a burst of coldness"); } @@ -1415,7 +1530,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_CONECOLD) { char lfname[BUFLEN]; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}', C_GREY); if (isplayer(caster) || cansee(player, caster)) { @@ -1457,7 +1572,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!targcell) { if ((power >= 5) && isplayer(caster)) { // control location - if (!validatespellcell(caster, &targcell, TT_NONE, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power)) return B_TRUE; // make sure it's empty if (!cellwalkable(NULL, targcell, NULL)) { targcell = NULL; @@ -1550,7 +1665,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } } else if (spellid == OT_S_CUREPOISON) { - if (!validatespellcell(caster, &targcell,TT_ALLY, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { fizzle(caster); @@ -1626,7 +1741,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int nretcell,i; // don't need line of fire OR sight! - if (!validatespellcell(caster, &targcell, TT_NONE, B_FALSE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power)) return B_TRUE; // calculate a line from caster to the target cell calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, @@ -1740,7 +1855,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // end if isplayer } else if (spellid == OT_S_DETONATE) { // don't need line of fire! - if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_DOOR, spellid, power)) return B_TRUE; explodecells(targcell, 20, B_TRUE, NULL, power / 4, DT_ORTH, B_TRUE); @@ -1751,7 +1866,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_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_OBJECT, spellid, power)) return B_TRUE; // how much metal is there? for (o = targcell->obpile->first ; o ; o = nexto) { @@ -1863,7 +1978,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ rv = B_FALSE; } else if (spellid == OT_S_DRAINLIFE) { char lfname[BUFLEN]; - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; target = haslf(targcell); if (target) { @@ -1930,6 +2045,37 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } } + } else if (spellid == OT_S_FEAR) { + char targname[BUFLEN]; + // ask for target + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; + target = targcell->lf; + if (!target) { + fizzle(caster); + return B_TRUE; + } + getlfname(target, targname); + + if (isplayer(caster)) { + msg("You emit an aura of fear!"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (cansee(player, caster)) { + msg("%s emits an aura of fear!",castername); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + if (lfhasflag(target, F_ASLEEP)) { + if (isplayer(target)) { + msg("You suffer terrifying nightmares!"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (cansee(player, caster)) { + msg("%s thrashes about in its sleep!",targname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + losehp(target, roll("2d6"), DT_DIRECT, caster, "terrifying nightmares"); + } else { + scare(target, caster, 5+rnd(1,power), 5+power); + } } else if (spellid == OT_S_FEEBLEMIND) { // ask for target if (!validatespelllf(caster, &target)) return B_TRUE; @@ -1978,7 +2124,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_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}', C_CYAN); if (isplayer(caster) || cansee(player, caster)) { @@ -2007,7 +2153,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_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; if (targcell) { if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { int dir; @@ -2026,7 +2172,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ anim(caster->cell, targcell, '^', C_RED); - // add fires as follows (3 = large, 2 = medium, 1 = smell) + // add fires as follows (3 = medium, 2 = medium, 1 = smell) // // 1 // 232 @@ -2034,11 +2180,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // 232 // 1 // add large fires to surrounding cells - addob(targcell->obpile, "large fire"); + addob(targcell->obpile, "medium fire"); for (dir = D_N; dir <= D_W; dir++) { c = getcellindir(targcell, dir); if (c && (!c->type->solid || hasflag(c->type->material->flags, F_FLAMMABLE)) ) { - o = addob(c->obpile, "large fire"); + o = addob(c->obpile, "medium fire"); if (o) { setobcreatedby(o, caster); } @@ -2096,7 +2242,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_FIREDART) { char lfname[BUFLEN]; - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}', C_RED); if (isplayer(caster) || cansee(player, caster)) { @@ -2160,7 +2306,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, LOF_WALLSTOP, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; if (targcell && haslos(caster, targcell)) { if (!targcell->type->solid || hasflag(targcell->type->material->flags, F_FLAMMABLE)) { flag_t *f; @@ -2225,7 +2371,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_ENDUREELEMENTS) { flag_t *f; // always targetted at caster - if (!validatespellcell(caster, &targcell,TT_ALLY, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { fizzle(caster); @@ -2241,7 +2387,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ flag_t *f; object_t *o; - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { @@ -2408,7 +2554,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_HAILSTORM) { int failed = B_FALSE; // ask for a target cell - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; if (targcell) { if (!targcell->type->solid) { object_t *o; @@ -2459,7 +2605,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, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; @@ -2484,7 +2630,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_HEALING) { int donesomething = B_FALSE; - if (!validatespellcell(caster, &targcell,TT_ALLY, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { fizzle(caster); @@ -2534,7 +2680,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_HEALINGMIN) { int donesomething = B_FALSE; - if (!validatespellcell(caster, &targcell,TT_ALLY, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { fizzle(caster); @@ -2661,7 +2807,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_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}', C_CYAN); if (isplayer(caster) || cansee(player, caster)) { @@ -2877,7 +3023,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_FALSE, LOF_WALLSTOP, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; // 4 is the same as ST_TITANIC strength // 10 = gun speed @@ -2983,7 +3129,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ addflag(target->flags, F_BEINGSTONED, 2, NA, NA, NULL); } else if (spellid == OT_S_POISONBOLT) { char lfname[BUFLEN]; - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_FALSE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '}', C_GREEN); @@ -3014,7 +3160,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_POSSESSION) { char targname[BUFLEN]; - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { @@ -3132,7 +3278,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = addtempflag(caster->flags, F_MAGICARMOUR, power*4, NA, NA, "psychic barrier", 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; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; @@ -3154,7 +3300,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(target) || cansee(player, target)) { char buf[BUFLEN]; getlfname(target, buf); - msg("%s %s pulled forward slightly.", buf, isplayer(target) ? "are" : "is"); + msg("%s %s pulled forward slightly.", buf, is(target)); if (seenbyplayer) *seenbyplayer = B_TRUE; } return B_FALSE; @@ -3164,7 +3310,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_PULLMETAL) { int donesomething = B_FALSE; - if (!validatespellcell(caster, &targcell,TT_OBJECT, B_TRUE, LOF_WALLSTOP, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_OBJECT, spellid, power)) return B_TRUE; if (targcell->lf) { object_t *o; @@ -3220,7 +3366,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(target) || haslos(player, target->cell)) { char buf[BUFLEN]; getlfname(target, buf); - msg("%s %s pulled forward slightly.", buf, isplayer(target) ? "are" : "is"); + msg("%s %s pulled forward slightly.", buf, is(target)); if (seenbyplayer) *seenbyplayer = B_TRUE; } return B_FALSE; @@ -3307,7 +3453,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ createmap(newmap, newdepth, caster->cell->map->habitat); } - // find a random cell there newcell = getrandomcell(newmap); @@ -3356,8 +3501,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // if blind, garble text somewhat for (p = buf ; *p; p++) { if (*p != ' ') { - if (rnd(1,4) == 1) { - if (rnd(1,2) == 1) { + if (onein(4)) { + if (onein(2)) { *p = rnd('a','z'); } else { *p = rnd('A','Z'); @@ -3388,7 +3533,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (caster->race->id == R_GHOST) { targcell = caster->cell; } else { - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; } target = targcell->lf; @@ -3413,7 +3558,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_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_DOOR, spellid, power)) return B_TRUE; target = targcell->lf; @@ -3421,7 +3566,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (target && (power >= 7)) { int dir; dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); - knockback(target, dir, 2, caster); + knockback(target, dir, 2, caster, 0); } else { o = hasobwithflag(targcell->obpile, F_DOOR); if (o) { @@ -3460,7 +3605,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // at power 8, the light is permenant if (power >= 3) { // 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; + if (!validatespellcell(caster, &targcell,TT_NONE, spellid, power)) return B_TRUE; } else { targcell = caster->cell; } @@ -3516,6 +3661,62 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } + } else if (spellid == OT_S_LIGHTNINGSTORM) { + char targname[BUFLEN]; + lifeform_t *poss[MAXCANDIDATES], *targ[MAXCANDIDATES]; + int nposs = 0,ntarg = 0; + int seen = B_FALSE; + int i; + + for (i = 0; i < caster->nlos; i++) { + target = caster->los[i]->lf; + if (target) { + poss[nposs++] = target; + } + } + + if (nposs) { + int nhits; + nhits = power*3; + for (i = 0; (i < nhits) && (nposs > 0); i++) { + int sel,n; + // select a random target + sel = rnd(0,nposs-1); + targ[ntarg++] = poss[sel]; + // remove selection from list + for (n = sel; n < nposs-1; n++) { + poss[n] = poss[n+1]; + } + nposs--; + } + + for (i = 0; i < ntarg; i++) { + if (haslos(player, targ[i]->cell)) { + // hit this target with lightning + animsky(targ[i]->cell, '}', C_CYAN); + seen = B_TRUE; + } + } + + if (seen) { + drawlevelfor(player); + } + + for (i = 0; i < ntarg; i++) { + if (cansee(player, targ[i])) { + getlfname(targ[i],targname); + msg("%s %s struck by a bolt of lightning!",targname, is(targ[i])); + } + losehp(targ[i], rolldie(3,6), DT_ELECTRIC, caster, "a bolt of lightning"); + } + + if (seen) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + } else { + fizzle(caster); + } } else if (spellid == OT_S_GRAVBOOST) { // ask for target if (!target) { @@ -3559,6 +3760,70 @@ 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_GUSTOFWIND) { + obpile_t *op; + object_t *o, *nexto; + object_t *poss[MAXPILEOBS],*blowob[MAXPILEOBS]; + int nposs = 0,nblowobs = 0; + int i; + char targname[BUFLEN]; + + if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_OBJECT, spellid, power)) return B_TRUE; + + target = targcell->lf; + + if (target) { + getlfname(target, targname); + // objects held by target + op = target->pack; + } else { + // objects on ground + op = targcell->obpile; + } + + for (o = op->first ; o ; o = nexto) { + nexto = o->next; + if (getobunitweight(o) <= 5) { + poss[nposs++] = o; + } + } + + for (i = 0; ((i < power) && (nposs > 0)); i++) { + int sel,n; + sel = rnd(0,nposs-1); + blowob[nblowobs++] = poss[sel]; + // remove ob from possibility list + for (n = sel; n < (nposs-1); n++) { + poss[sel] = poss[sel+1]; + } + nposs--; + } + + if (target && cansee(player, target)) { + msg("A gust of wind whips up around %s!", targname); + } else if (haslos(player, targcell)) { + msg("A gust of wind whips up!"); + } + + // chance of blowing each ob away + for (i = 0; i < nblowobs; i++) { + char obname[BUFLEN]; + cell_t *c; + + getobname(blowob[i], obname, 1); + c = getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND); + if (c && ((rnd(1,100)+power) <= 33)) { + // move it + fireat(NULL, blowob[i], 1, c, 4, NULL); + } + } + + + // easyish save to avoid falling + if (target && !skillcheck(target, SC_FALL, 12, 0)) { + fall(target, NULL, B_TRUE); + } + needredraw = B_TRUE; } else if (spellid == OT_S_MENDING) { object_t *o; @@ -3599,7 +3864,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_PACIFY) { char targetname[BUFLEN]; - if (!validatespellcell(caster, &targcell, TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; target = targcell->lf; @@ -3642,17 +3907,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_PASSWALL) { int howlong = 7; + flag_t *f; target = caster; - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { - if (isplayer(target)) { - msg("You feel momentarily insubstantial."); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } - return B_FALSE; - } howlong = getspellduration(5,10,blessed) + (power/2); - addtempflag(target->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL, howlong); + f = addtempflag(target->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL, howlong); + f->obfrom = OT_S_PASSWALL; + + breakallgrabs(caster); } else if (spellid == OT_S_POLYMORPH) { race_t *r = NULL; @@ -3816,7 +4078,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *o,*nexto; int ndone = 0; - if (!validatespellcell(caster, &targcell,TT_OBJECT, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_OBJECT, spellid, power)) return B_TRUE; if (!targcell) { fizzle(caster); @@ -3871,7 +4133,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_LESSENPOISON) { flag_t *f; int ndone = 0; - if (!validatespellcell(caster, &targcell,TT_ALLY, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power)) return B_TRUE; target = targcell->lf; if (!target) { fizzle(caster); @@ -3978,7 +4240,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_SLEETSTORM) { int failed = B_FALSE; // ask for a target cell - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; if (targcell) { if (!targcell->type->solid) { int radius; @@ -4027,7 +4289,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int ndone = 0; int powerleft = power; // ask for a target cell - if (!validatespellcell(caster, &targcell, TT_NONE, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power)) return B_TRUE; if (targcell) { object_t *o; enum OBTYPE badoid[2]; @@ -4068,7 +4330,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_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, spellid, power)) return B_TRUE; if (haslos(player, targcell)) { msg("A small spark of flame appears."); @@ -4089,10 +4351,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int i; cell_t *poss[MAXCANDIDATES]; int nposs; + race_t *raceposs[MAXCANDIDATES],*r; + int nraceposs = 0; cell_t *c = NULL,*newcell = NULL; object_t *o,*nexto; int ndone = 0; + // power is always at lesat 2 for this spell + if (power < 2) power = 2; + + // get list of possible snakes + for (r = firstrace ; r ; r = r->next) { + if (strstr(r->name, " snake")) { + flag_t *f; + f = hasflag(r->flags, F_HITDICE); + // ie. 1hd needs power 2 + // ie. 2hd needs power 4 + // ie. 3hd needs power 6 + // ie. 4hd needs power 8 + if (f && (power >= (f->val[0] * 2))) { + raceposs[nraceposs++] = r; + } + } + } + + poss[0] = caster->cell; nposs = 1; for (i = 0; i < caster->nlos; i++) { @@ -4108,7 +4391,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if ((o->material->id == MT_WOOD) && hasflag(o->flags, F_RODSHAPED) && isequipped(o) && - !isblessed(o) ) { + (o->blessed == B_UNCURSED) && + !hasflag(o->flags, F_HASBRAND)) { char obname[BUFLEN]; char lfname[BUFLEN]; getobname(o, obname, o->amt); @@ -4117,11 +4401,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (newcell) { lifeform_t *snake; // add a snake there. - if (rnd(1,2) == 1) { - snake = addlf(newcell, R_SNAKE, 1); - } else { - snake = addlf(newcell, R_SNAKECARPET, 1); - } + snake = addlf(newcell, raceposs[rnd(0,nraceposs-1)]->id, 1); if (snake) { msg("%s%s %s transforms into a snake!",lfname, getpossessive(lfname), @@ -4129,6 +4409,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ killflagsofid(snake->flags, F_XPVAL); addflag(snake->flags, F_XPVAL, 0, NA, NA, NULL); makefriendly(snake, PERMENANT); + if (c->lf == caster) { + char fullobname[BUFLEN]; + getobnametrue(o, fullobname, 1); + killflagsofid(snake->flags, F_CORPSETYPE); + addflag(snake->flags, F_CORPSETYPE, NA, NA, NA, fullobname); + } killob(o); ndone++; } @@ -4158,11 +4444,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (newcell) { // add a snake there. - if (rnd(1,2) == 1) { - snake = addlf(newcell, R_SNAKE, 1); - } else { - snake = addlf(newcell, R_SNAKECARPET, 1); - } + snake = addlf(newcell, raceposs[rnd(0,nraceposs-1)]->id, 1); if (snake) { msg("%s transforms into a snake!",obname); killob(o); @@ -4484,12 +4766,93 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } } + } else if ((spellid == OT_S_SUMMONANIMALSSM) || + (spellid == OT_S_SUMMONANIMALSMD) || + (spellid == OT_S_SUMMONANIMALSLG)) { + int lifetime, nwant,ngot; + enum LFSIZE wantsize; + enum RACECLASS wantrc; + lifetime = (power * 9) + rnd(1,power*2); + nwant = rnd(2,3); + switch (spellid) { + case OT_S_SUMMONANIMALSSM: + wantrc = RC_ANIMAL; + wantsize = SZ_SMALL; + break; + case OT_S_SUMMONANIMALSMD: + wantrc = RC_ANIMAL; + wantsize = SZ_MEDIUM; + break; + case OT_S_SUMMONANIMALSLG: + wantrc = RC_ANIMAL; + wantsize = SZ_LARGE; + break; + default: + wantsize = SZ_ANY; + break; + } + ngot = summonlfs(caster, wantrc, wantsize, nwant, lifetime); + if (!ngot) { + fizzle(caster); + return B_TRUE; + } else { + if (haslos(player, caster->cell)) { // intentionally not using cansee + raceclass_t *rc; + rc = findraceclass(wantrc); + if (seenbyplayer) *seenbyplayer = B_TRUE; + msg("%s appear around %s!", makeplural(rc->name), castername); + } + } + } else if (spellid == OT_S_SUMMONANIMALSMD) { + } else if (spellid == OT_S_SUMMONANIMALSLG) { + } else if (spellid == OT_S_WATERJET) { + char lfname[BUFLEN]; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; + // animation + anim(caster->cell, targcell, '}', C_BLUE); + if (isplayer(caster) || cansee(player, caster)) { + msg("%s fire%s a jet of high-pressure water.",castername,isplayer(caster) ? "" : "s"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + target = haslf(targcell); + if (target) { + getlfname(target, lfname); + int dir,amt; + object_t *arm[MAXBODYPARTS]; + int narm = 0; + int i; + + // hit + if (cansee(caster, target)) { + msg("%s %s hit by a jet of water!",lfname, is(target)); + } + // water damage will generally be turn to zero unless people are specifically + // vulnerable to water, so do bashing damage too. + losehp(target, roll("3d4"), DT_WATER, caster, "a high-pressure jet of water"); + losehp(target, roll("3d4"), DT_BASH, caster, "a high-pressure jet of water"); + // knock backwards + dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); + amt = (power/3); if (amt < 2) amt = 2; + knockback(target, dir, amt, caster, 0); + // rust + getallouterarmour(target, arm, &narm); + for (i = 0; i < narm; i++) { + takedamage(arm[i], R_TRUSTY, DT_WATER); + } + } else { + object_t *o, *nexto; + for (o = targcell->obpile->first; o ; o = nexto) { + nexto = o->next; + takedamage(o, 0, DT_COLD); + } + } } else if (spellid == OT_S_WARPWOOD) { object_t *o,*nexto; flag_t *f; int ndone = 0; - if (!validatespellcell(caster, &targcell,TT_OBJECT, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_OBJECT, spellid, power)) return B_TRUE; if (!targcell) { fizzle(caster); @@ -4504,7 +4867,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int dam; f = hasflag(o->flags, F_OBHP); if (f) { - dam = rnd(1,f->val[0]); + dam = rnd(f->val[0]/2,f->val[0]); } else { dam = roll("1d6"); } @@ -4581,7 +4944,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int i; numtotext(power, numbuf); - if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_NEED, spellid, power)) return B_TRUE; + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; // animation anim(caster->cell, targcell, '^', C_GREY); if (isplayer(caster) || cansee(player, caster)) { @@ -4603,7 +4966,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (c) { addob(c->obpile, "web"); - if (c->lf) { + if (c->lf && (c->lf->race->baseid != R_SPIDER)) { if (isplayer(c->lf)) { msg("You are stuck in a web!"); } else if (cansee(player, c->lf)) { @@ -4874,7 +5237,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { // spellpower f = lfhasflagval(lf, F_CANWILL, spellid, NA, NA, NULL); if (f && strlen(f->text)) { - texttospellopts(f->text, &power, NULL, NULL); + texttospellopts(f->text, &power, NULL, NULL, NULL); if (power > 0) { return power; } @@ -5122,6 +5485,67 @@ void stopspell(lifeform_t *caster, enum OBTYPE spellid) { // remove any other specific effects based on spell type. } + +// returns # created +int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime) { + lifeform_t *newlf; + race_t *r = NULL; + enum RACE poss[MAXCANDIDATES]; + int nposs = 0; + int i; + int ncreated = 0; + cell_t *c; + + // determine possible types of race + for (r = firstrace ; r; r = r->next) { + int ok = B_FALSE; + if ((wantrc == RC_ANY) || (r->raceclass->id == wantrc)) { + flag_t *f; + if (wantsize == SZ_ANY) { + ok = B_TRUE; + } else { + f = hasflag(r->flags, F_SIZE); + if (f && (f->val[0] == wantsize)) { + ok = B_TRUE; + } + } + } + if (ok) { + poss[nposs++] = r->id; + } + } + + if (nposs == 0) { + return 0; + } + + ncreated = 0; + for (i = 0; i < howmany; i++) { + // get random adjacent cell + c = getrandomadjcell(caster->cell, WE_EMPTY, B_ALLOWEXPAND); + if (!c) { + return ncreated; + } + // determine exact type of monster + r = findrace(poss[rnd(0,nposs-1)]); + if (r) { + // add it! + newlf = addmonster(c, r->id, B_FALSE, 1, B_FALSE); + // not worth any xp + killflagsofid(newlf->flags, F_XPVAL); + addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); + // summoned + addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); + addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL); + if (areallies(player, caster)) { + makefriendly(newlf, PERMENANT); + } + ncreated++; + } + } + return ncreated; +} + lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target) { objecttype_t *ot; int maxrange; @@ -5168,10 +5592,24 @@ 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 needlos, enum LOFTYPE needlof, enum OBTYPE spellid, int power) { +cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power) { int maxrange = UNLIMITED; int done = B_FALSE; cell_t *where = NULL; + objecttype_t *sp; + int needlos = B_TRUE; + enum LOFTYPE needlof = LOF_NEED; + + sp = findot(spellid); + if (sp) { + flag_t *f; + f = hasflag(sp->flags, F_LOSLOF); + if (f) { + needlos = f->val[0]; + needlof = f->val[1]; + } + } + maxrange = getspellrange(spellid, power); diff --git a/spell.h b/spell.h index aba16f5..c450c0b 100644 --- a/spell.h +++ b/spell.h @@ -21,8 +21,9 @@ char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf); void pullobto(object_t *o, lifeform_t *lf); void stopspell(lifeform_t *caster, enum OBTYPE spellid); void stopallspells(lifeform_t *lf); +int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime); lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target); -cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, int needlos, enum LOFTYPE needlof, enum OBTYPE spellid, int power); +cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power); lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf); #endif diff --git a/text.c b/text.c index 13303d7..66fcf91 100644 --- a/text.c +++ b/text.c @@ -82,6 +82,39 @@ char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dic return dicebuf; } +int flip(int ch) { + switch (ch) { + case 'a': return 0x0250; + case 'b': return 'q'; + case 'c': return 0x0254; + case 'd': return 'p'; + case 'e': return 0x01dd; + case 'f': return 0x025f; + case 'g': return 0x0183; + case 'h': return 0x0265; + case 'i': return 0x0131; + case 'j': return 0x027e; + case 'k': return 0x029e; + case 'l': return 0x0283; + case 'm': return 0x026f; + case 'n': return 'u'; + case 'r': return 0x0279; + case 't': return 0x0287; + case 'v': return 0x028c; + case 'w': return 0x028d; + case 'y': return 0x028e; + case '.': return 0x02d9; + case '[': return ']'; + case '(': return ')'; + case '{': return '}'; + case '?': return 0x00bf; + case '!': return 0x00a1; + case '<': return '>'; + case '_': return 0x203e; + } + return ch; +} + char *getattrabbrev(enum ATTRIB att) { switch (att) { case A_NONE: @@ -255,6 +288,11 @@ char *getweighttext(float weight, char *buf) { return buf; } +char *is(lifeform_t *lf) { + if (isplayer(lf)) return "are"; + else return "is"; +} + int isvowel (char c) { switch (c) { case 'a': @@ -308,6 +346,8 @@ char *makeplural(char *text) { if (rv) return newtext; newtext = strrep(newtext, "splash ", "splashes ", &rv); if (rv) return newtext; + newtext = strrep(newtext, "set ", "sets ", &rv); + if (rv) return newtext; newtext = strrep(newtext, "suit ", "suits ", &rv); if (rv) return newtext; newtext = strrep(newtext, "vial ", "vials ", &rv); @@ -321,9 +361,12 @@ char *makeplural(char *text) { // default lastlet = text[strlen(text)-1]; switch (lastlet) { + char *temptext; case 'y': // change to 'ies' - text[strlen(text)-1] = '\0'; - asprintf(&newtext, "%sies",text); + temptext = strdup(text); + temptext[strlen(temptext)-1] = '\0'; + asprintf(&newtext, "%sies",temptext); + free(temptext); break; case 's': case 'o': // append "es" @@ -606,25 +649,28 @@ int texttodice(char *text, int *ndice, int *nsides, int *bonus) { return B_FALSE; } -void texttospellopts(char *text, int *power, char *damstr, int *needgrab) { +void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range) { char *p; int n; char *argname[] = { "pw:", "dam:", "needgrab:", + "range:", NULL, }; void *argval[] = { power, damstr, needgrab, + range, NULL, }; char argtype[] = { 'i', 's', 'b', + 'i', '\0', }; @@ -632,6 +678,7 @@ void texttospellopts(char *text, int *power, char *damstr, int *needgrab) { if (power) *power = 0; if (damstr) strcpy(damstr, ""); if (needgrab) *needgrab = B_FALSE; + if (range) *range = 0; if (!strlen(text)) { return; diff --git a/text.h b/text.h index 68cfd20..f3f314f 100644 --- a/text.h +++ b/text.h @@ -4,6 +4,7 @@ int needan(char *text); char *capitalise(char *text); char *capitaliseall(char *text); char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dicebuf, char *minmaxbuf); +int flip(int ch); char *getattrabbrev(enum ATTRIB att); char *getattrname(enum ATTRIB att); int gethitconferlifetime(char *text, int *min, int *max); @@ -13,6 +14,7 @@ char *getsizetext(enum LFSIZE sz); char *gettimetext(char *retbuf); char *gettimetextfuzzy(char *retbuf, int wantpm); char *getweighttext(float weight, char *buf); +char *is(lifeform_t *lf); int isvowel(char c); char *makeplural(char *text); char *makeuppercase(char *text); @@ -26,7 +28,7 @@ char *strrep(char *text, char *oldtok, char *newtok, int *rv); char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv); int strpixmatch(char *haystack, char *needle); int texttodice(char *text, int *ndice, int *nsides, int *bonus); -void texttospellopts(char *text, int *power, char *damstr, int *needgrab); +void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range); char *you(lifeform_t *lf); char *you_l(lifeform_t *lf); char *your(lifeform_t *lf);