- [+] 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!"
This commit is contained in:
Rob Pearce 2012-03-08 19:42:25 +00:00
parent ea5d012876
commit a6aab1afe1
16 changed files with 879 additions and 247 deletions

74
ai.c
View File

@ -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;
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) {
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
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) {

1
ai.h
View File

@ -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);

View File

@ -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;
}
}

257
data.c
View File

@ -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);

Binary file not shown.

View File

@ -1,12 +1,12 @@
@id:bear_cave
@map
##########
###....###
##......##
O......B.#
##......##
###....###
##########
###########
####....###
###......##
.O......B.#
###......##
####....###
###########
@end
@legend

23
defs.h
View File

@ -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.

View File

@ -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

21
io.c
View File

@ -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;

450
lf.c
View File

@ -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;
}

5
lf.h
View File

@ -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);

82
map.c
View File

@ -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);

4
move.c
View File

@ -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;
}

131
objects.c
View File

@ -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) {

52
spell.c
View File

@ -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);

View File

@ -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;