- [+] when throwin gn aobject, warn if you have no LOF (just like

spells)
- [+] allow dodge/catch of thrown object when there is no thrower (ie.
      arrow traps)
- [+] simplify monster spellcasting
    - [+] don't use any mp
    - [+] select power based on monster hit dice only
    - [+] monsters should cast spells less often  - use f_castchance,
          default of 15% chance
    - [+] TEST
    - [+] you keep your own mpdice when polymorphing into a mosnter
- [+] fxied: throw a tranq dart, then:
    - [+] The cockatrice loses consciousness.  The cockatrice falls
          asleep.
- [+] bug: can't operate a fridge on the ground cause it's too heavy to
      lift
- [+] monsters generated on dark levels should always have seeindark 3-4
- [+] vending machines not working... fixed.

- [+] in getchoicestr:
    - [+]  if !showall, and if it shows a longdesc, then you hit
          backspace, longdesc should be cleared.
    - [+] show completion in a different colour
- [+] bug: sometimes we seem to have map->room[x], but no cells with
      cell->room->id == thatid!!
    - [+] stop vaults from overlapping.
- [+] taking too long to walk down levels - enforce max number of
      monster free turns
- [+] inept weapon penalty should be slightly higher
- [+] bad feeling check is too easy.
- [+] skeletons should have f_noinjuries
- [+] shouldn't check for slipping on things while swimming
- [+] tweak how traps + perception skill impact search checks 
- [+] bug: sometimes we have no player start position.
    - [+] if the vault creation fails, restart map generation.
- [+] only give study scroll ability at high spellcasting skill
- [+] typo:  ring (1 charges left)
* [+] god effects when you die:
- [+] pea soup should work in the cell in FRONT of you.
- [+] bug: ring of control seems to work when you _weild_ it!!
- [+] non-lethal weapons
    - [+] sword of mercy (at <1hp, ko)
    - [+] tranq dart
- [+] add sleeptypes
    - [+] change all refernces to f_asleep->val[1] (now an enum)
    - [+] change "stirs in its slumber" if unconscious
    - [+] change all 'fallasleep' calls
    - [+] attacking a ko'd enemy with merciful weapon should do nothing.
    - [+] ai shouldn't target ko'd enemies
- [+] ai should stop targetting people once they're dead/ko'd
- [+] bashing damage should sometimes just knock unconscious instead of
      killing?
    - [+] if their hp would be >= -3, and onein(2)
- [+] different body part names? "metal frame" instead of "body"
    - [+]  implement F_BPNAME, v0=enum bodypart, text = name
    - [+] getbodypartname() needs a lf argument.
    - [+] once i add this, also make animals have "front legs" instead
          of "arms", "paws" rather than "hands" etc.
    - [+] fix calls to getbodypartname to pass in lf or null
- [+] cyborg mods:
    - [+] can't wear most armour?
        - [+] need f_noarmouron - we HAVE this bp, but can't put armour
              on it.
    - [+] large rust damage from water
- [+] if you have a bad feeling about an object, mark it as "[bad]"
    - [+] f_knownbad
- [+] killing should anger the god of mercy
This commit is contained in:
Rob Pearce 2011-09-22 02:00:16 +00:00
parent 7f33b6351c
commit 2db53bca61
19 changed files with 1112 additions and 474 deletions

49
ai.c
View File

