From a6aab1afe19fd1b8aa53411a31ace55b727af27b Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Thu, 8 Mar 2012 19:42:25 +0000 Subject: [PATCH] - [+] ai shuldn't want its home/life objects. - [+] lich - [+] lifeob = ornate glass jar - [+] can walk up to 12 away - [+] chilling touch - [+] mindshield - [+] teleport back to jar on death - [+] monster ghosts have lifeob = corpse, which we generate. - [+] but DONT let them possess the player ? or dont let them possess anyhting ? - [+] mosnters should say noooo! if their lifeob is destroyed - [+] lifeobs need a link back to owner f_lifeobfor xxx - [+] lifeob check wasn't including the lf's cell itself. - [+] spellcasttext for dryad - "Charm" = beckons - [+] poltergeist should be invisible - [+] troll should covet food - [+] avian - birds should be friendly - [+] scroll of permenance should make armour invulnerable - [+] amulet of mind sheild - immune to psionics - [+] parserace() shouhld handle "random _baseid_" ie. random ant, random troll etc - [+] vault: troll cave (very rare) - [+] trolls - [+] bones - [+] cooked corpses - [+] bug: minions not being created in vaults. - [+] vault: ant nest - [+] queen ant - [+] dirt floor - [+] lots of ants - [+] LOTS of food. - [+] reduce flame volume - [+] vault maintainedge not working. slightly fixed now? - [+] vampires are turning into gas clouds but then trying to attack. - [+] new amulets - [+] Of evolution (turn into a merman in deep water, aviad instead of falling, (fireres humanoid) in fire, (coldred human) in cold) - [+] in deep water and can't swim? turn into merman - [+] about to fall through a hole? turn into a flying aviad - [+] in fire and not resistant? turn into a Lavax - [+] in cold and not resistant? turn into sasquatch - [+] all polymorphs are TEMPORARY (5 turns or so). - [+] no autoid - [+] of bloodthirst - walking over blood heals you! - [+] no autoid - [+] Of graceful swimming (auto turn into a swan when you enter water) - [+] no autoid - [+] paranoia (5% chance per turn to create monsters out of sight, but in lof) - [+] they will make a "walk" noise right away - [+] or something just "you hear xxx right behind you!" --- ai.c | 76 +++++-- ai.h | 1 + attack.c | 1 + data.c | 257 +++++++++++++++++++--- data/hiscores.db | Bin 14336 -> 14336 bytes data/vaults/cave_bear.vlt | 14 +- defs.h | 23 +- doc/glyphs.txt | 7 +- io.c | 21 ++ lf.c | 450 +++++++++++++++++++++++++++++--------- lf.h | 5 +- map.c | 82 +++++-- move.c | 4 +- objects.c | 131 ++++++++--- spell.c | 52 +++-- vault.c | 2 +- 16 files changed, 879 insertions(+), 247 deletions(-) diff --git a/ai.c b/ai.c index 256f1d9..ca8c1c1 100644 --- a/ai.c +++ b/ai.c @@ -38,7 +38,7 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { } if (!canattack(lf)) { - dblog(".oO { canattack() is false }"); + if (db) dblog(".oO { canattack() is false }"); return B_TRUE; } @@ -646,6 +646,25 @@ int aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim return B_FALSE; } +cell_t *aigettargetcell(lifeform_t *lf, flag_t **targflag) { + flag_t *f; + + if (targflag) { + *targflag = NULL; + } + + f = hasflag(lf->flags, F_TARGETCELL); + if (!f) return NULL; + + if (targflag) { + // set this even if the actual cell is invalid. + *targflag = f; + } + + return getcellat(lf->cell->map, f->val[0], f->val[1]); +} + + object_t *aigetwand(lifeform_t *lf, enum FLAG purpose) { object_t *o; object_t *poss[MAXPILEOBS]; @@ -796,6 +815,7 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) { } } + if (!lfhasflag(lf, F_STUNNED)) { lifeform_t *hateposs[MAXCANDIDATES],*poss[MAXCANDIDATES]; int nposs = 0, nhateposs = 0; @@ -990,29 +1010,37 @@ int ai_handle_emergencies(lifeform_t *lf, enum ATTRBRACKET iqb) { if (lfhasflag(lf, F_RAGE)) return B_FALSE; - // if we are not near our life ob, move towards it! + // if we are not near our life ob, and not moving towards it, do so! f = lfhasflag(lf, F_LIFEOB); if (f) { - if (!findnearbylifeob(lf->cell, f, NULL)) { + if (!findnearbylifeob(lf->cell, NA, f, NULL)) { cell_t *poss[8]; int nposs = 0; int dir; - if (db) dblog(".oO { not near my lifeob! }"); - for (dir = DC_N; dir <= DC_NW; dir++) { - cell_t *c; - c = getcellindir(lf->cell, dir); - if (c && findnearbylifeob(c, f, NULL)) { - poss[nposs++] = c; - } - } - if (nposs) { - if (aigoto(lf, poss[rnd(0,nposs-1)], MR_OTHER, NULL, PERMENANT)) { - if (db) dblog(".oO { moving close to lifeob }"); - // success - return B_TRUE; - } else { - if (db) dblog(".oO { couldnt find an adjacent cell near lifeob }"); - // TODO: search all in los + cell_t *targcell; + // target cell near our life ob? if so, we're okay. + targcell = aigettargetcell(lf, NULL); + if (targcell && findnearbylifeob(targcell, NA, f, NULL)) { + } else { + if (db) dblog(".oO { not near my lifeob! }"); + for (dir = DC_N; dir <= DC_NW; dir++) { + cell_t *c; + c = getcellindir(lf->cell, dir); + if (c && findnearbylifeob(c, NA, f, NULL)) { + poss[nposs++] = c; + } + } + if (nposs) { + cell_t *c; + c = poss[rnd(0,nposs-1)]; + if (aigoto(lf, c, MR_OTHER, NULL, PERMENANT)) { + if (db) dblog(".oO { moving closer to lifeob }"); + // success + return B_TRUE; + } else { + if (db) dblog(".oO { couldnt find an adjacent cell near lifeob }"); + // TODO: search all in los + } } } } @@ -1341,17 +1369,16 @@ int ai_movement(lifeform_t *lf) { int valid = B_TRUE; cell_t *c; int db = B_FALSE; - flag_t *f; + flag_t *f = NULL; if (lfhasflag(lf, F_DEBUG)) db = B_TRUE; if (lfhasflagval(lf, F_DOESNTMOVE, NA, NA, B_TRUE, NULL)) return B_FALSE; // do we have a target cell? - f = hasflag(lf->flags, F_TARGETCELL); + c = aigettargetcell(lf, &f); if (!f) return B_FALSE; // is it still valid? - c = getcellat(lf->cell->map, f->val[0], f->val[1]); if (!c) { valid = B_FALSE; } else if (f->val[2] == MR_LF) { @@ -2567,6 +2594,11 @@ int aiwants(lifeform_t *lf, object_t *o, int *covets) { int aiwants_real(lifeform_t *lf, object_t *o, int *covets, int *noids, enum OBTYPE *oid, int *oidcovet,int *nwantflags, enum FLAG *wantflag, int *wantflagcovet) { int i; + + if (hasflagval(o->flags, F_HOMEOBFOR, lf->id, NA, NA, NULL)) { + return B_FALSE; + } + for (i = 0; i < *noids; i++) { if (oid[i] == o->type->id) { if (covets) { diff --git a/ai.h b/ai.h index 80b40fc..1190f71 100644 --- a/ai.h +++ b/ai.h @@ -8,6 +8,7 @@ int aigetchasetime(lifeform_t *lf); cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *lasty, int *lastdir); object_t *aigetrangedattack(lifeform_t *lf, lifeform_t *target, enum RANGEATTACK *ra, int *range); int aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose); +cell_t *aigettargetcell(lifeform_t *lf, flag_t **targflag); 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); int ai_attack_existing_target(lifeform_t *lf); diff --git a/attack.c b/attack.c index 40b5132..959cdf2 100644 --- a/attack.c +++ b/attack.c @@ -344,6 +344,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { switch (reason) { case E_NOSTAM: msg("You are too tired to fight at the moment."); break; case E_STUNNED: msg("You are too stunned to fight at the moment."); break; + case E_IMPOSSIBLE: msg("You have no way of attacking!"); break; default: msg("For some reason, you cannot attack."); break; } } diff --git a/data.c b/data.c index 702f582..c10594e 100644 --- a/data.c +++ b/data.c @@ -5068,6 +5068,10 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, NA, '!', NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 82, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addot(OT_GLASSJAR, "ornate glass jar", "A richly-painted glass jar, inlaid with valuable gemstones.", MT_GLASS, 0.2, OC_MISC, SZ_TINY); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_MAGENTA, '!', NA, NULL); + addflag(lastot->flags, F_VALUE, 800, NA, NA, NULL); addot(OT_BROKENGLASS, "piece of broken glass", "Sharp shards of broken glass.", MT_GLASS, 0.1, OC_MISC, SZ_MINI); addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 8, NA, NULL); @@ -5338,7 +5342,7 @@ void initobjects(void) { //addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dries up"); //addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "dry up"); addflag(lastot->flags, F_NODIECONVERTTEXT, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); + addflag(lastot->flags, F_OBHP, 15, 15, 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_LINKOB, OT_POT_BLOOD, NA, NA, NULL); @@ -5357,7 +5361,7 @@ void initobjects(void) { addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "blood stain"); addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dries up"); addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "dry up"); - addflag(lastot->flags, F_OBHP, 45, 45, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, 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_DRINKABLE, B_TRUE, 0, NA, NULL); @@ -5455,7 +5459,7 @@ void initobjects(void) { addflag(lastot->flags, F_ONFIRE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ONLYINROOM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); - addflag(lastot->flags, F_MAKESNOISE, 33, 3, NA, "crackling flames."); + addflag(lastot->flags, F_MAKESNOISE, 33, 1, NA, "crackling flames."); addot(OT_WEAPONRACK, "weapon rack", "A large matel frame, made to store weapons.", MT_METAL, 150, OC_FURNITURE, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 80, RR_UNCOMMON, NULL); @@ -5579,7 +5583,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 7, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); - addflag(lastot->flags, F_MAKESNOISE, 33, 3, NA, "crackling flames."); + addflag(lastot->flags, F_MAKESNOISE, 33, 2, NA, "roaring flames."); addot(OT_FIRESMALL, "small fire", "A small blaze.", MT_FIRE, 0, OC_EFFECT, SZ_SMALL); addflag(lastot->flags, F_GLYPH, C_RED, '}', NA, NULL); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "goes out"); @@ -5590,7 +5594,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 5, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); - addflag(lastot->flags, F_MAKESNOISE, 33, 3, NA, "crackling flames."); + addflag(lastot->flags, F_MAKESNOISE, 33, 1, NA, "crackling flames."); addot(OT_STEAMCLOUD, "cloud of steam", "A thick cloud of scalding steam.", MT_GAS, 0, OC_EFFECT, SZ_HUMAN); addflag(lastot->flags, F_GLYPH, C_WHITE, UNI_SHADEMED, NA, NULL); @@ -6293,6 +6297,9 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_RAGE, NA, NULL); addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); + addot(OT_AMU_BLOOD, "amulet of bloodthirst", "Causes its wearer's body to heal itself by absorbing nearby blood. As a result, the wearer will also never bleed.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_VERYRARE, NULL); + addflag(lastot->flags, F_VALUE, 1400, NA, NA, NULL); addot(OT_AMU_CHEF, "chef's amulet", "Greatly lowers its wearers' metabolism.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SLOWMETAB, 3, NA, NULL); @@ -6301,6 +6308,10 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_S_BLINK, NA, "pw:6;"); addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); + addot(OT_AMU_EVOLUTION, "amulet of evolution", "These rare amulets grant the wearer the ability to almost instantly evolve their body shape in response to danger.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + // no autoid + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_VERYRARE, NULL); + addflag(lastot->flags, F_VALUE, 1400, NA, NA, NULL); addot(OT_AMU_FALLING, "amulet of feather fall", "Limits the effects of gravity on its wearer, rendering them immune to fall damage.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FALL, NA, NULL); @@ -6313,21 +6324,35 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTVULN, DT_SONIC, NA, NULL); addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_AMU_PARANOIA, "amulet of paranoia", "Makes the caster periodically hear fake noises nearby. Or are they real....?", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + // no autoid! + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_PARANOIA, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); + addot(OT_AMU_SLEEP, "amulet of peaceful slumber", "Blocks out all sound while the wearer sleeps.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + // no autoid! addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); - addflag(lastot->flags, F_STARTBLESSED, B_CURSED, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); addot(OT_AMU_SPELLBOOST, "archmage's amulet", "Greatly increases the power of the wearer's spells.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, ""); addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 5, NA, NULL); + addot(OT_AMU_SWIMMING, "amulet of graceful swimming", "These amulets were created by the naiads, in an attempt to prolong the life of their thralls. Upon contact with deep water, its wearer will instantly transform into a white swan.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); addot(OT_AMU_THIEF, "thief's amulet", "Crafted by a master thief, it allows its wearer the uncanny ability to pick almost any lock.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_PICKLOCK, NA, NULL); addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); addot(OT_AMU_VICTIM, "amulet of victimisation", "Causes all creatures who view the wearer to become hostile and agressive.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + // no autoid! addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); + addot(OT_AMU_VSESP, "amulet versus esp", "Protects its wearer from all psionic attacks.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MINDSHIELD, B_TRUE, NA, NULL); + addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); addot(OT_AMU_VSMAGIC, "amulet versus magic", "Confers a moderate level of magic resistance upon its wearer.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 66, NA, NULL); @@ -8107,6 +8132,7 @@ void initrace(void) { addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, NULL); addflag(lastrace->flags, F_AUTOROTATE, 1, NA, NA, NULL); + addflag(lastrace->flags, F_FOLLOWTIME, 3, NA, NA, NULL); // human monsters... @@ -8857,7 +8883,8 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_AGI, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_HIGH, NA, NULL); addflag(lastrace->flags, F_LIFEOB, OT_TREE, 2, 3, NULL); addflag(lastrace->flags, F_HOMEOB, 100, NA, NA, "tree"); addflag(lastrace->flags, F_HOMEOB, 100, NA, NA, "random gem"); @@ -8872,6 +8899,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, "pw:1;"); //addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, 10, 10, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_PLANTWALK, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CHARM, NA, B_APPENDYOU, "beckons"); addflag(lastrace->flags, F_WANTSOBFLAG, F_GEM, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); @@ -9188,7 +9216,7 @@ void initrace(void) { 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_STR, AT_GTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 10, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 7, NA, NULL); addflag(lastrace->flags, F_STARTOBWEPSK, 50, SK_POLEARMS, NA, NULL); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "shield"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour"); @@ -9698,7 +9726,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTJOB, 15, J_WARRIOR, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 15, J_DRUID, NA, NULL); - addrace(R_MALIK, "malik", 5, 'n', C_BLUE, MT_FLESH, RC_MAGIC, "An evil fairy who thrives on murder. They delight in teleporting behind their victims for a quick backstab."); + addrace(R_MALIK, "malik", 5, 'n', C_YELLOW, MT_FLESH, RC_MAGIC, "An evil fairy who thrives on murder. They delight in teleporting behind their victims for a quick backstab."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, NA, NA, NA, NULL); @@ -9740,7 +9768,7 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACE, R_GNOLL, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4+6"); - addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 7, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_STAYINROOM, NA, NA, NA, NULL); // stay in our maze @@ -9774,7 +9802,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, 66, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_RARITY, H_SWAMP, 66, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+0"); - addflag(lastrace->flags, F_TR, 3, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, -5, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -9809,7 +9837,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, 66, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_RARITY, H_SWAMP, 66, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+0"); - addflag(lastrace->flags, F_TR, 3, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 8, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -10113,7 +10141,7 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, 3, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); - addrace(R_POLTERGEIST, "poltergeist", 50, 'P', C_GREEN, MT_FLESH, RC_UNDEAD, "An evil ghostly spirit who telekinetically throws objects at its enemies."); // sPirit + addrace(R_POLTERGEIST, "poltergeist", 50, 'p', C_GREEN, MT_FLESH, RC_UNDEAD, "An evil ghostly spirit who telekinetically throws objects at its enemies."); // sPirit addbodypart(lastrace, BP_BODY, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); @@ -10140,6 +10168,8 @@ void initrace(void) { addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_INVISIBLE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STAYINROOM, NA, NA, NA, NULL); addrace(R_PRIMALFIRE, "fire primality", 50, 'E', C_RED, MT_FIRE, RC_HUMANOID, "A living mass of fire, animated by powerful magic."); setbodytype(lastrace, BT_HUMANOID); @@ -10276,6 +10306,50 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + + + addrace(R_LAVAX, "lavax", 90, 'h', C_RED, MT_FLESH, RC_HUMANOID, "The Lavax are a race of humanoid creatures who dwell in volcanic regions. Their skin has hardened into a clay-like substance, and is completely immune to the effects of heat or fire."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + 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, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4"); + addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_ARMOURRATING, 6, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 9, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_WEAPON, RANDOM, NULL); + addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); + + addrace(R_SASQUATCH, "sasquatch", 90, 'h', C_CYAN, MT_FLESH, RC_HUMANOID, "Over the years, humans dwelling in cold climates have evolved into sasquatches, their skin now covered with fur to protect against the elements."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + 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, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4"); + addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_WEAPON, RANDOM, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 9, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); + + addrace(R_SATYR, "satyr", 80, 'h', C_GREEN, MT_FLESH, RC_HUMANOID, "A goat-like humanoid equipped with a set of magical panpipes."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -10514,19 +10588,20 @@ void initrace(void) { setbodypartname(lastrace, BP_HANDS, "claws"); setbodypartname(lastrace, BP_RIGHTFINGER, "right foreclaw"); setbodypartname(lastrace, BP_LEFTFINGER, "left foreclaw"); + lastrace->baseid = R_TROLL; addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, 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_SWAMP, NA, RR_COMMON, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4+0"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4"); addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 12, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 8, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 2, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); @@ -10535,6 +10610,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLL, NULL); addrace(R_TROLLKIN, "trollkin", 100, 't', C_GREY, MT_FLESH, RC_HUMANOID, "Trollkins are the horrific offspring of a troll and a human. While they lack the regenerative abilities of a standard troll, their human genes grant them a greater level of intelligence."); @@ -10554,7 +10631,7 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 8, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 7, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 1, NA, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 90, OC_WEAPON, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 70, OC_ARMOUR, NA, NULL); @@ -10573,6 +10650,7 @@ void initrace(void) { setbodypartname(lastrace, BP_HANDS, "claws"); setbodypartname(lastrace, BP_RIGHTFINGER, "right foreclaw"); setbodypartname(lastrace, BP_LEFTFINGER, "left foreclaw"); + lastrace->baseid = R_TROLL; addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); @@ -10598,14 +10676,17 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FROSTBITE, NA, NA, "exhales a freezing wind"); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLL, NULL); + addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLLSNOW, NULL); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "50"); + addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addrace(R_TROLLSWAMP, "swamp troll", 100, 't', C_BOLDGREEN, MT_FLESH, RC_HUMANOID, "Twisted trolls who roam the swamplands, their claws infected with a lethal poison."); setbodytype(lastrace, BT_HUMANOID); setbodypartname(lastrace, BP_HANDS, "claws"); setbodypartname(lastrace, BP_RIGHTFINGER, "right foreclaw"); setbodypartname(lastrace, BP_LEFTFINGER, "left foreclaw"); + lastrace->baseid = R_TROLL; addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); @@ -10617,7 +10698,7 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 12, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 8, NA, NULL); addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 32, "5-10"); addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 3, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 2, NA, NA, NULL); @@ -10629,7 +10710,9 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLL, NULL); + addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLLSWAMP, NULL); addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL, "Xats are wild pigs with the claws of a dog."); setbodytype(lastrace, BT_QUADRAPED); @@ -10669,6 +10752,29 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + addrace(R_FISHFOLK, "fishfolk", 75, 'h', C_BOLDBLUE, MT_FLESH, RC_HUMANOID, "Water-dwelling humanoids capable of breathing normally in both water and air."); + setbodytype(lastrace, BT_HUMANOID); + addbodypart(lastrace, BP_TAIL, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, 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_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d3+4"); + addflag(lastrace->flags, F_TR, 3, 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_HASATTACK, OT_FISTS, 2, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "trident"); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "spear"); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_ALIGNMENT, AL_NONE, NA, NA, "gne"); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, ""); + addrace(R_MERLOCH, "merloch", 250, 'm', C_ORANGE, MT_FLESH, RC_AQUATIC, "Merlochs are bipedal, fishlike beings. Equally at home in the water or on land, they use their sonic scream to disable foes."); setbodytype(lastrace, BT_HUMANOID); noarmouron(lastrace, BP_RIGHTFINGER); @@ -10687,6 +10793,8 @@ void initrace(void) { addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, ""); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 6, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 6, NA, NULL); @@ -11091,8 +11199,8 @@ void initrace(void) { addflag(lastrace->flags, F_NUMAPPEAR, 3, 4, NA, ""); 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, NA, NA, NA, "3d4+3"); - addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3"); + addflag(lastrace->flags, F_TR, 2, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -11105,7 +11213,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); - addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL, "The fighter of the giant ant family. Giant soldier ants are equipped with a powerful acidic stinger."); + addrace(R_ANTS, "giant soldier ant", 25, 'a', C_RED, MT_FLESH, RC_ANIMAL, "The fighter of the giant ant family. Giant soldier ants are equipped with a powerful acidic stinger."); setbodytype(lastrace, BT_QUADRAPED); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -11115,15 +11223,17 @@ void initrace(void) { 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, NA, NA, NA, "3d4+4"); - addflag(lastrace->flags, F_TR, 5, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, 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_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL); - addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:1d8+3;"); - addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:1d6+3;needgrab:1;"); + addflag(lastrace->flags, F_HASATTACK, OT_STING, 6, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:1d6;"); + addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:3d3;needgrab:1;"); 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_WALK, 1, NA, "^scuttling"); @@ -11141,13 +11251,13 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4+6"); - addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 7, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, 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_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 15, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, NA, NULL); 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); @@ -11157,6 +11267,33 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 14, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + // note: queen and does NOT have baseid ant. this is so that ant nests will only + // have one queen. + addrace(R_ANTQUEEN, "queen ant", 50, 'a', C_MAGENTA, MT_FLESH, RC_ANIMAL, "Like their regular-sized counterparts, giant queen ants prefer to rely largely on their workers and soldiers for protection. If required however, they are quite capable of protecting themselves."); + setbodytype(lastrace, BT_QUADRAPED); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, 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_FOREST, NA, RR_VERYRARE, NULL); + addflag(lastrace->flags, F_MINIONS, 100, 5, 8, "random ant"); + addflag(lastrace->flags, F_ARMOURRATING, 6, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "10d4"); + addflag(lastrace->flags, F_TR, 10, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, 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_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_STING, 12, NA, NULL); + 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_WALK, 1, NA, "^scuttling"); + addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 14, NA, NA, NULL); + addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addrace(R_BILCO, "bilco", 25, ';', C_BOLDCYAN, MT_FLESH, RC_ANIMAL, "Bilcos appear to be abnormally large frogs with a strange blue tinge. Seasoned travellers know to beware the bilco's gurgle, which portends them belching out a massive torrent of water."); setbodytype(lastrace, BT_QUADRAPED); @@ -11201,6 +11338,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "0d4+1"); addflag(lastrace->flags, F_TR, 0, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_BEAK, 2, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); @@ -11598,7 +11736,7 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addrace(R_SLUG, "acid slug", 150, 'p', C_GREY, MT_FLESH, RC_ANIMAL, "While acid slugs lack the protective shell of their snail cousings, their rubbery flesh is extremely resilient. Their acid-based attacks also make them much more dangerous."); + addrace(R_SLUG, "acid slug", 150, 'P', C_GREY, MT_FLESH, RC_ANIMAL, "While acid slugs lack the protective shell of their snail cousings, their rubbery flesh is extremely resilient. Their acid-based attacks also make them much more dangerous."); addbodypart(lastrace, BP_BODY, NULL); addbodypart(lastrace, BP_HEAD, NULL); addbodypart(lastrace, BP_EYES, NULL); @@ -11628,7 +11766,7 @@ void initrace(void) { addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addrace(R_SNAIL, "mottled snail", 150, 'p', C_BROWN, MT_FLESH, RC_ANIMAL, "An enormous snail, protected by a hard, scaled shell and gifted with long, sharp fangs."); + addrace(R_SNAIL, "mottled snail", 150, 'P', C_BROWN, MT_FLESH, RC_ANIMAL, "An enormous snail, protected by a hard, scaled shell and gifted with long, sharp fangs."); addbodypart(lastrace, BP_BODY, NULL); addbodypart(lastrace, BP_HEAD, NULL); addbodypart(lastrace, BP_EYES, NULL); @@ -11960,6 +12098,29 @@ void initrace(void) { addflag(lastrace->flags, F_FLEEONHPPCT, 25, NA, NA, ""); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + + 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_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+2"); + addflag(lastrace->flags, F_TR, 0, NA, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_BEAK, 1, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_BEAK, 1, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SWIMMING, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "squarks^squarking"); + addflag(lastrace->flags, F_MORALE, 0, NA, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_TIMID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_AVIAN, B_TRUE, NA, NA, NULL); + + addrace(R_WOLFYOUNG, "young wolf", 10, 'd', C_GREY, MT_FLESH, RC_ANIMAL, "Immature wolves."); setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); @@ -13155,7 +13316,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); - addrace(R_GHOST, "ghost", 50, 'P', C_BLUE, MT_MAGIC, RC_UNDEAD, "Wispy spirits formed when a soul refuses to depart the earthly realm after death, ghosts exist part way between dimensions. The sight of a ghost can cause fear in all who behold it, and their ethereal nature makes them immune to most attacks."); // p for sPirit + addrace(R_GHOST, "ghost", 50, 'p', C_BLUE, MT_MAGIC, RC_UNDEAD, "Wispy spirits formed when a soul refuses to depart the earthly realm after death, ghosts exist part way between dimensions. The sight of a ghost can cause fear in all who behold it, and their ethereal nature makes them immune to most attacks."); // p for sPirit setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); @@ -13183,8 +13344,11 @@ void initrace(void) { addflag(lastrace->flags, F_NATURALFLIGHT, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_INDUCEFEAR, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_INVISIBILITY, 40, 40, "pw:1;"); + addflag(lastrace->flags, F_LIFEOB, OT_CORPSE, 5, 4, NULL); + addflag(lastrace->flags, F_HOMEOB, 100, NA, NA, "humanoid corpse"); + // special: ghosts gain canwill->possession if they are near - // their previous corpse. use f_mycorpse->oid for this. + // their previous corpse. use f_lifeob with text=oid for this. addrace(R_GHOUL, "ghoul", 50, 'Z', C_GREEN, MT_FLESH, RC_UNDEAD, "Ghouls are monstrous, undead humanoids who feed on flesh and reek of carrion. Their bodies are grey and hairless, their teeth fanged, and their nails sharped into deadly claws."); setbodytype(lastrace, BT_HUMANOID); @@ -13214,6 +13378,36 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addrace(R_LICH, "lich", 50, 'L', C_MAGENTA, MT_FLESH, RC_UNDEAD, "Immensely powerful wizards can on rare occasions extend their own lives by becoming undead lichs. While their physical body continues to slowly decay, they remain all of their intellect and power."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, NULL); + addflag(lastrace->flags, F_INDUCEFEAR, 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, NA, NA, NA, "11d4"); + addflag(lastrace->flags, F_TR, 11, 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_HASATTACK, OT_TOUCHCHILL, 10, NA, NULL); + addflag(lastrace->flags, F_HITCONFER, F_PARALYZED, SC_CON, 30, "1-2"); + addflag(lastrace->flags, F_HITCONFERVALS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); + addflag(lastrace->flags, F_MINDSHIELD, 6, NA, NA, NULL); + addflag(lastrace->flags, F_RNDSPELLCOUNT, 6, NA, NA, NULL); + addflag(lastrace->flags, F_RNDSPELLSCHOOL, SS_DEATH, 1, 5, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_EXPERT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_DEATH, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_LIFEOB, OT_GLASSJAR, 12, 20, NULL); + addflag(lastrace->flags, F_HOMEOB, 100, NA, NA, "ornate glass jar"); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "shouts^a shout"); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + + addrace(R_MUMMY, "mummy", 54, 'M', C_GREY, MT_FLESH, RC_UNDEAD, "A rotting humanoid figure clad in bandages."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -13364,6 +13558,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+1"); addflag(lastrace->flags, F_TR, 1, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 300, NA, NA, NULL); + addflag(lastrace->flags, F_NOATTACK, B_TRUE, 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_NOINJURIES, B_TRUE, NA, NA, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index 6d17b95714f0ce6f10c78563c206824c251053a6..1888a7113ec61dbe84ca4208d04228c037344b07 100644 GIT binary patch delta 32 ocmZoDXegK<&3JvIOu8u(li1`!X_3h@P0c1->I-guV5-0b0J=j8rvLx| delta 32 ocmZoDXegK<&3JjEOu8u(!=K3xA|jJ#nwm|{FcaMTz*K<=0LT>!g#Z8m diff --git a/data/vaults/cave_bear.vlt b/data/vaults/cave_bear.vlt index 16ff1b5..095ed75 100644 --- a/data/vaults/cave_bear.vlt +++ b/data/vaults/cave_bear.vlt @@ -1,12 +1,12 @@ @id:bear_cave @map -########## -###....### -##......## -O......B.# -##......## -###....### -########## +########### +####....### +###......## +.O......B.# +###......## +####....### +########### @end @legend diff --git a/defs.h b/defs.h index 07ccb1d..baf1f5b 100644 --- a/defs.h +++ b/defs.h @@ -530,6 +530,7 @@ enum SAYPHRASE { SP_BEGTHANKS, SP_DIE, SP_DRUNK, + SP_LIFEOB_DESTROYED, SP_MERCYACCEPT, SP_INFO_ACCEPT, SP_INFO_ASKPRICE, @@ -1002,6 +1003,7 @@ enum RACE { R_HOBGOBLINWAR, R_KOBOLD, R_LEPRECHAUN, + R_LAVAX, R_LIZARDMAN, R_MALIK, R_MINOTAUR, @@ -1022,6 +1024,7 @@ enum RACE { R_PRIMALSTONE, R_PRIMALSTONEL, R_SANDMAN, + R_SASQUATCH, R_SATYR, R_SHADOWCAT, R_SINKMITE, @@ -1039,7 +1042,9 @@ enum RACE { R_XAT, // fish R_CRAB, + R_FISHFOLK, R_MERLOCH, + R_MERMAN, R_PIRANHA, R_PIRANHAKING, R_EELELEC, @@ -1054,6 +1059,7 @@ enum RACE { R_UNYON, // animals R_ANT, + R_ANTQUEEN, R_ANTS, R_ANTLION, R_BAT, @@ -1091,6 +1097,7 @@ enum RACE { R_SPIDERFUNNELWEB, R_SPIDERREDBACK, R_SPIDERTOMB, + R_SWAN, R_WOLFYOUNG, R_WOLF, R_WOLFWINTER, @@ -1131,6 +1138,7 @@ enum RACE { R_GHAST, R_GHOST, R_GHOUL, + R_LICH, R_MUMMY, R_MUMMYG, R_REVENANT, @@ -1796,6 +1804,7 @@ enum OBTYPE { OT_CHEST, OT_EMPTYFLASK, OT_EMPTYVIAL, + OT_GLASSJAR, OT_CALTROP, OT_BROKENGLASS, OT_ICECHUNK, @@ -1911,15 +1920,20 @@ enum OBTYPE { OT_SHIELDTOWER, // amulets OT_AMU_ANGER, + OT_AMU_BLOOD, OT_AMU_CHEF, OT_AMU_ESCAPE, + OT_AMU_EVOLUTION, OT_AMU_FALLING, OT_AMU_FLIGHT, OT_AMU_LISTEN, + OT_AMU_PARANOIA, OT_AMU_SLEEP, OT_AMU_SPELLBOOST, + OT_AMU_SWIMMING, OT_AMU_THIEF, OT_AMU_VICTIM, + OT_AMU_VSESP, OT_AMU_VSMAGIC, OT_AMU_VSPOISON, // rings @@ -2324,6 +2338,8 @@ enum FLAG { F_REVIVETIMER, // v0 = cur, v1 = max. v0 incremenets each tick. // when v0 == v1, this object changes into lf of race // v2. + F_LIFEOBFOR, // this ob is the lifeobject for lf id v0. + F_HOMEOBFOR, // this ob is a homeobject for lf id v0. F_DTCONVERT, // damtype val0 converts this to f->text F_DTCREATEOB, // damtype val0 creates object f->text here // v1 = radius to burst in @@ -2771,6 +2787,7 @@ enum FLAG { F_ARMOURPENALTY, // lower your acc/ev by val0 due to cumbersome // armour. lowered by sk_armour skill. // v0 is accuracy penalty, v1 is evasion penalty. + F_MINDSHIELD, // lf is immune to psionic attacks F_MISCASTCHANCE, // lf has +v0% chance of spell failure F_LEVRACE, // at level v0, this race is promoted to race v1 // must apply this to the BASE race. @@ -3083,7 +3100,8 @@ enum FLAG { F_CANTALK, // this lf can talk, even if its raceclass normally // wouldn't be able to. F_AQUATIC, // this race can attack normally in water and suffers no - // movement penalties + // movement penalties. they can also swim at master + // level. F_AVIAN, // this race is an avian F_CANINE, // this race is a canine F_HUMANOID, // this race is a humanoid @@ -3095,6 +3113,7 @@ enum FLAG { // if v0 is true or b_frominjury, you can regrow it // via a healing potion. F_NOINJURIES, // this race cannot sustain injuries. + F_NOATTACK, // this lf can't attack F_NOPACK, // this race cannot hold objects F_NOSPELLS, // this race cannot cast spells F_NOPRINTS, // this race doesn't leave footprints @@ -3216,6 +3235,8 @@ 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_PARANOIA, // mosnters randomly appear out of sight, or random + // noises happen from behind you. F_PRONE, // lying on the ground F_FROZEN, // made of ice F_HEAVENARM, // prevent the next v0 damage received. diff --git a/doc/glyphs.txt b/doc/glyphs.txt index d753c0f..0a71517 100644 --- a/doc/glyphs.txt +++ b/doc/glyphs.txt @@ -9,7 +9,7 @@ UNI_SOLID = deep water A = avian / bird a = ant B = bat -c = cockatrice / chicken +c = cockatrice / chicken / small bird C = celestial / divine ? d = canine/dog D = ? @@ -25,14 +25,15 @@ i = insect I = large insect j = jelly/ooze/leech k = kobold +L = lich, or other powerful undead ? m = mutant / magic creature M = mummy n = small humanoid / nymph / sprite N = necron o = orc O = monstrous humanoid (ie. ogre) -p = gastropod -P = sPirit +P = gastropod +p = sPirit q = quadraped Q = large quadraped r = rodent diff --git a/io.c b/io.c index dec3a4c..ab936de 100644 --- a/io.c +++ b/io.c @@ -1321,6 +1321,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_MINDSHIELD: + if (isplayer(lf)) { + msg("^gYour mind feels insulated.^n"); + donesomething = B_TRUE; + } + break; case F_MISCASTCHANCE: if (isplayer(lf)) { msg("Your magical ability feels unreliable..."); @@ -2048,6 +2054,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_MINDSHIELD: + if (isplayer(lf)) { + msg("Your mind no longer feels insulated."); + donesomething = B_TRUE; + } + break; case F_MISCASTCHANCE: if (isplayer(lf)) { msg("Your magical ability no longer feels unreliable."); @@ -6509,6 +6521,10 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s boosts the power of your spells by %d.\n", buf, f->val[1]); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_MINDSHIELD: + sprintf(buf2, "%s protects you from psionic attacks.\n", buf); + strncat(retbuf, buf2, HUGEBUFLEN); + break; case F_MISCASTCHANCE: sprintf(buf2, "%s causes your spells to become unreliable.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); @@ -12624,6 +12640,11 @@ void showlfstats(lifeform_t *lf, int showall) { isplayer(lf) ? "your" : "its", boost); y++; } + f = lfhasknownflag(lf, F_MINDSHIELD); + if (f && (f->known)) { + mvwprintw(mainwin, y, 0, "%s are protected from psionic attacks.", you(lf)); + y++; + } f = lfhasknownflag(lf, F_MISCASTCHANCE); if (f && (f->known)) { int chance; diff --git a/lf.c b/lf.c index 4519f3d..a52d4ff 100644 --- a/lf.c +++ b/lf.c @@ -200,6 +200,8 @@ void bleed(lifeform_t *lf, int splatter) { if (lf->cell->type->solid) return; if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) return; + if (hasequippedobid(lf->pack, OT_AMU_BLOOD)) return; + f = lfhasflag(lf, F_BLOODOB); if (f) { if (f->text) { @@ -540,7 +542,12 @@ int canattack(lifeform_t *lf) { } else if (lfhasflag(lf, F_STUNNED)) { reason = E_STUNNED; return B_FALSE; + } else if (lfhasflag(lf, F_NOATTACK)) { + reason = E_IMPOSSIBLE; + return B_FALSE; } + + return B_TRUE; } @@ -2089,7 +2096,7 @@ int charmedaction(lifeform_t *lf, flag_t *charmflag) { } else { char obname[BUFLEN]; getobname(o, obname, o->amt); - msg("You hand over your %s to %s.", obname, + msg("^wYou hand over your %s to %s.", obname, cansee(lf, charmer) ? charmername : "your new master"); moveob(o, charmer->pack, o->amt); } @@ -2108,7 +2115,7 @@ int charmedaction(lifeform_t *lf, flag_t *charmflag) { } } if (!ndone) { - msg("You bask in the glory of %s!", cansee(lf, charmer) ? charmername : "your new master"); + msg("^wYou bask in the glory of %s!", cansee(lf, charmer) ? charmername : "your new master"); taketime(lf, getactspeed(lf)); } } else { @@ -2117,10 +2124,10 @@ int charmedaction(lifeform_t *lf, flag_t *charmflag) { turntoface(lf, charmer->cell); dir = getdirtowards(lf->cell, charmer->cell, lf, B_FALSE, DT_ORTH); if (dir == D_NONE) { - msg("You try to %s towards %s, but fail.", getmoveverb(lf), + msg("^wYou try to %s towards %s, but fail.", getmoveverb(lf), cansee(lf, charmer) ? charmername : "your new master"); } else { - msg("You mindlessly %s towards %s.", getmoveverb(lf), + msg("^wYou mindlessly %s towards %s.", getmoveverb(lf), cansee(lf, charmer) ? charmername : "your new master"); trymove(lf, dir, B_FALSE, B_TRUE); } @@ -2163,12 +2170,35 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { return B_FALSE; } - i = getskill(lf, SK_SWIMMING) - isburdened(lf); - limit(&i, 0, NA); - slev = i; - depth = getobdepth(o, lf); + // activate amulet of swimming + if (depth >= DP_HEAD) { + object_t *o; + o = hasequippedobid(lf->pack, OT_AMU_SWIMMING); + if (o && !ispolymorphed(lf)) { + // transform into a swan! + if (!polymorphto(lf, R_SWAN, PERMENANT)) makeknown(o->type->id); + } + + o = hasequippedobid(lf->pack, OT_AMU_EVOLUTION); + if (o) { + if (!polymorphto(lf, R_FISHFOLK, 5)) makeknown(o->type->id); + } + } + + // recalculate depth now + depth = getobdepth(o, lf); + + if (lfhasflag(lf, F_AQUATIC)) { + slev = PR_MASTER; + } else { + i = getskill(lf, SK_SWIMMING) - isburdened(lf); + limit(&i, 0, NA); + slev = i; + } + + // apply water damage (ie rust etc) to armour. for (i = 0; i <= depth; i++) { object_t *armour = NULL; @@ -2740,12 +2770,35 @@ void die(lifeform_t *lf) { msg("^GYou feel the presence of a nearby coffin..."); } else { addflag(lf->flags, F_WANTS, OT_COFFIN, B_COVETS, NA, NULL); + //killflagsofid(lf->flags, F_HOSTILE); addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); } return; } } + if (lf->race->id == R_LICH) { + f = lfhasflag(lf, F_LIFEOB); + if (f) { + cell_t *loc; + loc = findnearbylifeob(lf->cell, UNLIMITED, f, NULL); + if (loc) { + // announce + if (thisisplayer) { + msg("^GYou feel your soul being pulled to safety!^n"); + } + // teleport back to life ob, and revive. + teleportto(lf, loc, B_FALSE); + // restore all hp + lf->hp = lf->maxhp; + killflagsofid(lf->flags, F_DEAD); + return; + } + } else { + noise(lf->cell, lf, NC_OTHER, SV_CAR, "a horrified scream!", "screams in horror!"); + } + } + if (lf->race->id == R_GLOWBUG) { // final spell... castspell(lf, OT_S_FLASH, NULL, NULL, lf->cell, NULL, NULL); @@ -5237,10 +5290,16 @@ lifeform_t *findlfunique(enum RACE rid) { return NULL; } -cell_t *findnearbylifeob(cell_t *src, flag_t *lifeobflag, object_t **retlifeob) { +// if maxdist is NA, use the distance from the flag +// if maxdist is UNLIMITED, search the entire map +cell_t *findnearbylifeob(cell_t *src, int maxdist, flag_t *lifeobflag, object_t **retlifeob) { object_t *corpse = NULL; - int maxdist; - maxdist = lifeobflag->val[1]; + + if (maxdist == NA) { + maxdist = lifeobflag->val[1]; + } else if (maxdist == UNLIMITED) { + maxdist = MAXOF(src->map->w, src->map->h); + } if (retlifeob) { *retlifeob = NULL; @@ -5256,13 +5315,13 @@ cell_t *findnearbylifeob(cell_t *src, flag_t *lifeobflag, object_t **retlifeob) } } else { // find closest location with corpse... - cell_t *retcell[MAXCANDIDATES]; + cell_t *retcell[MAX_MAPW*MAX_MAPH]; int nretcells,i; enum OBTYPE oid; int mindist = 9999; oid = lifeobflag->val[0]; - getradiuscells(src, maxdist, DT_COMPASS, B_FALSE, LOF_DONTNEED, B_FALSE, retcell, &nretcells, 0); + getradiuscells(src, maxdist, DT_COMPASS, B_FALSE, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 0); for (i = 0; i < nretcells; i++) { object_t *o; cell_t *c; @@ -5313,6 +5372,7 @@ race_t *findrace(enum RACE id) { race_t *findracebyname(char *name) { race_t *r; raceclass_t *rc; + char searchfor[BUFLEN]; // first check for exact matches for (r = firstrace; r ; r = r->next) { if (!strcmp(r->name, name)) { @@ -5329,6 +5389,15 @@ race_t *findracebyname(char *name) { } } + // ...then partial matches start of words in name + // ie. "ant" should match "soldier ant" before matching "giant" + sprintf(searchfor, " %s",name); + for (r = firstrace; r ; r = r->next) { + if (strstr(r->name, searchfor)) { + return r; + } + } + // ...then partial matches in names for (r = firstrace; r ; r = r->next) { if (strstr(r->name, name)) { @@ -7543,7 +7612,9 @@ int getnightvisrange(lifeform_t *lf) { } // populates heartext, seetext and volume -int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, char *heartext,char *seetext, int *volume) { +// "lf" is optional. if not given, "noiseflag" should be provided. +// returns +int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, flag_t *noiseflag, char *heartext,char *seetext, int *volume) { flag_t *retflag[MAXCANDIDATES],*nflag[MAXCANDIDATES]; int nretflags, i,nnflags = 0; @@ -7552,40 +7623,43 @@ int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, char *heartext, if (heartext) strcpy(heartext, ""); if (seetext) strcpy(seetext, ""); - if (lfhasflag(lf, F_FROZEN)) { - // can't make noise if frozen! - return B_TRUE; - } - - if ((nid == N_WALK) || nid == (N_FLY)) { - if (!movecausesnoise(lf)) { + if (lf) { + if (lfhasflag(lf, F_FROZEN)) { + // can't make noise if frozen! return B_TRUE; } - } - getflags(lf->flags, retflag, &nretflags, F_NOISETEXT, F_NONE); - for (i = 0; i < nretflags; i++) { - if (retflag[i]->val[0] == nid) { - nflag[nnflags++] = retflag[i]; + if ((nid == N_WALK) || nid == (N_FLY)) { + if (!movecausesnoise(lf)) { + return B_TRUE; + } + } + + getflags(lf->flags, retflag, &nretflags, F_NOISETEXT, F_NONE); + for (i = 0; i < nretflags; i++) { + if (retflag[i]->val[0] == nid) { + nflag[nnflags++] = retflag[i]; + } + } + + if (nnflags) { + noiseflag = nflag[rnd(0,nnflags-1)]; } } - if (nnflags) { - flag_t *f; + if (noiseflag) { char verb[BUFLEN], noun[BUFLEN]; - f = nflag[rnd(0,nnflags-1)]; + if (volume) *volume = noiseflag->val[1]; - if (volume) *volume = f->val[1]; - - if (f->text[0] == '^') { + if (noiseflag->text[0] == '^') { strcpy(verb, ""); - //noun = strtok_r(f->text, "^", &dummy); - strcpy(noun, f->text + 1); + //noun = strtok_r(noiseflag->text, "^", &dummy); + strcpy(noun, noiseflag->text + 1); } else { char *p; - p = readuntil(verb, f->text, '^'); + p = readuntil(verb, noiseflag->text, '^'); readuntil(noun, p, '^'); // ie eol - //verb = strtok_r(f->text, "^", &dummy); + //verb = strtok_r(noiseflag->text, "^", &dummy); //noun = strtok_r(NULL, "^", &dummy); } @@ -7600,10 +7674,10 @@ int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, char *heartext, } } if (nid == N_WALK) { - *volume += getarmournoise(lf); + if (lf) *volume += getarmournoise(lf); } return B_FALSE; - } else { + } else if (lf) { // some defaults if (nid == N_WALK) { enum LFSIZE sz; @@ -7664,6 +7738,7 @@ int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, char *heartext, if (seetext) strcpy(seetext, "shouts a blood-curdling war-cry!"); return B_FALSE; } + // failed! return B_TRUE; } return B_FALSE; @@ -14397,6 +14472,8 @@ void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fr // further effects if not dead... if (!isdead(lf)) { + object_t *o; + // fight back if required if (fromlf && retaliate && !ko) { fightback(lf, fromlf); @@ -14480,6 +14557,19 @@ void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fr more(); } } + + + o = hasequippedobid(lf->pack, OT_AMU_EVOLUTION); + if (o) { + enum DAMTYPE basedt; + basedt = basedamagetype(damtype); + if (basedt == DT_FIRE) { + if (!polymorphto(lf, R_LAVAX, 5)) makeknown(o->type->id); + } else if (basedt == DT_COLD) { + if (!polymorphto(lf, R_SASQUATCH, 5)) makeknown(o->type->id); + } + } + } // end if !isdead } @@ -14596,7 +14686,7 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { int volume = 1; char hear[BUFLEN], see[BUFLEN]; - if (!getnoisedetails(lf, nid, hear, see, &volume)) { + if (!getnoisedetails(lf, nid, NULL, hear, see, &volume)) { // success noise(lf->cell, lf, noisetypetoclass(nid), volume, strlen(hear) ? hear : NULL, strlen(see) ? see : NULL); } @@ -15684,6 +15774,27 @@ int poisonthreatenslife(lifeform_t *lf, flag_t *f) { return B_FALSE; } +int polymorphto(lifeform_t *lf, enum RACE rid, int howlong) { + // alreay that race? just update polymorph timer. + if (lf->race->id == rid) { + flag_t *f; + f = hasflag(lf->flags, F_POLYMORPHED); + if (f) { + f->lifetime = howlong; + } + return B_TRUE; + } + + if (!hasflag(lf->flags, F_ORIGRACE)) { + // remember the original race + addflag(lf->flags, F_ORIGRACE, lf->race->id, NA, NA, NULL); + } + killflagsofid(lf->flags, F_POLYMORPHED); + addtempflag(lf->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, howlong); + setrace(lf, rid, B_TRUE); + return B_FALSE; +} + // maybe practice a skill void practice(lifeform_t *lf, enum SKILL skid, int amt) { flag_t *f; @@ -16671,6 +16782,14 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t } say(lf, buf, volume); break; + case SP_LIFEOB_DESTROYED: + switch (rnd(1,3)) { + case 1: snprintf(buf, BUFLEN, "NOOOOOOOOO!"); break; + case 2: snprintf(buf, BUFLEN, "NO! What have you done!?"); break; + case 3: snprintf(buf, BUFLEN, "It cannot be!"); break; + } + rv = say(lf, buf, volume); + break; case SP_MERCYACCEPT: switch (rnd(1,2)) { case 1: @@ -17154,6 +17273,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } loseconcentration(lf); + loseaitargets(lf); // were we already polymorphed? f = lfhasflag(lf, F_ORIGRACE); @@ -17332,50 +17452,26 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { // TODO: new race can use magic (F_NOSPELLS) // new race can still hold all the items which you have if ((gamemode == GM_GAMESTARTED)) { - enum BODYPART bp; object_t *o,*nexto; + int donemeldmsg = B_FALSE; //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging // no pack? - if (lfhasflag(lf, F_NOPACK)) { - if (reverting) { - // drop everything - if (countobs(lf->pack, B_FALSE)) { - if (isplayer(lf)) { - msg("Your possessions drop to the ground!"); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s%s possessions drop to the ground!",buf, getpossessive(buf)); - } - } - for (o = lf->pack->first ; o ; o = nexto) { - nexto = o->next; - - moveob(o, lf->cell->obpile, o->amt); - } - } else { - // meld - if (countobs(lf->pack, B_FALSE)) { - if (isplayer(lf)) { - msg("Your possessions meld into your new form!"); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s%s possessions meld into its new form!",buf, getpossessive(buf)); - } - } - for (o = lf->pack->first ; o ; o = nexto) { - nexto = o->next; - - moveob(o, lf->polypack, o->amt); - } - } - } //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging - for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) { - if (!hasbp(lf, bp)) { - o = getequippedob(lf->pack, bp); - if (o) { + + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + + f = isequipped(o); + if (f) { + int stillok = B_TRUE; + if (!hasbp(lf, f->val[0])) { + stillok = B_FALSE; + } else if (isarmour(o) && !armourfits(lf, o, NULL)) { + stillok = B_FALSE; + } + if (!stillok) { if (reverting) { char obname[BUFLEN]; getobname(o, obname, o->amt); @@ -17391,25 +17487,28 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } else { char obname[BUFLEN]; getobname(o, obname, o->amt); - // drop it! - if (isplayer(lf)) { - msg("Your %s melds into your new form!",noprefix(obname)); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s%s %s melds into its new form!",buf, getpossessive(buf), - noprefix(obname)); + if (!donemeldmsg) { + if (isplayer(lf)) { + msg("Your equipment melds into your new form!"); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s equipment melds into its new form!",buf, getpossessive(buf)); + } + donemeldmsg = B_TRUE; } + // drop it! moveob(o, lf->polypack, o->amt); } } } } + //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging for (o = lf->pack->first ; o ; o = nexto) { nexto = o->next; - if (!canpickup(lf, o, o->amt)) { + if (!canpickup(lf, o, o->amt) && !isequipped(o)) { if (reverting) { char obname[BUFLEN]; getobname(o, obname, o->amt); @@ -17425,18 +17524,56 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } else { char obname[BUFLEN]; getobname(o, obname, o->amt); - if (isplayer(lf)) { - msg("Your %s melds into your new form!",noprefix(obname)); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s%s %s melds into its new form!",buf, getpossessive(buf), - noprefix(obname)); + if (!donemeldmsg) { + if (isplayer(lf)) { + msg("Your equipment melds into your new form!"); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s equipment melds into its new form!",buf, getpossessive(buf)); + } + donemeldmsg = B_TRUE; } moveob(o, lf->polypack, o->amt); } } } + // drop/meld everything which isn't equipped. + // equipped objects are okay because if our new form lacked the required + // body part, they would have already been melded above. + if (lfhasflag(lf, F_NOPACK)) { + if (reverting) { + // drop everything which isn't equipped + if (countobs(lf->pack, B_FALSE) - countobswithflag(lf->pack, F_EQUIPPED)) { + if (isplayer(lf)) { + msg("Your possessions drop to the ground!"); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s possessions drop to the ground!",buf, getpossessive(buf)); + } + } + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + if (!isequipped(o)) moveob(o, lf->cell->obpile, o->amt); + } + } else { + // meld + if (countobs(lf->pack, B_FALSE) - countobswithflag(lf->pack, F_EQUIPPED)) { + if (isplayer(lf)) { + msg("Your possessions meld into your new form!"); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s possessions meld into its new form!",buf, getpossessive(buf)); + } + donemeldmsg = B_TRUE; + } + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + if (!isequipped(o)) moveob(o, lf->polypack, o->amt); + } + } + } + //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging if (isplayer(lf)) { @@ -18042,7 +18179,7 @@ void startlfturn(lifeform_t *lf) { int db = B_FALSE; map_t *map; enum ERROR error; - object_t *o; + object_t *o,*nexto; flag_t *f; flag_t *asp, *sf; char buf[BUFLEN]; @@ -18052,6 +18189,7 @@ void startlfturn(lifeform_t *lf) { flag_t *retflag[MAXCANDIDATES]; int nretflags; int movedlastturn = B_FALSE; + object_t *bloodamu = NULL; map = lf->cell->map; @@ -18157,7 +18295,14 @@ void startlfturn(lifeform_t *lf) { if (checkfordrowning(lf, o)) { if (isdead(lf)) return; } + } else { + // amulet of swimming? + if (hasequippedobid(lf->pack, OT_AMU_SWIMMING) && (lf->race->id == R_SWAN) && ispolymorphed(lf)) { + // revert to normal form + abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL); + } } + // suffocate? if (lfhasflag(lf, F_NEEDSWATER) && !hasobwithflag(lf->cell->obpile, F_DEEPWATER)) { int dam; @@ -18220,6 +18365,7 @@ void startlfturn(lifeform_t *lf) { } } + // oooooo replace with f_bleeding ? if (lfhasflagval(lf, F_INJURY, IJ_ARTERYPIERCE, NA, NA, NULL)) { if (!bleedfrom(lf, BP_HANDS, B_SPLATTER)) { @@ -18321,6 +18467,58 @@ void startlfturn(lifeform_t *lf) { } } + if (pctchance(25) && lfhasflag(lf, F_PARANOIA) && !lfhasflag(lf, F_AWARENESS)) { + if (isplayer(lf)) { + cell_t *c; + c = getcellindir(lf->cell, diropposite(lf->facing)); + if (c && cellwalkable(NULL, c, NULL)) { + int monisreal = B_FALSE; + race_t *r; + lifeform_t *mon; + + if (pctchance(15)) monisreal = B_TRUE; + + // either make a random noise from right behind the player, + // or ACTUALL create a monster behind them! + + // get random mosnter who makes walk noise + f = NULL; + while (!f) { + r = getreallyrandomrace(RC_ANY); + f = hasflagval(r->flags, F_NOISETEXT, N_WALK, NA, NA, NULL); + // don't want mosnters which will create objects, since we are going + // to palce a temporary one! + if (hasflag(r->flags, F_AUTOCREATEOB)) f = NULL; + } + // create the monster directly behind you + if (monisreal) { + // set autogen to false, we don't want minions appearing too. + mon = addmonster(c, r->id, NULL, B_FALSE, 1, B_FALSE, NULL); + } else { + mon = addlf(c, r->id, 1); + } + + if (mon) { + if (monisreal) { + killflagsofid(mon->flags, F_XPVAL); + addflag(mon->flags, F_XPVAL, 0, NA, NA, NULL); + turntoface(mon, lf->cell); + } + // it makes noise + makenoise(mon, N_WALK); + if (!monisreal) { + // now kill the monster + killlf(mon); + } + } + } + } else { + // monster just turns around to look behind. + loseaitargets(lf); + setfacing(lf, diropposite(lf->facing)); + } + } + // sixth sense spell warnings f = lfhasflag(lf, F_SIXTHSENSE); if (f) { @@ -18521,7 +18719,7 @@ void startlfturn(lifeform_t *lf) { object_t *corpse; char corpsename[BUFLEN]; - corpseloc = findnearbylifeob(lf->cell, f, &corpse); + corpseloc = findnearbylifeob(lf->cell, NA, f, &corpse); if (corpse) { // did we find a corpse in range ? if (corpse->type->id == OT_CORPSE) { @@ -18531,22 +18729,24 @@ void startlfturn(lifeform_t *lf) { } if (lf->race->id == R_GHOST) { // give possession ability - if (!lfhasflagval(lf, F_CANWILL, OT_S_POSSESSION, NA, NA, NULL)) { + if (isplayer(lf) && !lfhasflagval(lf, F_CANWILL, OT_S_POSSESSION, NA, NA, NULL)) { + flag_t *f2; char pwbuf[BUFLEN]; int power; power = lf->level / 3; if (power < 1) power = 1; if (power > 10) power = 10; snprintf(pwbuf, BUFLEN, "pw:%d;",power); - f = addflag(lf->flags, F_CANWILL, OT_S_POSSESSION, NA, NA, pwbuf); - f->lifetime = FROMRACE; + f2 = addflag(lf->flags, F_CANWILL, OT_S_POSSESSION, NA, NA, pwbuf); + f2->lifetime = FROMRACE; } } } else { // can't see corpse if (lf->race->id == R_GHOST) { - f = lfhasflagval(lf, F_CANWILL, OT_S_POSSESSION, NA, NA, NULL); - if (f) killflag(f); + flag_t *f2; + f2 = lfhasflagval(lf, F_CANWILL, OT_S_POSSESSION, NA, NA, NULL); + if (f2) killflag(f2); } // drain life if (isplayer(lf)) { @@ -18901,8 +19101,31 @@ void startlfturn(lifeform_t *lf) { } if (isdead(lf)) return; + bloodamu = hasequippedobid(lf->pack, OT_AMU_BLOOD); + // effects from cell objects? - for (o = lf->cell->obpile->first ; o ; o = o->next) { + for (o = lf->cell->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (bloodamu && (o->material->id == MT_BLOOD)) { + int amt; + amt = getobhp(o, NULL) * o->amt; + limit(&amt, 1, 10); + if (!isknown(bloodamu)) { + if (isplayer(lf) || cansee(player, lf)) { + char obname[BUFLEN],bname[BUFLEN]; + char lfname[BUFLEN]; + getlfname(lf, lfname); + getobname(bloodamu, obname, 1); + getobname(o, bname, 1); + msg("^%c%s%s %s sucks up %s!", getlfcol(lf, CC_GOOD), lfname, getpossessive(lfname), noprefix(obname), bname); + makeknown(bloodamu->type->id); + } + } + gainhp(lf, amt); + killob(o); + continue; + } + f = hasflag(o->flags, F_WALKDAM); if (f) { applywalkdam(lf, roll(f->text), f->val[0], o); @@ -19570,6 +19793,11 @@ int takeoff(lifeform_t *lf, object_t *o) { unequipeffects(lf, o); + // if you don't have a pack, it goes to the ground. + if (lfhasflag(lf, F_NOPACK)) { + moveob(o, lf->cell->obpile, o->amt); + } + return B_FALSE; } @@ -19737,7 +19965,18 @@ void timeeffectslf(lifeform_t *lf) { int willfall = B_FALSE; donesomething = B_FALSE; if ((dir == D_DOWN) && !isairborne(lf)) { + object_t *amu; + willfall = B_TRUE; + + amu = hasequippedobid(lf->pack, OT_AMU_EVOLUTION); + if (amu) { + if (!polymorphto(lf, R_AVIAD, 5)) { + makeknown(amu->type->id); + dospelleffects(lf, OT_S_FLIGHT, 1, lf, NULL, lf->cell, B_UNCURSED, NULL, B_FALSE); + willfall = B_FALSE; + } + } } else if ((dir == D_UP) && lfhasflag(lf, F_LEVITATING)) { willfall = B_TRUE; } @@ -20117,6 +20356,11 @@ void unequipeffects(lifeform_t *lf, object_t *o) { if (f) { stopspell(lf, f->val[0]); } + + if ((o->type->id == OT_AMU_SWIMMING) && (lf->race->id == R_SWAN) && ispolymorphed(lf)) { + // revert to normal form + abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL); + } } void unsummon(lifeform_t *lf, int vanishobs) { @@ -20218,6 +20462,11 @@ int unweild(lifeform_t *lf, object_t *o) { unequipeffects(lf, o); + // if you don't have a pack, it goes to the ground. + if (lfhasflag(lf, F_NOPACK)) { + moveob(o, lf->cell->obpile, o->amt); + } + return B_FALSE; } @@ -21901,6 +22150,9 @@ int willbleedfrom(lifeform_t *lf, enum BODYPART bp) { // don't bleed. return B_FALSE; } + + if (hasequippedobid(lf->pack, OT_AMU_BLOOD)) return B_FALSE; + return B_TRUE; } diff --git a/lf.h b/lf.h index 0a97092..9d59695 100644 --- a/lf.h +++ b/lf.h @@ -108,7 +108,7 @@ job_t *findjob(enum JOB jobid); job_t *findjobbyname(char *name); lifeform_t *findlf(map_t *m, int lfid); lifeform_t *findlfunique(enum RACE rid); -cell_t *findnearbylifeob(cell_t *src, flag_t *lifeobflag, object_t **retlifeob); +cell_t *findnearbylifeob(cell_t *src, int maxdist, flag_t *lifeobflag, object_t **retlifeob); poisontype_t *findpoisontype(enum POISONTYPE id); race_t *findrace(enum RACE id); race_t *findracebyname(char *name); @@ -188,7 +188,7 @@ int getmiscastchance(lifeform_t *lf); int getmorale(lifeform_t *lf); int getnextshortcut(lifeform_t *lf); int getnightvisrange(lifeform_t *lf); -int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, char *heartext,char *seetext, int *volume); +int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, flag_t *noiseflag, char *heartext,char *seetext, int *volume); char *getlfconditionname(enum LFCONDITION cond); object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp); //int getowing(lifeform_t *buyer, int shopid, int *retnitems); @@ -392,6 +392,7 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int anta void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat, enum RACE srcraceid); int poisoncausesvomit(enum POISONTYPE ptype); int poisonthreatenslife(lifeform_t *lf, flag_t *f); +int polymorphto(lifeform_t *lf, enum RACE rid, int howlong); void practice(lifeform_t *lf, enum SKILL skid, int amt); //void precalclos_old(lifeform_t *lf); void precalclos(lifeform_t *lf); diff --git a/map.c b/map.c index f61f2c0..445ea5b 100644 --- a/map.c +++ b/map.c @@ -124,9 +124,9 @@ void addhomeobs(lifeform_t *lf, int dolevelobs) { cell_t *homeobloc; homeobloc = lf->cell; for (f = lf->flags->first ; f ; f = f->next) { + object_t *o = NULL; if ((f->id == F_HOMEOB) && pctchance(f->val[0])) { cell_t *c; - object_t *o; o = addob(homeobloc->obpile, f->text); if (o && (homeobloc == lf->cell) && isimpassableob(o, lf, SZ_ANY)) { c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL); @@ -145,9 +145,17 @@ void addhomeobs(lifeform_t *lf, int dolevelobs) { while (!cellwalkable(NULL, c, NULL)) { c = getrandomcell(lf->cell->map); } - addob(c->obpile, f->text); + o = addob(c->obpile, f->text); } } + + if (o) { + if (lfhasflagval(lf, F_LIFEOB, o->type->id, NA, NA, NULL)) { + addflag(o->flags, F_LIFEOBFOR, lf->id, NA, NA, NULL); + killflagsofid(o->flags, F_OBHPDRAIN); + } + addflag(o->flags, F_HOMEOBFOR, lf->id, NA, NA, NULL); + } } } @@ -197,7 +205,8 @@ map_t *addmap(void) { // when monsters are made during level generation, autogen will be true. otherwise false; -// if "rid" RR_SPECIFIED, parse racename to get the race. +// if "rid" R_SPECIFIED, parse racename to get the race. +// rid can also be R_RANDOM. // otherwise just use the given race. lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok, int amt, int autogen, int *nadded) { lifeform_t *lf = NULL; @@ -386,26 +395,31 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok // everything is hostile. if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); } else { - // adjust hostility based on player's alignment - switch (getalignment(player)) { - case AL_GOOD: - if (getalignment(lf) == AL_GOOD) { - killflagsofid(lf->flags, F_HOSTILE); - } else if (getalignment(lf) == AL_EVIL) { - if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - } - break; - case AL_EVIL: - if (getalignment(lf) == AL_GOOD) { - if (!lfhasflag(lf, F_HOSTILE)) { - addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + // adjust hostility based on player's race + if ((player->race->id == R_AVIAD) && hasflag(lf->flags, F_AVIAN)) { + killflagsofid(lf->flags, F_HOSTILE); + } else { + // adjust hostility based on player's alignment + switch (getalignment(player)) { + case AL_GOOD: + if (getalignment(lf) == AL_GOOD) { + killflagsofid(lf->flags, F_HOSTILE); + } else if (getalignment(lf) == AL_EVIL) { + if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); } - } - break; - default: - break; + break; + case AL_EVIL: + if (getalignment(lf) == AL_GOOD) { + if (!lfhasflag(lf, F_HOSTILE)) { + addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } + } + break; + default: + break; + } } - } + } // end if hasequipped amu_victimisation } lf->born = B_TRUE; @@ -476,12 +490,14 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok for (n = 0; n < nminions; n++) { lifeform_t *newlf; + enum RACE newrid; race_t *newr; adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL); if (!adjcell) break; - newr = findracebyname(f->text); + newrid = parserace(f->text, NULL, NULL, NULL); + newr = findrace(newrid); if (!newr) break; newlf = addlf(adjcell, newr->id, getrandommonlevel(newr, adjcell->map)); @@ -942,6 +958,9 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in getroomedge(map, roomid, minx, miny, maxx, maxy, d, cell, &ncells, B_TRUE); for (i = 0; i < ncells; i++) { cell_t *newcell; + + if (cellisfixedvaultwall(cell[i])) continue; + // is there empty space on the other side of this wall segment? newcell = getcellindir(cell[i], d); if (newcell && !newcell->type->solid) { @@ -7394,6 +7413,25 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum S // now get raceid if (streq(p, "random")) { return R_RANDOM; + } else if (strstarts(p, "random ")) { + race_t *baser,*r; + // ie. "random xxx_baseraceid_xxx" + p += strlen("random "); + baser = findracebyname(p); + if (baser) { + enum RACE poss[MAXCANDIDATES]; + int nposs = 0; + // find all races with this baseid + for (r = firstrace ; r ; r = r->next) { + if (r->baseid == baser->id) { + poss[nposs++] = r->id; + if (nposs == MAXCANDIDATES) break; + } + } + if (nposs) { + return poss[rnd(0,nposs-1)]; + } + } } else { race_t *r; r = findracebyname(p); diff --git a/move.c b/move.c index 4736b0c..749b9f1 100644 --- a/move.c +++ b/move.c @@ -225,7 +225,7 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err f = hasflag(o->flags, F_DEEPWATER); if (f) { // non swimming creature in water? - if (!isairborne(lf)) { + if (!isairborne(lf) && !lfhasflag(lf, F_AQUATIC)) { if ((getobdepth(o, lf) >= DP_HEAD)) { if (getskill(lf, SK_SWIMMING) - isburdened(lf) <= 0) { if (error) { @@ -3396,7 +3396,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { if (!cell->lf) { f = lfhasflag(lf, F_LIFEOB); if (f) { - if (!findnearbylifeob(cell, f, NULL)) { + if (!findnearbylifeob(cell, NA, f, NULL)) { if (error) *error = E_WONT; return B_FALSE; } diff --git a/objects.c b/objects.c index c57d753..3f6c3a3 100644 --- a/objects.c +++ b/objects.c @@ -479,12 +479,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum int wantblessed = B_UNCURSED; race_t *corpserace = NULL; int dorandombrand = B_FALSE; - char wantnamed[BUFLEN]; brand_t *wantbrand = NULL; brand_t *br; obmod_t *om; obmod_t *wantom[MAXOBMODS]; - int wanthot = B_FALSE; int wanthppct = 100; regionthing_t *wantregionthing = NULL; int bonus = 0; @@ -505,10 +503,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum int donesomething; object_t *addedob[MAXPILEOBS]; int nadded = 0; + flagpile_t *wantflags; // for doors enum FLAG doorflag[5]; int ndoorflags = 0; - char *signtext = NULL; int trapchance = 0; int lockchance = 0; flag_t *retflag[MAXCANDIDATES]; @@ -519,8 +517,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum nadded = 0; nretobs = 0; - strcpy(wantnamed, ""); - if ((gamemode == GM_GAMESTARTED) && where->where) { assert(!where->where->type->solid); } @@ -531,6 +527,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum return NULL; } + wantflags = addflagpile(NULL, NULL); + if (forceoid != OT_NONE) { ot = findot(forceoid); howmany = 1; @@ -561,6 +559,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum // check if we want a name. if so, remember it and strip off the suffix. p2 = strstr(localname, " named "); if (p2) { + char wantnamed[BUFLEN]; char *wantp; char *copyfrom; copyfrom = p2 + strlen(" named "); @@ -573,6 +572,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum *wantp = '\0'; // now strip the suffix *p2 = '\0'; + + addflag(wantflags, F_NAMED, NA, NA, NA, wantnamed); } // check for premods. eg. "flaming xxx" "frozen xxx" etc @@ -707,9 +708,14 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum wantblessed = B_CURSED; p += strlen("cursed "); donesomething = B_TRUE; + // food flags + } else if (strstarts(p, "cooked ")) { + addflag(wantflags, F_PREPARED, B_TRUE, NA, NA, NULL); + p += strlen("cooked "); + donesomething = B_TRUE; // flags } else if (strstarts(p, "red-hot ")) { - wanthot = B_TRUE; + addflag(wantflags, F_HOT, 3, NA, NA, "1d4"); p += strlen("red-hot "); donesomething = B_TRUE; // condition flags @@ -947,6 +953,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum targetcell = NULL; } } else { + killflagpile(wantflags); return NULL; } @@ -966,7 +973,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum pp++; } *sbp = '\0'; - signtext = strdup(sbuf); + addflag(wantflags, F_SIGNTEXT, NA, NA, NA, sbuf); } ot = findot(OT_SIGN); } else if (strstr(p, "spellbook of ")) { @@ -1052,6 +1059,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum //if (gamestarted) msg("DB: No match for object name '%s'", p ); if (db) dblog("DB: No match for object name '%s'", p ); nretobs = 0; + killflagpile(wantflags); return NULL; } } @@ -1095,6 +1103,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum if (hasob(where, ot->id)) { if (db) dblog("DB: trying to add >1 ONEPERCELL object to a cell. (%s) bailing out.", ot->name); nretobs = 0; + killflagpile(wantflags); return NULL; } } @@ -1113,6 +1122,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum if (where->owner || where->where) { if (db) dblog("DB: Cannot give a spell object to a player, or a cell! object name '%s'", ot->name ); nretobs = 0; + killflagpile(wantflags); return NULL; } } @@ -1128,6 +1138,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum if (hasflag(ot->flags, F_NOPICKUP) && where->owner) { if (db) dblog("DB: trying to give NOPICKUP object '%s' to a lifeform ('%s').", ot->name, where->owner->race->name ); nretobs = 0; + killflagpile(wantflags); return NULL; } @@ -1152,6 +1163,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum if (obexists(ot->id)) { if (db) dblog("DB: Unique ob %s already exists!", p ); nretobs = 0; + killflagpile(wantflags); return NULL; } @@ -1310,7 +1322,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum } /* - need to do the below for _all_ objects added (searchfor"each object added")! + need to do the below for _all_ objects added (search "foreach object added")! */ for (i = 0; i < nadded; i++) { cell_t *obloc; @@ -1342,10 +1354,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum changemat(o, wantdiffmat); } - if (strlen(wantnamed)) { - addflag(o->flags, F_NAMED, NA, NA, NA, wantnamed); - } - if (wanthppct != 100) { f = hasflag(o->flags, F_OBHP); if (f) { @@ -1361,11 +1369,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum } } - // fill in sign text - if (signtext) { - addflag(o->flags, F_SIGNTEXT, NA, NA, NA, signtext); - } - // fill in portal destinations if (targetmap) { int tx = NA,ty = NA; @@ -1455,7 +1458,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum } } - // food flags if ((ot->obclass->id == OC_FOOD) && wantfoodtaint) { addflag(o->flags, F_TAINTED, B_TRUE, NA, NA, NULL); @@ -1464,10 +1466,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum if (o && hasflag(o->flags, F_LIGHTSOURCE) && wantlit) { turnon(NULL, o); } - // hot? - if (o && wanthot) { - addflag(o->flags, F_HOT, 3, NA, NA, "1d4"); - } // firearms usually come loaded if (o && isfirearm(o)) { @@ -2009,6 +2007,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum } } } + + // wantflags + if (o) { + copyflags(o->flags, wantflags, NA); + } } // end if !loading if ((gamemode == GM_GAMESTARTED) && !inaskcoords) { @@ -2031,6 +2034,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum nretobs = nadded; // return the first object given + killflagpile(wantflags); return addedob[0]; } @@ -8255,6 +8259,9 @@ object_t *obexists(enum OBTYPE obid) { void obdie(object_t *o) { char obname[BUFLEN]; flag_t *f; + cell_t *loc; + + loc = getoblocation(o); o->dying = B_TRUE; @@ -8319,10 +8326,10 @@ void obdie(object_t *o) { if (f) { if (f->val[2] == B_IFACTIVATED) { if (isactivated(o)) { - brightflash(getoblocation(o),f->val[0], NULL); + brightflash(loc,f->val[0], NULL); } } else { - brightflash(getoblocation(o),f->val[0], NULL); + brightflash(loc,f->val[0], NULL); } } @@ -8341,6 +8348,20 @@ void obdie(object_t *o) { } } + + if (loc) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags = 0,i; + getflags(o->flags, retflag, &nretflags, F_LIFEOBFOR, F_NONE); + for (i = 0; i < nretflags; i++) { + lifeform_t *l; + l = findlf(loc->map, retflag[i]->val[0]); + if (l) { + sayphrase(l, SP_LIFEOB_DESTROYED, SV_CAR, NA, NULL); + } + } + } + killob(o); } @@ -10152,6 +10173,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE int amt; int failed; int seenbyplayer; + object_t *o2; flag_t *f; if (isplayer(lf)) { @@ -10168,6 +10190,13 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE getlfname(lf, lfname); + // override? + if ((oid == OT_POT_BLOODC) && !lfhasflag(lf, F_BEINGSTONED)) { + if ((lf->race->id == R_VAMPIRE) || hasequippedobid(lf->pack, OT_AMU_BLOOD)) { + oid = OT_POT_BLOOD; + } + } + switch (oid) { case OT_POT_ACID: if (isplayer(lf)) { @@ -10511,9 +10540,18 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } break; case OT_POT_BLOOD: - if (lf->race->id == R_VAMPIRE) { + o2 = hasequippedobid(lf->pack, OT_AMU_BLOOD); + if ((lf->race->id == R_VAMPIRE) || o2) { int b = B_UNCURSED; - if (isplayer(lf)) msg("This blood is delicious!"); + if (isplayer(lf)) { + if (o2 && !isknown(o2)) { + char o2name[BUFLEN]; + getobname(o2, o2name, o2->amt); + msg("^gYour %s pulses as your drink!^n", noprefix(o2name)); + makeknown(o2->type->id); + } + msg("This blood is delicious!"); + } if (potblessed == B_BLESSED) { b = B_CURSED; } else if (potblessed == B_CURSED) { @@ -11029,10 +11067,39 @@ int readsomething(lifeform_t *lf, object_t *o) { } if (isplayer(lf)) { - if (ndone) { - msg("You are surrounded by a stabilising aura."); - } else { - nothinghappens(); + msg("You are surrounded by a stabilising aura."); + } + if (!ndone) { + object_t *oo,*poss[MAXPILEOBS]; + int nposs = 0; + + // make a piece of armour invulnerable + for (oo = lf->pack->first ; oo ; oo = oo->next) { + if (isequipped(oo) && !hasflag(o->flags, F_INVULNERABLE)) { + poss[nposs++] = oo; + } + } + + if (nposs) { + oo = poss[rnd(0,nposs-1)]; + addflag(oo->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL); + if (isplayer(lf)) { + char ooname[BUFLEN]; + getobname(oo, ooname, oo->amt); + msg("Your %s become%s ultra-dense!", obname, (oo->amt == 1) ? "s" : ""); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + char ooname[BUFLEN]; + getlfname(lf, lfname); + getobname(oo, ooname, oo->amt); + msg("%s%s %s become%s ultra-dense!", lfname, getpossessive(lfname), + obname, (oo->amt == 1) ? "s" : ""); + } + ndone++; + } + // still nothing done? + if (!ndone) { + if (isplayer(lf)) msg("Unfortunately, it doesn't seem to affect you."); } } @@ -11204,6 +11271,10 @@ object_t *relinkob(object_t *src, obpile_t *dst) { // unweild killflagsofid(src->flags, F_EQUIPPED); + if (src->pile->owner) { + unequipeffects(src->pile->owner, src); + } + // adjust letter... // gold should always have letter '$' if (src->type->obclass->id == OC_MONEY) { diff --git a/spell.c b/spell.c index 1931b78..8dbd4e4 100644 --- a/spell.c +++ b/spell.c @@ -310,7 +310,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (inway) { // just get the lf in the way - if (getnoisedetails(inway, N_WALK, thismovetext, NULL, &vol)) { + if (getnoisedetails(inway, N_WALK, NULL, thismovetext, NULL, &vol)) { // doesn't make noise nposs = 0; } else { @@ -327,7 +327,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef for (lf = c->map->lf ; lf ; lf = lf->next) { if (lf == user) continue; // get movement text - if (getnoisedetails(lf, N_WALK, thismovetext, NULL, &vol)) continue; + if (getnoisedetails(lf, N_WALK, NULL, thismovetext, NULL, &vol)) continue; if (slev >= PR_EXPERT) { // overwrite name real_getlfnamea(lf, thismovetext, B_FALSE, B_FALSE); @@ -4593,7 +4593,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } - howlong = getspellduration(2,5,blessed) + power; + if (isplayer(target)) { + howlong = 2+(power/5); // ie. 2-4 + } else { + howlong = getspellduration(2,5,blessed) + power; + } if (isplayer(target)) { addtempflag(target->flags, F_CHARMEDBY, caster->id, NA, NA, NULL, howlong); @@ -6516,16 +6520,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } } else { + int howlong; if (isplayer(caster) || haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } - // remember the original race - addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL); - if (target->race->id != R_VAMPIRE) { - // polymorph is temporary - addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, 10); + if (target->race->id == R_VAMPIRE) { + howlong = PERMENANT; + } else { + howlong = 10; } - setrace(target, R_GASCLOUD, B_TRUE); + polymorphto(target, R_GASCLOUD, howlong); } } else if (spellid == OT_S_GLACIATE) { object_t *o,*nexto; @@ -7768,9 +7772,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // teleport to destination. - msg("orig cell: %d,%d.", caster->cell->x, caster->cell->y); teleportto(caster, targcell, B_FALSE); - msg("new cell: %d,%d.", caster->cell->x, caster->cell->y); } else if (spellid == OT_S_PARALYZE) { int howlong; int saved = B_FALSE; @@ -9095,28 +9097,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (r) { + int howlong; //int rememberorig = B_FALSE; - getlfname(target, buf); - - // if this is the player, remember the original race and job... - if (!hasflag(target->flags, F_ORIGRACE)) { - // remember the original race - addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL); - } if (isplayer(target)) { - int howlong; // polymorph will be temporary... howlong = rnd(20,50); - addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, howlong); } else { - // permenant - addflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL); + howlong = PERMENANT; } - - - // become the new race! - setrace(target, r->id, B_TRUE); + polymorphto(target, r->id, howlong); // if someone cast the spell at themself and it's controlled, they can change back at will. if (target == caster) { @@ -12793,6 +12783,7 @@ int spellokformonsters(int spellid) { int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce) { char text[BUFLEN],buf[BUFLEN]; int bonus = 0; + int resisted = B_FALSE; // cannot resist spells from gods when they are on their home plane if (caster && (caster->race->raceclass->id == RC_GOD)) { @@ -12825,7 +12816,14 @@ int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power // cancel out the difficulty from NULLIFY being a level 4 spell bonus += 8; } - if (skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), bonus)) { + + if (spellisfromschool(spellid, SS_MENTAL) && lfhasflag(target, F_MINDSHIELD)) { + resisted = B_TRUE; + } else { + resisted = skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), bonus); + } + + if (resisted) { if (isplayer(target) || haslos(player, target->cell)) { if (announce) { msg("%s",text); diff --git a/vault.c b/vault.c index c926866..d801c01 100644 --- a/vault.c +++ b/vault.c @@ -395,7 +395,7 @@ int addvaultthing(cell_t *c, vault_t *v, enum VAULTTHING vt, char *what) { break; case VT_LF: - lf = addmonster(c, R_SPECIFIED, what, B_TRUE, 1, B_FALSE, NULL); + lf = addmonster(c, R_SPECIFIED, what, B_TRUE, 1, B_TRUE, NULL); if (!lf) { dblog("invalid racename '%s' in vault", what); rv = B_TRUE;