- [+] fixed CRASH when energy blade vanishes

- [+] gods of opposing alignments should never make offers.
- [+] new armour flag:
    - [+] f_underclothing
    - [+] getequippedob() - get the outer one.
    - [+] if you have f_underclothing, can wear other armour on top of
          it.
    - [+] can't remove underclothes without removing outer first.
    - [+] TEST with cotton shirt
    - [+] make sure autoequip handles undercltohing
    - [+] fix other objects
    - [+] adjust ']' output
- [+] make armour help against some magical damage too
    - [+] move armour check and reduction into losehpeffects().
    - [+] pass damreducedbyarmour to losehpeffects
- [+] psionic spells:
    - [+] dampen missiles - lots of extra evasion vs missiles only
    * [+] soul link (l4, share damage)
    - [+] mind sheidl (l4, like the amulet)
    - [+] delay death (l5, don't die if hp <= 0 and this spell is
          active)
    - [+] remote ko (l6)
- [+] Silence spell / effect - air.
    - [+] f_silenced.
    - [+] announce in io.c
    - [+] prevents spellcasting
    - [+] prevents docomms()
    - [+] prevents reading scrolls
    - [+] prevents speech-based abilities like warcry and sonic bolt
    - [+] say() will fail
    - [+] sayphrase() wil fail
    - [+] test the spell.......
- [+] CRASH when adjusting glyph on edge of map
- [+] non-humanoids can't climb without climb skill.
- [+] player sohuld be able to swap with unconscious/asleep lfs <= same
      size
- [+] too easy to knock things unconscious??? bug. fixed.
- [+] reusable cells being set to empty! think this was a vault
      definition problem.
- [+] demon chameleon / deech
    - [+] low-level mosnter which can hide
This commit is contained in:
Rob Pearce 2012-12-06 04:57:13 +00:00
parent 38a788ca5f
commit d7f6991a40
36 changed files with 963 additions and 346 deletions

15
ai.c
View File