@ -571,6 +571,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
if (attackok) {
objecttype_t *st;
flag_t *f;
int spellchance = 0;
// drink boost potions
if (!useitemwithflag(lf, F_AIBOOSTITEM)) {
return B_FALSE;
@ -579,7 +581,17 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
// try spells first.
// can we attack with spells (ie. ones which target the victim)?
// if target is adjacent, we will normally just attack rather than try a spell.
spell = aigetattackspell(lf, target);
// random chance of casting a spell
f = lfhasflag(lf, F_CASTCHANCE);
if (f) spellchance = f->val[0];
else spellchance = 15;
if (pctchance(spellchance)) {
spell = aigetattackspell(lf, target);
} else {
spell = OT_NONE;
}
st = findot(spell);
if ( (spell != OT_NONE) && // found a valid spell/ability to use
((dist != 1) || // there is distance between us and target
@ -1237,20 +1249,27 @@ void aiturn(lifeform_t *lf) {
// do we already have a target we are attacking?
if (target) {
if (db) dblog(".oO { i have a target: lfid %d (%s). }", target->id, target->race->name);
// aquatic grabbers will try to drag their prey into the water
if (lfhasflagval(lf, F_GRABBING, target->id, NA, NA, NULL) && isaquatic(lf) ) {
if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) &&
!hasobwithflag(target->cell->obpile, F_DEEPWATER)) {
// move away!
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE, B_TRUE)) {
return;
// target dead or unconscious?
if (isdead(target) || isunconscious(target)) {
if (db) dblog(".oO { my target is dead/ko'd }", target->id, target->race->name);
loseaitargets(lf);
} else {
// aquatic grabbers will try to drag their prey into the water
if (lfhasflagval(lf, F_GRABBING, target->id, NA, NA, NULL) && isaquatic(lf) ) {
if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) &&
!hasobwithflag(target->cell->obpile, F_DEEPWATER)) {
// move away!
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE, B_TRUE)) {
return;
}
}
}
}
// try to move towards them.
if (!aimovetolf(lf, target, B_TRUE)) {
// success
return;
// try to move towards them.
if (!aimovetolf(lf, target, B_TRUE)) {
// success
return;
}
}
}
@ -1375,7 +1394,7 @@ void aiturn(lifeform_t *lf) {
lifeform_t *who;
if (lf->los[n] != lf->cell) {
who = lf->los[n]->lf;
if (who && cansee(lf, who)) {
if (who && !isdead(who) && !isunconscious(who) && cansee(lf, who)) {
if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) ||
lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) {
if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name);
@ -1391,7 +1410,7 @@ void aiturn(lifeform_t *lf) {
if (lf->los[n] != lf->cell) {
lifeform_t *who;
who = lf->los[n]->lf;
if (who && cansee(lf, who)) {
if (who && cansee(lf, who) && !isdead(who) && !isunconscious(who)) {
if (areenemies(lf, who)) {
if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name);
newtarget = who;

315
attack.c
View File

@ -172,6 +172,8 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
int attackedfriend = B_FALSE;
int attackedpeaceful = B_FALSE;
stoprunning(lf);
// anyone there? if so just attack.
if (c->lf) {
if (!force && isplayer(lf) && !areenemies(lf,c->lf) && (getraceclass(c->lf) != RC_PLANT)) {
@ -462,7 +464,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) {
}
// god effects...
if (attacktype == AT_LF) {
if ((attacktype == AT_LF) && isplayer(lf)) {
if (attackedfriend) {
angergodmaybe(R_GODMERCY, 100);
angergodmaybe(R_GODPURITY, 100);
@ -587,6 +589,22 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
}
if (wep && lfhasflagval(victim, F_ASLEEP, NA, ST_KO, NA, NULL)) {
f = hasflag(wep->flags, F_MERCIFUL);
if (f) {
if (isplayer(lf)) {
msg("^wYour %s refuses to attack %s!", noprefix(wepname), victimname);
if (!f->known) f->known = B_TRUE;
} else if (cansee(player, lf)) {
msg("^w%s%s %s refuses to attack %s!", attackername, getpossessive(attackername),
noprefix(wepname), victimname);
if (!f->known) f->known = B_TRUE;
}
taketime(lf, getattackspeed(lf));
return B_FALSE;
}
}
getflags(lf->flags, retflag, &nretflags, F_NONCORPOREAL, F_NONE);
for (i = 0; i < nretflags; i++) {
@ -613,10 +631,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
critpos = getrandomcorebp(victim);
// replace victicname to include body part
if ((lf == victim) && !isplayer(lf)) {
snprintf(victimbpname, BUFLEN, "its %s", getbodypartname(critpos));
snprintf(victimbpname, BUFLEN, "its %s", getbodypartname(victim, critpos));
} else {
getlfname(victim, buf);
snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), getbodypartname(critpos));
snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), getbodypartname(victim, critpos));
}
} else {
strcpy(victimbpname, "");
@ -751,7 +769,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
dam[0] *= 2;
}
// bonus for knowledge about the other lf's race? applied LAST.
slev = getlorelevel(lf, victim->race->raceclass->id);
if (slev == PR_INEPT) {
@ -907,7 +924,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
strcpy(extradambuf, "");
if (dam[i] == 0) {
if (getlorelevel(lf, victim->race->raceclass->id) >= PR_ADEPT) {
if (getlorelevel(lf, victim->race->raceclass->id)) {
//strcpy(extradambuf, " but do no damage");
strcpy(extradambuf, " ineffectually");
}
@ -1040,7 +1057,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
// other effects
if (!isdead(victim) && !blocked) {
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW)) {
if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) {
wepeffects(wep->flags, victim->cell, damflag, dam[0]);
}
if (isunarmed) {
@ -1106,7 +1123,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
// confer flags from attacker?
wepeffects(lf->flags, victim->cell, damflag, dam[0]);
if (dam[0]) {
wepeffects(lf->flags, victim->cell, damflag, dam[0]);
}
// special lifeform-based effects
if ((lf->race->id == R_COCKATRICE) && dam[0]) {
@ -1135,7 +1154,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
}
}
fightback(victim, lf);
// if victim can still move...
if (hasfreeaction(victim)) {
fightback(victim, lf);
}
} // end if !isdead(victim)
// retaliation happens even if victim died
@ -1371,7 +1393,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
} // end foreach damtype
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW)) {
if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) {
wepeffects(wep->flags, obloc, damflag, dam[0]);
}
@ -1393,8 +1415,8 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) {
void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum DAMTYPE damtype) {
object_t *o;
char lfname[BUFLEN],victimname[BUFLEN];
object_t *o,*armour;
char lfname[BUFLEN],victimname[BUFLEN],obname[BUFLEN];
// replace some dam types
if (damtype == DT_UNARMED) damtype = DT_BASH;
if (damtype == DT_BITE) damtype = DT_SLASH;
@ -1410,51 +1432,117 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum
switch (rnd(1,2)) {
case 1: fall(victim, lf, B_TRUE); break;
case 2:
if (cansee(player, lf) || cansee(player, victim)) {
getlfname(lf, lfname);
getlfname(victim, victimname);
setfacing(victim, getrandomdirexcept(DT_COMPASS, victim->facing));
msg("%s%s blow spins %s around!", lfname, getpossessive(lfname),victimname);
if (lf) {
if (cansee(player, lf) || cansee(player, victim)) {
getlfname(lf, lfname);
getlfname(victim, victimname);
setfacing(victim, getrandomdirexcept(DT_COMPASS, victim->facing));
msg("%s%s blow spins %s around!", lfname, getpossessive(lfname),victimname);
}
} else {
if (isplayer(victim) || cansee(player, victim)) {
getlfname(victim, victimname);
setfacing(victim, getrandomdirexcept(DT_COMPASS, victim->facing));
msg("%s is spun around!", victimname);
}
}
break;
}
}
if (!getarmour(victim, BP_BODY)) injure(victim, BP_BODY, damtype);
if ((armour = getarmour(victim, BP_BODY)) != NULL) {
getobname(armour, obname, armour->amt);
if (isplayer(victim)) {
msg("Your %s protects you.", noprefix(obname));
} else if (cansee(player, victim)) {
msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname));
}
} else {
injure(victim, BP_BODY, damtype);
}
break;
case BP_HEAD:
if (pctchance(80)) fall(victim, lf, B_TRUE);
stun(victim, 1);
stun(victim, 2);
// chance of your helmet falling off
o = getarmour(victim, BP_HEAD);
if (o) {
if (isplayer(victim)) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
msg("Your %s falls off!", noprefix(buf));
} else if (cansee(player, victim)) {
char buf[BUFLEN], lfname[BUFLEN];
getobname(o, buf, o->amt);
getlfname(victim, lfname);
msg("%s%s %s falls off!", lfname, getpossessive(lfname), noprefix(buf));
if (onein(2)) {
if (isplayer(victim)) {
char buf[BUFLEN];
getobname(o, buf, o->amt);
msg("Your %s falls off!", noprefix(buf));
} else if (cansee(player, victim)) {
char buf[BUFLEN], lfname[BUFLEN];
getobname(o, buf, o->amt);
getlfname(victim, lfname);
msg("%s%s %s falls off!", lfname, getpossessive(lfname), noprefix(buf));
}
moveob(o, victim->cell->obpile, o->amt);
} else {
if (isplayer(victim)) {
msg("Your %s protects you.", noprefix(obname));
} else if (cansee(player, victim)) {
msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname));
}
}
moveob(o, victim->cell->obpile, o->amt);
} else {
injure(victim, BP_HEAD, damtype);
}
break;
case BP_HANDS:
if (!getarmour(victim, BP_HANDS)) injure(victim, BP_HANDS, damtype);
// drop your weapon!
o = getweapon(victim);
if (o) drop(o, ALL);
break;
if ((armour = getarmour(victim, BP_HANDS)) != NULL) {
getobname(armour, obname, armour->amt);
if (isplayer(victim)) {
msg("Your %s protects you.", noprefix(obname));
} else if (cansee(player, victim)) {
msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname));
}
} else {
injure(victim, BP_HANDS, damtype);
}
if (onein(2)) {
// drop your weapon!
o = getweapon(victim);
if (o) drop(o, ALL);
break;
}
case BP_LEGS:
if (pctchance(70)) fall(victim, lf, B_TRUE);
if (!getarmour(victim, BP_LEGS)) injure(victim, BP_LEGS, damtype);
if ((armour = getarmour(victim, BP_LEGS)) != NULL) {
getobname(armour, obname, armour->amt);
if (isplayer(victim)) {
msg("Your %s protects you.", noprefix(obname));
} else if (cansee(player, victim)) {
msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname));
}
} else {
injure(victim, BP_LEGS, damtype);
}
break;
}
} else if (damtype == DT_SLASH) {
if (!getarmour(victim, hitpos)) injure(victim, hitpos, damtype);
if ((armour = getarmour(victim, hitpos)) != NULL) {
getobname(armour, obname, armour->amt);
if (isplayer(victim)) {
msg("Your %s protects you.", noprefix(obname));
} else if (cansee(player, victim)) {
msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname));
}
} else {
injure(victim, hitpos, damtype);
}
} else if (damtype == DT_EXPLOSIVE) {
if ((armour = getarmour(victim, hitpos)) != NULL) {
int min,max;
max = getobmaxhp(o);
min = max / 2;
limit(&min, 1, NA);
takedamage(armour, rnd(min,max), DT_EXPLOSIVE);
} else {
injure(victim, hitpos, damtype);
}
}
if (lf) {
@ -1581,16 +1669,18 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
} else if (damtype == DT_BASH) {
if (pct <= 5) {
return "whack";
} else if (pct <= 20) {
} else if (pct <= 15) {
if (onein(2)) {
return "hit";
} else {
return "bash";
}
} else if (pct <= 30) {
} else if (pct <= 25) {
return "pummel";
} else {
} else if (pct <= 35) {
return "slam";
} else {
return "clobber";
}
} else if (damtype == DT_BITE) {
if (lf && (ownersize <= SZ_SMALL)) {
@ -1807,6 +1897,10 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d
float pct;
pct = (int)(((float) dam / (float) maxhp) * 100.0);
if (wep && hasflag(wep->flags, F_MERCIFUL)) {
return "knock out";
}
if (victim->race->id == R_DANCINGWEAPON) {
return "defeat";
}
@ -1876,6 +1970,11 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d
// can't "kill" the undead
return "destroy";
}
// never use 'kill' for bashing since you might just knock them out
if (damtype == DT_BASH) {
return "clobber";
}
return "kill";
}
@ -2324,94 +2423,88 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) {
f->known = B_TRUE;
} else if ((f->id == F_HITCONFER) && victim ) {
// only works if we did damage
if (dam) {
enum FLAG fid;
int howlong;
flag_t *valflag = NULL;
enum FLAG fid;
int howlong;
flag_t *valflag = NULL;
fid = f->val[0];
// the f_poisoned flag stacks, others don't.
if (!lfhasflag(victim, fid) || (fid == F_POISONED)) {
int passedcheck = B_FALSE;
// do they get a saving throw?
if (f->val[1] != NA) {
int scdiff;
if (f->val[2] == NA) {
scdiff = 20; // default
} else {
scdiff = f->val[2];
}
if (skillcheck(victim, f->val[1], scdiff, 0)) {
passedcheck = B_TRUE;
}
fid = f->val[0];
// the f_poisoned flag stacks, others don't.
if (!lfhasflag(victim, fid) || (fid == F_POISONED)) {
int passedcheck = B_FALSE;
// do they get a saving throw?
if (f->val[1] != NA) {
int scdiff;
if (f->val[2] == NA) {
scdiff = 20; // default
} else {
scdiff = f->val[2];
}
if (skillcheck(victim, f->val[1], scdiff, 0)) {
passedcheck = B_TRUE;
}
}
if (!passedcheck) {
howlong = gethitconferlifetime(f->text, NULL, NULL);
if (!passedcheck) {
howlong = gethitconferlifetime(f->text, NULL, NULL);
// get conferred flag values
valflag = hasflag(f->pile, F_HITCONFERVALS);
// get conferred flag values
valflag = hasflag(f->pile, F_HITCONFERVALS);
if (fid == F_POISONED) {
// need to fill in the name of what poisoned us
char frombuf[BUFLEN];
enum POISONTYPE ptype;
int ppower;
if (wep) {
if (owner) {
char lfname[BUFLEN];
char wepname[BUFLEN];
getlfnamea(owner, lfname);
getobname(wep, wepname, 1);
// ie. "a goblin's poisoned short sword"
snprintf(frombuf, BUFLEN, "%s%s %s",lfname,getpossessive(lfname), wepname);
} else {
char wepname[BUFLEN];
getobname(wep, wepname, 1);
// ie "a poisoned short sword"
snprintf(frombuf, BUFLEN, "%s", wepname);
}
if (fid == F_POISONED) {
// need to fill in the name of what poisoned us
char frombuf[BUFLEN];
enum POISONTYPE ptype;
int ppower;
if (wep) {
if (owner) {
char lfname[BUFLEN];
char wepname[BUFLEN];
getlfnamea(owner, lfname);
getobname(wep, wepname, 1);
// ie. "a goblin's poisoned short sword"
snprintf(frombuf, BUFLEN, "%s%s %s",lfname,getpossessive(lfname), wepname);
} else {
strcpy(frombuf, "something unknown");
char wepname[BUFLEN];
getobname(wep, wepname, 1);
// ie "a poisoned short sword"
snprintf(frombuf, BUFLEN, "%s", wepname);
}
} else {
strcpy(frombuf, "something unknown");
}
if (valflag) {
ptype = valflag->val[0];
if (valflag->val[1] == NA) {
ppower = 1;
} else {
ppower = valflag->val[1];
}
} else {
// should never happen.
ptype = P_VENOM;
if (valflag) {
ptype = valflag->val[0];
if (valflag->val[1] == NA) {
ppower = 1;
} else {
ppower = valflag->val[1];
}
poison(victim, howlong, ptype, ppower, frombuf);
} else {
flag_t *conferredflag;
conferredflag = addtempflag(victim->flags, fid, NA, NA, NA, NULL, howlong);
// flag values
if (valflag) {
conferredflag->val[0] = valflag->val[0];
conferredflag->val[1] = valflag->val[1];
conferredflag->val[2] = valflag->val[2];
free(conferredflag->text);
conferredflag->text = strdup(valflag->text);
}
// should never happen.
ptype = P_VENOM;
ppower = 1;
}
} // end if passedcheck
} // end (if victim doesn't already have the flag)
// was this from a poisoned weapon? if so the poison vanishes
if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) {
killflag(f);
if (owner && isplayer(owner)) {
addflag(owner->flags, F_USEDPOISON, B_TRUE, NA, NA, NULL);
poison(victim, howlong, ptype, ppower, frombuf);
} else {
// flag values
if (valflag) {
addtempflag(victim->flags, fid, valflag->val[0], valflag->val[1], valflag->val[2], valflag->text, howlong);
} else {
addtempflag(victim->flags, fid, NA, NA, NA, NULL, howlong);
}
}
} // end if passedcheck
} // end (if victim doesn't already have the flag)
// was this from a poisoned weapon? if so the poison vanishes
if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) {
killflag(f);
if (owner && isplayer(owner)) {
addflag(owner->flags, F_USEDPOISON, B_TRUE, NA, NA, NULL);
}
}
} // end if (fid == hitconfer)

213
data.c
View File

@ -161,6 +161,7 @@ void initjobs(void) {
// stat mods
// initial objects
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 bananas");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "short sword");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 potions of healing");
@ -178,7 +179,6 @@ void initjobs(void) {
addflag(lastjob->flags, F_CANLEARN, i, NA, NA, NULL);
}
// abilities
addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL);
addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL);
addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL);
@ -268,6 +268,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_ADEPT, NA, NULL);
addflag(lastjob->flags, F_STARTSKILL, SK_SS_NATURE, PR_NOVICE, NA, NULL);
// learnable skills
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
@ -607,6 +608,7 @@ void initjobs(void) {
f = addflag(lastjob->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 33);
f = addflag(lastjob->flags, F_CANCAST, OT_S_HASTE, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 20);
f = addflag(lastjob->flags, F_CANCAST, OT_S_HEALING, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 20);
addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL);
// non-player jobs
addjob(J_SHOPKEEPER, "Shopkeeper");
@ -742,14 +744,16 @@ void initobjects(void) {
// weapons
addbrand(BR_BALANCE, "of balance", BP_WEAPON);
addflag_real(lastbrand->flags, F_BALANCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_IMPACT, "of impact", BP_WEAPON); // TODO: make thisonly go ont obashing weapons
addflag_real(lastbrand->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_MERCY, "of mercy", BP_WEAPON);
addflag_real(lastbrand->flags, F_MERCIFUL, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_PYROMANIA, "of pyromania", BP_WEAPON);
addflag_real(lastbrand->flags, F_FLAMESTRIKE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_REVENGE, "of revenge", BP_WEAPON);
addflag_real(lastbrand->flags, F_REVENGE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_SHARPNESS, "of sharpness", BP_WEAPON);
addflag_real(lastbrand->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
addbrand(BR_IMPACT, "of impact", BP_WEAPON); // TODO: make thisonly go ont obashing weapons
addflag_real(lastbrand->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1);
// feet
addbrand(BR_LEVITATION, "of hovering", BP_FEET);
@ -3077,7 +3081,7 @@ void initobjects(void) {
addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers");
addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out");
addot(OT_FRIDGE, "refrigerator", "An insulated household appliance, made for storing food.", MT_METAL, 80, OC_TOOLS, SZ_HUMAN);
addot(OT_FRIDGE, "refrigerator", "An insulated household appliance, made for storing food.", MT_METAL, 120, OC_TOOLS, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "]");
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -3542,7 +3546,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid");
addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -3556,7 +3560,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "~");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -3570,7 +3574,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, NA, NA, NA, ",");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -4350,7 +4354,7 @@ void initobjects(void) {
addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINVIS, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 2, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 3, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL);
addot(OT_RING_MANA, "ring of mana", "Increases the wearer's MP pool.", MT_METAL, 0.1, OC_RING, SZ_MINI);
addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, "");
@ -4533,22 +4537,31 @@ void initobjects(void) {
addot(OT_DART, "dart", "A small, sharp projectile weapon.", MT_WOOD, 0.5, OC_MISSILE, SZ_SMALL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 1, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL);
addot(OT_NANODART, "nanodart", "A metal dart with a laser-sharpened point.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY);
addot(OT_DARTNANO, "nanodart", "A metal dart with a nanofibre point. Capable of piercing most armour.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, "");
addflag(lastot->flags, F_MISSILEDAM, 1, NA, NA, "");
addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, "");
addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, "");
addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL);
addot(OT_DARTTRANQ, "tranquiliser dart", "A metal dart coated with a strong sleep-inducing serum.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_MISSILEDAM, 0, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_NUMAPPEAR, 1, 4, NA, NULL);
addflag(lastot->flags, F_HITCONFER, F_ASLEEP, SC_CON, 27, "20-30");
addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, ST_ASLEEP, NA, NULL);
addot(OT_NEEDLE, "needle", "A tiny pointed needle.", MT_METAL, 0.02, OC_MISSILE, SZ_TINY);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, "");
@ -4618,7 +4631,6 @@ void initobjects(void) {
addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+1");
addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL);
addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL);
@ -5196,6 +5208,9 @@ void initrace(void) {
addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL);
// other special stuff
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "screechs^a screech");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "talons");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right claw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left claw");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL);
addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL);
@ -5207,25 +5222,39 @@ void initrace(void) {
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL);
addrace(R_CYBORG, "cyborg", 150, 'R', C_GREY, MT_METAL, RC_HUMANOID);
addrace(R_CYBORG, "cyborg", 150, 'R', C_GREY, MT_FLESH, RC_HUMANOID);
// stats
addflag(lastrace->flags, F_PLAYABLE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_DEX, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL);
// bonuses
addflag(lastrace->flags, F_EXTRAINFO, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_TECHUSAGE, PR_ADEPT, NA, NULL);
// penalties
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, "2d6");
addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_BODY, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_RIGHTFINGER, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_LEFTFINGER, NA, NA, NULL);
// other special stuff
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "puddle of oil");
addflag(lastrace->flags, F_BODYPARTNAME, BP_EARS, NA, NA, "audio inputs");
addflag(lastrace->flags, F_BODYPARTNAME, BP_EYES, NA, NA, "video inputs");
addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "metal frame");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEGS, NA, NA, "stabilisers");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "robotic hands");
addflag(lastrace->flags, F_BODYPARTNAME, BP_FEET, NA, NA, "lower propulsion units");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right sensor");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left sensor");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL);
addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL);
@ -5273,8 +5302,6 @@ void initrace(void) {
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3");
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
addflag(lastrace->flags, F_MEDITATES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "1-50 gold coins");
@ -5290,6 +5317,10 @@ void initrace(void) {
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_FLEEONHPPCT, 50, NA, NA, NULL);
// bonuses
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
addflag(lastrace->flags, F_MEDITATES, B_TRUE, NA, NA, NULL);
// human monsters...
addrace(R_BANDITLDR, "bandit leader", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID);
@ -5572,10 +5603,12 @@ void initrace(void) {
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "50d4");
addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed longsword of mercy");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 blessed vials of ambrosia");
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "2 rings of regeneration");
addflag(lastrace->flags, F_STARTSKILL, SK_FIRSTAID, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_LONGBLADES, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "raises her hand");
// god abilities
addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Mercy");
@ -5631,6 +5664,8 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_EYES, NA, NA, "eyestalks");
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addrace(R_BUGBEAR, "bugbear", 120, 'G', C_BROWN, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -5654,6 +5689,9 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "goblin");
addflag(lastrace->flags, F_MINIONS, 20, 1, 3, "goblin warrior");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_COCKATRICE, "cockatrice", 5, 'c', C_YELLOW, MT_FLESH, RC_MAGIC);
addflag(lastrace->flags, F_STARTATT, A_DEX, AT_VHIGH, NA, NULL);
@ -5701,6 +5739,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTFINGER, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:1d6;");
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;");
addflag(lastrace->flags, F_CASTCHANCE, 70, NA, NA, NULL);
addrace(R_DARKMANTLE, "darkmantle", 70, 'U', C_BLUE, MT_FLESH, RC_MAGIC);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -5748,8 +5787,6 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLSPEED, SP_VERYSLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_MPDICE, 0, 25, NA, NULL);
addflag(lastrace->flags, F_MPREGEN, 12, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_DISPERSAL, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_GRAVBOOST, NA, NA, NULL);
addflag(lastrace->flags, F_CASTTYPE, CT_GAZE, NA, NA, NULL);
@ -5764,6 +5801,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings");
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addrace(R_GIANTHILL, "hill giant", 160, 'H', C_GREY, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -5854,8 +5892,6 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow");
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL);
addflag(lastrace->flags, F_MPDICE, 0, 9, NA, NULL);
addflag(lastrace->flags, F_MPREGEN, 1, NA, NA, NULL);
addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_FIREDART, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_FLAMEPILLAR, NA, NA, NULL);
@ -5922,6 +5958,9 @@ void initrace(void) {
addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_GNOLLHM, "gnoll huntmaster", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID);
lastrace->baseid = R_GNOLL;
@ -5952,6 +5991,9 @@ void initrace(void) {
addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll");
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_GNOLLMR, "gnoll marauder", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID);
lastrace->baseid = R_GNOLL;
@ -5981,6 +6023,9 @@ void initrace(void) {
addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll");
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_GOBLIN, "goblin", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -6093,14 +6138,13 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL);
addflag(lastrace->flags, F_MPDICE, 0, 10, NA, NULL);
addflag(lastrace->flags, F_MPREGEN, 3, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_BLINDNESS, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_PAIN, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin");
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addrace(R_HOBGOBLIN, "hobgoblin", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -6109,7 +6153,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_FOREST, 73, NA, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 1, 2, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+3");
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3");
addflag(lastrace->flags, F_ARMOURRATING, 8, NA, NA, NULL);
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
@ -6180,7 +6224,7 @@ void initrace(void) {
addflag(lastrace->flags, F_EVASION, 5, 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, NA, NA, "1d3");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3-1");
addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_DEX, AT_HIGH, NA, NULL);
@ -6209,8 +6253,8 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_DEX, AT_AVERAGE, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
addflag(lastrace->flags, F_HASATTACK, OT_TAIL, NA, NA, "1d3");
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d4");
addflag(lastrace->flags, F_HASATTACK, OT_TAIL, NA, NA, "1d6");
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "club");
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "buckler");
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-10 gold coins");
@ -6268,10 +6312,12 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;");
addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roar");
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_HEAD, NA, NA, NULL);
addrace(R_OGRE, "ogre", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID);
@ -6496,8 +6542,6 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLSPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_MPDICE, 0, 4, NA, NULL);
addflag(lastrace->flags, F_MPREGEN, 4, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures");
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
@ -6511,6 +6555,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addrace(R_SATYR, "satyr", 80, 'h', C_GREEN, MT_FLESH, RC_HUMANOID);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -6532,8 +6577,6 @@ void initrace(void) {
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "plays its pipes");
addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MPDICE, 0, 16, NA, NULL);
addflag(lastrace->flags, F_MPREGEN, 8, NA, NA, NULL);
addflag(lastrace->flags, F_NEEDOBFORSPELLS, OT_PANPIPES, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, NA, NA, NULL);
@ -6544,6 +6587,7 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTHIDDENPCT, 60, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addrace(R_SHADOWCAT, "shadowcat", 5, 'f', C_BLUE, MT_FLESH, RC_MAGIC);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -6561,6 +6605,9 @@ void initrace(void) {
addflag(lastrace->flags, F_CANSEETHROUGHMAT, MT_GAS, NA, NA, NULL);
addflag(lastrace->flags, F_AUTOCREATEOB, 1, NA, NA, "cloud of smoke");
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_OOZEGREY, "grey ooze", 10, 'j', C_GREY, MT_SLIME, RC_SLIME);
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pool of slime");
@ -6571,6 +6618,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTFINGER, NA, NA, NULL);
@ -6602,8 +6650,6 @@ void initrace(void) {
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_MPDICE, 0, 4, NA, NULL);
addflag(lastrace->flags, F_MPREGEN, 1, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_FIREDART, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
@ -6615,6 +6661,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addrace(R_SPRITEICE, "ice sprite", 5, 'n', C_WHITE, MT_ICE, RC_MAGIC);
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "sheet of ice");
@ -6628,8 +6675,6 @@ void initrace(void) {
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_MPDICE, 4, 2, NA, NULL);
addflag(lastrace->flags, F_MPREGEN, 1, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_FROSTBITE, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_FREEZEOB, NA, NA, NULL);
addflag(lastrace->flags, F_CANCAST, OT_S_ICICLE, NA, NA, NULL);
@ -6641,6 +6686,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL);
addrace(R_TROLL, "troll", 100, 't', C_GREEN, MT_FLESH, RC_HUMANOID);
@ -6660,6 +6706,9 @@ void initrace(void) {
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL);
@ -6676,6 +6725,9 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
// fish
addrace(R_CRAB, "giant crab", 250, ';', C_ORANGE, MT_FLESH, RC_AQUATIC);
@ -6691,13 +6743,16 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4");
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTFINGER, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTFINGER, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "pincers");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addflag(lastrace->flags, F_NOARMOURON, BP_RIGHTFINGER, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_LEFTFINGER, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOARMOURON, BP_FEET, NA, NA, NULL);
addrace(R_PIRANHA, "piranha", 0.5, ';', C_GREEN, MT_FLESH, RC_AQUATIC);
addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -6921,6 +6976,9 @@ void initrace(void) {
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d4;");
addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "bear cub");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_YELLOW, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_BEAR;
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -6946,6 +7004,9 @@ void initrace(void) {
addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_BLEEDABIL, OT_A_RAGE, NA, NA, NULL);
addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "bear cub");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_BEARCUB, "bear cub", 60, 'q', C_BROWN, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_BEAR;
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -6966,6 +7027,9 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL);
addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, "");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_ANT, "giant ant", 20, 'a', C_BROWN, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_ANT;
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -7068,7 +7132,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
@ -7076,6 +7139,9 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_FLEEONHPPCT, 60, NA, NA, "");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -7092,7 +7158,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL);
@ -7102,6 +7167,9 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_DOGDEATH, "death hound", 40, 'd', C_MAGENTA, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, "");
@ -7121,7 +7189,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
@ -7131,6 +7198,9 @@ void initrace(void) {
addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 24, "10-15");
addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL);
addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_DOGWAR, "war hound", 40, 'd', C_BROWN, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NUMAPPEAR, 1, 4, NA, "");
@ -7147,7 +7217,6 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
@ -7155,6 +7224,9 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 2, NA, "growls^growling");
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian
lastrace->baseid = R_HAWK;
@ -7290,6 +7362,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:4;");
addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:0d1+4;");
addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addrace(R_NEWT, "giant newt", 4, ':', C_BROWN, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
@ -7300,6 +7373,9 @@ void initrace(void) {
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_HASATTACK, OT_CLAWS, NA, NA, "1d2-1");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2-1");
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
addflag(lastrace->flags, F_FLEEONDAM, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
@ -7346,6 +7422,9 @@ void initrace(void) {
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_SNAKE, "brown snake", 3, 's', C_BROWN, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, "");
@ -7414,6 +7493,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing");
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 2, 2, NULL);
addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addrace(R_SNAKECOBRABLACK, "black cobra", 3, 's', C_BLUE, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, "");
@ -7532,6 +7612,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:1;range:4;");
addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
@ -7539,6 +7620,8 @@ void initrace(void) {
addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web");
addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "1-10 webs");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "cephalothorax");
addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "abdomen");
addrace(R_SPIDERFUNNELWEB, "giant funnelweb", 5, 'S', C_MAGENTA, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_SPIDER;
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, "");
@ -7558,6 +7641,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:5;range:2;");
addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
@ -7565,6 +7649,8 @@ void initrace(void) {
addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web");
addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "20-30 webs");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "cephalothorax");
addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "abdomen");
addrace(R_SPIDERREDBACK, "giant redback", 5, 'S', C_RED, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_SPIDER;
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, "");
@ -7584,6 +7670,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:7;range:3;");
addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
@ -7591,6 +7678,8 @@ void initrace(void) {
addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web");
addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "10-20 webs");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "cephalothorax");
addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "abdomen");
addrace(R_WOLFYOUNG, "young wolf", 10, 'd', C_GREY, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
@ -7616,6 +7705,9 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_FLEEONHPPCT, 75, NA, NA, "");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_WOLF, "wolf", 25, 'd', C_GREY, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
@ -7641,6 +7733,9 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling");
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, "");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
// insects
addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL);
@ -7733,6 +7828,9 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:1d4;");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw");
addrace(R_CENTIPEDE, "giant centipede", 3, 'w', C_GREEN, MT_FLESH, RC_INSECT);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
@ -7894,12 +7992,27 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5");
addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTOBDT, 50, DT_CHOP, NA, NULL);
addflag(lastrace->flags, F_STARTOB, 25, DT_CHOP, NA, "buckler");
addflag(lastrace->flags, F_STARTOB, 25, NA, NA, "buckler");
addflag(lastrace->flags, F_DTVULN, DT_BASH, NA, NA, NULL);
addflag(lastrace->flags, F_DTRESIST, DT_SLASH, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL);
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_EARS, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_WEAPON, NA, NA, "right metacarpals");
addflag(lastrace->flags, F_BODYPARTNAME, BP_SECWEAPON, NA, NA, "left metacarpals");
addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "ribs");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "skull");
addflag(lastrace->flags, F_BODYPARTNAME, BP_SHOULDERS, NA, NA, "scapulas");
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "carpals");
addflag(lastrace->flags, F_BODYPARTNAME, BP_WAIST, NA, NA, "coccyx");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEGS, NA, NA, "fibulas");
addflag(lastrace->flags, F_BODYPARTNAME, BP_FEET, NA, NA, "tarsals");
addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right phalange");
addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left phalange");
addrace(R_GHAST, "ghast", 50, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -7921,6 +8034,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addrace(R_GHOST, "ghost", 50, 'p', C_BLUE, MT_MAGIC, RC_UNDEAD); // p for sPirit
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -7934,6 +8048,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+2");
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_XRAYVIS, 3, NA, NA, NULL);
@ -7964,6 +8079,7 @@ void initrace(void) {
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws");
addrace(R_VAMPIRE, "vampire", 75, 'V', C_BLUE, MT_FLESH, RC_UNDEAD);
addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL);
@ -7993,11 +8109,11 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4+3");
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_RETAINHPMPONPOLY, B_TRUE, NA, NA, "");
addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;");
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 5, 5, "range:3;");
addflag(lastrace->flags, F_CANWILL, OT_S_STUN, 5, 5, "pw:1;");
addflag(lastrace->flags, F_CANWILL, OT_S_POLYMORPH, 3, 3, "pw:1;race:vampire bat;");
addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL);
addflag(lastrace->flags, F_DETECTOBS, 10, OT_COFFIN, NA, NULL);
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash");
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "gestures");
@ -8030,6 +8146,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 4, NA, NA, NULL);
addflag(lastrace->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
@ -8054,6 +8171,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
@ -8079,6 +8197,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
@ -8237,7 +8356,7 @@ void initskills(void) {
addskilldesc(SK_SPEECH, PR_EXPERT, "^gShop item prices are reduced by 25%.^n", B_FALSE);
addskilldesc(SK_SPEECH, PR_MASTER, "^gShop item prices are reduced by 30%.^n", B_FALSE);
addskill(SK_SPELLCASTING, "Sorcery", "Increases the power of spells from all schools except Allomancy, Nature and Psionics.", 50);
addskilldesc(SK_SPELLCASTING, PR_NOVICE, "^gYou gain the 'study scrolls' ability.^n", B_FALSE);
addskilldesc(SK_SPELLCASTING, PR_SKILLED, "^gYou gain the 'study scrolls' ability.^n", B_FALSE);
addskill(SK_PERCEPTION, "Perception", "Your ability to notice hidden details, from simple footprints to sinister traps.", 50);
addskilldesc(SK_PERCEPTION, PR_INEPT, "- At higher levels this skill will also let you obscure your own tracks.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now see footprints.^n", B_TRUE);

Binary file not shown.

37
defs.h
View File

@ -251,7 +251,7 @@ enum RELATIVEDIR {
#define SAVEDIR "data/save"
#define VAULTDIR "vaults"
// rank, score, name, job, killer
#define HISCOREFORMAT "%-6s%-7s%-10s%-18s%s"
#define HISCOREFORMAT "%-5s%-7s%-10s%-23s%s"
// game strings
#define MORESTRING "--More--"
@ -292,8 +292,8 @@ enum RELATIVEDIR {
// Time periods
#define TM_DRUNKTIME (10) // how long it takes for alcohol to wear off
#define TM_WETTIME (10) // how long it takes for things to dry
#define TM_SCENT (15) // how long scents take to fade
#define TM_FOOTPRINT (20) // how long footprints take to fade
#define TM_SCENT (30) // how long scents take to fade
#define TM_FOOTPRINT (35) // how long footprints take to fade
// object conditions for random objects
#define RO_NONE 0
@ -1503,7 +1503,8 @@ enum OBTYPE {
OT_ARROW,
OT_BOLT,
OT_DART,
OT_NANODART,
OT_DARTNANO,
OT_DARTTRANQ,
OT_NEEDLE,
OT_JAVELIN,
OT_BULLET,
@ -1684,6 +1685,12 @@ enum RANGEATTACK {
RA_WAND,
};
enum SLEEPTYPE {
ST_ASLEEP = 0,
ST_MEDITATING,
ST_KO,
};
enum FLAG {
F_NONE = 0, // dummy flag
// map flags
@ -1792,11 +1799,12 @@ enum FLAG {
F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit
F_HITCONFER, // hitting with this gives flagid=v0
// unless you pass a val1 skillcheck, diff val2
// with timeleft = text ("min-max")
// unless you pass a val1 skillcheck, diff val2
// MUST ALSO HAVE HITCONFERVALS.
F_HITCONFERVALS,// specifies values for conferred flag.
F_ACTIVATED, // val0 = is this object turned on?
F_GRENADE, // this obkejct will drain charge when activated, then die
F_GRENADE, // this object will drain charge when activated, then die
F_EXPLODEONDEATH, // explodes when it dies, deals TEXT damage.
// val1 = BIG means hit surrounding cells
// val2 = ifactivated, only explodes if activated.
@ -1848,6 +1856,7 @@ enum FLAG {
// v2 = max trap chance
F_TRAPPED, // this object HAS a trap.
// v0 is the trap object type
// v1 - 'curtime' when this trap was last triggered
// v2 = TRUE means we've spotted this.
F_TRAP, // this object _IS_ a trap. v0 is sc_disarm/sc_spot difficulty.
// (NA = impossible)
@ -1945,6 +1954,7 @@ enum FLAG {
// end gun flags
F_FLAMESTRIKE, // causes fires where you hit
F_BALANCE, // heals target if their maxhp < your maxhp
F_MERCIFUL, // puts to sleep instead of killing.
F_REVENGE, // causes damage based on your hp
F_HELPSREST, // makes you heal mp/hp faster when using 'R'
// reduces skillcheck difficulty by v0.
@ -1983,6 +1993,7 @@ enum FLAG {
// ob identification flags
F_HASHIDDENNAME, // whether this object class has a hidden name
F_IDENTIFIED, // whether this object is fully identified
F_KNOWNBAD, // you know this object is somehow bad
// bad flags
F_DEEPWATER, // v0 = depth.
F_WALKDAM, // val0 = damtype, text = dam per sec
@ -2133,6 +2144,8 @@ enum FLAG {
F_LOSLOF, // v0 = whether this spell needs line of sight
// v1 = whether this spell needs line of fire
// MONSTER AI FLAGS
F_CASTCHANCE, // this lf has v0% chance of using spell/abil
// (default is 15%)
F_DEMANDSBRIBE, // lf will demand gold from the player.
F_NOSWAP, // other mosnters won't swap with this one.
// cleared at start of turn.
@ -2248,7 +2261,7 @@ enum FLAG {
F_ORIGRACE, // original player race (if you polymorphed)
F_ORIGJOB, // original player job (if you polymorphed)
F_POLYMORPHED, // lf has been polymorphed
F_RETAINHPMPONPOLY, // don't take on hp/mp of what you polymorph
F_RETAINHPONPOLY, // don't take on hp/mp of what you polymorph
// into
F_SHORTCUT, // spell keyboard shortcut.
// v0=slot (0-9)
@ -2257,13 +2270,18 @@ enum FLAG {
F_DOESNTMOVE, // this race doesn't move (but can still attack)
F_AQUATIC, // this race can attack normally in water and suffers no
// movement penalties
F_BODYPARTNAME, // for this race, bodypart v0 is called 'text'
F_HUMANOID, // this race can wear armour / use weapons
F_INSECT, // this race is classed as an insect
F_UNDEAD, // this race is classed as undead
F_COLDBLOOD, // this race is coldblooded
F_NOARMOURON, // this race can't wear armour on bodypart v0
// obviously doesn't make sense to have both this
// and f_nobodypart for the same body part.
F_NOBODYPART, // this race doesn't have bodypart val0
// if v0 is true or b_frominjury, you can regrow it
// via a healing potion.
F_NOINJURIES, // this race cannot sustain injuries.
F_NOPACK, // this race cannot hold objects
F_NOSPELLS, // this race cannot cast spells
F_INDUCEFEAR, // causes fear when you attack it
@ -2543,7 +2561,8 @@ enum INJURY {
IJ_FINGERMISSING,
IJ_EYELIDSCRAPED,
IJ_EYEDESTROYED,
//
// explosive
IJ_HANDMISSING,
};
@ -2639,6 +2658,7 @@ enum ERROR {
E_DRUNK,
//
E_NOBP,
E_DOESNTFIT,
E_VEGETARIAN,
E_PARTVEGETARIAN,
E_CARNIVORE,
@ -3170,6 +3190,7 @@ enum OBMOD {
enum BRAND {
BR_BALANCE,
BR_MERCY,
BR_NIMBLENESS,
BR_FEEBLENESS,
BR_FLIGHT,

1
flag.c
View File

@ -420,6 +420,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
case F_ATTRMOD:
case F_BLIND:
case F_CONFUSED:
case F_DRUNK:
case F_EATING:
case F_FASTMOVE:
case F_FLYING:

22
god.c
View File

@ -386,6 +386,22 @@ enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness) {
return PL_INDIFFERENT;
}
// get a random god which player has prayed to
lifeform_t *getrandomprayedgod(void) {
int i,nposs = 0;
lifeform_t *god,*poss[MAXGODS];
for (i = 0; i < ngodlfs; i++) {
god = godlf[i];
if (lfhasflag(god, F_PRAYEDTO)) {
poss[nposs++] = god;
}
}
if (nposs == 0) {
return NULL;
}
return poss[rnd(0,nposs-1)];
}
lifeform_t *godappears(enum RACE rid, cell_t *where) {
lifeform_t *god;
char killedname[BUFLEN],godname[BUFLEN];
@ -805,7 +821,11 @@ int prayto(lifeform_t *lf, lifeform_t *god) {
msg("\"Behold, the power of death!\"");
for (l = lf->cell->map->lf ; l ; l = l->next) {
if ((l != lf) && lfhasflagval(l, F_TARGETLF, lf->id, NA, NA, NULL)) {
castspell(god, OT_S_PAIN, l, NULL, l->cell);
if (isundead(l)) {
makepeaceful(l);
} else {
castspell(god, OT_S_PAIN, l, NULL, l->cell);
}
}
}
dospelleffects(god, OT_S_ANIMATEDEAD, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE);

1
god.h
View File

@ -6,6 +6,7 @@ void dooffer(void);
lifeform_t *findgod(enum RACE rid);
int getpiety(enum RACE rid);
enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness);
lifeform_t *getrandomprayedgod(void);
lifeform_t *godappears(enum RACE rid, cell_t *where);
int godgiftmaybe(enum RACE rid);
int godisangry(enum RACE rid);

154
io.c
View File

@ -690,8 +690,10 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
f = lfhasflag(c->lf, F_ASLEEP);
if (f) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
if (f->val[1] != B_TRUE) {
if (f->val[1] == ST_MEDITATING) {
strcat(extrainfo, "meditating");
} else if (f->val[1] == ST_KO) {
strcat(extrainfo, "unconscious");
} else if (f->val[2] == NA) {
strcat(extrainfo, "sleeping");
} else {
@ -1147,7 +1149,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
if (isplayer(lf) && (f->val[2] != NA)) { // ie. resting, not forced asleep
object_t *restob;
int meditating = B_FALSE;
if (f->val[1] != NA) meditating = B_TRUE;
if (f->val[1] == ST_MEDITATING) meditating = B_TRUE;
restob = getrestob(lf);
if (restob) {
char restobname[BUFLEN];
@ -1157,7 +1159,11 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
msg("You start %s (on the ground)...", meditating ? "meditating" : "resting" );
}
} else {
msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s");
if (f->val[1] == ST_ASLEEP) {
msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s");
} else {
msg("%s lose%s consciousness.",lfname, isplayer(lf) ? "" : "s");
}
}
donesomething = B_TRUE;
break;
@ -1740,10 +1746,16 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
}
break;
case F_ASLEEP:
if (f->val[1] == NA) {
msg("%s wake%s up.",lfname, isplayer(lf) ? "" : "s");
} else {
msg("%s stop%s meditating.",lfname, isplayer(lf) ? "" : "s");
switch (f->val[1]) {
case ST_ASLEEP:
msg("%s wake%s up.",lfname, isplayer(lf) ? "" : "s");
break;
case ST_MEDITATING:
msg("%s stop%s meditating.",lfname, isplayer(lf) ? "" : "s");
break;
case ST_KO:
msg("%s regain%s consciousness.",lfname, isplayer(lf) ? "" : "s");
break;
}
donesomething = B_TRUE;
break;
@ -2308,10 +2320,13 @@ void announceobflagloss(object_t *o, flag_t *f) {
}
int confirm_badfeeling(void) {
int confirm_badfeeling(object_t *o) {
char ch;
ch = askchar("You have a bad feeling about this. Continue?", "yn", "n", B_TRUE);
if (ch == 'y') return B_TRUE;
if (o && !hasflag(o->flags, F_KNOWNBAD)) {
addflag(o->flags, F_KNOWNBAD, B_TRUE, NA, NA, NULL);
}
return B_FALSE;
}
@ -2566,11 +2581,11 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int
}
// draw prompt
if (strlen(numstring) > 0) {
mvwprintw(mainwin, 0, 0, "%s (%sesc to quit) [%s]: ",prompt,
mvwprintw(mainwin, 0, 0, "%s (%sESC to quit) [%s]: ",prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "",
numstring);
} else {
mvwprintw(mainwin, 0, 0, "%s (%sesc to quit): ", prompt,
mvwprintw(mainwin, 0, 0, "%s (%sESC to quit): ", prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "");
}
if (nextpage != -1) {
@ -2763,11 +2778,11 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) {
mvwprintw(mainwin, y, 0, MORESTRING);
}
if (strlen(numstring) > 0) {
snprintf(pbuf, BUFLEN,"%s (%s','=all, esc to quit) [%s]: ",prompt,
snprintf(pbuf, BUFLEN,"%s (%s','=all, ESC to quit) [%s]: ",prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "",
numstring);
} else {
snprintf(pbuf, BUFLEN,"%s (%sesc to quit): ", prompt,
snprintf(pbuf, BUFLEN,"%s (%sESC to quit): ", prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "");
}
@ -3799,8 +3814,8 @@ void doeat(obpile_t *op) {
eatob = askobject(op, "Eat what", NULL, AO_EDIBLE);
}
if (eatob) {
if (isunknownbadobject(eatob) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
if (isunknownbadobject(eatob) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(eatob)) {
msg("Cancelled.");
return;
}
@ -3918,8 +3933,8 @@ int dowear(obpile_t *op) {
int rv;
o = askobject(op, "Wear what", NULL, AO_WEARABLE);
if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(o)) {
msg("Cancelled.");
return B_TRUE;
}
@ -3940,8 +3955,8 @@ int doweild(obpile_t *op) {
int rv;
o = askobject(op, "Weild what", &count, AO_WEILDABLE | AO_INCLUDENOTHING);
if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(o)) {
msg("Cancelled.");
return B_TRUE;
}
@ -4433,7 +4448,7 @@ char *makedesc_ob(object_t *o, char *retbuf) {
if (isarmour(o)) {
f = hasflag(o->flags, F_GOESON);
if (f) {
snprintf(buf, BUFLEN, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(f->val[0]));
snprintf(buf, BUFLEN, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0]));
} else {
strcpy(buf, "");
}
@ -4480,7 +4495,7 @@ char *makedesc_ob(object_t *o, char *retbuf) {
// non armour, but still wearable.
f = hasflag(o->flags, F_GOESON);
if (f) {
snprintf(buf, BUFLEN, "It is worn %s your %s.\n",getbodypartequipname(f->val[0]), getbodypartname(f->val[0]));
snprintf(buf, BUFLEN, "It is worn %s your %s.\n",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0]));
strncat(retbuf, buf, HUGEBUFLEN);
}
}
@ -5514,7 +5529,8 @@ void dooperate(obpile_t *op) {
// operable objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
if (isoperable(o) && canpickup(player, o, 1)) {
//if (isoperable(o) && canpickup(player, o, 1)) {
if (isoperable(o)) {
char obname[BUFLEN],buf[BUFLEN];
char verb[BUFLEN];
int ch;
@ -5819,8 +5835,8 @@ void doquaff(obpile_t *op) {
}
if (liquid) {
if (canquaff(player, liquid)) {
if (isunknownbadobject(liquid) && skillcheck(player, A_WIS, 26, 0)) {
if (!confirm_badfeeling()) {
if (isunknownbadobject(liquid) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(liquid)) {
msg("Cancelled.");
return;
}
@ -6139,13 +6155,17 @@ void dothrow(obpile_t *op) {
if (where) {
cell_t *newwhere = NULL;
if (!haslof(player->cell, where, LOF_WALLSTOP, &newwhere)) {
if (newwhere) {
// update destination cell.
where = newwhere;
if (newwhere && (newwhere != player->cell)) {
char ch;
ch = askchar("Your line of fire is blocked - really throw here", "yn", "y", B_TRUE);
if (ch == 'y') {
// update destination cell.
where = newwhere;
} else return;
} else {
if (reason == E_NOLOS) {
msg("You can't see there!");
} else { // ie. E_NOLOF
} else { // ie. E_NOLOF and no new cell
msg("You don't have a clear line of fire to there.");
}
return;
@ -6833,16 +6853,27 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) {
}
if (strlen(prompt->choice[validchoice].longdesc)) {
int dummy;
wmove(mainwin, 5, 0);
if (showall) y++;
wmove(mainwin, y, 0);
textwithcol(mainwin, prompt->choice[validchoice].longdesc);
getyx(mainwin, descendy, dummy); // remember bottom of description
}
} else if ((descendy != -1) && showall) {
int yy;
// clear to bottom of screen
for (yy = y ; yy < lastline; yy++) {
wmove(mainwin, yy, 0);
wclrtoeol(mainwin);
} else if (descendy != -1) {
if (showall) {
int yy;
// clear to bottom of screen
for (yy = y ; yy < lastline; yy++) {
wmove(mainwin, yy, 0);
wclrtoeol(mainwin);
}
} else {
int yy;
char gamewinbuf[BUFLEN];
// copy text from gamewin
for (yy = y ; yy < lastline; yy++) {
mvwinchstr(gamewin, yy-2, 0, (chtype *)gamewinbuf);
mvwaddchstr(mainwin, yy, 0,(chtype *) gamewinbuf);
}
}
descendy = -1;
}
@ -6858,6 +6889,7 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) {
// if there's only one match, complete it
if (nvalid == 1) {
char remainder[BUFLEN];
int cx,cy;
// remember cursor pos
getyx(mainwin, cy, cx);
@ -6868,13 +6900,20 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) {
prompt->choice[validone].text);
*/
// 'validchoice' was calculated earlier
snprintf(promptstr, BUFLEN, "%s [%s%s] %s",
/*
snprintf(promptstr, BUFLEN, "%s [%s%s] ",
prompt->q[prompt->whichq],
prompt->maycancel ? "ESC," : "",
showall ? "'=next page,?=toggle" : "?=list",
showall ? "'=next page,?=toggle" : "?=list");
prompt->choice[validchoice].text);
mvwprintw(mainwin, 0, 0, "%s", promptstr);
*/
// show the remainder of what we have typed.
// ('validchoice' was calculated earlier)
snprintf(remainder, BUFLEN, "^g%s",prompt->choice[validchoice].text + strlen(inpstring));
textwithcol(mainwin, remainder);
// move cursor back
wmove(mainwin, cy, cx);
}
wrefresh(mainwin);
@ -7794,15 +7833,19 @@ void drawstatus(void) {
// paralysed somehow?
if ((f = isresting(player)) != NULL) {
setcol(statwin, C_CYAN);
if (f->val[1] == NA) {
if (f->val[1] == ST_ASLEEP) {
wprintw(statwin, " Resting");
} else {
wprintw(statwin, " Meditating");
}
unsetcol(statwin, C_CYAN);
} else if (lfhasflag(player, F_ASLEEP)) {
} else if ((f = lfhasflag(player, F_ASLEEP)) != NULL) {
setcol(statwin, C_MAGENTA);
wprintw(statwin, " Asleep");
if (f->val[2] == ST_KO) {
wprintw(statwin, " KO");
} else {
wprintw(statwin, " Asleep");
}
unsetcol(statwin, C_MAGENTA);
} else if (isprone(player)) {
setcol(statwin, C_YELLOW);
@ -8131,6 +8174,11 @@ void setobcolour(WINDOW *win, object_t *o, int set) {
return;
}
if (hasflag(o->flags, F_KNOWNBAD)) {
funcptr(win, C_RED);
return;
}
if (o->blessknown) {
if (iscursed(o)) {
funcptr(win, C_RED);
@ -8200,7 +8248,7 @@ void showlfarmour(lifeform_t *lf) {
if (!lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
object_t *outerob;
snprintf(buf, BUFLEN, "%15s:%3s",getbodypartname(bp), " ");
snprintf(buf, BUFLEN, "%13s:%1s",getbodypartname(lf, bp), " ");
o = getequippedob(lf->pack, bp);
arm[bp] = o; // remember for later
outerob = getouterequippedob(lf, bp);
@ -8678,7 +8726,6 @@ void showlfstats(lifeform_t *lf, int showall) {
if (lorelev >= PR_BEGINNER) unsetcol(mainwin, lorecol);
}
y2++;
} // end if o
} // end if fid == hasattack
} // end for each flag
@ -8869,7 +8916,16 @@ void showlfstats(lifeform_t *lf, int showall) {
// obvious physical effects here.
f = lfhasknownflag(lf, F_ASLEEP);
if (f) {
wrapprint(mainwin, &y, &x, "%s %s %s.", you(lf), is(lf), (f->val[1] == NA) ? "sleeping" : "meditating");
char sleepname[BUFLEN];
switch (f->val[1]) {
case ST_ASLEEP:
strcpy(sleepname, "sleeping"); break;
case ST_MEDITATING:
strcpy(sleepname, "meditating"); break;
case ST_KO:
strcpy(sleepname, "unconscious"); break;
}
wrapprint(mainwin, &y, &x, "%s %s %s.", you(lf), is(lf), sleepname);
}
f = lfhasknownflag(lf, F_ATTACHEDTO);
if (f && (f->known)) {
@ -9022,16 +9078,16 @@ void showlfstats(lifeform_t *lf, int showall) {
}
if (nmissingbp) {
snprintf(buf, BUFLEN, "%s %s no %s",you(lf), isplayer(lf) ? "have" : "has", getbodypartname(missingbp[0]));
snprintf(buf, BUFLEN, "%s %s no %s",you(lf), isplayer(lf) ? "have" : "has", getbodypartname(lf, missingbp[0]));
if (nmissingbp > 1) {
// construct list of missing body parts
for (i = 1; i < nmissingbp ; i++) {
if (i == nmissingbp - 1) { // last
strcat(buf, " or ");
strcat(buf, getbodypartname(missingbp[i]));
strcat(buf, getbodypartname(lf, missingbp[i]));
} else {
strcat(buf, ", ");
strcat(buf, getbodypartname(missingbp[i]));
strcat(buf, getbodypartname(lf, missingbp[i]));
}
}
}
@ -9150,9 +9206,9 @@ void showlfstats(lifeform_t *lf, int showall) {
if (lfhasknownflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT)) {
if (f->lifetime != PERMENANT) {
if (f->lifetime > 0) {
char buf3[BUFLEN];
snprintf(buf3, BUFLEN, "[%dt]",f->lifetime);
snprintf(buf3, BUFLEN, "[%dturns]",f->lifetime);
strcat(buf2, buf3);
}
}

2
io.h
View File

@ -16,7 +16,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f);
int announceflagloss(lifeform_t *lf, flag_t *f);
int announceobflaggain(object_t *o, flag_t *f);
void announceobflagloss(object_t *o, flag_t *f);
int confirm_badfeeling(void);
int confirm_badfeeling(object_t *o);
lifeform_t *askgod(char *prompt);
object_t *askobject(obpile_t *op, char *title, int *count, long opts);
object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, enum FLAG withflag);

428
lf.c
View File

@ -563,7 +563,11 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
return B_FALSE;
}
// how much mp does it take to cast this?
cost = getmpcost(lf, oid);
if (isplayer(lf)) {
cost = getmpcost(lf, oid);
} else {
cost = 0;
}
if (mpcost) *mpcost = cost;
if (lf->mp >= cost) {
castable = B_TRUE;
@ -678,7 +682,8 @@ int canhear(lifeform_t *lf, cell_t *dest, int volume) {
// can't hear when dead.
if (isdead(lf)) return B_FALSE;
// can't hear if you are deaf
// can't hear if you are deaf or have no ears
if (!hasbp(lf, BP_EARS)) return B_FALSE;
if (lfhasflag(lf, F_DEAF)) return B_FALSE;
// can't hear when training
@ -992,10 +997,16 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) {
int nretflags;
reason = E_OK;
if ((where != BP_NONE) && !hasbp(lf, where)) {
reason = E_NOBP;
return B_FALSE;
if (where != BP_NONE) {
if (!hasbp(lf, where)) {
reason = E_NOBP;
return B_FALSE;
} else if (lfhasflagval(lf, F_NOARMOURON, where, NA, NA, NULL)) {
reason = E_DOESNTFIT;
return B_FALSE;
}
}
// already equipped?
if (hasflag(o->flags, F_EQUIPPED)) {
@ -1295,33 +1306,39 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar
}
// announce
if (!isplayer(lf) && cansee(player, lf)) {
char lfname[BUFLEN];
char whattosay[BUFLEN];
getlfname(lf, lfname);
if (!isplayer(lf)) {
if (cansee(player, lf)) {
char lfname[BUFLEN];
char whattosay[BUFLEN];
getlfname(lf, lfname);
// special case
f = lfhasflag(lf,F_SPELLCASTTEXT);
if (f) {
if (strlen(f->text)) {
snprintf(whattosay, BUFLEN, "%s %s", lfname, f->text);
if (targlf && (f->val[2] == B_APPENDYOU)) {
char targname[BUFLEN];
if (targlf == lf) {
strcpy(targname, "itself");
} else {
getlfname(targlf, targname);
// special case
f = lfhasflag(lf, F_SPELLCASTTEXT);
if (f) {
if (strlen(f->text)) {
snprintf(whattosay, BUFLEN, "%s %s", lfname, f->text);
if (targlf && (f->val[2] == B_APPENDYOU)) {
char targname[BUFLEN];
if (targlf == lf) {
strcpy(targname, "itself");
} else {
getlfname(targlf, targname);
}
strcat(whattosay, " at ");
strcat(whattosay, targname);
}
strcat(whattosay, " at ");
strcat(whattosay, targname);
strcat(whattosay, ".");
msg("%s", whattosay);
}
strcat(whattosay, ".");
msg("%s", whattosay);
}
} else {
if (hasflag(sp->flags, F_CASTINGTIME)) {
} else {
msg("%s starts casting a spell.", lfname);
if (hasflag(sp->flags, F_CASTINGTIME)) {
} else {
msg("%s starts casting a spell.", lfname);
}
}
} else { // player can't see them
if ((targlf == player) || (targcell = player->cell)) {
msg("Something casts a spell at you.");
}
}
}
@ -1506,7 +1523,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) {
flag_t *f;
enum SKILLLEVEL slev;
if (!isairborne(lf)) {
if (isairborne(lf)) {
return B_FALSE;
}
@ -1926,6 +1943,7 @@ void die(lifeform_t *lf) {
}
if (isplayer(lf)) {
lifeform_t *god;
// force screen redraw so you see your hp = 0
drawscreen();
@ -1935,9 +1953,39 @@ void die(lifeform_t *lf) {
} else {
msg("^BYou die.");
}
more();
// force msg redraw!
drawmsg();
more(); drawmsg();
// god effects...
if (!vaporised) {
god = getrandomprayedgod();
if (god && !godisangry(god->race->id)) {
switch (god->race->id) {
case R_GODDEATH:
godsay(god->race->id, "Come to me, my servant..."); more();
msg("Bony claws rise up and drag your corpse underground."); more(); break;
case R_GODPURITY:
msg("Your spirit ascends to the heavens."); more(); break;
case R_GODTHIEVES:
msg("All your possessions suddenly vanish!"); more();
godsay(god->race->id, "Yoink!"); more();
break;
case R_GODMERCY:
if (onein(10)) {
godsay(god->race->id, "I will grant you a second chance, mortal... use it wisely."); more();
lf->hp = lf->maxhp;
lf->alive = B_TRUE;
killflagsofid(lf->flags, F_DEAD);
statdirty = B_TRUE;
// teleport somewhere different.
dospelleffects(god, OT_S_TELEPORT, 3, lf, NULL, NULL, B_UNCURSED, NULL, B_TRUE);
return;
}
break;
default:
break;
}
}
}
} else {
if (!hasflag(lf->flags, F_NODEATHANNOUNCE)) {
if (cansee(player, lf)) {
@ -1972,6 +2020,9 @@ void die(lifeform_t *lf) {
} else { // ie. neutral
pleasegodmaybe(R_GODDEATH, 1);
}
// mercy god doesn't like killing
angergodmaybe(R_GODMERCY, 1);
}
}
@ -2396,6 +2447,8 @@ void do_eyesight_adjust(lifeform_t *lf) {
int i,nlitcells = 0;
int preea;
if (isblind(lf)) return;
// any lit cells within los?
for (i = 0; i < lf->nlos; i++) {
if (lf->los[i]->lit) {
@ -2993,7 +3046,7 @@ void enhanceskills(lifeform_t *lf) {
if (lf->skillpoints >= cost) {
char buf[BUFLEN];
char buf2[HUGEBUFLEN];
snprintf(buf, BUFLEN, "%s (%s, cost:%d points)", getskillname(f->val[0]),
snprintf(buf, BUFLEN, "%s -> %s (cost:%d points)", getskillname(f->val[0]),
getskilllevelname(f->val[1] + 1), cost);
makedesc_skill(f->val[0], buf2);
addchoice(&prompt, ch++, getskillname(f->val[0]), buf, f, buf2);
@ -3303,11 +3356,12 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) {
// if you are going to sleep on purpose, use 'gotosleep'.
// this function is for when it is forced upon you by a spell, etc.
int fallasleep(lifeform_t *lf, int howlong) {
int fallasleep(lifeform_t *lf, enum SLEEPTYPE how, int howlong) {
if (lfhasflag(lf, F_ASLEEP)) {
return B_TRUE;
}
if (lfhasflag(lf, F_CAFFEINATED)) {
if ((how == ST_ASLEEP) && lfhasflag(lf, F_CAFFEINATED)) {
if (isplayer(lf)) {
msg("You feel momentarily tired.");
} else if (cansee(player, lf)) {
@ -3323,7 +3377,7 @@ int fallasleep(lifeform_t *lf, int howlong) {
killflagsofid(lf->flags, F_RAGE);
killflagsofid(lf->flags, F_TRAINING);
addtempflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL, howlong);
addtempflag(lf->flags, F_ASLEEP, B_TRUE, how, NA, NULL, howlong);
return B_FALSE;
}
@ -3331,7 +3385,7 @@ int fallasleep(lifeform_t *lf, int howlong) {
void fightback(lifeform_t *lf, lifeform_t *attacker) {
interrupt(lf);
if (lfhasflag(lf, F_FEIGNINGDEATH)) {
if (lfhasflag(lf, F_FEIGNINGDEATH) || lfhasflagval(lf, F_ASLEEP, NA, ST_KO, NA, NULL)) {
// don't respond.
return;
}
@ -3345,8 +3399,12 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) {
}
if (attacker) {
// wake up
killflagsofid(lf->flags, F_ASLEEP);
flag_t *f;
f = lfhasflag(lf, F_ASLEEP);
if (f && (f->val[1] != ST_KO)) {
// wake up
killflagsofid(lf->flags, F_ASLEEP);
}
// monsters might flee, fight back, etc
if (!isplayer(lf)) {
if (isplayer(attacker) && ishirable(lf)) {
@ -4856,7 +4914,16 @@ int getbodyparthitchance(enum BODYPART bp) {
return 0; // ie rings, ears, weapon
}
char *getbodypartname(enum BODYPART bp) {
char *getbodypartname(lifeform_t *lf, enum BODYPART bp) {
flag_t *f;
if (lf) {
f = lfhasflagval(lf, F_BODYPARTNAME, bp, NA, NA, NULL);
if (f) {
return f->text;
}
}
switch (bp) {
case BP_WEAPON:
return "right hand";
@ -6912,6 +6979,8 @@ void givejob(lifeform_t *lf, enum JOB jobid) {
for (i = 0; i < nretflags; i++) {
f = retflag[i];
modattr(lf, f->val[0], f->val[1]);
// these aren't temporary.
lf->baseatt[f->val[0]] = lf->att[f->val[0]];
}
// inherit all flags except:
@ -7083,13 +7152,18 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) {
int flagsknown = 0, flagsfound = 0;
flag_t *f,*newflag;
int held, equipped,activated;
int held = B_FALSE, equipped = B_FALSE,activated = B_FALSE;
int lifetimeval;
if (o->pile->owner == lf) held = B_TRUE;
if (held && hasflag(o->flags, F_EQUIPPED)) {
equipped = B_TRUE;
if (held) {
f = hasflag(o->flags, F_EQUIPPED);
// make sure it's equipped in the right place - ie. weilded rings don't
// do anything.
if (f && hasflagval(o->flags, F_GOESON, f->val[0], NA, NA, NULL)) {
equipped = B_TRUE;
}
}
if (held && hasflag(o->flags, F_ACTIVATED)) {
activated = B_TRUE;
@ -7212,12 +7286,6 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL);
newf->lifetime = FROMSKILL;
}
} else if (id == SK_SPELLCASTING) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL);
newf->lifetime = FROMSKILL;
}
} else if (id == SK_THIEVERY) {
newf = addflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL);
newf->lifetime = FROMSKILL;
@ -7258,6 +7326,14 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
lf->losdirty = B_TRUE;
if (isplayer(lf)) needredraw = B_TRUE;
}
} else if (id == SK_SPELLCASTING) {
if (f->val[1] == PR_SKILLED) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL);
if (!newf) {
newf = addflag(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL);
newf->lifetime = FROMSKILL;
}
}
} else if (id == SK_STEALTH) {
if (f->val[1] == PR_BEGINNER) {
newf = addflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
@ -7628,13 +7704,13 @@ int gotosleep(lifeform_t *lf, int onpurpose) {
return B_TRUE;
}
if (onpurpose) taketime(lf, getactspeed(lf));
addflag(lf->flags, F_ASLEEP, B_TRUE, lfhasflag(lf, F_MEDITATES) ? B_TRUE : NA, onpurpose ? B_TRUE : NA, NULL);
addflag(lf->flags, F_ASLEEP, B_TRUE, lfhasflag(lf, F_MEDITATES) ? ST_MEDITATING : ST_ASLEEP, onpurpose ? B_TRUE : NA, NULL);
return B_FALSE;
}
int hasfreeaction(lifeform_t *lf) {
if (isdead(lf)) return B_FALSE;
if (isimmobile(lf)) return B_FALSE;
if (lfhasflag(lf, F_ASLEEP)) return B_FALSE;
if (lfhasflag(lf, F_CASTINGSPELL)) return B_FALSE;
if (lfhasflag(lf, F_EATING)) return B_FALSE;
return B_TRUE;
@ -7671,8 +7747,10 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
enum BODYPART bp2;
object_t *wep = NULL;
int howlong;
if (where == BP_NONE) return B_TRUE;
if (!hasbp(lf, where)) return B_TRUE;
if (lfhasflag(lf, F_NOINJURIES)) return B_TRUE;
if (lfhasflagval(lf, F_INJURY, NA, where, NA, NULL)) return B_TRUE;
howlong = rnd(30,80); // might be overridden depending on injury
@ -7759,7 +7837,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
o = getequippedob(lf->pack, bp2);
addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL);
inj = IJ_FINGERMISSING;
sprintf(buf, "%s is severed^cannot wear rings on this hand", getbodypartname(bp2));
sprintf(buf, "%s is severed^cannot wear rings on this hand", getbodypartname(lf, bp2));
desc = strdup(buf);
howlong = PERMENANT;
if (o) {
@ -7811,6 +7889,62 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
}
default: break;
}
} else if (damtype == DT_EXPLOSIVE) {
switch (where) {
case BP_BODY:
switch (rnd(1,2)) {
case 1:
break;
case 2:
break;
}
// massive burns
// collapsed lung
break;
case BP_HANDS:
// lose limb
if (onein(2)) bp2 = BP_WEAPON;
else bp2 = BP_SECWEAPON;
if (hasbp(lf, bp2)) {
object_t *o[2];
char buf[BUFLEN];
int i;
// drop anyting in that hand
o[0] = getequippedob(lf->pack, bp2);
if (bp2 == BP_WEAPON) o[1] = getequippedob(lf->pack, BP_RIGHTFINGER);
else o[1] = getequippedob(lf->pack, BP_LEFTFINGER);
addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL);
inj = IJ_HANDMISSING;
sprintf(buf, "%s is destroyed^cannot use this hand", getbodypartname(lf, bp2));
desc = strdup(buf);
howlong = PERMENANT;
for (i = 0; i < 2; i++) {
if (o[i]) {
char obname[BUFLEN];
if (isplayer(lf)) {
getobname(o[i],obname,o[i]->amt);
msg("Your %s drops to the ground.",noprefix(obname));
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getobname(o[i],obname,o[i]->amt);
getlfname(lf,lfname);
msg("%s%s %s drops to the ground.",lfname,getpossessive(lfname),noprefix(obname));
}
moveob(o[i], lf->cell->obpile, o[i]->amt);
}
}
}
break;
case BP_HEAD:
// ringing ears
// burnt eyes
break;
case BP_LEGS:
// lose limb
break;
default:
break;
}
}
if (inj == IJ_NONE) {
@ -8383,7 +8517,7 @@ int isblind(lifeform_t *lf) {
if (!lf) return B_FALSE;
f = lfhasflag(lf, F_ASLEEP);
if (f && (f->val[1] == NA)) {
if (f && (f->val[1] != ST_MEDITATING)) {
return B_TRUE;
}
if (lfhasflag(lf, F_BLIND)) {
@ -8741,10 +8875,12 @@ int ispolymorphed(lifeform_t *lf) {
}
int isprone(lifeform_t *lf) {
flag_t *f;
if (lfhasflag(lf, F_PRONE)) {
return B_TRUE;
}
if (lfhasflag(lf, F_ASLEEP)) {
f = lfhasflag(lf, F_ASLEEP);
if (f && (f->val[1] != ST_MEDITATING)) {
return B_TRUE;
}
return B_FALSE;
@ -9058,10 +9194,13 @@ void addtrail(lifeform_t *lf, int dir) {
object_t *footprint, *scent;
flag_t *fpflag;
if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
// no tracks at all
// no tracks at all?
if (lf->cell->type->solid) {
return;
} else if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
return;
}
// footprints first
if (!isairborne(lf) && !lfhasflag(lf, F_NONCORPOREAL)) {
int fpdir;
@ -9601,6 +9740,11 @@ int isswimming(lifeform_t *lf) {
return B_FALSE;
}
int isunconscious(lifeform_t *lf) {
if (lfhasflagval(lf, F_ASLEEP, NA, ST_KO, NA, NULL)) return B_TRUE;
return B_FALSE;
}
int isundead(lifeform_t *lf) {
if (lf->race->raceclass->id == RC_UNDEAD) {
return B_TRUE;
@ -9866,7 +10010,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
char buf[BUFLEN];
char buf2[BUFLEN];
char lfname[BUFLEN];
int prebleed = B_FALSE,postbleed = B_FALSE;
int prebleed = B_FALSE,postbleed = B_FALSE,ko = B_FALSE;
flag_t *f;
flag_t *retflag[MAXCANDIDATES];
int nretflags;
@ -9954,6 +10098,32 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
// stop hiding
killflagsofid(lf->flags, F_HIDING);
// merciful weapons
if (fromob) {
f = hasflag(fromob->flags, F_MERCIFUL);
if (f && (amt >= lf->hp)) {
amt = lf->hp - 1; // ie end up at 1hp
ko = B_TRUE;
if (fromob->pile->owner && cansee(player, fromob->pile->owner)) {
f->known = B_TRUE;
}
}
}
// bashing damage sometimes ko's
if (!ko) {
if (damtype == DT_BASH) {
int hpleft;
hpleft = lf->hp - amt;
if ((hpleft >= -5) && (hpleft <= 0)) {
if (onein(2)) {
ko = B_TRUE;
amt = lf->hp - 1; // ie end up at 1hp
}
}
}
}
// large damage?
if ((amt >= (lf->maxhp / 2)) && (amt >= 20)) {
if (useringofmiracles(lf, 1)) {
@ -10057,7 +10227,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
// further effects if not dead...
if (!isdead(lf)) {
// fight back if required
if (fromlf && retaliate) {
if (fromlf && retaliate && !ko) {
fightback(lf, fromlf);
}
@ -10073,8 +10243,19 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml
}
}
// you wake up if you were hit!
killflagsofid(lf->flags, F_ASLEEP);
if (ko) {
// you are knocked unconscious for a _long_ time
fallasleep(lf, ST_KO, rnd(50,100));
if (fromlf && isplayer(fromlf)) {
pleasegodmaybe(R_GODMERCY, 5);
}
} else {
// you wake up if you were hit, unless you were unconscious!
f = lfhasflag(lf, F_ASLEEP);
if (f && (f->val[1] != ST_KO)) {
killflagsofid(lf->flags, F_ASLEEP);
}
}
// automatic onbleed abilities?
if (postbleed && !prebleed) {
@ -10582,6 +10763,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
int dist;
int difficulty;
int lbonus;
flag_t *f;
if (l == noisemaker) continue;
@ -10601,7 +10783,10 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
// listen bonus is based on sound volume
lbonus = volume;
if (lfhasflag(l, F_ASLEEP)) {
f = lfhasflag(l, F_ASLEEP);
if (f) {
// can't hear while unconscious
if (f->val[1] == ST_KO) continue;
lbonus -= 4;
limit(&lbonus, 0, NA);
}
@ -10639,9 +10824,11 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
//strncpy(textnopunc, text, strlen(text)-1);
strcpy(textnopunc, text);
punc = textnopunc[strlen(textnopunc)-1];
if (punc != '\"') { // ie. not someone saying something
textnopunc[strlen(textnopunc)-1] = '\0';
if (punc == '\"') {
// ie. someone saying something
punc = '\0';
} else {
textnopunc[strlen(textnopunc)-1] = '\0';
}
dist = getcelldist(l->cell, c);
@ -10758,7 +10945,8 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
}
// still asleep?
if (lfhasflag(l, F_ASLEEP) && cansee(player, l)) {
f = lfhasflag(l, F_ASLEEP);
if (f && (f->val[1] != ST_KO) && cansee(player, l)) {
char lfname[BUFLEN];
getlfname(l, lfname);
msg("%s stir%s in %s slumber...", lfname,
@ -11855,7 +12043,7 @@ void setguntarget(lifeform_t *lf, lifeform_t *targ) {
void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
flag_t *f,*nextf;
int i,retainhpmp = B_FALSE;
int i,retainhp = B_FALSE;
int nkilled = 0;
race_t *newrace;
char buf[BUFLEN];
@ -11868,8 +12056,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
statdirty = B_TRUE;
}
if (lfhasflag(lf, F_RETAINHPMPONPOLY)) {
retainhpmp = B_TRUE;
if (lfhasflag(lf, F_RETAINHPONPOLY)) {
retainhp = B_TRUE;
}
if (frompolymorph && (gamemode == GM_GAMESTARTED) && lf->race) {
@ -11946,10 +12134,23 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
// set material
lf->material = lf->race->material;
// inherit flags from race
// inherit most flags from race
for (f = lf->race->flags->first ; f ; f = f->next) {
switch (f->id) {
case F_RARITY:
case F_MPDICE:
break;
default:
addflag_real(lf->flags, f->id, f->val[0], f->val[1], f->val[2], f->text, FROMRACE, f->known, -1);
break;
}
}
/*
copyflags(lf->flags, lf->race->flags, FROMRACE);
// don't want certain race only flags...
killflagsofid(lf->flags, F_RARITY);
*/
// certain other flags are rnadom
getflags(lf->flags, retflag, &nretflags, F_RNDHOSTILE, F_NONE);
@ -11969,7 +12170,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
lf->baseatt[i] = lf->att[i];
}
if (!retainhpmp) {
if (!retainhp) {
// generate hp/maxhp from hit dice
lf->maxhp = 0;
for (i = 0; i < lf->level; i++) {
@ -11978,6 +12179,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
}
lf->hp = lf->maxhp;
// don't regenerate mp
/*
// generate mp, if you have it.
f = hasflag(lf->flags, F_MPDICE);
if (f) {
@ -11990,6 +12193,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
lf->maxmp = 0;
}
lf->mp = lf->maxmp;
*/
}
lf->born = B_TRUE;
@ -12256,7 +12460,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r
attrib = (getattr(lf, A_CON)/6) + (getattr(lf, A_WIS)/6) + getmr(lf);
break;
case SC_SEARCH:
attrib = (getskill(lf, SK_PERCEPTION)*3);
attrib = (getskill(lf, SK_PERCEPTION)*2);
break;
case SC_STEAL:
attrib = (getskill(lf, SK_THIEVERY));
@ -13004,7 +13208,7 @@ void startlfturn(lifeform_t *lf) {
f = hasflag(o->flags, F_SECRET);
if (f && (f->val[0] != NA)) {
if (hasflag(o->flags, F_TRAP)) {
mod += getskill(lf, SK_TRAPS);
mod += (getskill(lf, SK_TRAPS)*2);
}
if (skillcheck(lf, SC_SEARCH, f->val[0], mod)) {
@ -13236,7 +13440,7 @@ void startlfturn(lifeform_t *lf) {
switch (damtype) {
case DT_WATER:
if ((bp == BP_FEET) && isplayer(lf) && hasbp(lf, bp) && !donefeetwet) {
msg("Your %s get wet.", getbodypartname(bp));
msg("Your %s get wet.", getbodypartname(lf, bp));
donefeetwet = B_TRUE; // don't keep repeating this
}
break;
@ -13542,7 +13746,7 @@ void stopresting(lifeform_t *lf) {
if (f) {
killflag(f);
if (isplayer(lf)) {
msg("Your %s is interrupted!", (f->val[1] == NA) ? "rest" : "meditation");
msg("Your %s is interrupted!", (f->val[1] == ST_MEDITATING) ? "meditation" : "rest");
} else if (cansee(player, lf)) {
char buf[BUFLEN];
getlfname(lf, buf);
@ -13553,12 +13757,7 @@ void stopresting(lifeform_t *lf) {
}
void stoprunning(lifeform_t *lf) {
flag_t *f;
f = hasflag(lf->flags, F_RUNNING);
if (f) {
killflag(f);
}
killflagsofid(lf->flags, F_RUNNING);
}
void stopsprinting(lifeform_t *lf) {
@ -14530,44 +14729,6 @@ int validateraces(void) {
printf("ERROR in race '%s' - F_STARTOB with zero length text.\n", r->name);
goterror = B_TRUE;
}
} else if ((f->id == F_CANCAST) || (f->id == F_CANWILL)) {
objecttype_t *sp;
enum SPELLSCHOOL school;
sp = findot(f->val[0]);
school = getspellschool(f->val[0]);
if (sp->obclass->id == OC_SPELL) {
if ((f->id == F_CANWILL) ||
hasflagval(r->flags, F_HASSKILL, SK_SPELLCASTING, NA, NA, NULL) ||
hasflagval(r->flags, F_STARTSKILL, SK_SPELLCASTING, NA, NA, NULL) ||
(school == SS_ALLOMANCY) || (school == SS_MENTAL)
) {
int power;
//power = (1 + ff->val[1]) / getspelllevel(f->val[0]);
power = getspellpower(lf, f->val[0]);
if (power <= 0) {
printf("ERROR in race '%s' - %s %s (l%d) but insufficient spell power.\n",
r->name,
(f->id == F_CANWILL) ? "F_CANWILL" : "F_CANCAST",
sp->name,getspelllevel(sp->id));
if (f->id == F_CANWILL) {
printf(" f_canwill text = '%s'\n\n",f->text);
}
goterror = B_TRUE;
}
} else {
objecttype_t *sp;
sp = findot(f->val[0]);
printf("ERROR in race '%s' - F_CANCAST %s (l%d) but no spellcasting skill\n", r->name, sp->name, getspelllevel(sp->id));
goterror = B_TRUE;
}
} else { // ie. ability
if (f->val[0] == OT_A_SWOOP) {
if (!hasflag(r->flags, F_SWOOPRANGE)) {
printf("ERROR in race '%s' - has SWOOP ability but no F_SWOOPRANGE.\n", r->name);
goterror = B_TRUE;
}
}
}
} else if (f->id == F_HITCONFER) {
if (!lfhasflag(lf, F_HITCONFERVALS)) {
printf("ERROR in race '%s' - F_HITCONFER, but no HITCONFERVALS defined.\n", r->name);
@ -14666,7 +14827,7 @@ int rest(lifeform_t *lf, int onpurpose) {
// restore full hp
lf->hp = lf->maxhp;
// fall asleep for a while
fallasleep(lf, 50);
fallasleep(lf, ST_ASLEEP, 50);
// mark screen as dirty
needredraw = B_TRUE;
if (isplayer(lf)) {
@ -14945,9 +15106,9 @@ int wear(lifeform_t *lf, object_t *o) {
if (inway) {
char inwayname[BUFLEN];
getobname(inway, inwayname, inway->amt);
snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(possbp[i]), inwayname);
snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(lf, possbp[i]), inwayname);
} else {
snprintf(buf, BUFLEN, "%s", getbodypartname(possbp[i]));
snprintf(buf, BUFLEN, "%s", getbodypartname(lf, possbp[i]));
}
addchoice(&prompt, ch++, buf, NULL, &possbp[i], NULL);
}
@ -14976,6 +15137,9 @@ int wear(lifeform_t *lf, object_t *o) {
case E_ALREADYUSING:
if (isplayer(lf)) msg("You're already wearing that!");
break;
case E_DOESNTFIT:
if (isplayer(lf)) msg("The unnatural shape of your %s prevents this from fitting.", getbodypartname(lf, bp));
break;
case E_INJURED:
if (isplayer(lf)) msg("Your injuries prevent you from wearing this.");
break;
@ -15019,7 +15183,7 @@ int wear(lifeform_t *lf, object_t *o) {
if (isplayer(lf)) msg("You can't wear that!");
break;
case E_NOBP:
if (isplayer(lf)) msg("You have no %s on which to wear that!", getbodypartname(bp));
if (isplayer(lf)) msg("You have no %s on which to wear that!", getbodypartname(lf, bp));
break;
case E_LOWCHA:
msg("You are not attractive enough to wear this.");
@ -15086,7 +15250,7 @@ int wear(lifeform_t *lf, object_t *o) {
if ((gamemode == GM_GAMESTARTED) && lf->created) {
if (isplayer(lf)) {
if (showpos) {
msg("You are now wearing %s (%s your %s).", obname, getbodypartequipname(bp), getbodypartname(bp));
msg("You are now wearing %s (%s your %s).", obname, getbodypartequipname(bp), getbodypartname(lf, bp));
} else {
msg("You are now wearing %s.", obname);
}
@ -15112,9 +15276,25 @@ int wear(lifeform_t *lf, object_t *o) {
// warn if it will be cumbersome
if (isplayer(lf)) {
char howmuch[BUFLEN];
f = hasflagval(o->flags, F_EQUIPCONFER, F_SHIELDPENALTY, NA, NA, NULL);
if (f && (getskill(lf, SK_SHIELDS) <= PR_INEPT) ) {
msg("^wYou find this shield very cumbersome to use.");
if (f) {
int penalty;
penalty = adjustshieldpenalty(lf, f->val[1]);
if (penalty) {
if (penalty >= 40) {
strcpy(howmuch, "incredibly");
} else if (penalty >= 30) {
strcpy(howmuch, "extremely");
} else if (penalty >= 20) {
strcpy(howmuch, "very");
} else if (penalty >= 10) {
strcpy(howmuch, "quite");
} else {
strcpy(howmuch, "slightly ");
}
msg("^wYou find this shield %s cumbersome to use.", howmuch);
}
}
}

5
lf.h
View File

@ -75,7 +75,7 @@ void enhanceskills(lifeform_t *lf);
void extinguishlf(lifeform_t *lf);
object_t *eyesshaded(lifeform_t *lf);
int fall(lifeform_t *lf, lifeform_t *fromlf, int announce);
int fallasleep(lifeform_t *lf, int howlong);
int fallasleep(lifeform_t *lf, enum SLEEPTYPE how, int howlong);
void fightback(lifeform_t *lf, lifeform_t *attacker);
job_t *findjob(enum JOB jobid);
job_t *findjobbyname(char *name);
@ -120,7 +120,7 @@ object_t *getbestthrowmissile(lifeform_t *lf);
object_t *getbestweapon(lifeform_t *lf);
object_t *getbestfirearm(lifeform_t *lf);
int getbodyparthitchance(enum BODYPART bp);
char *getbodypartname(enum BODYPART bp);
char *getbodypartname(lifeform_t *lf, enum BODYPART bp);
char *getbodypartequipname(enum BODYPART bp);
object_t *getequippedob(obpile_t *op, enum BODYPART bp);
int getexposedlimbs(lifeform_t *lf);
@ -273,6 +273,7 @@ flag_t *isresting(lifeform_t *lf);
object_t *isstuck(lifeform_t *lf);
int issmellablelf(lifeform_t *lf);
int isswimming(lifeform_t *lf);
int isunconscious(lifeform_t *lf);
int isundead(lifeform_t *lf);
flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt);
int isweaponskill(enum SKILL skid);

188
map.c
View File

@ -4,6 +4,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "io.h"
@ -44,6 +45,14 @@ extern long curtime;
cell_t *addcell(map_t *m, int x, int y) {
cell_t *cell;
// already allocated?
cell = m->cell[(y*m->w)+x];
if (cell) {
clearcell(cell);
free(cell);
}
m->cell[(y*m->w)+x] = malloc(sizeof(cell_t));
cell = m->cell[(y*m->w)+x];
cell->map = m;
@ -150,6 +159,9 @@ map_t *addmap(void) {
for (i = 0; i < MAXDIR_ORTH; i++) {
a->nextmap[i] = -1;
}
for (i = 0 ; i < MAX_MAPW*MAX_MAPH; i++) {
a->cell[i] = NULL;
}
a->flags = addflagpile(NULL, NULL);
a->beingcreated = B_TRUE;
a->habitat = findhabitat(H_DUNGEON); // default!!!
@ -272,9 +284,13 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int
}
// TODO: base this on the time, and whether monster is nocturnal
if (pctchance(asleepchance)) {
addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
addflag(lf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL);
}
}
// monsters who on dark levels can always see in the dark
if (!islit(lf->cell) && !lfhasflag(lf, F_SEEINDARK)) {
addflag(lf->flags, F_SEEINDARK, rnd(3,5), NA, NA, NULL);
}
}
// appears in groups?
@ -310,7 +326,10 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int
// if master is asleep, minions will also be asleep
if (lfhasflag(lf, F_ASLEEP)) {
addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
addflag(newlf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL);
}
if (!islit(newlf->cell) && !lfhasflag(newlf, F_SEEINDARK)) {
addflag(newlf->flags, F_SEEINDARK, rnd(3,5), NA, NA, NULL);
}
// minions never have certain flags.
@ -350,7 +369,11 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int
if (nadded) (*nadded)++;
newlf->born = B_FALSE;
if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL);
if (!islit(newlf->cell) && !lfhasflag(newlf, F_SEEINDARK)) {
addflag(newlf->flags, F_SEEINDARK, rnd(3,5), NA, NA, NULL);
}
newlf->born = B_TRUE;
}
}
@ -762,7 +785,9 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in
cell_t *poss[MAXCANDIDATES], *cell[MAXCANDIDATES]; // TODO: should this be maxroomw * maxroomh ?
int ncells = 0, npossible = 0;
int doorsadded = 0;
int db = B_FALSE;
int db = B_TRUE;
if (db) dblog("autodoors starting");
// for each side, make list of all possible door locations
// then pick one randomly.
@ -788,7 +813,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in
makedoor(cell[i], dooropenchance);
} else {
setcelltype(cell[i], cell[i]->habitat->emptycelltype);
addflag(map->flags, F_ROOMEXIT, roomid, cell[i]->x, cell[i]->y, NULL);
addflag(map->flags, F_ROOMEXIT, roomid, cell[i]->x, cell[i]->y, "from autodoors, only way out");
}
} else {
// otherwise mark this as a _potential_ door location.
@ -808,7 +833,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in
makedoor(poss[sel], dooropenchance);
} else {
setcelltype(poss[sel], poss[sel]->habitat->emptycelltype);
addflag(map->flags, F_ROOMEXIT, roomid, poss[sel]->x, poss[sel]->y, NULL);
addflag(map->flags, F_ROOMEXIT, roomid, poss[sel]->x, poss[sel]->y, "from autodoors, potential location");
}
doorsadded++;
@ -856,7 +881,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in
doorsadded++;
} else {
setcelltype(cell[sel], cell[sel]->habitat->emptycelltype);
addflag(map->flags, F_ROOMEXIT, roomid, cell[sel]->x, cell[sel]->y, NULL);
addflag(map->flags, F_ROOMEXIT, roomid, cell[sel]->x, cell[sel]->y, "from autodoors, forced at end");
doorsadded++;
}
}
@ -1139,7 +1164,7 @@ int dowaterspread(cell_t *c) {
return B_FALSE;
}
void fix_reachability(map_t *m) {
int fix_reachability(map_t *m) {
int i,keepgoing = B_TRUE, nfixed = 0;
int db = B_TRUE;
cell_t *c = NULL;
@ -1152,7 +1177,7 @@ void fix_reachability(map_t *m) {
case H_PIT:
case H_VILLAGE:
if (db) dblog("fix_reachability not required for this habitat.");
return;
return B_FALSE;
default: break;
}
@ -1164,7 +1189,7 @@ void fix_reachability(map_t *m) {
}
}
// no empty cells in map?
if (!c) return;
if (!c) return B_FALSE;
while (keepgoing) {
keepgoing = B_FALSE;
// mark all cells as non-filled
@ -1182,8 +1207,14 @@ void fix_reachability(map_t *m) {
m->cell[i]->x, m->cell[i]->y);
linkexit(m->cell[i], B_TRUE, &nadded);
if (db) dblog(" fixed unreachable area by adding %d cells.", nadded);
assert(nadded);
if (nadded) {
if (db) dblog(" fixed unreachable area by adding %d cells.", nadded);
} else {
// didn't add anything - fail!
if (db) dblog(" fix_reachability failed.");
return B_TRUE;
}
// now run the test again.
// 'c' will be where the next flood will will happen.
@ -1195,6 +1226,7 @@ void fix_reachability(map_t *m) {
}
}
if (db) dblog(" fix_reachability complete. fixed %d unreachable areas.", nfixed);
return B_FALSE;
}
@ -1520,7 +1552,6 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int
int includethiscell = B_FALSE;
cell = getcellat(map, rx,ry);
// NEVER create a vault whcih will:
// - be on top of the player (normally this can't happen,
// but debugging via 'create vault' could do it)
@ -1531,6 +1562,10 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int
if (hasobwithflag(cell->obpile, F_CLIMBABLE)) {
valid = B_FALSE;
}
// - overlap the inside of an existing room
if (cellwalkable(NULL, cell, NULL) && isroom(cell)) {
valid = B_FALSE;
}
// is this cell adjacent to an empty cell and not a
// corner (ie. a valid door location)
@ -2266,7 +2301,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
int i,x,y;
enum HABITAT habitat;
regionthing_t *thing[MAXOUTLINETHINGS];
int nthings = 0;
int nthings = 0,failed;
int db = B_FALSE;
// determine habitat based on region
@ -2477,54 +2512,66 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
}
if (db) dblog(" %d things remembered for later.",nthings);
failed = B_TRUE;
while (failed) {
failed = B_FALSE;
// build it...
if (db) dblog(" creating map habitat.");
createhabitat(map, depth, parentmap, exitdir, entryob);
// build it...
if (db) dblog(" creating map habitat.");
createhabitat(map, depth, parentmap, exitdir, entryob);
// add home objects
if (db) dblog(" adding home objects.");
for (lf = map->lf ; lf ; lf = lf->next) {
addhomeobs(lf);
}
// add home objects
if (db) dblog(" adding home objects.");
for (lf = map->lf ; lf ; lf = lf->next) {
addhomeobs(lf);
}
// add outline things
if (db) dblog(" adding remembered region outline things...");
for (i = 0; i < nthings ;i++) {
vault_t *v;
// add this thing
switch (thing[i]->whatkind) {
case RT_HABITAT: // already handled above
break;
case RT_REGIONLINK:
if (db) dblog(" adding regionlink");
createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region);
// ... don't need to do this since we know there won't be anywhere to link to.
//linkstairs(o);
break;
case RT_VAULT:
if (db) dblog(" adding vault");
v = findvault(thing[i]->what);
assert(v);
if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) {
dblog("ERROR - couldn't create vault %s on map %s", v->id, map->name);
failed = B_TRUE;
}
break;
case RT_RNDVAULTWITHFLAG:
if (db) dblog(" adding rndvaultwithflag");
v = findvaultwithflag(thing[i]->value);
assert(v);
if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) {
dblog("ERROR - couldn't create rndvaultwithflag %s on map %s", v->id, map->name);
failed = B_TRUE;
}
break;
}
}
// ensure there are no unreachable areas
if (!failed) {
if (fix_reachability(map)) {
failed = B_TRUE;
}
}
// add outline things
if (db) dblog(" adding remembered region outline things...");
for (i = 0; i < nthings ;i++) {
vault_t *v;
// add this thing
switch (thing[i]->whatkind) {
case RT_HABITAT: // already handled above
break;
case RT_REGIONLINK:
if (db) dblog(" adding regionlink");
createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region);
// ... don't need to do this since we know there won't be anywhere to link to.
//linkstairs(o);
break;
case RT_VAULT:
if (db) dblog(" adding vault");
v = findvault(thing[i]->what);
assert(v);
if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) {
dblog("ERROR - couldn't create vault %s on map %s", v->id, map->name);
}
break;
case RT_RNDVAULTWITHFLAG:
if (db) dblog(" adding rndvaultwithflag");
v = findvaultwithflag(thing[i]->value);
assert(v);
if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) {
dblog("ERROR - couldn't create rndvaultwithflag %s on map %s", v->id, map->name);
}
break;
if (failed) {
dblog("********* got errors - restarting map creation. *********");
}
}
// ensure there are no unreachable areas
fix_reachability(map);
// special cases
// village - add town walls and clear it out
if (db) dblog(" finalising village creation...");
@ -2798,7 +2845,7 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
if (calcroompos(map, w, h, xmargin, ymargin, &minx, &miny, B_TRUE)) {
// forced calcroompos should never fail since it's
// allowed to overlap other rooms.
dblog("** couldn't make vault room!\n");
dblog("** couldn't find position for vault %s (roomid %d)!\n", v->id, roomid);
//msg("** ALERT: couldn't make vault room!\n");
return B_TRUE;
}
@ -2815,7 +2862,6 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r
thisroom = &(map->room[map->nrooms]);
map->nrooms++;
// now make it
if (db) dblog("making vault %s at pos %d,%d on map %s", v->id, minx, miny, map->name);
for (y = miny; y <= maxy; y++) {
@ -2894,10 +2940,10 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
while (c) {
dist[d]++;
if ((roomid >= 0) && getroomid(c) == roomid) { // same room
if (wantfilled && c->type->solid) {
//if (wantfilled && c->type->solid) {
if (c->type->solid) {
// EXCEPTION:
// if we are calling this function from fix_reachability, then
// startcell will actually be a cell _inside_ the room as opposed to
// if startcell is a cell _inside_ the room as opposed to
// a cell inside the room's walls.
// in this case, we ARE allowed to travel through the room's walls.
} else {
@ -2985,7 +3031,13 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) {
startdir = startposs[rnd(0,nstartposs-1)];
}
assert(startdir != D_NONE);
if (wantfilled) {
// if startdir is D_NONE here, it means that we've called
// linkexit for a cell internal to a room.
// if we called this function from fix_reachable (ie. wantfilled=true)
// then this is a bad thing.
assert(startdir != D_NONE);
}
// figure out perpendicular dirs
perpdir[0] = startdir - 1; if (perpdir[0] < D_N) perpdir[0] = D_W;
@ -3256,6 +3308,9 @@ int linkexits(map_t *m, int roomid) {
}
assert(roomidx != -1);
// does this roomid actually exist??
c = getrandomroomcell(m, roomid);
if (!c) return B_FALSE;
if (db) {
char buf[BUFLEN];
@ -3620,6 +3675,14 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int
mydist = getcelldist(c,cc);
if (cc && (mydist <= (range+1))) {
if (cc->lf && !isdead(cc->lf)) {
int critchance;
// critical hit? 100% chance in middle, 60 at one cell, 20 at two cells
critchance = 100 - (mydist*40);
if (pctchance(critchance)) {
//criticalhit(NULL, cc->lf, getrandomcorebp(cc->lf), DT_EXPLOSION);
criticalhit(NULL, cc->lf, BP_HANDS, DT_EXPLOSIVE);
}
// move away from centre of explosion
knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 2, NULL, 40-(mydist*10));
}
@ -5051,6 +5114,7 @@ void mapentereffects(map_t *m) {
if (m->lastplayervisit != -1) {
int nturns;
nturns = (curtime - m->lastplayervisit) / TICK_INTERVAL;
limit(&nturns, NA, 20);
//nturns *= countlfs(m);
for (i = 0; i < nturns; i++) {
donextturn(m);
@ -5070,7 +5134,7 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob) {
donesomething = B_FALSE;
if (strstarts(p, "sleeping ")) {
p += strlen("sleeping ");
if (wantflags) addflag(wantflags, F_ASLEEP, NA, NA, NA, NULL);
if (wantflags) addflag(wantflags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL);
donesomething = B_TRUE;
}
}

3
map.h
View File

@ -17,7 +17,7 @@ int cellhaslos(cell_t *c1, cell_t *dest);
void clearcell(cell_t *c);
void clearcell_exceptflags(cell_t *c, ...);
int dowaterspread(cell_t *c);
void fix_reachability(map_t *m);
int fix_reachability(map_t *m);
int fix_unreachable_cell(cell_t *badcell);
void floodfill(cell_t *startcell);
cell_t *getcellat(map_t *map, int x, int y);
@ -51,6 +51,7 @@ void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t
void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir, object_t *entryob);
void createpit(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob);
void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIONTYPE newregiontype, region_t *parent);
void createregionthing(map_t *map, regionthing_t *rt);
int createroom(map_t *map, int roomid, int overrideminw, int overrideminh, int xmargin, int ymargin, int *retx, int *rety, int *retw, int *reth, int doorpct, int forcewalls);
int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *retx, int *rety);
int dirtox(int dt, int dir);

9
move.c
View File

@ -348,6 +348,8 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
enum RELATIVEDIR getrelativedir(lifeform_t *lf, int dir) {
int tempdir;
if (lfhasflag(lf, F_AWARENESS)) return RD_FORWARDS;
// facing N, dir N == forwards
if (lf->facing == dir) return RD_FORWARDS;
@ -905,7 +907,10 @@ int moveeffects(lifeform_t *lf) {
int didmsg = B_FALSE;
if (lfhasflagval(lf, F_INJURY, IJ_HAMSTRUNG, NA, NA, NULL)) {
if (!skillcheck(lf, SC_FALL, 20, 0)) fall(lf, NULL, B_TRUE);
if (!skillcheck(lf, SC_FALL, 20, 0)) {
fall(lf, NULL, B_TRUE);
if (isplayer(lf)) didmsg = B_TRUE;
}
}
if (isbleeding(lf)) {
@ -1432,7 +1437,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
}
// slip on blood in new cell?
if (!isairborne(lf)) {
if (!isairborne(lf) && !isswimming(lf)) {
int slip;
object_t *o,*nexto;
object_t *slipob;

View File

@ -3071,7 +3071,7 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder) {
switch (slev) {
case PR_INEPT:
acc -= 30;
acc -= 35;
break;
case PR_NOVICE:
acc -= 10;
@ -3641,6 +3641,7 @@ int getobattackdelay(object_t *o) {
return delay;
}
float getobhppct(object_t *o) {
float pct;
flag_t *f;
@ -3653,6 +3654,16 @@ float getobhppct(object_t *o) {
return pct;
}
// returns '1' if object has no F_OBHP
int getobmaxhp(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_OBHP);
if (f) {
return f->val[1];
}
return 1;
}
int getletidx(char let) {
int i;
for (i = 0; i < MAXPILEOBS; i++) {
@ -3941,7 +3952,7 @@ char *getobequipinfo(object_t *o, char *buf) {
strcat(buf, " (");
strcat(buf, getbodypartequipname(f->val[0]));
strcat(buf, " ");
strcat(buf, getbodypartname(f->val[0]));
strcat(buf, getbodypartname(o->pile->owner, f->val[0]));
strcat(buf, ")");
}
}
@ -3971,7 +3982,7 @@ char *getobextrainfo(object_t *o, char *buf) {
}
} else {
if (f->val[0] > 0) {
snprintf(chargestr, BUFLEN, " (%d charges left)",f->val[0]);
snprintf(chargestr, BUFLEN, " (%d charge%s left)",f->val[0], (f->val[0] == 1) ? "" : "s");
} else {
snprintf(chargestr, BUFLEN, " (empty)");
}
@ -4082,10 +4093,10 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
}
if (who) {
char lfname[BUFLEN];
real_getlfname(who, lfname, B_FALSE);
snprintf(buf, BUFLEN, "%s%s %sscent",lfname,getpossessive(lfname), adjective);
real_getlfnamea(who, lfname, B_FALSE);
snprintf(buf, BUFLEN, "%s%s%s %sscent",adjective,lfname,getpossessive(lfname));
} else {
snprintf(buf, BUFLEN, "%s %sscent",r->name, adjective);
snprintf(buf, BUFLEN, "%s%s scent",adjective, r->name );
}
strcat(basename, buf);
@ -4530,6 +4541,10 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
}
}
if (hasflag(o->flags, F_KNOWNBAD)) {
strcat(localbuf, " [bad]");
}
if (getskill(player, SK_COOKING) >= PR_BEGINNER) {
if (isbadfood(o)) {
strcat(localbuf, " [badfood]");
@ -6029,11 +6044,13 @@ void killob(object_t *o) {
object_t *nextone, *lastone;
// debugging
/*
if (o->type->id == OT_STAIRSUP) {
msg("warning: removing an up staircase!");
dblog("warning: removing an up staircase!");
assert(1 == 0);
}
*/
// remove flags conferred by this object
if (o->pile->owner) {
@ -6588,8 +6605,11 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) {
// triggered a trap?
for (oo = dst->where->obpile->first ; oo ; oo = nextoo ) {
nextoo = oo->next;
if ((oo != o) && hasflag(oo->flags, F_TRAP)) {
triggertrap(NULL, o, oo, dst->where);
if (oo != o) {
f = hasflag(oo->flags, F_TRAP);
if (f && (f->val[1] != curtime)) {
triggertrap(NULL, o, oo, dst->where);
}
}
}
}
@ -10384,8 +10404,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
// saving throws
if (youhit && !willcatch && !isprone(target)) {
// can the victim see the thrower?
if (thrower && cansee(target, thrower)) {
// can the victim see where the object came from?
if (haslos(target, srcloc)) {
int catchmod,dodgemod;
enum LFSIZE sz;
sz = getobsize(o);
@ -10413,7 +10433,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
!isimmobile(target) &&
skillcheck(target, SC_DEX, 15*speed, catchmod)) {
willcatch = B_TRUE;
} else if (!lfhasflag(target, F_CASTINGSPELL) && skillcheck(target, SC_DODGE, 10*speed, dodgemod)) {
} else if (!lfhasflag(target, F_CASTINGSPELL) && skillcheck(target, SC_DODGE, 7*speed, dodgemod)) {
// then check if we dodge it...
youhit = B_FALSE;
}
@ -11016,9 +11036,9 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) {
lf = c->lf;
if (lf) getlfname(lf, lfname);
temp = findot(oid);
// saving throw?
if (temp && lf) {
flag_t *f;
@ -11041,6 +11061,13 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) {
}
}
}
// for actual trap objects (ie. not not doors etc), remember when we last
// triggered this trap. this is to avoid infinite loops with arrow traps!
if (trapob) {
flag_t *f;
f = hasflag(trapob->flags, F_TRAP);
if (f) f->val[1] = curtime;
}
if (oid == OT_TRAPWIND) {
// can't be dodged
@ -11546,6 +11573,8 @@ int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim) {
int chance = 0;
if (!o) return 0;
if (hasflag(o->flags, F_MERCIFUL)) return 0;
f = hasflag(o->flags, F_CRITCHANCE);
if (f) {
chance += f->val[0];

View File

@ -94,6 +94,7 @@ char *genhiddenname(enum OBCLASS id);
char *gethiddenname(object_t *o);
int getobattackdelay(object_t *o);
float getobhppct(object_t *o);
int getobmaxhp(object_t *o);
int getletindex(char let);
int getmaterialvalue(enum MATERIAL mat );
int getmaxthrowrange(lifeform_t *lf, object_t *o);

103
spell.c
View File

@ -1972,7 +1972,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// 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) {
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) {
char buf[BUFLEN];
char castername[BUFLEN];
int rv = B_FALSE;
@ -3278,10 +3278,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// announce
getobname(o, obname, 1);
if (isplayer(target)) {
msg("%s forms %s your %s!", obname, getbodypartequipname(bp[i]), getbodypartname(bp[i]));
msg("%s forms %s your %s!", obname, getbodypartequipname(bp[i]), getbodypartname(target, bp[i]));
} else if (cansee(player, target)) {
msg("%s forms %s %s%s %s!", obname, getbodypartequipname(bp[i]),
castername, getpossessive(castername), getbodypartname(bp[i]));
castername, getpossessive(castername), getbodypartname(target, bp[i]));
}
wear(target, o);
// set its values
@ -4636,13 +4636,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
for (i = 0; i < nretflags; i++) {
if ((retflag[i]->id == F_NOBODYPART) && (retflag[i]->val[1] == B_FROMINJURY)) {
if (isplayer(target)) {
msg("Your %s grows back!", getbodypartname(retflag[0]->val[0]));
msg("Your %s grows back!", getbodypartname(target, retflag[0]->val[0]));
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else if (cansee(player, target)) {
char targname[BUFLEN];
getlfname(target, targname);
msg("%s%s %s grows back!", targname, getpossessive(targname),
getbodypartname(retflag[0]->val[0]));
getbodypartname(target, retflag[0]->val[0]));
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
killflag(retflag[i]);
@ -4978,11 +4978,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if ((f->val[0] == BP_RIGHTFINGER) || (f->val[0] == BP_LEFTFINGER)) {
if (isplayer(caster)) {
getobname(o, buf, 1);
msg("Your %s slides off your %s!", buf, getbodypartname(f->val[0]));
msg("Your %s slides off your %s!", buf, getbodypartname(caster, f->val[0]));
} else if (cansee(player, caster)) {
getobname(o, buf, 1);
msg("%s%s %s slides off its %s!", castername,
getpossessive(castername), buf, getbodypartname(f->val[0]));
getpossessive(castername), buf, getbodypartname(caster, f->val[0]));
}
moveob(o, caster->cell->obpile, o->amt);
} else {
@ -6172,7 +6172,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
object_t *o;
lifeform_t *l;
targcell = caster->cell;
targcell = getcellindir(caster->cell, caster->facing);
if (!targcell || targcell->type->solid) {
fizzle(caster);
return B_TRUE;
}
if (haslos(player, targcell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -6194,6 +6198,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
// hack - make all monsters who can see you stop targetting you.
// otherwise they will just try to go to your last known location.
for (l = caster->cell->map->lf ; l ; l = l->next) {
flag_t *f;
if ((l != caster) && (gethitdice(l) <= gethitdice(caster)) ) {
@ -6367,7 +6372,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// - can't turn into monsters which aren't randomly generated.
// - can't turn into unique monsters
// - can't turn into undead monsters
if (r && !canpolymorphto(r->id)) r = NULL;
if (r && !canpolymorphto(r->id) && !hasjob(caster, J_GOD)) {
if (isplayer(caster)) msg("As you think of a %s, magic energy dampens around you.", r->name);
r = NULL;
}
} else { // random
if (isplayer(target) && lfhasflag(target, F_CONTROL)) {
askstring("What will you become", '?', buf, BUFLEN, NULL);
@ -6774,7 +6782,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
return B_FALSE;
}
howlong = getspellduration(5,10,blessed) + (power/2);
fallasleep(target, howlong);
fallasleep(target, ST_ASLEEP, howlong);
if (isplayer(target) || haslos(player, target->cell)) {
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -6990,7 +6998,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, spellid, power, frompot)) return B_TRUE;
if (haslos(player, targcell)) {
msg("A small spark of flame appears.");
if (targcell->lf && cansee(player, targcell->lf)) {
char lfname[BUFLEN];
getlfname(targcell->lf, lfname);
msg("A small spark of flame singes %s.", lfname);
} else {
msg("A small spark of flame appears.");
}
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
@ -7293,9 +7307,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int nallies = 0;
// target is always the caster
target = caster;
if (!target) target = caster;
if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) {
if (isplayer(target)) {
msg("You flicker.");
@ -8672,35 +8685,40 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) {
////////////////////////////////////
// HOW POWERFUL IS THIS SPELL?
////////////////////////////////////
if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) {
// always okay
usesorcery = B_FALSE;
} else if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) {
// dont need spellcasting skill for mental/allomancy
usesorcery = B_FALSE;
} else {
usesorcery = B_TRUE;
}
if (isplayer(lf)) {
if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) {
// always okay
usesorcery = B_FALSE;
} else if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) {
// dont need spellcasting skill for mental/allomancy
usesorcery = B_FALSE;
} else {
usesorcery = B_TRUE;
}
power = 1; // base power of 1.
// plus either your hitdice/3 OR your sorcery skill
if (usesorcery) {
power += spellcastskill;
} else {
power += (gethitdice(lf)/3);
}
power = 1; // base power of 1.
// plus either your hitdice/3 OR your sorcery skill
if (usesorcery) {
power += spellcastskill;
} else {
power += (gethitdice(lf)/3);
}
// plus intelligence modifier
if (school == SS_MENTAL) {
// +/- 2 for iq
power += (getstatmod(lf, A_IQ) / 25);
} else if (school == SS_NATURE) {
// +/- 1 for wisdom
power += (getstatmod(lf, A_WIS) / 50);
// TODO: clerical +/- 2 for wisdom
// plus intelligence modifier
if (school == SS_MENTAL) {
// +/- 2 for iq
power += (getstatmod(lf, A_IQ) / 25);
} else if (school == SS_NATURE) {
// +/- 1 for wisdom
power += (getstatmod(lf, A_WIS) / 50);
// TODO: clerical +/- 2 for wisdom
} else {
// +/- 1 for iq
power += (getstatmod(lf, A_IQ) / 50);
}
} else {
// +/- 1 for iq
power += (getstatmod(lf, A_IQ) / 50);
// for monsters, just based on hitdice:
power = gethitdice(lf);
}
limit(&power, 0, getspellmaxpower(spellid));
@ -9018,6 +9036,13 @@ int spellisfromschool(int spellid, enum SPELLSCHOOL school) {
// returns true if the spell was resisted.
int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce) {
char text[BUFLEN],buf[BUFLEN];
// cannot resist spells from gods when they are on their home plane
if (caster && (caster->race->raceclass->id == RC_GOD)) {
if (caster->cell && (caster->cell->map->region->rtype->id == RG_HEAVEN)) {
return B_FALSE;
}
}
if (announce) {
getlfname(target, buf);

2
text.c
View File

@ -423,6 +423,8 @@ char *gettimetextfuzzy(char *retbuf, int wantpm) {
hours -= 12;
pm = B_TRUE;
}
if (hours == 0) hours = 12;
if (mins == 0) {
snprintf(retbuf, BUFLEN, "exactly %d o'clock", hours);