From c1cb8ea62e4f6f1522da0dfcdf297a7a607c6151 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Wed, 12 Dec 2012 01:00:17 +0000 Subject: [PATCH] - [+] new monsters - [+] creeping coins - [+] pretends to be gold - [+] poison breath - [+] rat swarm - [+] locust swarm - [+] baby mind leech - [+] mind whip - [+] adult mind leech - [+] mental feedback - [+] l5 psionic - drain intellect spell. 3d6 IQ drain. - [+] summon swarm spell - [+] ai: only pathfind if we are >= animal intelligence. - [+] shadow - drain strength - [+] show: "you swap places with the _sleeping_ lf" - [+] problem: - [+] i have metalwork = beginner, sewing = novice - [+] ...but i could resize cloth objects! - [+] SAVE broken again. fixed? - [+] in fixreachability, glass walls count as nonsolid - [+] aligned temples: - [+] detect auras: free - [+] curse removal: free - [+] blessings: half price - [+] change surface map. - [+] map difficulty should be very high. --- Makefile | 40 +++---- ai.c | 120 +++++++++++--------- attack.c | 8 +- data.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++------ defs.h | 24 +++- god.c | 3 + io.c | 3 +- lf.c | 82 +++++++++++++- lf.h | 2 + map.c | 4 +- move.c | 8 +- objects.c | 69 +++++++----- save.c | 14 ++- shops.c | 48 ++++++-- shops.h | 1 + spell.c | 83 +++++++++++++- text.c | 1 + 17 files changed, 674 insertions(+), 162 deletions(-) diff --git a/Makefile b/Makefile index bb95f24..83b6c64 100644 --- a/Makefile +++ b/Makefile @@ -1,62 +1,62 @@ #all: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h data.c data.h flag.c flag.h god.c god.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h shops.c shops.h spell.c spell.h vault.c vault.h -# gcc -Wall -g -o nexus nexus.c ai.c attack.c data.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c shops.c vault.c -lncurses -lsqlite3 +# gcc -Wall -g -pg -o nexus nexus.c ai.c attack.c data.c flag.c god.c io.c lf.c map.c move.c objects.c text.c save.c spell.c shops.c vault.c -lncurses -lsqlite3 nexus: ai.o astar.o attack.o data.o findleak.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o ai.h attack.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h - gcc -g -Wall -o nexus ai.o astar.o attack.o data.o findleak.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o -lncurses -lsqlite3 + gcc -g -pg -Wall -o nexus ai.o astar.o attack.o data.o findleak.o flag.o god.o io.o lf.o map.o move.o nexus.o objects.o save.o shops.o spell.o text.o vault.o -lncurses -lsqlite3 ai.o: ai.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h ai.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o ai.o ai.c + gcc -Wall -c -g -pg -o ai.o ai.c attack.o: attack.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h attack.h astar.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o attack.o attack.c + gcc -Wall -c -g -pg -o attack.o attack.c astar.o: astar.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h attack.h astar.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o astar.o astar.c + gcc -Wall -c -g -pg -o astar.o astar.c data.o: data.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h data.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o data.o data.c + gcc -Wall -c -g -pg -o data.o data.c findleak.o: findleak.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h findleak.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o findleak.o findleak.c + gcc -Wall -c -g -pg -o findleak.o findleak.c flag.o: flag.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h flag.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o flag.o flag.c + gcc -Wall -c -g -pg -o flag.o flag.c god.o: god.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h god.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o god.o god.c + gcc -Wall -c -g -pg -o god.o god.c io.o: io.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h io.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o io.o io.c + gcc -Wall -c -g -pg -o io.o io.c lf.o: lf.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h lf.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o lf.o lf.c + gcc -Wall -c -g -pg -o lf.o lf.c map.o: map.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h map.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o map.o map.c + gcc -Wall -c -g -pg -o map.o map.c move.o: move.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h move.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o move.o move.c + gcc -Wall -c -g -pg -o move.o move.c nexus.o: nexus.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h nexus.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o nexus.o nexus.c + gcc -Wall -c -g -pg -o nexus.o nexus.c objects.o: objects.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h objects.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o objects.o objects.c + gcc -Wall -c -g -pg -o objects.o objects.c save.o: save.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h save.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o save.o save.c + gcc -Wall -c -g -pg -o save.o save.c shops.o: shops.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h shops.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o shops.o shops.c + gcc -Wall -c -g -pg -o shops.o shops.c spell.o: spell.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h spell.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o spell.o spell.c + gcc -Wall -c -g -pg -o spell.o spell.c text.o: text.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h text.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o text.o text.c + gcc -Wall -c -g -pg -o text.o text.c vault.o: vault.c ai.h attack.h astar.h data.h defs.h findleak.h flag.h god.h io.h lf.h map.h move.h vault.h objects.h save.h shops.h spell.h text.h vault.h - gcc -Wall -c -g -o vault.o vault.c + gcc -Wall -c -g -pg -o vault.o vault.c ###################### diff --git a/ai.c b/ai.c index 807ee6c..3a6bf22 100644 --- a/ai.c +++ b/ai.c @@ -1596,8 +1596,9 @@ int ai_housekeeping(lifeform_t *lf, lifeform_t *master) { if (lfhasflag(lf, F_RAGE)) return B_FALSE; - if (lfhasflag(lf, F_ISPRISONER) && master && isplayer(master) && cansee(lf, master)) { - if (isoutdoors(lf->cell->map) && pctchance(20)) { + if (lfhasflag(lf, F_ISPRISONER) && master && isplayer(master) && + (cansee(lf, master) || isadjacent(lf->cell,master->cell))) { + if (isoutdoors(lf->cell->map) && pctchance(85)) { object_t *o; say(lf, "Thanks for getting me out!", SV_TALK); o = addobfast(master->pack, OT_MANUAL); @@ -1680,13 +1681,15 @@ int ai_inventory_mgt(lifeform_t *lf, int *canattack) { object_t *curgun,*bestgun; enum BODYPART bp; int icanattack = B_FALSE; + enum ATTRBRACKET iqb; + iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); if (lfhasflag(lf, F_DEBUG)) db = B_TRUE; if (lfhasflag(lf, F_RAGE)) return B_FALSE; // burdened? - if (isburdened(lf)) { + if (isburdened(lf) && (iqb >= IQ_ANIMAL)) { object_t *o,*heaviest = NULL; float hevweight = 0; @@ -1717,69 +1720,74 @@ int ai_inventory_mgt(lifeform_t *lf, int *canattack) { if (db) dblog(".oO { couldn't drop anything }"); } + // do we have a better weapon we could use? - curwep = getweapon(lf); - bestwep = getbestweapon(lf); + + if (iqb >= AT_AVERAGE) { + curwep = getweapon(lf); + bestwep = getbestweapon(lf); - if ((curwep != bestwep) && !isfirearm(curwep)) { - if (db) dblog(".oO { i have a better weapon than my current one (%s > %s) }",bestwep->type->name, curwep ? curwep->type->name : "nothing"); - // weild better one - if (!weild(lf, bestwep)) return B_TRUE; - } - - // do we have a better firearm ? - curgun = getfirearm(lf); - if (curwep && istwohandedfor(curwep, lf)) { - // we are using a two handed weapon. don't - // check for guns. - } else { - bestgun = getbestfirearm(lf); - - if (curgun != bestgun) { - if (db) dblog(".oO { i have a better gun than my current one (%s > %s) }",bestgun->type->name, curgun ? curgun->type->name : "nothing"); + if ((curwep != bestwep) && !isfirearm(curwep)) { + if (db) dblog(".oO { i have a better weapon than my current one (%s > %s) }",bestwep->type->name, curwep ? curwep->type->name : "nothing"); // weild better one - if (!weild(lf, bestgun)) return B_TRUE; + if (!weild(lf, bestwep)) return B_TRUE; } - } - // do we have ammo for an empty gun? - if (curgun) { - object_t *curammo; - curammo = getammo(curgun); - if (!curammo) { - o = getrandomammo(lf); - if (o && !loadfirearm(lf, curgun, o)) { - // success - return B_TRUE; + // do we have a better firearm ? + curgun = getfirearm(lf); + if (curwep && istwohandedfor(curwep, lf)) { + // we are using a two handed weapon. don't + // check for guns. + } else { + bestgun = getbestfirearm(lf); + + if (curgun != bestgun) { + if (db) dblog(".oO { i have a better gun than my current one (%s > %s) }",bestgun->type->name, curgun ? curgun->type->name : "nothing"); + // weild better one + if (!weild(lf, bestgun)) return B_TRUE; } } - } - // do we have better armour? - for (i = 0; i < lf->race->nbodyparts; i++) { - object_t *curarm; - bp = lf->race->bodypart[i].id; - curarm = getarmour(lf, bp); - // is it red hot? - if (curarm && hasflag(curarm->flags, F_HOT) && !isimmuneto(lf->flags, DT_FIRE, B_FALSE)) { - if (db) dblog("%s o O { wearing a red-hot item. will try to remove it. } ", lf->race->name); - if (cantakeoff(lf, curarm, NULL)) { - if (!takeoff(lf, curarm)) { + // do we have ammo for an empty gun? + if (curgun) { + object_t *curammo; + curammo = getammo(curgun); + if (!curammo) { + o = getrandomammo(lf); + if (o && !loadfirearm(lf, curgun, o)) { + // success return B_TRUE; } - } else { - if (db) dblog("%s o O { cannot remove it. maybe cursed? } ", lf->race->name); } } - // do we have a better one? - for (o = lf->pack->first ; o ; o = o->next) { - if (!isdangerousob(o, lf, B_TRUE) && canwear(lf, o, bp) && isbetterarmourthan(o, curarm)) { - // wear this armour instead - if (!wear(lf, o)) return B_TRUE; - } + } + + if (iqb >= AT_GTAVERAGE) { + // do we have better armour? + for (i = 0; i < lf->race->nbodyparts; i++) { + object_t *curarm; + bp = lf->race->bodypart[i].id; + curarm = getarmour(lf, bp); + // is it red hot? + if (curarm && hasflag(curarm->flags, F_HOT) && !isimmuneto(lf->flags, DT_FIRE, B_FALSE)) { + if (db) dblog("%s o O { wearing a red-hot item. will try to remove it. } ", lf->race->name); + if (cantakeoff(lf, curarm, NULL)) { + if (!takeoff(lf, curarm)) { + return B_TRUE; + } + } else { + if (db) dblog("%s o O { cannot remove it. maybe cursed? } ", lf->race->name); + } + } + // do we have a better one? + for (o = lf->pack->first ; o ; o = o->next) { + if (!isdangerousob(o, lf, B_TRUE) && canwear(lf, o, bp) && isbetterarmourthan(o, curarm)) { + // wear this armour instead + if (!wear(lf, o)) return B_TRUE; + } + } } } - // now check whetehr we have ANY weapon @@ -2310,6 +2318,8 @@ int aimovetotargetcell(lifeform_t *lf, flag_t *f) { int x,y; cell_t *c = NULL,*origc,*targetc; int db = B_FALSE; + enum ATTRBRACKET iqb; + iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); if (lfhasflag(lf, F_DEBUG)) { db = B_TRUE; @@ -2328,8 +2338,10 @@ int aimovetotargetcell(lifeform_t *lf, flag_t *f) { // do we ahv an existing path? pathf = lfhasflag(lf, F_AIPATH); if (!pathf) { - // if we DONT have a direct path, then pathfind. - pathf = ai_createpathto(lf, targetc); + if (iqb >= IQ_ANIMAL) { + // if we DONT have a direct path, then pathfind. + pathf = ai_createpathto(lf, targetc); + } } if (pathf) { diff --git a/attack.c b/attack.c index d51e472..03389d3 100644 --- a/attack.c +++ b/attack.c @@ -1636,7 +1636,7 @@ 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)) { + } else if ((lf->race->id == R_STIRGE) || (lf->race->baseid == R_LEECH)) { if (getexposedlimbs(victim)) { // automatically latch on if (!lfhasflag(victim, F_NONCORPOREAL) && !hasflag(lf->flags, F_ATTACHEDTO)) { @@ -3296,7 +3296,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu } } - getflags(fp, retflag, &nretflags, F_AUTOTANGLE, F_DRAINONHIT, F_FLAMESTRIKE, F_HEAVYBLOW, F_HITCONFER, + getflags(fp, retflag, &nretflags, F_AUTOTANGLE, F_DRAINONHIT, F_DRAINATTONHIT, F_FLAMESTRIKE, F_HEAVYBLOW, F_HITCONFER, F_RACESLAY, F_REVENGE, F_RUSTED, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -3312,6 +3312,10 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isu gainhp(owner, roll(f->text)); } } + } else if ((f->id == F_DRAINATTONHIT) && victim && !isdead(victim)) { + int amt; + amt = roll(f->text); + statdrain(victim, f->val[0], amt, f->val[1], f->val[2], owner); } else if (f->id == F_FLAMESTRIKE) { if (!hasob(where->obpile, OT_FIRESMALL)) { // ignite diff --git a/data.c b/data.c index 08709d4..8efa2a6 100644 --- a/data.c +++ b/data.c @@ -306,8 +306,11 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_THROWING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_LANGUAGE, PR_NOVICE, NA, NULL); // learnable skills @@ -2826,12 +2829,18 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); // "traps" - hiding monsters + addot(OT_COINSHIDING, "coins", "A sneaky hidden creeping coins!", MT_GOLD, 0.01, OC_TRAP, SZ_MINI); + addflag(lastot->flags, F_GLYPH, C_YELLOW, '$', NA, NULL); + addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ISMONSTER, R_COINS, OT_GOLD, 150, "3,5d10+50"); // reveal if within 3 cells + addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addot(OT_GARGOYLE, "gargoyle", "A sneaky hidden gargoyle!", MT_STONE, 80, OC_TRAP, SZ_HUMAN); addflag(lastot->flags, F_GLYPH, C_STONE, '\'', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_ISMONSTER, R_GARGOYLE, OT_STATUE, 140, "3"); // reveal if within 3 cells + addflag(lastot->flags, F_ISMONSTER, R_GARGOYLE, OT_STATUE, 140, "3,1"); // reveal if within 3 cells addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); // traps - object only @@ -5264,6 +5273,7 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addot(OT_S_MFEEDBACK, "mental feedback", "Assaults the target's brain with a mental feedback loop, dealing damage based on their intelligence.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Damage dealt is between 10% and 20% of target's intelligence."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Creatures with higher intelligence will take more damage."); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -5361,6 +5371,15 @@ void initobjects(void) { addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addot(OT_S_DRAINIQ, "drain intellect", "Mentally destroys some of the target's brain cells, resulting in a permenant loss of intelligence.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The target loses 2d6 + ^bpower^nd6 points of IQ."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l6 addot(OT_S_REMOTEKO, "remote ko", "Disable the conscious part of a creature's mind, instantly knocking it unconscious.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); @@ -5412,6 +5431,17 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_SUMMONSWARM, "summon swarm", "Summons a swarm of small creatures into existence to aid the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level I, a rat swarm is created."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level II, a spider swarm is created."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level III, a locust swarm is created."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l3 addot(OT_S_CREATEMONSTER, "create monster", "Summons a (probably hostile) monster to a nearby location.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power V you can control where the monster appears."); @@ -12231,6 +12261,38 @@ void initrace(void) { addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + // weight & hp come from amt of gold held. + addrace(R_COINS, "creeping coin pile", 50, '\'', C_YELLOW, MT_GOLD, RC_MAGIC, "These magically animated gold coins are often used as traps by paranoid wizards."); + addbodypart(lastrace, BP_BODY, "metal"); + addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, NULL); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "50-100 gold coins"); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_GETKILLEDVERB, NA, NA, NA, "defeat"); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_MASTERVAULTS, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 6, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOSTAM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOTAKECRITS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NONAUSEA, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_CLOUDKILL, NA, NA, "pw:1;range:1;"); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_PRETENDSTOBE, OT_GOLD, NA, NA, NULL); + addrace(R_DARKMANTLE, "darklurk", 70, 'U', C_DARKBLUE, MT_FLESH, RC_MAGIC, "A floating squid-like creature, rarely seen due to its ability to cloak itself in a magical darkness. They use their huge tentacles to grab then crush their unsuspecting prey."); addbodypart(lastrace, BP_BODY, NULL); addbodypart(lastrace, BP_LEGS, "tentacles"); @@ -15638,8 +15700,8 @@ void initrace(void) { addflag(lastrace->flags, F_EATCONFER, F_MUTABLE, B_TRUE, NA, "100"); addrace(R_BATBRAIN, "brain bat", 6, 'B', C_PINK, MT_FLESH, RC_ANIMAL, "Rare bats, said to exhibit strange psionic behaviour."); setbodytype(lastrace, BT_BIRD); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); - addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); @@ -15869,7 +15931,7 @@ void initrace(void) { addflag(lastrace->flags, F_FELINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACEWITHFLAG, F_CANINE, NA, NA, NULL); - addrace(R_CATSHADOW, "shadowcat", 5, 'f', C_DARKGREY, MT_FLESH, RC_MAGIC, "A huge, feral black cat, surrounded by clouds of black smoke."); + addrace(R_CATSHADOW, "shadowcat", 5, 'f', C_VDARKGREY, MT_FLESH, RC_MAGIC, "A huge, feral black cat, surrounded by clouds of black smoke."); setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -16821,6 +16883,78 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "slither"); + addrace(R_LEECHMIND, "baby mind leech", 10, 'j', C_PINK, MT_FLESH, RC_ANIMAL, "A mutated form of leech which feeds on one's intellect."); + addbodypart(lastrace, BP_BODY, NULL); + lastrace->baseid = R_LEECH; + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_VULNTOSALT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, 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, NA, RR_VERYRARE, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_VERYRARE, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); + addflag(lastrace->flags, F_NOPACK, 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_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:2;"); + addflag(lastrace->flags, F_CANWILL, OT_S_MINDWHIP, NA, NA, "range:1;pw:1;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_MINDWHIP, NA, NA, "sways"); + addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); + addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "slither"); + + addrace(R_LEECHMINDA, "mind leech", 10, 'j', C_LIGHTPINK, MT_FLESH, RC_ANIMAL, "A mutated form of leech which feeds on one's intellect."); + addbodypart(lastrace, BP_BODY, NULL); + lastrace->baseid = R_LEECH; + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_VULNTOSALT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, 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, NA, RR_VERYRARE, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_VERYRARE, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); + addflag(lastrace->flags, F_NOPACK, 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_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:2;"); + addflag(lastrace->flags, F_CANWILL, OT_S_MFEEDBACK, NA, NA, "range:1;pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_DRAINIQ, NA, NA, "range:1;pw:2;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_MFEEDBACK, NA, NA, "sways"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_DRAINIQ, NA, NA, "sways"); + addflag(lastrace->flags, F_CASTCHANCE, 80, NA, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); + addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "slither"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_MAGIC, BLOODFORPOT, NA, NULL); + addflag(lastrace->flags, F_EATCONFER, F_ATTRMOD, A_IQ, 10, "75"); + addrace(R_MAMMOTH, "mammoth", 6000, 'Q', C_DARKYELLOW, MT_LEATHER, RC_ANIMAL, "A massive ancenstor of the elephant, mammoths are covered with fur, slightly larger and more dangerous."); setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); @@ -16973,6 +17107,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^squeaking"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 1, NA, "squeaks^squeaking"); + addrace(R_RATMIND, "mesmerat", 3, 'r', C_PINK, MT_FLESH, RC_ANIMAL, "Glowing, irradiated rats which have developed amazing intellects and mental powers."); setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); @@ -17480,6 +17615,36 @@ void initrace(void) { addflag(lastrace->flags, F_FLEEONHPPCT, 25, NA, NA, ""); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "creep"); + addrace(R_SPIDERPHASE, "phase spider", 5, 'S', C_PINK, MT_FLESH, RC_DEMON, "A strange eight legged beast which seems to be vaguely translucent."); + setbodytype(lastrace, BT_SPIDER); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_NONAUSEA, B_TRUE, NA, 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_NONCORPOREAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_XRAYVIS, 3, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 4, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, NULL); // don't announce spellcasting + addflag(lastrace->flags, F_SPIDERCLIMB, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 100, "20-30"); + addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL); // weak + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "creep"); + addrace(R_SPIDERFUNNELWEB, "giant funnelweb", 5, 'S', C_MAGENTA, MT_FLESH, RC_ANIMAL, "Like a giant spider... but extremely venomous."); setbodytype(lastrace, BT_SPIDER); lastrace->baseid = R_SPIDER; @@ -17562,33 +17727,6 @@ void initrace(void) { addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "creep"); addflag(lastrace->flags, F_FILLPOT, OT_POT_POISON, BLOODFORPOT, NA, NULL); - addrace(R_SPIDERSWARM, "swarm of spiders", 10, UNI_SWARM, C_DARKGREY, MT_FLESH, RC_HUMANOID, "A fast-moving swarm of deadly spiders."); - addbodypart(lastrace, BP_BODY, "swarm"); - addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); - addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL); - addflag(lastrace->flags, F_RARITY, H_MASTERVAULTS, NA, RR_UNCOMMON, NULL); - addflag(lastrace->flags, F_GETKILLEDVERB, NA, NA, NA, "disperse"); - addflag(lastrace->flags, F_NOTAKECRITS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOGIVECRITS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); - addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); - addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL); - addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); - addflag(lastrace->flags, F_MAXATTACKS, 7, 7, NA, NULL); - addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_SWARM, NA, NA, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_STR, AT_VLOW, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_AGI, AT_HIGH, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_WIS, AT_VLOW, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL); - addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addrace(R_SPIDERTOMB, "tomb spider", 5, 'S', C_DARKBLUE, MT_FLESH, RC_ANIMAL, "Tomb spiders are truly nightmarish beings. Their skin can absorb light itself, and they can boost their own life force by consuming the flesh of their victims."); setbodytype(lastrace, BT_SPIDER); @@ -17628,6 +17766,95 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "creep"); + addrace(R_SWARMLOCUST, "swarm of locusts", 50, UNI_SWARM, C_GREY, MT_FLESH, RC_INSECT, "An enormous swarm of angry locusts."); + addbodypart(lastrace, BP_BODY, "swarm"); + addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_MASTERVAULTS, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_GETKILLEDVERB, NA, NA, NA, "disperse"); + addflag(lastrace->flags, F_NOTAKECRITS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOGIVECRITS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 6, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 8, 8, NA, NULL); + addflag(lastrace->flags, F_STENCH, 1, 2, NA, NULL); + addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOSTAM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SWARM, NA, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, SV_TALK, NA, "^buzzing wings"); + addflag(lastrace->flags, F_NATURALFLIGHT, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_CANWILL, OT_A_FLY, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_A_FLY, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_FLIGHT, PR_BEGINNER, NA, NULL); + + addrace(R_SWARMRAT, "swarm of rats", 40, UNI_SWARM, C_BROWN, MT_FLESH, RC_ANIMAL, "A large swarm of vile rodents."); + addbodypart(lastrace, BP_BODY, "swarm"); + addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_MASTERVAULTS, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_GETKILLEDVERB, NA, NA, NA, "disperse"); + addflag(lastrace->flags, F_NOTAKECRITS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOGIVECRITS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 3, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 5, 5, NA, NULL); + addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SWARM, NA, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); + + addrace(R_SWARMSPIDER, "swarm of spiders", 10, UNI_SWARM, C_DARKGREY, MT_FLESH, RC_ANIMAL, "A fast-moving swarm of deadly spiders."); + addbodypart(lastrace, BP_BODY, "swarm"); + addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_MASTERVAULTS, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_GETKILLEDVERB, NA, NA, NA, "disperse"); + addflag(lastrace->flags, F_NOTAKECRITS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOGIVECRITS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, 15, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 7, 7, NA, NULL); + addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SWARM, NA, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); + addrace(R_SWAN, "swan", 1, 'c', C_WHITE, MT_FLESH, RC_ANIMAL, "A graceful waterbird."); setbodytype(lastrace, BT_BIRD); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); @@ -17769,6 +17996,7 @@ void initrace(void) { addrace(R_WOLFWINTER, "winter wolf", 25, 'd', C_WHITE, MT_FLESH, RC_ANIMAL, "Wolves which have lived in close proximity to the undead sometimes mutate into these frosty beasts. While their claws have become less sharp, they instead deal unnatural cold damage."); setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); + addflag(lastrace->flags, F_TERRITORIAL, 3, NA , NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); @@ -18467,7 +18695,7 @@ void initrace(void) { addbodypart(lastrace, BP_TAIL, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL); addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); @@ -19326,6 +19554,38 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "growls^a growl"); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addrace(R_SHADOW, "shadow", 0.01, 'Z', C_DARKGREY, MT_FLESH, RC_UNDEAD, "A dark shadowy shape which seems to move on its own..."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_EXLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_NOSTAIRS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TOUCHNECROTIC, 3, NA, NULL); + addflag(lastrace->flags, F_HITCONFER, F_REVIVETIMER, NA, 0, NULL); + addflag(lastrace->flags, F_HITCONFERVALS, 0, 1, R_SHADOW, "rises up as a shadow"); + addflag(lastrace->flags, F_HITCONFERRC, RC_HUMANOID, NA, NA, NULL); + addflag(lastrace->flags, F_HITCONFERDEADONLY, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DRAINATTONHIT, A_STR, SC_NONE, -1, "3d6"); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addrace(R_SKELETON, "skeleton", 20, 'Z', C_BONE, MT_BONE, RC_UNDEAD, "A walking set of bones, animated through the use of necromancy. Due to their lack of soft flesh, they have little to fear from edged weapons."); setbodytype(lastrace, BT_HUMANOID); setbodypartname(lastrace, BP_WEAPON, "right metacarpals"); @@ -19454,7 +19714,7 @@ void initrace(void) { addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); diff --git a/defs.h b/defs.h index 553e961..e0df73a 100644 --- a/defs.h +++ b/defs.h @@ -738,6 +738,7 @@ enum COLOUR { C_LIGHTMAGENTA, C_LIGHTRED, C_LIGHTYELLOW, + C_LIGHTPINK, C_LAST }; @@ -966,6 +967,7 @@ enum ATTRIB { #define MAXATTS 6 enum CHECKTYPE { + SC_NONE = 0, SC_STR, SC_DEX, SC_IQ, @@ -1297,6 +1299,7 @@ enum RACE { R_CENTAUR, R_CHIMERA, R_COCKATRICE, + R_COINS, R_CREEPINGCLAW, R_CRYMIDIA, R_DARKMANTLE, @@ -1439,6 +1442,8 @@ enum RACE { R_HORSE, R_FROG, R_LEECH, + R_LEECHMIND, + R_LEECHMINDA, R_MAMMOTH, R_NEWT, R_PORCUPINE, @@ -1459,11 +1464,14 @@ enum RACE { R_SNAKETREE, R_SNAKEWATER, R_SPIDER, + R_SPIDERPHASE, R_SPIDERFUNNELWEB, R_SPIDERREDBACK, - R_SPIDERSWARM, R_SPIDERTOMB, R_SWAN, + R_SWARMSPIDER, + R_SWARMRAT, + R_SWARMLOCUST, R_WOLFYOUNG, R_WOLF, R_WOLFDIRE, @@ -1521,6 +1529,7 @@ enum RACE { R_MUMMY, R_MUMMYG, R_REVENANT, + R_SHADOW, R_SKELETON, R_SKELETONFIRE, R_SKELLION, @@ -1732,6 +1741,7 @@ enum OBTYPE { OT_TRAPTRIP, OT_TRAPWIND, // traps - hiding monsters + OT_COINSHIDING, OT_GARGOYLE, // rocks OT_ASH, @@ -2030,6 +2040,7 @@ enum OBTYPE { OT_S_CHISTRIKE, OT_S_DELAYDEATH, OT_S_DISORIENT, + OT_S_DRAINIQ, OT_S_HUNGER, OT_S_LETHARGY, OT_S_LOWERMETAB, @@ -2101,6 +2112,7 @@ enum OBTYPE { OT_S_GLYPHWARDING, OT_S_CLEARLEVEL, OT_S_CREATEMONSTER, + OT_S_SUMMONSWARM, OT_S_SUMMONWEAPON, // -- translocation OT_S_APPORTATION, @@ -2995,7 +3007,9 @@ enum FLAG { // v0 = race id of monster // v1 = object id to hide as // v2 = spot check difficulty (or NA) - // text = reveal ourselves if prey <= this distance + // text = dist,xdy + // dist = reveal ourselves if prey <= dist + // xdy = dice string amount of obs to appear // // Also see: F_PRETENDSTOBE @@ -3039,8 +3053,12 @@ enum FLAG { F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit F_DRAINONHIT, // victims hit by this lf get v0 xplevs drained unless // they pass a skillcheck of type v1, diff v2. - // v1 can be NA. + // v1 can be SC_NONE. // if successful, lf gains 'text' hp (in dice format) + F_DRAINATTONHIT, // victims hit by this lf lose 'text' (dice format) + // from attrib v0, unless they make a skill check + // of type v1, diff v2. v1 can be SC_NONE. + // if ATT drops to zero, target dies. F_HITCONFER, // hitting with this gives flagid=v0 // with timeleft = text ("min-max" // or NULL for permenant) diff --git a/god.c b/god.c index acaf590..7076465 100644 --- a/god.c +++ b/god.c @@ -2328,6 +2328,9 @@ int prayto(lifeform_t *lf, lifeform_t *god) { dospelleffects(god, OT_S_CUREPOISON, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_FALSE, NULL); } + // fix drained stats + restoredrainedstats(lf); + if (isinbattle(lf, B_INCLUDEDISTANT, B_FALSE)) { int i,nretflags; flag_t *retflag[MAXCANDIDATES]; diff --git a/io.c b/io.c index 483970f..c1ddc7a 100644 --- a/io.c +++ b/io.c @@ -9768,6 +9768,7 @@ void initgfx(void) { initcol(C_LIGHTGREEN, 500, 1000, 500); initcol(C_LIGHTMAGENTA, 1000, 500, 1000); initcol(C_LIGHTYELLOW, 1000, 1000, 500); + initcol(C_PINK, 1000, 584, 776); // placeholder initcol(C_LAST, 0, 0, 0); @@ -13392,7 +13393,7 @@ void showlfstats(lifeform_t *lf, int showall) { if (!lfhasflag(lf, F_NOSTAM)) { pen = gettempstammod(lf, temp); if (pen != 100) { - mvwprintw(mainwin, y, 0, " %d%% Stamina usage due to heat.",pen); y++; + mvwprintw(mainwin, y, 0, " %d%% stamina usage due to heat.",pen); y++; } } if (!lfhasflag(lf, F_NOSLEEP) && (temp >= T_HOT)) { diff --git a/lf.c b/lf.c index 8cd35bf..18b3876 100644 --- a/lf.c +++ b/lf.c @@ -3293,6 +3293,8 @@ void die(lifeform_t *lf) { if (hunger > 0) { modhunger(lf, -hunger); } + // fix drained attribs + restoredrainedstats(lf); // put out fires extinguishlf(lf); if (thisisplayer) { @@ -5351,6 +5353,9 @@ int eat(lifeform_t *lf, object_t *o) { // blink! dospelleffects(lf, OT_S_BLINK, 1, lf, NULL, NULL, B_UNCURSED, NULL, B_TRUE, NULL); + stopeating = B_TRUE; + } else if (hasflagval(o->flags, F_CORPSEOF, R_SPIDERPHASE, NA, NA, NULL)) { + addtempflag(lf->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL, 15); stopeating = B_TRUE; } else if (hasflagval(o->flags, F_CORPSEOF, R_BLASTBUG, NA, NA, NULL)) { dospelleffects(lf, OT_S_DETONATE, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE, NULL); @@ -13695,7 +13700,6 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR return B_FALSE; } - // return TRUE on failure int leveldrain(lifeform_t *lf, int amt, enum CHECKTYPE sctype, int scdiff, lifeform_t *fromlf) { int resisted = B_FALSE; @@ -14733,6 +14737,7 @@ int isfullyhealed(lifeform_t *lf) { } int isexhausted(lifeform_t *lf) { + if (lfhasflag(lf, F_NOSTAM)) return B_FALSE; if (!getstamina(lf)) return B_TRUE; return B_FALSE; } @@ -18228,6 +18233,11 @@ int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o, int *pctmod) { int mightflee(lifeform_t *lf) { flag_t *f; enum ATTRBRACKET iqb; + iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); + if (iqb < IQ_ANIMAL) { + // too stupid to know to flee + return B_FALSE; + } if (hasflag(lf->flags, F_NOFLEE)) { return B_FALSE; @@ -22308,6 +22318,8 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r int roll,db = B_FALSE; char dbtag[BUFLEN]; + if (ct == SC_NONE) return B_FALSE; + if (lfhasflag(lf, F_DEBUG)) { if (ct != SC_STEALTH) { // dont show debug info for stealth checks db = B_TRUE; @@ -22367,6 +22379,18 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r return B_FALSE; } +int restoredrainedstats(lifeform_t *lf) { + enum ATTRIB a; + int donesomething = B_FALSE; + for (a = 0; a < MAXATTS; a++) { + if ((lf->baseatt[a] > 0) && (getattr(lf, a) <= 0)) { + setattr(lf, a, lf->baseatt[a]); + donesomething = B_TRUE; + } + } + return donesomething; +} + // returns TRUE if lf1 succeeded, FALSE if lf1 failed. int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, enum CHECKTYPE ct2, int mod2) { int roll1,roll2; @@ -22531,6 +22555,44 @@ void sortlf(map_t *map, lifeform_t *lf) { } } +// return TRUE on failure +int statdrain(lifeform_t *lf, enum ATTRIB attr, int amt, enum CHECKTYPE sctype, int scdiff, lifeform_t *fromlf) { + int resisted = B_FALSE; + if (isimmuneto(lf->flags, DT_NECROTIC, B_FALSE)) resisted = B_TRUE; + if (!resisted && isresistantto(lf->flags, DT_NECROTIC, B_FALSE) && onein(2)) resisted = B_TRUE; + + // skill check + if (!resisted && skillcheck(lf, sctype, scdiff, 0 )) { + resisted = B_TRUE; + } + if (resisted) { + if (isplayer(lf)) { + msg("You struggle to retain your %s!", getattrname(attr)); + } + return B_TRUE; + } + + // announce + if (fromlf) { + char lfname[BUFLEN]; + char buf[BUFLEN]; + sprintf(buf, "%s-drained",getattrname(attr)); + setkillverb(lf, buf); + real_getlfnamea(fromlf, lfname, NULL, B_TRUE, B_TRUE); + setlastdam(lf, lfname); + } else { + char buf[BUFLEN]; + sprintf(buf, "%s drain",getattrname(attr)); + setkillverb(lf, "Killed"); + setlastdam(lf, buf); + } + if (fromlf) { + lf->lastdamlf = fromlf->id; + } + modattr(lf, attr, -amt); + return B_FALSE; +} + ////////////////////////////////// // effects which happen before every TURN // (ie. the faster the player is, the faster they happen) @@ -22551,6 +22613,7 @@ void startlfturn(lifeform_t *lf) { int nretflags; int movedlastturn = B_FALSE; object_t *bloodamu = NULL; + enum ATTRIB a; enum TIMEPHASE tp; enum FLAG inair = F_NONE; enum TEMPERATURE temp; @@ -22701,7 +22764,7 @@ void startlfturn(lifeform_t *lf) { if (!cellwalkable(lf, lf->cell, &error)) { if ((error == E_WALLINWAY) && !isclimbing(lf)) { if (isplayer(lf)) { - msg("You reintegrate inside a solid object!"); + msg("^%cYou reintegrate inside a solid object!",getlfcol(lf, CC_VBAD)); } losehp(lf, 9999, DT_DIRECT, NULL, "re-integration inside a solid object"); //} @@ -23497,6 +23560,21 @@ void startlfturn(lifeform_t *lf) { ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// + for (a = 0; a < MAXATTS; a++) { + if ((lf->baseatt[a] > 0) && (getattr(lf, a) <= 0)) { + char buf[BUFLEN]; + sprintf(buf, "%s drain",getattrname(a)); + setkillverb(lf, "Killed"); + setlastdam(lf, buf); + if (isplayer(lf)) { + msg("^%cThe last of your %s drains away...", getlfcol(lf, CC_VBAD), getattrname(a)); more(); + } + lf->hp = 0; + return; + } + } + + o = hasequippedobid(lf->pack, OT_AMU_CHOKING); if (o && needstobreath(lf)) { int seen = B_FALSE; diff --git a/lf.h b/lf.h index d918d01..9389b55 100644 --- a/lf.h +++ b/lf.h @@ -518,9 +518,11 @@ int shoot(lifeform_t *lf); int getskillcheckchance(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod) ; int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod); int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *result); +int restoredrainedstats(lifeform_t *lf); int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, enum CHECKTYPE ct2, int mod2); int slipon(lifeform_t *lf, object_t *o); void sortlf(map_t *map, lifeform_t *lf); +int statdrain(lifeform_t *lf, enum ATTRIB attr, int amt, enum CHECKTYPE sctype, int scdiff, lifeform_t *fromlf); void startlfturn(lifeform_t *lf); int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag); int stir(lifeform_t *lf, int vol, int dist, char *noisetext); diff --git a/map.c b/map.c index ea3ecad..619efa7 100644 --- a/map.c +++ b/map.c @@ -2639,7 +2639,7 @@ void floodfill(cell_t *startcell) { int d; object_t *o; if (startcell && // not off the map - !startcell->type->solid && // empty cell + (!startcell->type->solid || (startcell->type->id == CT_WALLGLASS)) && // empty cell !startcell->filled) { // not already filled startcell->filled = B_TRUE; } else { @@ -8768,7 +8768,7 @@ void initmap(void) { addbranch(BH_BABAYAGAHUT, "Baba Yaga's Hut", B_FALSE, H_BYHUT, 0, 0, D_NONE, B_FALSE, 0, B_FALSE); - addbranch(BH_WORLDMAP, "The Surface", B_FALSE, H_FOREST, 10, 0, D_NONE, B_TRUE, 0, B_FALSE); + addbranch(BH_WORLDMAP, "The Surface", B_FALSE, H_FOREST, 10, 0, D_NONE, B_TRUE, 20, B_FALSE); addbranch(BH_HEAVEN, "The Realm of Gods", B_FALSE, H_HEAVEN, 1, 0, D_NONE, B_FALSE, 0, B_FALSE); // main branches addbranch(BH_MAINDUNGEON, "The Main Dungeon", B_FALSE, H_DUNGEON, 25, 3, D_DOWN, B_TRUE, 0, B_FALSE); diff --git a/move.c b/move.c index 1d3788b..7c17eec 100644 --- a/move.c +++ b/move.c @@ -3527,7 +3527,13 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { // act of moving will clear the message line and we'll never // see it. if (isplayer(lf)) { - msg("You swap places with %s.", lfname); + if (isunconscious(lfinway)) { + msg("You swap places with the unconscious %s.", noprefix(lfname)); + } else if (isasleep(lfinway)) { + msg("You swap places with the sleeping %s.", noprefix(lfname)); + } else { + msg("You swap places with %s.", lfname); + } dontclearmsg = B_TRUE; } diff --git a/objects.c b/objects.c index d88d7d6..a48e39c 100644 --- a/objects.c +++ b/objects.c @@ -1583,9 +1583,16 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum // hiding monsters? f = hasflag(o->flags, F_ISMONSTER); if (f) { + char *cp,nbuf[BUFLEN]; + int amt; object_t *oo; oo = addobfast(o->contents, f->val[1]); assert(oo); + cp = readuntil(nbuf,f->text, ','); + cp = readuntil(nbuf,cp, '-'); // really eol + amt = roll(nbuf); + if (amt < 0) amt = 1; + oo->amt = amt; } // extra chance of bone items being cursed @@ -5825,7 +5832,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan cell_t *where; int no_a = B_FALSE; flag_t *retflag[MAXCANDIDATES]; - int nretflags = 0; + int nretflags = 0,i; // default to normal name /* @@ -5838,7 +5845,11 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan if (hasflag(o->flags, F_ISMONSTER)) { if (o->contents->first) { + if ((count == o->amt) || (count == ALL)) { + count = o->contents->first->amt; + } o = o->contents->first; + limit(&count, 1, o->amt); } } @@ -5856,8 +5867,8 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan float pct; char dname[BUFLEN]; char adjective[BUFLEN]; - lifeform_t *who = NULL; + pct = ((float)f->lifetime / (float)TM_SCENT)*100; if (pct >= 66) { strcpy(adjective, "strong "); @@ -6369,29 +6380,31 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan // include mods if identified // ie. a blessed flaming +5 silver sword ->of pyromania<- - for (br = firstbrand; br; br = br->next) { - if (hasflagval(o->flags, F_HASBRAND, br->id, NA, NA, NULL)) { - flag_t *brf; - int ok = B_TRUE; - // are all of the brand flags known? - for (brf = br->flags->first ; brf ; brf = brf->next) { - int i; - getflags(o->flags, retflag, &nretflags, brf->id, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - if (f->lifetime == FROMBRAND) { - if (f->known || showall) { - } else { - ok = B_FALSE; - hasunknownmod = B_TRUE; - break; - } + getflags(o->flags, retflag, &nretflags, F_HASBRAND, F_NONE); + for (i = 0; i < nretflags; i++) { + flag_t *brf; + int ok = B_TRUE; + f = retflag[i]; + br = findbrand(f->val[0]); + // are all of the brand flags known? + for (brf = br->flags->first ; brf ; brf = brf->next) { + flag_t *retflag2[MAXCANDIDATES],*f2; + int nretflags2 = 0,n; + getflags(o->flags, retflag2, &nretflags2, brf->id, F_NONE); + for (n = 0; n < nretflags2; n++) { + f2 = retflag2[n]; + if (f2->lifetime == FROMBRAND) { + if (f2->known || showall) { + } else { + ok = B_FALSE; + hasunknownmod = B_TRUE; + break; } } } - if (ok) { - strcat(localbuf, br->suffix); - } + } + if (ok) { + strcat(localbuf, br->suffix); } } @@ -15467,8 +15480,6 @@ void timeeffectsob(object_t *o) { if (hasflag(o->flags, F_DEAD)) return; - getobname(o, obname, o->amt); - location = getoblocation(o); if (o->pile->owner) { owner = o->pile->owner; @@ -15481,6 +15492,12 @@ void timeeffectsob(object_t *o) { onground = B_TRUE; } + if (haslos(player, location)) { + getobname(o, obname, o->amt); + } else { + strcpy(obname, "?some_ob?"); + } + checkflagpile(o->flags); // special case for trail flags @@ -15555,7 +15572,9 @@ void timeeffectsob(object_t *o) { f = hasflag(o->flags, F_ISMONSTER); if (strlen(f->text)) { int dist; - dist = atoi(f->text); + char dbuf[BUFLEN]; + readuntil(dbuf, f->text, ','); + dist = atoi(dbuf); // player within reveal distance? if ((getcelldist(player->cell, location) <= dist) && !haslos(player, location)) { diff --git a/save.c b/save.c index fc6d4fa..16a363f 100644 --- a/save.c +++ b/save.c @@ -58,10 +58,11 @@ int loadflagpile(FILE *f, flagpile_t *fp) { flag_t *fl; char buf[BUFLEN]; int rv; + int skid; int db = B_FALSE; - rv = fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%ld\n", - &tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2],&tempflag.lifetime, &tempflag.known,&tempflag.obfrom); + rv = fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%ld,%d\n", + &tempflag.id, &tempflag.nvals, &tempflag.val[0], &tempflag.val[1], &tempflag.val[2],&tempflag.lifetime, &tempflag.known,&tempflag.obfrom,&skid); while (tempflag.id != -1) { dblog("got flag id=%d\n",tempflag.id); @@ -73,6 +74,7 @@ int loadflagpile(FILE *f, flagpile_t *fp) { tempflag.val[0], tempflag.val[1], tempflag.val[2], strcmp(buf, "^^^") ? buf : NULL, tempflag.lifetime, tempflag.known, tempflag.obfrom); + fl->skillfrom = findskill((enum SKILL)skid); if (db) { @@ -363,7 +365,7 @@ map_t *loadmap(FILE *f) { fgets(line, BUFLEN, f); //if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; - sscanf(line, "%d,%d,%d,%d,%d,%[ a-xA-Z_0-9+'*/-]\n",&m->room[i].id, + sscanf(line, "%d,%d,%d,%d,%d,%[ a-zA-Z_0-9+'*/-]\n",&m->room[i].id, &m->room[i].x1, &m->room[i].y1, &m->room[i].x2, &m->room[i].y2, buf); m->room[i].vault = findvault(buf); @@ -650,7 +652,7 @@ int loadregions(FILE *f) { fscanf(f, " thingdepth:%d,%d,%d\n",&depth, &x, &y); fscanf(f, " thingkind:%d\n",(int *)&whatkind); fscanf(f, " thingval:%d\n",&val); - fscanf(f, " thingwhat:%[ a-xA-Z_0-9+'*/-]\n",buf); + fscanf(f, " thingwhat:%[ a-zA-Z_0-9+'*/-]\n",buf); fscanf(f, "endthing\n"); // replace ^ with ' ' in thingwhat @@ -917,8 +919,8 @@ int saveflagpile(FILE *f, flagpile_t *fp) { flag_t *fl; fprintf(f, "flags:\n"); for (fl = fp->first ; fl ; fl = fl->next) { - fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%ld\n", - fl->id, fl->nvals, fl->val[0], fl->val[1], fl->val[2],fl->lifetime,fl->known,fl->obfrom); + fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%ld,%d\n", + fl->id, fl->nvals, fl->val[0], fl->val[1], fl->val[2],fl->lifetime,fl->known,fl->obfrom, fl->skillfrom->id); if (!fl->text || !strcmp(fl->text, "")) { fprintf(f, "%s\n","^^^"); } else { diff --git a/shops.c b/shops.c index 3612825..395cfd3 100644 --- a/shops.c +++ b/shops.c @@ -133,6 +133,15 @@ int getshopblessprice(object_t *o, object_t *shop) { return cost; } +int isalignedtemple(object_t *shop) { + flag_t *f; + f = hasflag(shop->flags, F_LINKGOD); + if (f && godprayedto(f->val[0])) { + return B_TRUE; + } + return B_FALSE; +} + int obmatchessellflag(object_t *o, flag_t *f, enum SHOPACTION action) { if ((f->val[0] == F_NONE) || hasflag(o->flags, f->val[0])) { if ((f->val[2] == NA) || (o->type->obclass->id == f->val[2])) { @@ -407,6 +416,7 @@ enum SHOPRETURN shopdetectcurse(lifeform_t *lf, object_t *vm, int starty, char * int y; int cost = 0,possible = B_TRUE; y = starty; + // calculate cost for (o = lf->pack->first ; o; o = o->next) { if (!o->blessknown && !hasflag(o->flags, F_NOBLESS)) { @@ -414,17 +424,23 @@ enum SHOPRETURN shopdetectcurse(lifeform_t *lf, object_t *vm, int starty, char * } } - if (cost) { - cost = applyshoppricemod(cost, lf, vm, SA_BUY); - } - if (!cost) { mvwprintw(mainwin, y, 0, "You do not seem to possess anything which merits our services."); y += 2; possible = B_FALSE; } else { + // aligned templte? + if (isalignedtemple(vm)) { + cost = 0; + } else { + cost = applyshoppricemod(cost, lf, vm, SA_BUY); + } // ask what to detect - mvwprintw(mainwin, y, 0, "It will cost $%d to perform an divination on your items.", cost); + if (cost) { + mvwprintw(mainwin, y, 0, "It will cost $%d to perform an divination on your items.", cost); + } else { + mvwprintw(mainwin, y, 0, "For a fellow worshipper, we will perform divinations on your items for free.", cost); + } y += 2; if (countmoney(lf->pack) < cost) { mvwprintw(mainwin, y, 0, "Unfortunately, you cannot afford this.", cost); @@ -434,7 +450,11 @@ enum SHOPRETURN shopdetectcurse(lifeform_t *lf, object_t *vm, int starty, char * } if (possible){ - mvwprintw(mainwin, y, 0, "Pay to detect auras on your items (you have $%d) [yn]? ", countmoney(lf->pack)); + if (cost) { + mvwprintw(mainwin, y, 0, "Pay to detect auras on your items (you have $%d) [yn]? ", countmoney(lf->pack)); + } else { + mvwprintw(mainwin, y, 0, "Detect auras on your items [yn]? "); + } } else { mvwprintw(mainwin, y, 0, "[Press a key to return]"); } @@ -629,11 +649,23 @@ enum SHOPRETURN shopbless(lifeform_t *lf, object_t *vm, int starty, char *toptex blesscost = applyshoppricemod(DEF_BLESSCOST, lf, vm, SA_BUY); surcharge = applyshoppricemod(DEF_SURCHARGE, lf, vm, SA_BUY); + if (isalignedtemple(vm)) { + blesscost /= 2; limit(&blesscost, 1, NA); + remcursecost = 0; + surcharge = 0; + } + mvwprintw(mainwin, y, 0, "So long as their aura is known, we can bestow a blessing on most items."); y += 2; - mvwprintw(mainwin, y, 0, "Curse removal - $%d each",remcursecost); y++; + if (remcursecost == 0) { + mvwprintw(mainwin, y, 0, "Curse removal - FREE",remcursecost); y++; + } else { + mvwprintw(mainwin, y, 0, "Curse removal - $%d each",remcursecost); y++; + } mvwprintw(mainwin, y, 0, "Blessings - $%d each",blesscost); y += 2; - mvwprintw(mainwin, y, 0, "(there is a $%d surcharge for uncursing an equipped item)",surcharge); y += 2; + if (surcharge != 0) { + mvwprintw(mainwin, y, 0, "(there is a $%d surcharge for uncursing an equipped item)",surcharge); y += 2; + } mvwprintw(mainwin, y, 0, "Pay for a blessing (you have $%d) [yn]? ", countmoney(lf->pack)); ch = getch(); diff --git a/shops.h b/shops.h index 684ee50..733e0c5 100644 --- a/shops.h +++ b/shops.h @@ -4,6 +4,7 @@ int apply_shopob_restrictions(char *buf); float applyshoppricemod(float origprice, lifeform_t *lf, object_t *shop, enum SHOPACTION action); int canafford(lifeform_t *lf, int amt); int getshopblessprice(object_t *o, object_t *shop); +int isalignedtemple(object_t *shop); int obmatchessellflag(object_t *o, flag_t *f, enum SHOPACTION action); void shop(lifeform_t *lf, object_t *vm); enum SHOPRETURN shopabsolve(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated); diff --git a/spell.c b/spell.c index b69687b..eaa1b32 100644 --- a/spell.c +++ b/spell.c @@ -362,6 +362,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef strcpy(verb, "charge"); break; } + // check baseid too + if (user->race->baseid == R_LEECH) { + strcpy(verb, "leap"); + } msg("%s %s%s towards %s!",username,verb, isplayer(user) ? "" : "s",targetname); needredraw = B_TRUE; drawlevelfor(player); @@ -1950,8 +1954,12 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // get list of resizable materials - getworkablematerials(user, SK_METALWORK, repairablemats, cutoffpct, &nmats); - getworkablematerials(user, SK_SEWING, repairablemats, cutoffpct, &nmats); + if (getskill(user, SK_METALWORK) >= PR_BEGINNER) { + getworkablematerials(user, SK_METALWORK, repairablemats, cutoffpct, &nmats); + } + if (getskill(user, SK_SEWING) >= PR_BEGINNER) { + getworkablematerials(user, SK_SEWING, repairablemats, cutoffpct, &nmats); + } // 1.compile a list of resizable objects initprompt(&prompt, "Resize which object?"); @@ -6888,6 +6896,30 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ nothinghappens(); } rv = B_FALSE; + } else if (spellid == OT_S_DRAINIQ) { + target = targcell->lf; + if (!target) { + fizzle(caster); + return B_TRUE; + } + + if (isplayer(target)) { + msg("^%cYour brain cells are blasted!",getlfcol(target, CC_VBAD)); + } else if (isplayer(caster)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("^%cYou blast %s%s brain cells!", getlfcol(target, CC_VBAD), + lfname, getpossessive(lfname)); + } + if (!ischarmable(target) && (reason != F_CHARMEDBY) && (reason != E_LOWIQ)) { + if (isplayer(caster)) { + char tname[BUFLEN]; + getlfname(target, tname); + msg("%s %s unaffected.", tname, isplayer(target) ? "are" : "is"); + } + return B_TRUE; + } + statdrain(target, A_IQ, roll("2d6") + rolldie(power,6),SC_NONE,-1,caster); } else if (spellid == OT_S_DRAINLIFE) { char lfname[BUFLEN]; target = haslf(targcell); @@ -8726,6 +8758,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = addtempflag(caster->flags, F_MINDSHIELD, B_TRUE, NA, NA, NULL, FROMSPELL); f->obfrom = spellid; } else if (spellid == OT_S_MINDWHIP) { + int fail = B_FALSE; target = targcell->lf; if (!target) { fizzle(caster); @@ -8740,10 +8773,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ lfname, getpossessive(lfname)); } if (getattrbracket(getattr(target, A_IQ), A_IQ, NULL) <= AT_VLOW) { + fail = B_TRUE; + } else if (!ischarmable(target) && (reason != F_CHARMEDBY)) { + fail = B_TRUE; + } + if (fail) { if (isplayer(caster)) { char tname[BUFLEN]; getlfname(target, tname); - msg("%s is unaffected.", tname); + msg("%s %s unaffected.", tname, isplayer(target) ? "are" : "is"); } return B_TRUE; } @@ -9698,6 +9736,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int dam,iq; enum ATTRBRACKET iqb; char targetname[BUFLEN]; + int fail = B_FALSE; if (!target) { target = targcell->lf; } @@ -9709,11 +9748,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ iqb = getattrbracket(iq, A_IQ, NULL); // not smart enough if (iqb <= AT_EXLOW) { - fizzle(caster); + fail = B_TRUE; + } else if (!ischarmable(target) && (reason != F_CHARMEDBY)) { + fail = B_TRUE; + } + + if (fail) { + if (isplayer(caster)) { + char tname[BUFLEN]; + getlfname(target, tname); + msg("%s %s unaffected.", tname, isplayer(target) ? "are" : "is"); + } return B_TRUE; } dam = rnd((iq/10),(iq/5)); - losehp(target, dam, DT_DIRECT, caster, "a psionic blast"); + losehp(target, dam, DT_DIRECT, caster, "a mental feedback loop"); getlfname(target, targetname); if (isplayer(target)) { msg("^%cYour brain is blasted!",getlfcol(target, CC_BAD) ); @@ -13080,6 +13129,7 @@ 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) || + (spellid == OT_S_SUMMONSWARM) || (spellid == OT_S_FRIENDS) || (spellid == OT_S_HECTASSERVANT) || (spellid == OT_S_SUMMONDEMON)) { @@ -13150,6 +13200,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ successrate = 100; friendly = B_TRUE; break; + case OT_S_SUMMONSWARM: + wantrc = RC_ANY; + wantsize = SZ_ANY; + nwant = 1; + switch (power) { + case 1: wantrace = R_SWARMRAT; break; + case 2: wantrace = R_SWARMSPIDER; break; + default: wantrace = R_SWARMLOCUST; break; + } + successrate = 100; + friendly = B_TRUE; + break; default: wantrc = RC_ANY; wantsize = SZ_ANY; @@ -14991,6 +15053,17 @@ char *getspelldesc(enum OBTYPE spellid, int power, char *buf) { case OT_S_SIXTHSENSE: snprintf(buf, BUFLEN, "warnings about adjacent enemies"); break; + case OT_S_SUMMONSWARM: + switch (power) { + case 1: + snprintf(buf, BUFLEN, "Summon a rat swarm."); break; + case 2: + snprintf(buf, BUFLEN, "Summon a spider swarm."); break; + default: + case 3: + snprintf(buf, BUFLEN, "Summon a locust swarm."); break; + } + break; case OT_S_SUMMONWEAPON: snprintf(buf, BUFLEN, "Create a %d damage rating magical weapon",2+(power*2)); break; diff --git a/text.c b/text.c index 1caf5ae..e230f13 100644 --- a/text.c +++ b/text.c @@ -1058,6 +1058,7 @@ char *getcolname(enum COLOUR c) { case C_LIGHTGREEN: return "lightgreen"; case C_LIGHTMAGENTA: return "lightmagenta"; case C_LIGHTYELLOW: return "lightyellow"; + case C_LIGHTPINK: return "lightpink"; case C_LAST: return "last_colour"; } return "?unknowncolour?";