@ -1763,7 +1763,7 @@ int ai_inventory_mgt(lifeform_t *lf, int *canattack) {
// is it red hot?
if (curarm && hasflag(curarm->flags, F_HOT) && !isimmuneto(lf->flags, DT_FIRE, B_FALSE)) {
if (db) dblog("%s o O { wearing a red-hot item. will try to remove it. } ", lf->race->name);
if (cantakeoff(lf, curarm)) {
if (cantakeoff(lf, curarm, NULL)) {
if (!takeoff(lf, curarm)) {
return B_TRUE;
}
@ -2606,6 +2606,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
return B_FALSE;
}
if (lfhasflag(lf, F_SILENCED)) {
if (db) dblog(".oO { can't cast spells, i am silenced }");
return B_FALSE;
}
ot = findot(spellid);
if (ot) {
flag_t *f;
@ -3151,6 +3156,9 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
if ((ot->id == OT_S_SMITEEVIL) && (getalignment(victim) != AL_EVIL)) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_A_SONICBOLT) && lfhasflag(lf, F_SILENCED)) {
specificcheckok = B_FALSE;
}
if (ot->id == OT_S_SPIKEVOLLEY) {
if ((lf->race->id == R_MANTICORE) && lfhasflagval(lf, F_INJURY, IJ_TAILBROKEN, NA, NA, NULL)) {
specificcheckok = B_FALSE;
@ -3219,6 +3227,9 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
specificcheckok = B_FALSE;
}
}
if ((ot->id == OT_A_WARCRY) && lfhasflag(lf, F_SILENCED)) {
specificcheckok = B_FALSE;
}
if ((ot->id == OT_S_WARPWOOD)) {
specificcheckok = B_FALSE;
@ -3661,7 +3672,7 @@ int useitemwithflag(lifeform_t *lf, enum FLAG whichflag) {
quaff(lf, o);
return B_FALSE;
}
} else if (o->type->obclass->id == OC_SCROLL) {
} else if ((o->type->obclass->id == OC_SCROLL) && !lfhasflag(lf, F_SILENCED)) {
if (!readsomething(lf, o)) {
return B_FALSE;
}

121
attack.c
View File

@ -41,8 +41,8 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty
// special case - missiles always hit flak jacket
if (damtype == DT_PROJECTILE) {
object_t *o;
o = getequippedob(lf->pack, BP_BODY);
if (o && (o->type->id == OT_FLAKJACKET)) {
o = hasequippedobid(lf->pack, OT_FLAKJACKET);
if (o) {
armour = o;
}
}
@ -1056,7 +1056,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (critpos == BP_NONE) {
strcpy(victimbpname, victimname);
} else {
armour = getequippedob(victim->pack, critpos);
armour = getouterequippedob(victim, critpos);
if (armour) {
char armname[BUFLEN];
real_getobname(armour, armname, 1, B_NOPREMODS, B_NOCONDITION, B_BLINDADJUST, B_NOBLESSINGS, B_NOUSED, B_NOSHOWALL);
@ -1152,7 +1152,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
dam[0] = getdamroll(wep, victim, damflag);
if (isunarmed) {
object_t *gloves;
gloves = getequippedob(lf->pack, BP_HANDS);
gloves = getouterequippedob(lf, BP_HANDS);
if (gloves && hasflag(gloves->flags, F_HARDNESS)) {
dam[0]++;
}
@ -1318,12 +1318,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// armour doesn't reduce damage for backstabs or critical hits.
// BUT in the case of a critical hit, the armour might get
// damaged during the call to criticalhit() later on.
if ((dam[i] > 0) && !backstab && !critical && ismeleedam(damtype[i])) {
// modify for defender's armour
// first figure out how much to reduce the damage by.
damreducedbyarmour = getarmourdamreduction(victim, wep, dam[i], damtype[i]);
// now actually reduce the damage amount
applyarmourdamreduction(victim, wep, damreducedbyarmour, &dam[i], damtype[i]);
//
// normally armour would be handled by losehp() & losehpeffects(), but
// in this case we need to know whether the armour was hit beforehand,
// in order to construct the "you hit xxx" string.
if ((dam[i] > 0) && !backstab && !critical) {
damreducedbyarmour = handlearmour(victim, wep, &dam[i], damtype[i]);
}
// if damage has been reduced zero, it's not a critical hit anymore.
@ -1436,7 +1437,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
damreducedbyarmour = 0;
} else if (lfhasflag(lf, F_QUIVERINGPALM)) {
// victim explodes!
losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL, B_FALSE, NULL, B_FALSE, BP_NONE);
losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL, B_FALSE, NULL, B_FALSE, BP_NONE, B_NOCRIT);
damreducedbyarmour = 0;
} else {
// actually deal the melee damage!
@ -1478,7 +1479,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// don't adjust damage for resistences - we've already done that
losehp_real(victim, dam[i], damtype[i], lf, buf, B_NODAMADJUST, wep, B_NORETALIATE,
&waskod, B_NODAMEFFECTS, critpos);
&waskod, B_NODAMEFFECTS, critpos, critical);
}
// was it fatal ? override previously calculated value.
if ((victim->hp <= 0) && !waskod) {
@ -1556,41 +1557,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
}
// now magic armour will pulse and maybe vanish.
if (magicarm) {
int damprevented;
// prevent all damage if possible
damprevented = dam[i];
magicarm->val[0] -= damprevented;
if (magicarm->val[0] <= 0) {
// did magic armour come from a spell?
if (magicarm->lifetime == FROMSPELL) {
flag_t *spellflag;
spellflag = hasactivespell(victim, magicarm->obfrom);
if (spellflag) {
killflag(spellflag);
}
}
// magic armour vanishes now.
killflag(magicarm);
} else {
if (cansee(player, victim)) {
msg("^%d%s%s %s pulses!^n",
CC_GOOD,
victimname, getpossessive(victimname),
magicarm->text);
}
}
} else {
// victim's armour loses hp. note that it loses the full
// amount of damage dealt, not just what it reduced.
if (damreducedbyarmour && !critical) {
applyarmourdamage(victim, wep, dam[i] + damreducedbyarmour, damtype[i], lf);
// train armour
practice(victim, SK_ARMOUR, 1);
}
}
/// ... used to apply armour damage here...
// make noise
// UNLESS this fighting involved the player.
@ -1606,8 +1574,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
// now handle the extra hp loss effects which we postponed above.
losehpeffects(victim, dam[i], damtype[i], lf, wep, B_NORETALIATE, waskod, &waskod, prebleed,
BP_NONE);
losehpeffects(victim, dam[i], damtype[i], lf, wep, B_NORETALIATE, waskod,
&waskod, prebleed, BP_NONE, damreducedbyarmour, critical);
if (fatal || waskod || dodged || stopnow) break; // stop now, don't process further damtypes!
} // end foreach damtype
@ -1722,7 +1690,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
attackername);
}
snprintf(damstring, BUFLEN, "%s%s %s", victimname, getpossessive(victimname), noprefix(obname));
losehp_real(lf, rdam, f->val[0], victim, damstring, B_TRUE, NULL, B_TRUE, NULL, B_TRUE, critpos);
losehp_real(lf, rdam, f->val[0], victim, damstring, B_TRUE, NULL, B_TRUE, NULL, B_TRUE, critpos, critical);
free(loctext);
}
}
@ -1975,7 +1943,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(o->flags, F_HARDNESS)) {
object_t *gloves;
gloves = getequippedob(lf->pack, BP_HANDS);
gloves = getouterequippedob(lf, BP_HANDS);
if (gloves && hasflag(gloves->flags, F_HARDNESS)) {
// ok
} else if ((o->material->id == MT_WOOD) && (getskill(lf, SK_UNARMED) >= PR_ADEPT)) {
@ -2174,7 +2142,7 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) {
if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(c->type->material->flags, F_HARDNESS)) {
object_t *gloves;
gloves = getequippedob(lf->pack, BP_HANDS);
gloves = getouterequippedob(lf, BP_HANDS);
if (gloves && hasflag(gloves->flags, F_HARDNESS)) {
// ok
} else if ((c->type->material->id == MT_WOOD) && (getskill(lf, SK_UNARMED) >= PR_ADEPT)) {
@ -2563,12 +2531,10 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d
int ar,min,max;
//int pctrange;
object_t *o;
flag_t *pierce = NULL;
if (hasflag(wep->flags, F_ARMOURIGNORE)) {
reduceamt = 0;
}
if (wep && hasflag(wep->flags, F_ARMOURIGNORE)) {
return 0;
}
ar = getarmourrating(lf, NULL, NULL, NULL, NULL);
// between 25% and 75% of AR.
@ -2582,22 +2548,25 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d
// special case
if (damtype == DT_PROJECTILE) {
o = getequippedob(lf->pack, BP_BODY);
if (o && (o->type->id == OT_FLAKJACKET)) {
o = hasequippedobid(lf->pack, OT_FLAKJACKET);
if (o) {
// stop ALL missile damage
reduceamt = dam;
}
}
// and if weapon is armour piercing, you always take at least its
// armourpiercing valut.
pierce = hasflag(wep->flags, F_ARMOURPIERCE);
if (pierce) {
if (pierce->val[0] < 0) reduceamt = 0;
else reduceamt -= pierce->val[0];
if (wep && reduceamt) {
flag_t *pierce = NULL;
// and if weapon is armour piercing, you always take at least its
// armourpiercing valut.
pierce = hasflag(wep->flags, F_ARMOURPIERCE);
if (pierce) {
if (pierce->val[0] < 0) reduceamt = 0;
else reduceamt -= pierce->val[0];
}
}
limit(&reduceamt, 0, dam);
if (reduceamt < 0) reduceamt = 0;
return reduceamt;
}
@ -2934,6 +2903,26 @@ int getstrdammod(lifeform_t *lf) {
}
int armourcanstopdam(enum DAMTYPE damtype) {
switch (damtype) {
case DT_PIERCE:
case DT_SLASH:
case DT_BASH:
case DT_BITE:
case DT_CHOP:
case DT_PROJECTILE:
case DT_UNARMED:
case DT_ACID:
case DT_EXPLOSIVE:
case DT_MAGIC:
case DT_CRUSH:
return B_TRUE;
default:
break;
}
return B_FALSE;
}
// ie. caused by hitting something with a melee weapon
int ismeleedam(enum DAMTYPE damtype) {
switch (damtype) {

View File

@ -26,6 +26,7 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag);
//int getunarmeddamroll(flag_t *f);
int getstrdammod(lifeform_t *lf);
//obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag);
int armourcanstopdam(enum DAMTYPE damtype);
int iskineticdam(enum DAMTYPE damtype);
int ismeleedam(enum DAMTYPE damtype);
int isphysicaldam(enum DAMTYPE damtype);

89
data.c
View File

@ -4365,6 +4365,13 @@ void initobjects(void) {
addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_S_SILENCE, "silence", "Prevents vibration of air molecules around the target's mouth, preventing them from uttering a sound.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the silence will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addot(OT_S_SLOW, "slowness", "Causes the air around the target to thicken to a water-like consistency, greatly decreasing their speed.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the slowness will last.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL);
@ -5162,6 +5169,9 @@ void initobjects(void) {
addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL);
addot(OT_S_STUN, "stun", "Stuns the target, preventing them from taking agressive action for a few seconds.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power I-IV, target is stunned for 2 turns.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power V-IX, target is stunned for 3 turns.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power X, target is stunned for 4 turns.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
@ -5233,6 +5243,12 @@ void initobjects(void) {
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_SLOWMISSILES, "dampen missiles", "Creates a weak wall of outward psionic force around you, slowing down incoming projectiles and making them easier to dodge.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL);
// l3
addot(OT_S_ANTICIPATE, "anticipate action", "Allows the caster to automatically dodge the target's attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power detemines the number of attacks dodged.");
@ -5267,7 +5283,7 @@ void initobjects(void) {
addot(OT_S_BAFFLE, "baffle", "Confuses the target, causing them to lose control of their movement.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The target will be confused for ^bpower^n*4 turns.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
@ -5305,20 +5321,51 @@ void initobjects(void) {
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL);
addot(OT_S_SOULLINK, "soul link", "Creates a psychic bond between two creatures. As long as the bond holds, damage dealt to either creature will be felt by the other.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power I, you can only link creatures to yourself.");
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power III, you can form a link between two other creatures.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 3, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_STASIS, "stasis", "Freezes time inside your body, preventing many effects such as poison, hunger, and even breathing.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Note that health regeneration is also prevented while in stasis.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l5
addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines resistability and duration.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_MINDSHIELD, "mind shield", "Erects an impenetrable mental shield around the caster's mind, rendering them immune to all psionic abilities (but also unable to use them).", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l5
addot(OT_S_DELAYDEATH, "delay death", "This power will allow its user to defy death itself, remaining alive even after their HP drops to zero.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "WARNING: losing concentration before damage is healed will result in instant death.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l6
addot(OT_S_REMOTEKO, "remote ko", "Disable the conscious part of a creature's mind, instantly knocking it unconscious.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_RANGE, 3, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
///////////////////
// summoning
///////////////////
@ -7483,7 +7530,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SHRINKSTO, OT_STICK, VT_OB, NA, NULL);
addot(OT_BARRICADE, "barricade", "A short barricade constructed of metal. Looks like you might able to climb over it.", MT_METAL, 200, OC_DFEATURE, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL);
addflag(lastot->flags, F_GLYPH, C_METAL, '\\', NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
@ -7866,6 +7913,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL);
addflag(lastot->flags, F_UNDERCLOTHING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 0, 5, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_COLD, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
@ -7892,6 +7940,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_UNDERCLOTHING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL);
@ -7905,6 +7954,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL);
addflag(lastot->flags, F_UNDERCLOTHING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FIRE, NA, NULL);
addflag(lastot->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL);
@ -8003,6 +8053,7 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL);
addflag(lastot->flags, F_UNDERCLOTHING, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL);
@ -12065,7 +12116,7 @@ void initrace(void) {
addflag(lastrace->flags, F_AVIAN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_EATCONFER, F_MUTABLE, B_TRUE, NA, "100");
addrace(R_CENTAUR, "centaur", 500, 'u', C_BROWN, MT_FLESH, RC_ANIMAL, "Centaurs look like horses with their neck upwards replaced by a human torso and arms.");
addrace(R_CENTAUR, "centaur", 500, 'u', C_FLESH, MT_FLESH, RC_ANIMAL, "Centaurs look like horses with their neck upwards replaced by a human torso and arms.");
setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_NEUTRAL, NA, NA, NULL);
@ -18797,6 +18848,34 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flaming barbed whip");
addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL);
addrace(R_DEECH, "deech", 20, ':', C_MAGENTA, MT_FLESH, RC_DEMON, "The name deech is short for 'Demon Chameleon'. These minor demonic reptiles can blend into their surroundings, becoming all but invisible to their prey.");
setbodytype(lastrace, BT_QUADRAPED);
addbodypart(lastrace, BP_TAIL, NULL);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_RARITY, H_MASTERVAULTS, NA, RR_RARE, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL);
addflag(lastrace->flags, F_TR, 2, 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_HASATTACK, OT_CLAWS, 3, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_AGI, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_RANDOM, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_RANDOM, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_RANDOM, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "hisses^a hiss");
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTHIDDENPCT, 100, NA, NA, NULL);
addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_EXPERT, NA, NULL);
addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL);
addrace(R_DRETCH, "dretch", 30, '&', C_BROWN, MT_FLESH, RC_DEMON, "An ape-like creature with extended forearms ending in clawed hands. They stand about 4 feet tall and weigh 60 pounds.");
setbodytype(lastrace, BT_HUMANOID);

Binary file not shown.

View File

@ -15,6 +15,7 @@ d:cell:dirt wall
.:cell:dirt
O:exit
R:reusable
R:cell:dirt wall
@end
@flags

View File

@ -28,6 +28,7 @@ C:ob:ornate chest
X:ob:hut's doorway
w:ob:great random weapon
r:reusable
r:cell:brick wall
@end
@flags

View File

@ -15,6 +15,7 @@ O:ob:boulder
O:exit
B:mon:grizzly bear
r:reusable
r:cell:dirt wall
@end
@flags

View File

@ -14,6 +14,7 @@ rrr######rr
O:ob:boulder
O:exit
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -27,6 +27,7 @@ _:ob:pentagram
_:ob:ancient stone key
C:ob:ornate chest
r:reusable
r:cell:metal wall
@end
@flags

View File

@ -29,6 +29,7 @@ _:ob:cursed excellent weapon
_:ob:ancient stone key
C:ob:ornate chest
r:reusable
r:cell:metal wall
@end
@flags

View File

@ -16,6 +16,7 @@ rr###+###rr
+:ob:wooden door
+:exit
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -16,6 +16,7 @@ r##..#..##r
O:ob:large fire:50
X:exit
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -19,6 +19,7 @@ f:ob:immutable large fire
c:ob:untrapped ornate chest
d:ob:secret door:15:cell:SOLID
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -15,6 +15,7 @@ r#ggggg#r
g:cell:glass wall
w:ob:very deep water:100
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -14,6 +14,7 @@ rr##+##rr
+:ob:wooden door
+:exit
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -14,6 +14,7 @@ _:ob:barricade
m:mon:humanoid with firearm
X:exit
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -13,6 +13,7 @@ r#####r
p:ob:playerstart
x:exit
r:reusable
r:cell:SOLID
@end
@flags
goesin:dungeon

View File

@ -15,6 +15,7 @@ rrr###
p:ob:playerstart
x:exit
r:reusable
r:cell:SOLID
@end
@flags
goesin:dungeon

View File

@ -13,6 +13,7 @@ r##x##r
#:cell:SOLID
x:exit
r:reusable
r:cell:SOLID
@end
@flags

View File

@ -10,6 +10,7 @@ r#+#r
@legend
#:cell:wyrmwood wall
r:reusable
r:cell:wyrmwood wall
+:exit
+:ob:wooden door
h:cell:tiled floor

View File

@ -10,6 +10,7 @@ r#########r
#:cell:SOLID
X:exit
r:reusable
r:cell:SOLID
@end
@flags

20
defs.h
View File

@ -109,6 +109,9 @@
#define B_MAYBE (-2)
#define B_ONEOF (-3)
#define B_FROMCRIT (-1)
#define B_NOCRIT (0)
#define B_BLINDABLE (-1)
#define B_ALLOWEXTRA (-1)
@ -259,6 +262,7 @@
// must be >= max # of spells/abilities AND
// >= max # of cells on the map
// >= MAXFLAGS
#define MAXCANDIDATES 2048
#define MAXCHOICES 400
@ -1493,6 +1497,7 @@ enum RACE {
R_STIRGE,
// demons
R_BALROG,
R_DEECH,
R_DRETCH,
R_GRIDDLER,
R_LURKINGHORROR,
@ -1996,6 +2001,7 @@ enum OBTYPE {
OT_S_GRAVBOOST,
OT_S_HASTE,
OT_S_LEVITATION,
OT_S_SILENCE,
OT_S_SLOW,
OT_S_TRUESTRIKE,
OT_S_WHATGOESUP,
@ -2019,6 +2025,7 @@ enum OBTYPE {
OT_S_CHARM,
OT_S_CHIBOLT,
OT_S_CHISTRIKE,
OT_S_DELAYDEATH,
OT_S_DISORIENT,
OT_S_HUNGER,
OT_S_LETHARGY,
@ -2026,6 +2033,7 @@ enum OBTYPE {
OT_S_KNOWWEAKNESS,
OT_S_MFEEDBACK,
OT_S_MINDSCAN,
OT_S_MINDSHIELD,
OT_S_MINDWHIP,
OT_S_MIRRORIMAGE,
OT_S_PACIFY,
@ -2033,8 +2041,11 @@ enum OBTYPE {
OT_S_PSIBLAST,
OT_S_PSYARMOUR,
OT_S_PSYSHOVE,
OT_S_REMOTEKO,
OT_S_SLEEP,
OT_S_SLEEPMASS,
OT_S_SLOWMISSILES,
OT_S_SOULLINK,
OT_S_STASIS,
OT_S_STUN,
OT_S_TELEKINESIS,
@ -2910,6 +2921,8 @@ enum FLAG {
F_GOESON, // val0 = where it can be equipped.
F_GOESONMULTI, // ob is equipped on _ALL_ F_GOESON flags, rather than
// equipped on _ONE OF_ the.
F_UNDERCLOTHING, // yuo can wear other armour on top of this one
// (on the same body part)
F_BONUS, // val0=bonus/penalty to damage+accuracy/armour. ie. +1 sword
F_THROWMISSILE, // weapon would make a good thrown missle - used by AI
F_THROWNBY, // this object was thrown by lifeform id v0.
@ -4041,8 +4054,12 @@ enum FLAG {
F_AWARENESS, // you can see 360 degrees around yourself
F_BEINGSTONED,// turn to stone when v0 drops to zero. (drops 1/turn)
F_BLIND, // cannot see anything
F_SOULLINK, // lf is soul-linked to lfid v0. if they take damage, so do
// we.
// text = damstring, ie. "x's soullink spell"
F_CONFUSED, // move randomly about
F_DEAF, // cannot hear
F_SILENCED, // cannot make nosies
F_NEEDOBFORSPELLS, // if v0 != NA, lf can only cast spells if
// it has object v0
// if v1 != NA, lf can only cast spells if they
@ -4492,6 +4509,7 @@ enum ERROR {
E_NOUNARMEDATTACK,
E_NOTEQUIPPED,
E_EQUIPPED,
E_UNDERNEATH,
E_NOPICKUP,
E_STUCK,
E_MONSTERNEARBY,
@ -4516,6 +4534,7 @@ enum ERROR {
E_NOTARGET,
E_NOAMMO,
E_GRAVBOOSTED,
E_NOABIL,
E_NOMP,
E_NOSTAM,
E_NOSPELLS,
@ -4542,6 +4561,7 @@ enum ERROR {
E_OFFMAP,
E_RAGE,
E_STUNNED,
E_SILENCED,
// charm failure reasons
// LOWIQ
E_UNDEAD,

1
flag.c
View File

@ -763,6 +763,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
case F_PRODUCESLIGHT:
case F_PRONE:
case F_RAGE:
case F_SILENCED:
case F_SPRINTING:
case F_SLOWMOVE:
case F_STUNNED:

127
io.c
View File

@ -2092,6 +2092,14 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
}
donesomething = B_TRUE;
break;
case F_SILENCED:
if (isplayer(lf)) {
msg("^%cYou are surrounded in a field of silence!",getlfcol(lf, CC_BAD));
} else {
msg("^%c%s is surrounded in a field of silence!", getlfcol(lf, CC_BAD), lfname);
}
donesomething = B_TRUE;
break;
case F_SILENTMOVE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You now move silently.");
@ -2116,6 +2124,23 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("^%c%s %s",getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "feel slow and sluggish." : "looks slow and sluggish.");
donesomething = B_TRUE;
break;
case F_SOULLINK:
if (isplayer(lf)) { // don't know if monsters get it
lf2 = findlf(lf->cell->map, f->val[0]);
if (lf2) {
if (cansee(player, lf2)) {
real_getlfname(lf2, buf, NULL, B_NOSHOWALL, B_REALRACE);
} else {
real_getlfnamea(lf2, buf, NULL, B_NOSHOWALL, B_REALRACE);
}
msg("^wA psychic bond forms between you and %s!", buf);
} else {
// shouldn't happen.
msg("^wA psychic bond forms between you and something unknown.");
}
donesomething = B_TRUE;
}
break;
case F_SPIDERCLIMB:
if (isplayer(lf)) { // don't know if monsters get it
msg("Your skin becomes adhesive!");
@ -2881,6 +2906,14 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
}
donesomething = B_TRUE;
break;
case F_SILENCED:
if (isplayer(lf)) {
msg("You can now make noises again.");
} else {
msg("The field of silence around %s vanishes.", lfname);
}
donesomething = B_TRUE;
break;
case F_SILENTMOVE:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer move silently.");
@ -2905,6 +2938,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
donesomething = B_TRUE;
}
break;
case F_SOULLINK:
if (isplayer(lf)) { // don't know if monsters get it
msg("^wYour psychic soul-link vanishes.");
donesomething = B_TRUE;
}
break;
case F_SPIDERCLIMB:
if (isplayer(lf)) {
msg("Your skin is no longer adhesive.");
@ -5030,6 +5069,12 @@ void docomms(lifeform_t *lf) {
char ch;
lifeform_t *lfarg;
cell_t *cellarg;
if (lfhasflag(player, F_SILENCED)) {
msg("You are unable to make a sound!");
return;
}
//int moneyowing = 0;
if (!lf) {
where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
@ -6054,7 +6099,7 @@ char *makedesc_ob(object_t *o, char *retbuf) {
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->id == F_GOESON) {
compareob = getequippedob(player->pack, f->val[0]);
compareob = getouterequippedob(player, f->val[0]);
if (compareob) {
break;
}
@ -7352,6 +7397,10 @@ char *makedesc_ob(object_t *o, char *retbuf) {
sprintf(buf2, "%s prevents distant creatures from seeing you.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SILENCED:
sprintf(buf2, "%s prevents you from making sounds.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SILENTMOVE:
sprintf(buf2, "%s allows you to move silently.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
@ -11332,12 +11381,25 @@ void drawstatus(void) {
unsetcol(statwin, C_LIGHTBLUE);
}
if (hasactivespell(player, OT_S_DELAYDEATH)) {
setcol(statwin, C_LIGHTBLUE);
wprintw(statwin, " DelayDeath");
unsetcol(statwin, C_LIGHTBLUE);
}
if (lfhasflag(player, F_RAGE)) {
setcol(statwin, C_RED);
wprintw(statwin, " Rage");
unsetcol(statwin, C_RED);
}
if (lfhasflag(player, F_SILENCED)) {
setcol(statwin, C_RED);
wprintw(statwin, " Mute");
unsetcol(statwin, C_RED);
}
if (isswimming(player)) {
setcol(statwin, C_LIGHTBLUE);
wprintw(statwin, " Swim");
@ -11847,12 +11909,13 @@ int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname) {
void showlfarmour(lifeform_t *lf) {
enum BODYPART bp;
object_t *o;
object_t *arm[MAXBODYPARTS];
object_t *arm[MAXBODYPARTS*2];
int narm = 0;
int y,i;
char buf[BUFLEN],ch;
int keepgoing = B_TRUE;
for (i = 0; i < MAXBODYPARTS; i++) {
for (i = 0; i < MAXBODYPARTS*2; i++) {
arm[i] = NULL;
}
@ -11870,17 +11933,27 @@ void showlfarmour(lifeform_t *lf) {
char rhs[BUFLEN];
// default
strcpy(rhs, "");
if (hasbp(lf, bp)) {
object_t *outerob;
object_t *oo;
int nhere = 0;
snprintf(buf, BUFLEN, "%13s:%1s",getbodypartname(lf, bp), " ");
o = getequippedob(lf->pack, bp);
arm[bp] = o; // remember for later
// get outermost armour here so that we can show 'covered' if needed
outerob = getouterequippedob(lf, bp);
if (o) {
for (oo = lf->pack->first ;oo ; oo = oo->next) {
flag_t *f;
int thisar = 0,showar = B_FALSE;
char obname[BUFLEN];
o = NULL;
// is this object equipped in the right place?
if (hasflagval(oo->flags, F_EQUIPPED, bp, NA, NA, NULL)) {
o = oo;
nhere++;
}
if (!o) continue;
arm[narm++] = o; // remember for later
// two handed weapons.
if ((bp == BP_SECWEAPON ) && (o == arm[BP_WEAPON])) {
@ -11923,16 +11996,22 @@ void showlfarmour(lifeform_t *lf) {
strcat(rhs, numbuf);
}
}
} else {
strcpy(rhs, "-");
}
mvwprintw(mainwin, y, 0, "%s", buf);
if (o) setobcolour(mainwin, o, B_TRUE);
//wprintw(mainwin, "%s", rhs);
textwithcol(mainwin, rhs);
if (o) setobcolour(mainwin, o, B_FALSE);
y++;
mvwprintw(mainwin, y, 0, "%s", buf);
setobcolour(mainwin, o, B_TRUE);
//wprintw(mainwin, "%s", rhs);
textwithcol(mainwin, rhs);
setobcolour(mainwin, o, B_FALSE);
y++;
}
// no armour in this body part?
if (!nhere) {
strcpy(rhs, "-");
mvwprintw(mainwin, y, 0, "%s", buf);
//wprintw(mainwin, "%s", rhs);
textwithcol(mainwin, rhs);
y++;
}
}
}
@ -11945,9 +12024,9 @@ void showlfarmour(lifeform_t *lf) {
keepgoing = B_FALSE;
} else {
// does it match an object?
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
if (arm[bp] && (arm[bp]->letter == ch)) {
describeob(arm[bp]);
for (o = 0; i < MAXBODYPARTS*2; i++) {
if (arm[i] && (arm[i]->letter == ch)) {
describeob(arm[i]);
}
}
keepgoing = B_TRUE;
@ -13615,7 +13694,7 @@ void showlfstats(lifeform_t *lf, int showall) {
f = hasflag_real(lf->flags, F_VEGETARIAN, B_TRUE, NULL, FROMRACE);
if (f) {
getflagsourcetext(f,source);
mvwprintw(mainwin, y, 0, "%s %s a vegetarian (will not eat meat).%s", you(lf), is(lf));
mvwprintw(mainwin, y, 0, "%s %s a vegetarian (will not eat meat).%s", you(lf), is(lf),source);
y++;
}
f = hasflag_real(lf->flags, F_PARTVEGETARIAN, B_TRUE, NULL, FROMRACE);
@ -14380,6 +14459,14 @@ void showlfstats(lifeform_t *lf, int showall) {
y++;
}
f = hasflag_real(lf->flags, F_SILENCED, B_TRUE, NULL, FROMRACE);
if (f) {
getflagsourcetext(f,source);
mvwprintw(mainwin, y, 0, "%s %s been magically silenced.%s", you(lf),
isplayer(lf) ? "have" : "has", source);
y++;
}
f = lfhasflag(lf, F_STRIKETOKO);
if (f && (f->known)) {
getflagsourcetext(f,source);

497
lf.c
View File

@ -108,6 +108,7 @@ void autoweild(lifeform_t *lf) {
object_t *o,*firearm;
int donesecondary = B_FALSE;
int pretimespent;
int pass;
pretimespent = lf->timespent;
@ -128,15 +129,22 @@ void autoweild(lifeform_t *lf) {
// weild armour/2nd weapons if required,
// and mark other weapons as secondary
for (o = lf->pack->first ; o ; o = o->next) {
if (isweapon(o) && !isequipped(o) && getskill(lf, SK_TWOWEAPON) && !getequippedob(lf->pack, BP_SECWEAPON) && canweild(lf, o)) {
weild(lf, o);
} else if (!donesecondary && isweapon(o) && !isequipped(o)) {
addflag(o->flags, F_SECONDARY, B_TRUE, NA, NA, NULL);
donesecondary = B_TRUE;
} else {
if (canwear(lf, o, BP_NONE)) {
wear(lf, o);
for (pass = 0; pass < 2; pass++) {
for (o = lf->pack->first ; o ; o = o->next) {
if (isweapon(o) && !isequipped(o) && getskill(lf, SK_TWOWEAPON) &&
!getequippedob(lf->pack, BP_SECWEAPON) && canweild(lf, o)) {
weild(lf, o);
} else if (!donesecondary && isweapon(o) && !isequipped(o)) {
addflag(o->flags, F_SECONDARY, B_TRUE, NA, NA, NULL);
donesecondary = B_TRUE;
} else {
if (canwear(lf, o, BP_NONE)) {
if ((pass == 0) && !hasflag(o->flags, F_UNDERCLOTHING)) {
// only equip underclothing on the first pass.
} else {
wear(lf, o);
}
}
}
}
}
@ -701,8 +709,10 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
flag_t *f;
objecttype_t *ot;
int stamcost = 0;
// TODO: check for mute?
if (lfhasflag(lf, F_SILENCED)) {
reason = E_SILENCED;
return B_FALSE;
}
if (lfhasflag(lf, F_STUNNED)) {
reason = E_STUNNED;
return B_FALSE;
@ -879,6 +889,9 @@ int canclimb(lifeform_t *lf, enum ERROR *reason) {
} else if (isburdened(lf) || lfhasflag(lf, F_GRAVBOOSTED)) {
if (reason) *reason = E_TOOHEAVY;
return B_FALSE;
} else if ((getraceclass(lf) != RC_HUMANOID) && !getskill(lf, SK_CLIMBING)) {
if (reason) *reason = E_NOABIL;
return B_FALSE;
}
return B_TRUE;
}
@ -1625,7 +1638,7 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) {
return B_FALSE;
}
// is the GIVEN part free?
if (!isfreebp(lf, where)) {
if (!isfreebp(lf, where, o)) {
reason = E_WEARINGSOMETHINGELSE;
return B_FALSE;
}
@ -1633,7 +1646,7 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) {
if (hasflag(o->flags, F_GOESONMULTI)) {
// are ALL of these body parts free?
for (i = 0; i < nparts; i++) {
if (!isfreebp(lf, possbp[i])) {
if (!isfreebp(lf, possbp[i], o)) {
reason = E_WEARINGSOMETHINGELSE;
return B_FALSE;
}
@ -1643,7 +1656,7 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) {
int ok = B_FALSE;
// are ANY of these body parts free?
for (i = 0; i < nparts; i++) {
if (isfreebp(lf, possbp[i])) {
if (isfreebp(lf, possbp[i], o)) {
ok = B_TRUE;
break;
}
@ -1769,8 +1782,12 @@ int canweild(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
int cantakeoff(lifeform_t *lf, object_t *o) {
int cantakeoff(lifeform_t *lf, object_t *o, object_t **errob) {
flag_t *f;
object_t *oo;
enum BODYPART bp = BP_NONE;
if (errob) *errob = NULL;
reason = E_OK;
f = hasflag(o->flags, F_EQUIPPED);
@ -1778,6 +1795,14 @@ int cantakeoff(lifeform_t *lf, object_t *o) {
reason = E_NOTEQUIPPED;
return B_FALSE;
}
bp = f->val[0];
// something else equipped here?
oo = getouterequippedob(lf, bp);
if (oo && (oo != o)) {
if (errob) *errob = oo;
reason = E_UNDERNEATH;
return B_FALSE;
}
// cursed?
if (o->blessed == B_CURSED) {
@ -1798,6 +1823,9 @@ int cantakeoff(lifeform_t *lf, object_t *o) {
}
int cantalk(lifeform_t *lf) {
if (lfhasflag(lf, F_SILENCED)) {
return B_FALSE;
}
// phantasms dont talk
if (lfhasflag(lf, F_PHANTASM)) {
return B_FALSE;
@ -1884,6 +1912,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
case E_STUNNED:
msg("You can't cast spells while stunned.");
break;
case E_SILENCED:
msg("You are unable to utter the words to your spell!");
break;
default:
msg("For some reason, you can't cast that.");
break;
@ -5231,18 +5262,20 @@ int eat(lifeform_t *lf, object_t *o) {
}
}
}
if ((fid != F_NONE) && f->id == F_EATMUTATE) {
// lose half your max hp!
losehp_real(lf, (lf->maxhp/2), DT_DIRECT, NULL,
"the shock of mutation",
B_NODAMADJUST, o, B_NORETALIATE, NULL, B_DAMEFFECTS,
BP_NONE);
if (isplayer(lf)) {
msg("^%cYou convulse in agony as your body mutates!",
getlfcol(lf, CC_BAD));
} else if (cansee(player, lf)) {
msg("^%c%s convulses in agony as its body mutates!",
getlfcol(lf, CC_BAD), lfname);
if (fid != F_NONE) {
if (f->id == F_EATMUTATE) {
// lose half your max hp!
losehp_real(lf, (lf->maxhp/2), DT_DIRECT, NULL,
"the shock of mutation",
B_NODAMADJUST, o, B_NORETALIATE, NULL, B_DAMEFFECTS,
BP_NONE, B_NOCRIT);
if (isplayer(lf)) {
msg("^%cYou convulse in agony as your body mutates!",
getlfcol(lf, CC_BAD));
} else if (cansee(player, lf)) {
msg("^%c%s convulses in agony as its body mutates!",
getlfcol(lf, CC_BAD), lfname);
}
}
// still alive? you gain the ability!
if (!isdead(lf)) {
@ -8331,12 +8364,28 @@ char *getbodypartequipname(enum BODYPART bp) {
}
object_t *getequippedob(obpile_t *op, enum BODYPART bp) {
object_t *o;
object_t *o,*poss[MAXCANDIDATES];
int nposs = 0,i;
// first get a list of all objects equipped there.
// normally there will only be one, unless we have
// underclothing (ie. shirt + body armour).
for (o = op->first; o ; o = o->next) {
if (hasflagval(o->flags, F_EQUIPPED, bp, NA, NA, NULL)) {
return o;
poss[nposs++] = o;
}
}
if (!nposs) {
return NULL;
} else if (nposs == 1) {
return poss[0];
}
// we have more than one item equipped. get the inner one with F_UNDERCLOTHING.
for(i = 0; i < nposs; i++) {
if (hasflag(poss[i]->flags, F_UNDERCLOTHING)) return poss[i];
}
// should never get here...
assert("bug in getequippedob()." == 0);
return NULL;
}
@ -9364,23 +9413,45 @@ char *getlfconditionname(enum LFCONDITION cond) {
}
object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp) {
object_t *o;
object_t *o,*poss[MAXCANDIDATES];
enum BODYPART where = bp;
int i,nposs = 0;
switch (bp) {
case BP_RIGHTFINGER:
case BP_LEFTFINGER:
o = getequippedob(lf->pack, BP_HANDS);
if (o) return o;
else return getequippedob(lf->pack, bp);
if (getequippedob(lf->pack, BP_HANDS)) {
where = BP_HANDS;
}
break;
case BP_BODY:
o = getequippedob(lf->pack, BP_SHOULDERS);
if (o) return o;
else return getequippedob(lf->pack, bp);
if (getequippedob(lf->pack, BP_SHOULDERS)) {
where = BP_SHOULDERS;
}
break;
default:
break;
}
return getequippedob(lf->pack, bp);
// get all obs equipped here.
for (o = lf->pack->first ; o ; o = o->next) {
if (hasflagval(o->flags, F_EQUIPPED, where, NA, NA, NULL)) {
poss[nposs++] = o;
}
}
if (!nposs) {
return NULL;
} else if (nposs == 1) {
return poss[0];
}
// return the OUTER one.
for (i = 0;i < nposs; i++) {
if (!hasflag(poss[i]->flags, F_UNDERCLOTHING)) {
return poss[i];
}
}
// should never get here.
assert("bug in getouterequippedob()." == 0);
return NULL;
}
/*
@ -10106,7 +10177,7 @@ char *real_getlfname(lifeform_t *lf, char *buf, lifeform_t *usevis, int showall,
racesize = SZ_HUMAN; // default
}
size = getlfsize(lf);
if (size != racesize) {
if (!useorigrace && (size != racesize)) {
strcat(descstring, getsizetext(size));
strcat(descstring, " ");
}
@ -13939,6 +14010,17 @@ void loseobflags(lifeform_t *lf, object_t *o, int kind) {
}
}
int handlearmour(lifeform_t *lf, object_t *fromob, int *dam, enum DAMTYPE dt) {
int damreducedbyarmour = 0;
if (!armourcanstopdam(dt)) return 0;
// modify for defender's armour
// first figure out how much to reduce the damage by.
damreducedbyarmour = getarmourdamreduction(lf, fromob, *dam, dt);
// now actually reduce the damage amount
applyarmourdamreduction(lf, fromob, damreducedbyarmour, dam, dt);
return damreducedbyarmour;
}
int hasbp(lifeform_t *lf, enum BODYPART bp) {
int i;
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
@ -14408,7 +14490,12 @@ int isclimbing(lifeform_t *lf) {
int isdead(lifeform_t *lf) {
if (!lf->alive) return B_TRUE;
if (lf->hp <= 0) return B_TRUE;
if (lf->hp <= 0) {
if (hasactivespell(lf, OT_S_DELAYDEATH) && (lf->hp > -15)) {
} else {
return B_TRUE;
}
}
return B_FALSE;
}
@ -14550,8 +14637,17 @@ int isflyingwithwings(lifeform_t *lf) {
return B_FALSE;
}
int isfreebp(lifeform_t *lf, enum BODYPART bp) {
if (hasobwithflagval(lf->pack, F_EQUIPPED, bp, NA, NA, NULL)) return B_FALSE;
int isfreebp(lifeform_t *lf, enum BODYPART bp, object_t *whatfor) {
object_t *o;
o = hasobwithflagval(lf->pack, F_EQUIPPED, bp, NA, NA, NULL);
if (o) {
if (whatfor && !hasflag(whatfor->flags, F_UNDERCLOTHING) &&
hasflag(o->flags, F_UNDERCLOTHING)) {
// ok.
} else {
return B_FALSE;
}
}
if (!hasbp(lf, bp)) return B_FALSE;
@ -16839,15 +16935,15 @@ void loseconsciousness(lifeform_t *lf, int howlong, lifeform_t *fromlf) {
// lose hp, and adjust damage based on resistances
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc) {
return losehp_real(lf, amt, damtype, fromlf, damsrc, B_DAMADJUST, NULL, B_RETALIATE, NULL, B_DAMEFFECTS, BP_NONE);
return losehp_real(lf, amt, damtype, fromlf, damsrc, B_DAMADJUST, NULL, B_RETALIATE, NULL, B_DAMEFFECTS, BP_NONE, B_NOCRIT);
}
int losehp_bp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int bodypart) {
return losehp_real(lf, amt, damtype, fromlf, damsrc, B_DAMADJUST, NULL, B_RETALIATE, NULL, B_DAMEFFECTS, bodypart);
return losehp_real(lf, amt, damtype, fromlf, damsrc, B_DAMADJUST, NULL, B_RETALIATE, NULL, B_DAMEFFECTS, bodypart, B_NOCRIT);
}
// returns the amt of damage taken
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate, int *waskod, int doeffects, int bodypart) {
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate, int *waskod, int doeffects, int bodypart, int fromcrit) {
char buf[BUFLEN];
char buf2[BUFLEN];
char lfname[BUFLEN];
@ -16855,6 +16951,8 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
int murder = B_FALSE;
flag_t *f;
int predead = B_FALSE;
int damreducedbyarm = 0;
int hpleftafterdam;
if (gamemode < GM_GAMESTARTED) return 0;
@ -16876,6 +16974,11 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
murder = B_TRUE;
}
if (doeffects) {
// handle armour
damreducedbyarm = handlearmour(lf, fromob, &amt, damtype);
}
// adjust for source object's material
if (fromob) {
if (lfhasflagval(lf, F_MATIMMUNE, fromob->material->id, NA, NA, NULL)) {
@ -16910,13 +17013,16 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
killflagsofid(lf->flags, F_HIDING);
// methods of knocking unconscious
if (lfcanbekod(lf)) {
// would this damage reduce the lf to < 0 hp ???
hpleftafterdam = lf->hp - amt;
if (lfcanbekod(lf) && (lf->hp > 1) && (hpleftafterdam <= 0)) {
int threshold = 0,kochance = 0;
// merciful weapons - these will ALWAYS ko, even if
// they are already unconscious.
if (!ko && fromob) {
f = hasflag(fromob->flags, F_MERCIFUL);
if (f && (amt >= lf->hp)) {
ko = B_TRUE;
kochance = 100;
if (fromob->pile->owner && cansee(player, fromob->pile->owner)) {
f->known = B_TRUE;
}
@ -16926,7 +17032,6 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
// bashing damage sometimes ko's
// damage when eating corpses also does this.
if (!ko && !isunconscious(lf)) {
int threshold,kochance = 0;
int damtypeok = B_FALSE;
int playerinvolved = B_FALSE;
@ -16946,28 +17051,34 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
if (playerinvolved && godprayedto(R_GODMERCY)) {
threshold = -10;
if (isplayer(lf)) {
kochance = 75;
// player being hit?
kochance += 75;
} else {
kochance = 50;
// player hitting something else?
kochance += 30;
}
} else {
threshold = -5;
kochance = 30;
kochance += 15; // base chance to KO with bashing.
}
// TRYING to ko rather than kill?
if (fromlf && lfhasflag(fromlf, F_STRIKETOKO)) {
if (cansee(fromlf, lf)) {
kochance += 30;
threshold -= 5;
}
}
}
if (kochance) {
int hpleftafterdam;
// if this damage would reduce the lf to between -threshold and 0 hp
hpleftafterdam = lf->hp - amt;
if ((lf->hp > 1) && (hpleftafterdam >= threshold) && (hpleftafterdam <= 0)) {
if (pctchance(kochance)) {
ko = B_TRUE;
}
if (kochance && (hpleftafterdam >= threshold)) {
if (pctchance(kochance)) {
ko = B_TRUE;
}
}
}
/*
if (!ko && !isunconscious(lf)) {
if (fromlf && lfhasflag(fromlf, F_STRIKETOKO)) {
if (cansee(fromlf, lf)) {
@ -16975,11 +17086,13 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
}
}
}
*/
// just knock them out, don't kill.
if (ko) {
amt = lf->hp - 1; // ie end up at 1hp
}
}
// just knock them out, don't kill.
if (ko) {
amt = lf->hp - 1; // ie end up at 1hp
}
@ -17051,7 +17164,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
}
if (doeffects || ko) {
losehpeffects(lf, amt, damtype, fromlf, fromob, retaliate, ko, waskod, prelowhp, bodypart);
losehpeffects(lf, amt, damtype, fromlf, fromob, retaliate, ko, waskod, prelowhp, bodypart, damreducedbyarm, fromcrit);
}
if ((lf->hp > 0) && !ko && fromlf && (getcelldist(lf->cell, fromlf->cell) > 1)) {
@ -17141,15 +17254,70 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
// update screen
drawstatus();
updatestatus();
f = lfhasflag(lf, F_SOULLINK);
if (f && (damtype != DT_DIRECT)) {
lifeform_t *otherlf;
otherlf = findlf(lf->cell->map, f->val[0]);
if (otherlf) {
losehp_real(otherlf, amt, DT_DIRECT, lf, f->text, B_FALSE, NULL, B_FALSE, NULL, B_NODAMEFFECTS, BP_NONE, B_NOCRIT);
}
}
return amt;
}
void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fromlf, object_t *fromob, int retaliate, int ko, int *waskod, int prelowhp, int bodypart) {
void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fromlf, object_t *fromob, int retaliate, int ko, int *waskod, int prelowhp, int bodypart, int damreducedbyarm, int crit) {
int postlowhp = B_FALSE;
flag_t *retflag[MAXCANDIDATES],*f;
flag_t *retflag[MAXCANDIDATES],*f,*magicarm = NULL;
int nretflags;
char buf[BUFLEN],lfname[BUFLEN];
getlfname(lf, lfname);
// armour damage
if ((dam > 0) && isphysicaldam(damtype)) {
getflags(lf->flags, retflag, &nretflags, F_HEAVENARM, F_MAGICARMOUR, F_NONE);
if (nretflags) {
magicarm = retflag[0];
}
}
// now magic armour will pulse and maybe vanish.
if (magicarm) {
int damprevented;
// prevent all damage if possible
damprevented = dam;
magicarm->val[0] -= damprevented;
if (magicarm->val[0] <= 0) {
// did magic armour come from a spell?
if (magicarm->lifetime == FROMSPELL) {
flag_t *spellflag;
spellflag = hasactivespell(lf, magicarm->obfrom);
if (spellflag) {
killflag(spellflag);
}
}
// magic armour vanishes now.
killflag(magicarm);
} else {
if (cansee(player, lf)) {
msg("^%d%s%s %s pulses!^n",
CC_GOOD,
lfname, getpossessive(lfname),
magicarm->text);
}
}
} else {
// victim's armour loses hp. note that it loses the full
// amount of damage dealt, not just what it reduced.
if (damreducedbyarm && !crit) {
applyarmourdamage(lf, fromob, dam + damreducedbyarm, damtype, fromlf);
// train armour
practice(lf, SK_ARMOUR, 1);
}
}
if (lf->hp > 0) {
// effects based on damage type, if lf is still alive
if (damtype == DT_COLD) {
@ -17227,7 +17395,7 @@ void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fr
for (i = 0 ; i < nretcells; i++) {
if (retcell[i]->lf && (retcell[i]->lf != lf)) {
if (!isairborne(retcell[i]->lf, NULL)) {
losehp_real(retcell[i]->lf, dam, DT_ELECTRIC, fromlf, "an electric shock", B_TRUE, NULL, B_FALSE, NULL, B_FALSE, BP_NONE);
losehp_real(retcell[i]->lf, dam, DT_ELECTRIC, fromlf, "an electric shock", B_TRUE, NULL, B_FALSE, NULL, B_FALSE, BP_NONE, B_NOCRIT);
}
}
}
@ -17744,7 +17912,7 @@ int makelearnable(lifeform_t *lf, enum SKILL skid) {
// returns TRUE on failure.
int makenauseated(lifeform_t *lf, int amt, int howlong, enum ERROR *why) {
flag_t *f;
flag_t *f,*nflag = NULL;
if (why) *why = E_OK;
switch (lf->race->raceclass->id) {
@ -17777,27 +17945,28 @@ int makenauseated(lifeform_t *lf, int amt, int howlong, enum ERROR *why) {
//if (!lfhasflag(lf, F_HUMANOID)) return B_TRUE;
nflag = lfhasflag(lf, F_NAUSEATED);
// skillcheck to avoid this.
if (skillcheck(lf, SC_CON, 80 + (amt*10), gettr(lf)*2)) {
// passed skillcheck
if (why) *why = E_RESISTED;
// announce
if (isplayer(lf)) {
msg("You feel momentarily unwell.");
msg("You feel momentarily %sunwell.", nflag ? "more " : "");
} else if (cansee(player, lf)) {
char buf[BUFLEN];
getlfname(lf, buf);
msg("%s looks momentarily unwell.", buf);
msg("%s looks momentarily %sunwell.", buf, nflag ? "more " : "");
}
return B_TRUE;
}
// already nauseated?
f = lfhasflag(lf, F_NAUSEATED);
if (f) {
if ((f->lifetime >= 0) && (f->lifetime < howlong)) {
f->lifetime = howlong;
f->val[0] = MAXOF(f->val[0], amt);
if (nflag) {
if ((nflag->lifetime >= 0) && (nflag->lifetime < howlong)) {
nflag->lifetime = howlong;
nflag->val[0] = MAXOF(f->val[0], amt);
}
} else {
addtempflag(lf->flags, F_NAUSEATED, amt, NA, NA, NULL, howlong);
@ -18615,57 +18784,9 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume,
}
} // end if isplayer and not asleep
// wake up a little
f = lfhasflag(l, F_ASLEEP);
if (f && (f->val[1] != ST_KO)) {
if (f->lifetime > 0) { // ie. temporary
timeeffectsflag(f, myvol + rnd(1,3));
} else if (f->lifetime == PERMENANT) {
if (f->val[2] == NA) {
// ie asleep rather than 'resting'
// wake up!
if (isplayer(l)) {
msg("^wA nearby noise %s you!", (f->val[1] == ST_MEDITATING) ? "" : "awakens" );
rv = B_TRUE;
}
killflag(f);
} else {
// ie resting on purpose via 'R'
// only wake up if the sound if very close
if (myvol >= getcelldist(c, l->cell)) {
// wake up!
if (isplayer(l)) {
char wakenoise[BUFLEN];
char *punc;
strcpy(wakenoise, text);
// omit punctuation
punc = &(wakenoise[strlen(wakenoise)-1]);
switch (*punc) {
case '"': break;
default:
*punc = '\0';
break;
}
//msg("A nearby noise awakens you!");
msg("^wThe sound of %s awakens you!", wakenoise);
rv = B_TRUE;
}
killflag(f);
}
}
// make it temporary
//f->lifetime = rnd(1,10);
}
// still asleep?
f = lfhasflag(l, F_ASLEEP);
if (f && (f->val[1] == ST_ASLEEP) && cansee(player, l)) {
char lfname[BUFLEN];
getlfname(l, lfname);
msg("%s stir%s in %s slumber...", lfname,
isplayer(l) ? "" : "s",
isplayer(l) ? "your" : "its");
}
stir(l,myvol,getcelldist(c, l->cell), text);
} else { // not asleep, but can hear it.
// monsters will go to investigate the sound, as long as they're
// not otherwise occupied
@ -20173,6 +20294,10 @@ int say(lifeform_t *lf, char *text, int volume) {
char *localtext;
int rv;
if (lf && lfhasflag(lf, F_SILENCED)) {
return B_FALSE;
}
localtext = strdup(text);
// adjust text and volume for gods
@ -20245,6 +20370,9 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t
char buf3[BUFLEN];
char *p,*p2;
race_t *r;
if (lf && lfhasflag(lf, F_SILENCED)) {
return B_FALSE;
}
switch (what) {
case SP_ALLY_ATTACK:
switch (rnd(1,3)) {
@ -22373,6 +22501,7 @@ void startlfturn(lifeform_t *lf) {
if (db) dblog("startlfturn for lf id %d %s", lf->id, lf->race->name);
// if (lf->hp < 0) lf->hp = 0;
// debugging
lf->redraws = 0;
@ -23463,7 +23592,7 @@ void startlfturn(lifeform_t *lf) {
msg("^%c%s%s spine snaps!", getlfcol(lf, CC_VBAD),
lfname, getpossessive(lfname));
}
losehp_real(lf, lf->maxhp, DT_DIRECT, NULL, "tetanus", B_FALSE, NULL, B_FALSE, NULL, B_FALSE, BP_NONE);
losehp_real(lf, lf->maxhp, DT_DIRECT, NULL, "tetanus", B_FALSE, NULL, B_FALSE, NULL, B_FALSE, BP_NONE, B_FROMCRIT);
}
break;
case BP_TAIL:
@ -23816,7 +23945,7 @@ void startlfturn(lifeform_t *lf) {
// effects for/on your own flags
getflags(lf->flags, retflag, &nretflags, F_ANTICIPATE, F_ATTACHEDTO, F_CANCAST, F_CANWILL, F_CHARMEDBY, F_CLIMBING, F_FEIGNFOOLEDBY,F_FLEEFROM,
F_GRABBEDBY, F_GRABBING, F_HIDING, F_BOOSTSPELL, F_FEIGNINGDEATH, F_FULLSHIELD,F_HPDRAIN, F_INCUBATING, F_INJURY,
F_NOFLEEFROM, F_PETOF, F_SIZETIMER, F_SPOTTED, F_STRIKETOKO, F_TARGETCELL, F_TARGETLF, F_NONE);
F_NOFLEEFROM, F_PETOF, F_SIZETIMER, F_SOULLINK, F_SPOTTED, F_STRIKETOKO, F_TARGETCELL, F_TARGETLF, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
// remove impossible/expired flags
@ -23909,7 +24038,7 @@ void startlfturn(lifeform_t *lf) {
if (f->obfrom == B_NEWINJURY) f->obfrom = B_FALSE;
arm = getequippedob(lf->pack, f->val[1]);
arm = getouterequippedob(lf, f->val[1]);
if (arm && !hasobmod(arm, findobmod(OM_BLOODSTAINED)) && pctchance(5)) applyobmod(arm, findobmod(OM_BLOODSTAINED));
}
@ -23934,6 +24063,14 @@ void startlfturn(lifeform_t *lf) {
}
}
*/
if (f->id == F_SOULLINK) {
lifeform_t *lf2;
lf2 = findlf(lf->cell->map, f->val[0]);
if (!lf2) {
killflag(f);
continue;
}
}
if (f->id == F_SPOTTED) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
@ -24173,6 +24310,68 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) {
return B_FALSE;
}
// returns TRUE if l woke up.
int stir(lifeform_t *l, int vol, int dist, char *noisetext) {
flag_t *f;
int rv = B_FALSE;
// wake up a little
f = lfhasflag(l, F_ASLEEP);
if (f && (f->val[1] != ST_KO)) {
if (f->lifetime > 0) { // ie. temporary
timeeffectsflag(f, vol + rnd(1,3));
} else if (f->lifetime == PERMENANT) {
if (f->val[2] == NA) {
// ie asleep rather than 'resting'
// wake up!
if (isplayer(l)) {
msg("^wA nearby noise %s you!", (f->val[1] == ST_MEDITATING) ? "startles" : "awakens" );
rv = B_TRUE;
}
killflag(f);
} else {
// ie resting on purpose via 'R'
// only wake up if the sound if very close
if (vol >= dist) {
// wake up!
if (isplayer(l)) {
if (noisetext) {
char wakenoise[BUFLEN];
char *punc;
strcpy(wakenoise, noisetext);
// omit punctuation
punc = &(wakenoise[strlen(wakenoise)-1]);
switch (*punc) {
case '"': break;
default:
*punc = '\0';
break;
}
msg("^wThe sound of %s awakens you!", wakenoise);
} else {
msg("Something awakens you!");
}
rv = B_TRUE;
}
killflag(f);
}
}
// make it temporary
//f->lifetime = rnd(1,10);
}
// still asleep?
f = lfhasflag(l, F_ASLEEP);
if (f && (f->val[1] == ST_ASLEEP) && cansee(player, l)) {
char lfname[BUFLEN];
getlfname(l, lfname);
msg("%s stir%s in %s slumber...", lfname,
isplayer(l) ? "" : "s",
isplayer(l) ? "your" : "its");
}
}
return rv;
}
int stone(lifeform_t *lf) {
char lfname[BUFLEN];
@ -24364,6 +24563,7 @@ lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, char *ra
int takeoff(lifeform_t *lf, object_t *o) {
char obname[BUFLEN];
char buf[BUFLEN];
object_t *errob = NULL;
if (!isarmour(o)) {
return unweild(lf, o);
@ -24376,7 +24576,7 @@ int takeoff(lifeform_t *lf, object_t *o) {
getobname(o, obname, 1);
if (!cantakeoff(lf, o)) {
if (!cantakeoff(lf, o, &errob)) {
switch (reason) {
case E_CURSED:
if (isplayer(lf)) {
@ -24396,6 +24596,16 @@ int takeoff(lifeform_t *lf, object_t *o) {
msg("Your injury prevents you from removing your %s.", noprefix(obname));
}
break;
case E_UNDERNEATH:
if (isplayer(lf)) {
if (errob) {
getobname(errob, buf, 1);
msg("Your %s is in the way!", noprefix(buf));
} else {
msg("You will need to remove your outer armour first.");
}
}
break;
default:
if (isplayer(lf)) {
msg("For some reason, you cannot remove your %s!", noprefix(obname));
@ -24819,7 +25029,7 @@ int real_touch(lifeform_t *lf, object_t *o, int onpurpose) {
f = hasflag(lf->flags, F_FREEZINGTOUCH);
if (f) {
// not wearing gloves?
if (!getequippedob(lf->pack, BP_HANDS)) {
if (!getouterequippedob(lf, BP_HANDS)) {
// default power of 4
dospelleffects(lf, OT_S_FREEZEOB, 4, NULL, o, NULL, B_UNCURSED, NULL, B_FALSE, NULL);
@ -24838,7 +25048,7 @@ int real_touch(lifeform_t *lf, object_t *o, int onpurpose) {
}
}
gloves = getequippedob(lf->pack, BP_HANDS);
gloves = getouterequippedob(lf, BP_HANDS);
// undead and blessed objects?
if (isundead(lf) && isblessed(o)) {
@ -25138,6 +25348,7 @@ void unsummon(lifeform_t *lf, int vanishobs) {
int unweild(lifeform_t *lf, object_t *o) {
char obname[BUFLEN];
char buf[BUFLEN];
object_t *errob;
getobname(o, obname, 1);
@ -25146,7 +25357,7 @@ int unweild(lifeform_t *lf, object_t *o) {
return B_TRUE;
}
if (!cantakeoff(lf, o)) {
if (!cantakeoff(lf, o, &errob)) {
switch (reason) {
case E_CURSED:
if (isplayer(lf)) {
@ -25161,9 +25372,19 @@ int unweild(lifeform_t *lf, object_t *o) {
msg("You are not weilding that!");
}
break;
case E_UNDERNEATH:
if (isplayer(lf)) {
if (errob) {
getobname(errob, buf, 1);
msg("Your %s is in the way!", noprefix(buf));
} else {
msg("You will need to remove your outer armour first.");
}
}
break;
default:
if (isplayer(lf)) {
msg("For some reason, you cannot stop weilding your %s!", noprefix(obname));
msg("For some reason, you cannot take off your %s!", noprefix(obname));
}
break;
}
@ -26457,7 +26678,7 @@ int wear(lifeform_t *lf, object_t *o) {
if (o->type->obclass->id == OC_RING) {
bp = BP_NONE;
for (i = 0; i < nparts; i++) {
if (isfreebp(lf, possbp[i])) {
if (isfreebp(lf, possbp[i], o)) {
bp = possbp[i];
break;
}
@ -26478,11 +26699,15 @@ int wear(lifeform_t *lf, object_t *o) {
initprompt(&prompt, buf);
for (i = 0; i < nparts; i++) {
object_t *inway;
inway = getequippedob(lf->pack, possbp[i]);
inway = getouterequippedob(lf, possbp[i]);
if (inway) {
char inwayname[BUFLEN];
getobname(inway, inwayname, inway->amt);
snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(lf, possbp[i]), inwayname);
if (hasflag(inway->flags, F_UNDERCLOTHING)) {
snprintf(buf, BUFLEN, "%s (over %s)", getbodypartname(lf, possbp[i]), inwayname);
} else {
snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(lf, possbp[i]), inwayname);
}
} else {
snprintf(buf, BUFLEN, "%s", getbodypartname(lf, possbp[i]));
}
@ -27227,8 +27452,8 @@ int willbackstab(lifeform_t *lf, lifeform_t *victim, object_t *wep) {
int willbleedfrom(lifeform_t *lf, enum BODYPART bp) {
object_t *o;
o = getequippedob(lf->pack, bp);
if (o && (o->type->id == OT_BANDAGE)) {
o = hasequippedobidon(lf->pack, OT_BANDAGE, bp);
if (o) {
// don't bleed.
return B_FALSE;
}

10
lf.h
View File

@ -72,7 +72,7 @@ int canthrow(lifeform_t *lf, object_t *o, enum ERROR *why);
int canuseweapons(lifeform_t *lf);
int canwear(lifeform_t *lf, object_t *o, enum BODYPART where);
int canweild(lifeform_t *lf, object_t *o);
int cantakeoff(lifeform_t *lf, object_t *o);
int cantakeoff(lifeform_t *lf, object_t *o, object_t **errob);
int cantalk(lifeform_t *lf);
int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell, object_t *fromob, int *seen);
int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange);
@ -347,6 +347,7 @@ int lfproduceslight(lifeform_t *lf, object_t **fromwhat);
int lighthurtseyes(lifeform_t *lf);
int lockpick(lifeform_t *lf, cell_t *targcell, object_t *target, object_t *device);
void loseobflags(lifeform_t *lf, object_t *o, int kind);
int handlearmour(lifeform_t *lf, object_t *fromob, int *dam, enum DAMTYPE dt);
int hasbp(lifeform_t *lf, enum BODYPART bp);
flag_t *hasactivespell(lifeform_t *lf, enum OBTYPE sid);
int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest);
@ -371,7 +372,7 @@ object_t *isdualweilding(lifeform_t *lf);
flag_t *isfleeing(lifeform_t *lf);
flag_t *isfleeingfrom(lifeform_t *lf, lifeform_t *runfrom);
int isflyingwithwings(lifeform_t *lf);
int isfreebp(lifeform_t *lf, enum BODYPART bp);
int isfreebp(lifeform_t *lf, enum BODYPART bp, object_t *whatfor);
int isfriendly(lifeform_t *lf);
int isfullyhealed(lifeform_t *lf);
int isexhausted(lifeform_t *lf);
@ -425,8 +426,8 @@ void loseconcentration(lifeform_t *lf);
void loseconsciousness(lifeform_t *lf, int howlong, lifeform_t *fromlf);
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc);
int losehp_bp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int bodypart);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate, int *waskod, int doeffects, int bodypart);
void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fromlf, object_t *fromob, int retaliate, int ko, int *waskod, int prelowhp, int bodypart);
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob, int retaliate, int *waskod, int doeffects, int bodypart, int fromcrit);
void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fromlf, object_t *fromob, int retaliate, int ko, int *waskod, int prelowhp, int bodypart, int damreducebyarm, int crit);
void losemp(lifeform_t *lf, int amt);
void loselevel(lifeform_t *lf, int amt, lifeform_t *fromlf);
void loseskill(lifeform_t *lf, enum SKILL skid);
@ -519,6 +520,7 @@ int slipon(lifeform_t *lf, object_t *o);
void sortlf(map_t *map, lifeform_t *lf);
void startlfturn(lifeform_t *lf);
int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag);
int stir(lifeform_t *lf, int vol, int dist, char *noisetext);
int stone(lifeform_t *lf);
int stopclimbing(lifeform_t *lf, int onpurpose);
void stopeating(lifeform_t *lf);

45
map.c
View File

@ -985,24 +985,37 @@ void adjustcellglyph(cell_t *c, glyph_t *g, enum CELLADJUSTTYPE how) {
if ((how == CA_CH) || (how == CA_BOTH)) {
// for certain cell types, select glyph based on surrounding cells of same type
if (g->ch == UNI_DYNAMIC) {
int adj = 0,i;
int adj = 0,i,ndirslinked = 0,n;
cell_t *c2;
for (i = D_N; i <= D_W; i++) {
int this;
c2 = getcellindir(c,i);
if (c2 && c2->known && ((c2->type->id == c->type->id) || hasdoor(c2)) ) {
//if (c2 && c2->known && (issolid(c2) || hasdoor(c2)) ) {
this = 1;
// we want:
// N E S W
// 8 4 2 1
if (i == D_N) this <<= 3;
else if (i == D_E) this <<= 2;
else if (i == D_S) this <<= 1;
} else {
this = 0;
for (n = 0; ((ndirslinked == 0) && (n < 2)); n++) {
for (i = D_N; i <= D_W; i++) {
int this = 0;
int typematches = B_FALSE;
c2 = getcellindir(c,i);
if (c2) {
if (n == 0) { // first pass
if (c2->type->id == c->type->id) {
typematches = B_TRUE;
}
} else { // second pass
if (issolid(c2)) {
typematches = B_TRUE;
}
}
if (c2->known && (typematches || hasdoor(c2)) ) {
this = 1;
ndirslinked++;
// we want:
// N E S W
// 8 4 2 1
if (i == D_N) this <<= 3;
else if (i == D_E) this <<= 2;
else if (i == D_S) this <<= 1;
}
}
adj |= this;
}
adj |= this;
}
switch (adj) {
case 1: // left

22
move.c
View File

@ -132,17 +132,18 @@ int canswapwith(lifeform_t *lf, lifeform_t *lf2) {
return B_FALSE;
}
// cannot swap with sleeping lfs
if (lfhasflag(lf2, F_ASLEEP)) {
return B_FALSE;
}
// allies can always swap
if (areallies(lf, lf2)) {
return B_TRUE;
}
if (isplayer(lf) && !areenemies(lf, lf2)) {
if (isknownpeaceful(lf2)) {
if (isplayer(lf)) {
if (lfhasflag(lf2, F_ASLEEP)) {
if (getlfsize(lf2) <= getlfsize(lf)) {
return B_TRUE;
}
} else if (!areenemies(lf, lf2) && isknownpeaceful(lf2)) {
// player can swap with peaceful lfs
// if they are a lot smaller
//if (getlfsize(lf) - getlfsize(lf2) >= 2) {
@ -1459,7 +1460,7 @@ int movelf(lifeform_t *lf, cell_t *newcell, int onpurpose) {
if (f && hasbp(lf, BP_FEET) && !lfhasflag(lf, F_CAREFULMOVE) && !isairborne(lf, NULL)) {
object_t *boots;
// has boots on?
boots = getequippedob(lf->pack, BP_FEET);
boots = getouterequippedob(lf, BP_FEET);
if (!boots) {
// take damage
getobname(o, obname, 1);
@ -2862,6 +2863,11 @@ void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int changedir1, int changedir2
}
setlosdirty(lf1);
setlosdirty(lf2);
// ie. asleep, meditating or unconscious
if (lfhasflag(lf2, F_ASLEEP)) {
stir(lf2, SV_TALK, 1, NULL);
}
}
// teleport somewhere, along with puffs of smoke etc
@ -3061,7 +3067,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
*/
// warn before moving onto dangerous cells
if (onpurpose && isplayer(lf) && !lfhasflag(lf, F_CAREFULMOVE) && !rndmove) {
if (onpurpose && isplayer(lf) && !lfhasflag(lf, F_CAREFULMOVE) && !rndmove && !lfhasflag(lf, F_RAGE)) {
char ques[BUFLEN];
char ch;
if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) {

View File

@ -810,9 +810,12 @@ void checkdeath(void) {
removedeadobs(lf->pack);
// check for death
if (lf->hp <= 0) {
// die!
die(lf);
continue;
if (hasactivespell(lf, OT_S_DELAYDEATH) && (lf->hp > -15)) {
} else {
// die!
die(lf);
continue;
}
}
}

View File

@ -7430,6 +7430,13 @@ object_t *hasequippedobid(obpile_t *op, enum OBTYPE oid) {
}
return NULL;
}
object_t *hasequippedobidon(obpile_t *op, enum OBTYPE oid, enum BODYPART bp) {
object_t *o;
for (o = op->first ; o ; o = o->next) {
if ((o->type->id == oid) && isequippedon(o, bp)) return o;
}
return NULL;
}
object_t *hasknownob(obpile_t *op, enum OBTYPE oid) {
object_t *o;
@ -12817,6 +12824,15 @@ int readsomething(lifeform_t *lf, object_t *o) {
}
return B_TRUE;
}
if (lfhasflag(lf, F_SILENCED)) {
if (o->type->obclass->id != OC_BOOK) {
if (isplayer(lf)) {
msg("You are unable to make a sound!");
}
return B_TRUE;
}
}
strcpy(triedonbuf, "");
@ -14179,7 +14195,7 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce, lif
// now use the REAL name
real_getobname(o, obname, o->amt, B_PREMODS, B_NOCONDITION, B_NOBLINDADJUST, B_NOBLESSINGS, B_NOUSED, B_SHOWALL);
losehp_real(owner, howmuch , damtype, NULL, obname, B_DAMADJUST, o, B_NORETALIATE, NULL, B_DAMEFFECTS, f ? f->val[0] : BP_NONE);
losehp_real(owner, howmuch , damtype, NULL, obname, B_DAMADJUST, o, B_NORETALIATE, NULL, B_DAMEFFECTS, f ? f->val[0] : BP_NONE, B_NOCRIT);
if (isdead(owner)) {
return howmuch;
}
@ -15009,6 +15025,16 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
youhit = B_FALSE;
myroll = rnd(1,100);
// target has 'nudge missiles' spell? penalty, and the missile
// gets slightly slowed.
if (target && hasactivespell(target, OT_S_SLOWMISSILES)) {
myroll += 10;
if (speed > 1) speed--;
}
// easier to hit with faster projectiles.
myroll -= (speed*2);
// blessed projectile vs undead? 20% bonus.
if (isblessed(o) && isundead(target)) {
myroll -= 20;
@ -15261,7 +15287,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp
whogetsxp = thrower;
}
losehp_real(target, dam, DT_PROJECTILE, whogetsxp, damstring, B_DAMADJUST, o,
B_RETALIATE, NULL, B_DAMEFFECTS, BP_NONE);
B_RETALIATE, NULL, B_DAMEFFECTS, BP_NONE, B_NOCRIT);
}
if (reduceamt && (speed >= 3)) {

View File

@ -167,6 +167,7 @@ char *gettopobname(cell_t *c, char *retbuf);
enum BODYPART getweildloc(object_t *o, lifeform_t *lf, enum BODYPART *otherloc, int *twohanded);
int hasedibleob(obpile_t *op);
object_t *hasequippedobid(obpile_t *op, enum OBTYPE oid);
object_t *hasequippedobidon(obpile_t *op, enum OBTYPE oid, enum BODYPART bp);
object_t *hasknownob(obpile_t *op, enum OBTYPE oid);
object_t *hasob(obpile_t *op, enum OBTYPE oid);
object_t *hasobletter(obpile_t *op, char letter);

270
spell.c
View File

@ -826,6 +826,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
case E_LFINWAY: msg("Something is in the way!"); break;
case E_SWIMMING: msg("You can't climb while swimming!"); break;
case E_TOOHEAVY: msg("Your load is too heavy to climb with!"); break;
case E_NOABIL: msg("You cannot climb!"); break;
default: msg("For some reason, you can't climb."); break;
}
}
@ -2206,6 +2207,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (f) killflag(f);
} else if (abilid == OT_A_SONICBOLT) {
int volume,nwalls;
if (lfhasflag(user, F_SILENCED)) {
if (isplayer(user)) msg("You are unable to make a sound!");
return B_TRUE;
}
if (!validatespellcell(user, &targcell,TT_MONSTER, abilid, power, B_FALSE)) return B_TRUE;
target = targcell->lf;
@ -3668,6 +3673,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
practice(user, SK_THIEVERY, 1);
}
} else if (abilid == OT_A_WARCRY) {
if (lfhasflag(user, F_SILENCED)) {
if (isplayer(user)) msg("You are unable to make a sound!");
return B_TRUE;
}
// announce
if (isplayer(user)) {
msg("You shout a blood-curdling war cry!");
@ -3965,6 +3974,43 @@ void addbuildchoice(prompt_t *p, lifeform_t *lf, enum OBTYPE oid, char *ch) {
}
// returns true if you can't charm them.
int checkcharm(lifeform_t *caster, lifeform_t *target) {
char targetname[BUFLEN];
getlfname(target, targetname);
// if the target is of a different raceclass, you usually
// can't charm them.
if (getraceclass(target) != getraceclass(caster)) {
int willfail = B_FALSE;
switch (getraceclass(target)) {
case RC_DEMON:
case RC_DRAGON:
case RC_GOD:
case RC_SLIME:
case RC_MAGIC:
case RC_PLANT:
willfail = B_TRUE;
break;
default: break;
}
if (willfail) {
if (isplayer(caster)) {
msg("%s%s mind is too alien for you to charm.",targetname,getpossessive(targetname));
}
return B_TRUE;
}
}
if (!ischarmable(target)) {
if (isplayer(caster)) {
err_nocharm(reason, targetname);
}
return B_TRUE;
}
// ok
return B_FALSE;
}
// returns TRUE on error
int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer, int frompot, object_t *fromob) {
char buf[BUFLEN];
@ -5473,60 +5519,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
getlfname(target, targetname);
// if the target is of a different raceclass, you usually
// can't charm them.
if (getraceclass(target) != getraceclass(caster)) {
int willfail = B_FALSE;
switch (getraceclass(target)) {
case RC_DEMON:
case RC_DRAGON:
case RC_GOD:
case RC_SLIME:
case RC_MAGIC:
case RC_PLANT:
willfail = B_TRUE;
break;
default: break;
}
if (willfail) {
if (isplayer(caster)) {
msg("%s%s mind is too alien for you to charm.",targetname,getpossessive(targetname));
}
return B_FALSE;
}
}
if (checkcharm(caster, target)) return B_FALSE;
if (!ischarmable(target)) {
if (isplayer(caster)) {
switch (reason) {
case E_DRUNK:
msg("%s%s mind is too alcohol-impaired for you to charm.",targetname,getpossessive(targetname));
break;
case E_LOWIQ:
msg("%s%s intellect is too simple for you to charm.",targetname,getpossessive(targetname));
break;
case E_UNDEAD:
msg("The undead are immune to charming.");
break;
case E_ROBOT:
msg("Robots are immune to charming.");
break;
case E_ALREADYUSING:
msg("%s is already charmed by another!", targetname);
break;
default:
msg("You cannot charm %s.", targetname);
break;
}
}
return B_FALSE;
}
if (getallegiance(caster) == AL_PEACEFUL) {
fizzle(caster);
return B_TRUE;
}
if (ispetof(target, caster)) {
if ((getallegiance(target) == AL_PEACEFUL) || ispetof(target, caster)) {
if (isplayer(caster)) {
msg("%s is already allied with you!",targetname);
}
@ -5575,31 +5570,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_TRUE;
}
if (!ischarmable(target)) {
if (isplayer(caster)) {
switch (reason) {
case E_DRUNK:
msg("%s%s mind is too alcohol-impaired for you to charm.",targetname,getpossessive(targetname));
break;
case E_LOWIQ:
msg("%s%s intellect is too simple for you to charm.",targetname,getpossessive(targetname));
break;
case E_UNDEAD:
msg("The undead are immune to charming.");
break;
case E_ROBOT:
msg("Robots are immune to charming.");
break;
case E_ALREADYUSING:
msg("%s is already charmed by another!", targetname);
break;
default:
msg("You cannot charm %s.", targetname);
break;
}
}
return B_FALSE;
}
if (checkcharm(caster, target)) return B_FALSE;
if (getallegiance(caster) == AL_PEACEFUL) {
fizzle(caster);
@ -6257,6 +6228,15 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
} else if (spellid == OT_S_DELAYDEATH) {
if (!target) {
target = caster;
}
if (isplayer(target)) {
msg("^gYou bend your psionic will towards defying death!");
if (seenbyplayer) *seenbyplayer = B_TRUE;
statdirty = B_TRUE;
}
} else if (spellid == OT_S_DETECTAURA) {
if (isplayer(caster)) {
object_t *o;
@ -8704,6 +8684,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
return B_TRUE;
}
} else if (spellid == OT_S_MINDSHIELD) {
flag_t *f;
f = addtempflag(caster->flags, F_MINDSHIELD, B_TRUE, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_MINDWHIP) {
target = targcell->lf;
if (!target) {
@ -8816,6 +8800,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f = addtempflag(caster->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL, FROMSPELL);
f->obfrom = spellid;
} else if (spellid == OT_S_SLOWMISSILES) {
if (!target) {
target = caster;
}
if (isplayer(target)) {
msg("^gYou attune your mind to deflect incoming projectiles.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_NULLIFY) {
flag_t *retflag[MAXCANDIDATES],*poss[MAXCANDIDATES],*f;
int nretflags,i,ndone = 0,nposs;
@ -11295,6 +11287,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
msg("^%c%s%s body seems to shimmer and bend!", getlfcol(caster, CC_GOOD),
castername, getpossessive(castername));
}
} else if (spellid == OT_S_REMOTEKO) {
char targetname[BUFLEN];
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_TRUE;
}
getlfname(target, targetname);
if (checkcharm(caster, target)) return B_FALSE;
if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) {
// they get angry!
if (!isplayer(target) && cansee(target, caster)) {
fightback(target, caster);
}
} else {
// ko !
loseconsciousness(target, rnd(50,100), caster);
}
} else if (spellid == OT_S_REPELINSECTS) {
// just announce
if (isplayer(caster)) {
@ -11702,6 +11716,35 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
return B_TRUE;
}
} else if (spellid == OT_S_SILENCE) {
int howlong = 30;
target = targcell->lf;
if (!target || hasflag(target->flags, F_SILENCED)) {
fizzle(caster);
return B_TRUE;
}
if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (!isdeaf(player)) {
if (isplayer(target)) {
msg("Noise around you sound softer for a moment.");
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (haslos(player, target->cell)) {
getlfname(target, buf);
msg("Noises around %s sound softer for a moment.", buf);
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
}
return B_FALSE;
}
howlong = rnd(20,30) + power*2;
addtempflag(target->flags, F_SILENCED, NA, NA, NA, NULL, howlong);
if (isplayer(target) || haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else if (spellid == OT_S_SIXTHSENSE) {
flag_t *f;
if (!target) target = caster;
@ -11859,6 +11902,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int howlong = 15;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_TRUE;
}
if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) {
msg("You feel momentarily slower.");
@ -12063,6 +12111,64 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
return B_TRUE;
}
} else if (spellid == OT_S_SOULLINK) {
lifeform_t *targ2 = NULL;
char buf[BUFLEN],tname[BUFLEN],t2name[BUFLEN];
if (caster && !isplayer(caster)) {
fizzle(caster);
return B_TRUE;
}
if (!target) {
target = targcell->lf;
}
if (!target || (target == caster)) {
fizzle(caster);
return B_TRUE;
}
real_getlfnamea(target, tname, NULL, B_SHOWALL, B_REALRACE);
if (power < 3) {
// link caster to target
targ2 = caster;
} else {
cell_t *where;
char smallprompt[BUFLEN];
// link target to target2
// ask for a target cell
snprintf(buf, BUFLEN, "Who will you soul-link %s to?", tname);
snprintf(smallprompt, BUFLEN, "soul link:%s->", tname);
where = askcoords(buf, smallprompt, TT_MONSTER, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(caster, where->lf)) {
targ2 = where->lf;
} else {
fizzle(caster);
return B_TRUE;
}
}
if (targ2 == target) {
fizzle(caster);
return B_TRUE;
}
real_getlfnamea(targ2, t2name, NULL, B_SHOWALL, B_REALRACE);
if (hasflag(target->flags, F_SOULLINK) || hasflag(targ2->flags, F_SOULLINK)) {
msg("^bAn existing soul link prevents your spell from working!");
return B_TRUE;
}
// link caster to target
sprintf(buf, "%s%s soul link spell", castername, getpossessive(castername));
addflag(target->flags, F_SOULLINK, targ2->id, NA, NA, buf);
addflag(targ2->flags, F_SOULLINK, target->id, NA, NA, buf);
// soullink flag is only announce for the player, so oif we linked to someone else,
// provide some feedback.
if (targ2 != player) {
msg("^gYou establish a soul link between %s and %s!",tname,t2name);
}
} else if (spellid == OT_S_SPARK) {
object_t *o,*nexto;
int donesomething = B_FALSE;
@ -15206,8 +15312,12 @@ int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power
bonus += 8;
}
if (spellisfromschool(spellid, SS_MENTAL) && lfhasflag(target, F_MINDSHIELD)) {
resisted = B_TRUE;
if (spellisfromschool(spellid, SS_MENTAL)) {
if (lfhasflag(target, F_MINDSHIELD)) {
resisted = B_TRUE;
} else {
resisted = skillcheck(target, SC_IQ, getmrdiff(spellid,power), bonus);
}
} else {
resisted = skillcheck(target, SC_RESISTMAG, getmrdiff(spellid,power), bonus);
}

View File

@ -4,6 +4,7 @@
int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifeform_t *target, flag_t *cwflag);
void addbuildchoice(prompt_t *p, lifeform_t *lf, enum OBTYPE oid, char *ch);
int checkcharm(lifeform_t *caster, lifeform_t *target);
int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer, int frompot, object_t *fromob);
objecttype_t *findspelln(char *buf);
enum SPELLSCHOOL findspellschoolbyname(char *buf);

32
text.c
View File

@ -7,6 +7,7 @@
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
@ -485,6 +486,29 @@ char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dic
return dicebuf;
}
void err_nocharm(enum ERROR reason, char *targetname) {
switch (reason) {
case E_DRUNK:
msg("%s%s mind is too alcohol-impaired for you to charm.",targetname,getpossessive(targetname));
break;
case E_LOWIQ:
msg("%s%s intellect is too simple for you to charm.",targetname,getpossessive(targetname));
break;
case E_UNDEAD:
msg("The undead are immune to charming.");
break;
case E_ROBOT:
msg("Robots are immune to charming.");
break;
case E_ALREADYUSING:
msg("%s is already charmed by another!", targetname);
break;
default:
msg("You cannot charm %s.", targetname);
break;
}
}
int flip(int ch) {
switch (ch) {
case 'a': return 0x0250;
@ -1278,14 +1302,14 @@ char *getflagsourcetext(flag_t *f, char *buf) {
case FROMOBEQUIP:
case FROMOBHOLD:
case FROMOBACTIVATE:
if (f->lifetime == FROMOBEQUIP) strcpy(action, "equipping");
else if (f->lifetime == FROMOBEQUIP) strcpy(action, "holding");
else strcpy(action, "activating");
if (f->lifetime == FROMOBEQUIP) strcpy(action, "equipped");
else if (f->lifetime == FROMOBEQUIP) strcpy(action, "held");
else strcpy(action, "activated");
if (f->pile->ob) {
getobname(f->pile->ob, obname, f->pile->ob->amt);
} else {
strcpy(obname, "an object");
strcpy(obname, "object");
}
sprintf(buf," (from %s %s)", action, obname);
break;

1
text.h
View File

@ -8,6 +8,7 @@ char *capitaliseall(char *text);
enum COLOUR chartocol(char ch);
char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackername, char *victimname, char *victimbpname, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp, int damidx, int critical, int backstab, int fatal, int isunarmed, char *retbuf);
char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dicebuf, char *minmaxbuf);
void err_nocharm(enum ERROR reason, char *targetname);
int flip(int ch);
char *getaccuracyname(int accpct);
int getaccuracymodnum(int accmodpct);