14472 lines
411 KiB
C
14472 lines
411 KiB
C
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "ai.h"
|
|
#include "attack.h"
|
|
#include "defs.h"
|
|
#include "flag.h"
|
|
#include "io.h"
|
|
#include "lf.h"
|
|
#include "map.h"
|
|
#include "move.h"
|
|
#include "nexus.h"
|
|
#include "objects.h"
|
|
#include "spell.h"
|
|
#include "text.h"
|
|
|
|
extern FILE *logfile;
|
|
|
|
extern map_t *firstmap;
|
|
extern race_t *firstrace, *lastrace;
|
|
extern raceclass_t *firstraceclass, *lastraceclass;
|
|
extern job_t *firstjob, *lastjob;
|
|
extern skill_t *firstskill, *lastskill;
|
|
extern objecttype_t *objecttype;
|
|
extern lifeform_t *player;
|
|
|
|
extern glyph_t playerglyph;
|
|
extern glyph_t tempglyph;
|
|
|
|
extern int needredraw;
|
|
|
|
extern prompt_t prompt;
|
|
|
|
extern enum GAMEMODE gamemode;
|
|
|
|
extern long nextlfid;
|
|
|
|
extern WINDOW *msgwin;
|
|
extern WINDOW *statwin;
|
|
extern int statdirty;
|
|
extern int needredraw;
|
|
|
|
extern int loading;
|
|
|
|
extern int obdb;
|
|
|
|
extern enum ERROR reason;
|
|
|
|
// for xplist
|
|
race_t **raceposs;
|
|
int *xpposs;
|
|
int xplistlen;
|
|
|
|
|
|
void autoweild(lifeform_t *lf) {
|
|
object_t *bestwep,*bestfirearm;
|
|
object_t *o;
|
|
int pretimespent;
|
|
|
|
pretimespent = lf->timespent;
|
|
// weild weapons if required
|
|
bestwep = getbestweapon(lf);
|
|
if (bestwep) {
|
|
weild(lf, bestwep);
|
|
}
|
|
|
|
bestfirearm = getbestfirearm(lf);
|
|
if (bestfirearm) {
|
|
weild(lf, bestfirearm);
|
|
}
|
|
|
|
// weild armour if required
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (canwear(lf, o, BP_NONE)) {
|
|
wear(lf, o);
|
|
} else {
|
|
if (isplayer(lf) && (o->type->id == OT_RING_PROTFIRE)) {
|
|
dblog("zz");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// start using ammo if required
|
|
//if (isplayer(lf)) {
|
|
if (getfirearm(lf)) {
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
testammo(lf, o);
|
|
if (getammo(lf)) break;
|
|
}
|
|
}
|
|
//}
|
|
|
|
// make sure it doesn't take any time
|
|
lf->timespent = pretimespent;
|
|
}
|
|
|
|
int appearsrandomly(enum RACE rid) {
|
|
race_t *r;
|
|
r = findrace(rid);
|
|
if (!r) return B_FALSE;
|
|
|
|
if (!hasflag(r->flags, F_RARITY)) {
|
|
return B_FALSE;
|
|
} else if (hasflagval(r->flags, F_RARITY, NA, F_UNIQUE, NA, NULL)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
void awardxpfor(lifeform_t *killed, float pct) {
|
|
int xpval,xpeach,i,nposs;
|
|
lifeform_t *poss[MAXCANDIDATES], *l;
|
|
int n;
|
|
|
|
xpval = (int) ((float)calcxp(killed) * (pct/100));
|
|
|
|
// find all allies on the map
|
|
nposs = 0;
|
|
n = 0;
|
|
for (l = killed->cell->map->lf ; l ; l = l->next) {
|
|
if ((l != killed) && (getallegiance(l) == AL_FRIENDLY)) {
|
|
poss[nposs] = l;
|
|
nposs++;
|
|
}
|
|
}
|
|
if (nposs == 0) return;
|
|
|
|
xpeach = xpval / nposs;
|
|
|
|
for (i = 0; i < nposs; i++) {
|
|
gainxp(poss[i], xpeach);
|
|
}
|
|
}
|
|
|
|
void bleed(lifeform_t *lf) {
|
|
flag_t *f;
|
|
char obname[BUFLEN];
|
|
|
|
if (lf->cell->type->solid) {
|
|
return;
|
|
}
|
|
|
|
if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
|
|
return;
|
|
}
|
|
|
|
f = lfhasflag(lf, F_BLOODOB);
|
|
if (f) {
|
|
if (f->text) {
|
|
strcpy(obname, f->text);
|
|
} else {
|
|
strcpy(obname, "");
|
|
}
|
|
} else {
|
|
strcpy(obname, "splash of blood");
|
|
}
|
|
|
|
if (strlen(obname) > 0) {
|
|
addob(lf->cell->obpile, obname);
|
|
}
|
|
}
|
|
|
|
void breakallgrabs(lifeform_t *lf) {
|
|
flag_t *f;
|
|
lifeform_t *alf;
|
|
f = lfhasflag(lf, F_GRABBING);
|
|
if (f) {
|
|
lifeform_t *grabee;
|
|
grabee = findlf(NULL, f->val[0]);
|
|
assert(grabee);
|
|
killflagsofid(grabee->flags, F_GRABBEDBY);
|
|
killflagsofid(lf->flags, F_GRABBING);
|
|
}
|
|
f = lfhasflag(lf, F_GRABBEDBY);
|
|
if (f) {
|
|
lifeform_t *graber;
|
|
graber = findlf(NULL, f->val[0]);
|
|
assert(graber);
|
|
killflagsofid(graber->flags, F_GRABBING);
|
|
killflagsofid(lf->flags, F_GRABBEDBY);
|
|
}
|
|
|
|
for (alf = lf->cell->map->lf ; alf ; alf = alf->next) {
|
|
f = lfhasflagval(alf, F_ATTACHEDTO, lf->id, NA, NA, NULL);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
long calcscore(lifeform_t *lf) {
|
|
long points = 0;
|
|
object_t *o;
|
|
// objects
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
points += getobvalue(o);
|
|
}
|
|
// points for xp
|
|
points += (lf->xp / 10);
|
|
|
|
return points;
|
|
}
|
|
|
|
// figure out how much xp a race is worth
|
|
int calcxp(lifeform_t *lf) {
|
|
float multiplier = 1;
|
|
float xpval = 0;
|
|
float offense = 0;
|
|
float defence = 0;
|
|
float spells = 0;
|
|
flag_t *f;
|
|
float avgdam = 0;
|
|
int db = B_FALSE;
|
|
int maxhdroll;
|
|
|
|
float xpconstant = 1;
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
db = B_TRUE;
|
|
}
|
|
|
|
if (db) dblog("calcxp: calculating xpval for %s",lf->race->name);
|
|
|
|
f = lfhasflag(lf, F_XPVAL);
|
|
if (f) {
|
|
multiplier = f->val[0];
|
|
}
|
|
|
|
|
|
f = lfhasflag(lf, F_XPVAL);
|
|
if (f) {
|
|
if (db) dblog("calcxp: got F_XPVAL, forcing result to %d\n",f->val[0]);
|
|
return f->val[0] * multiplier;
|
|
}
|
|
|
|
// attack
|
|
|
|
// - get average attack damage
|
|
avgdam = getavgdam(lf, B_TRUE);
|
|
if (db) dblog("calcxp: avg damage dealt is %0.1f",avgdam);
|
|
|
|
|
|
// defense
|
|
// -- hitdice
|
|
f = lfhasflag(lf, F_HITDICE);
|
|
if (f) {
|
|
maxhdroll = f->val[0] * 4;
|
|
if (f->val[1] != NA) maxhdroll += f->val[1];
|
|
} else {
|
|
maxhdroll = 4;
|
|
}
|
|
|
|
defence += (maxhdroll * lf->level);
|
|
//defence /= 2;
|
|
|
|
// -- evasion ?
|
|
f = hasflag(lf->race->flags, F_EVASION);
|
|
if (f && (f->val[0] > 0)) {
|
|
defence += (f->val[0]);
|
|
}
|
|
|
|
// -- armour
|
|
f = hasflag(lf->race->flags, F_ARMOURRATING);
|
|
if (f && (f->val[0] > 0)) {
|
|
defence += pctof(150, f->val[0]);
|
|
}
|
|
|
|
|
|
if (db) dblog("calcxp: DEFENCE IS %0.1f",defence);
|
|
|
|
|
|
// spells
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_CANCAST) {
|
|
objecttype_t *ot;
|
|
int power,level;
|
|
ot = findot(f->val[0]);
|
|
power = getspellpower(lf, f->val[0]);
|
|
level = getspelllevel(f->val[0]);
|
|
spells += (power * level);
|
|
if (db) dblog("cancast %s: == power %d * spelllevel %d = %d",ot->name, power, level, power*level);
|
|
} else if (f->id == F_CANWILL) {
|
|
objecttype_t *ot;
|
|
// is this a spell?
|
|
ot = findot(f->val[0]);
|
|
if (ot && ot->obclass->id == OC_SPELL) {
|
|
int power,level;
|
|
power = getspellpower(lf, ot->id);
|
|
level = getspelllevel(ot->id);
|
|
spells += (power * level);
|
|
if (db) dblog("canwill spell %s: == power %d * spelllevel %d = %d",ot->name, power, level, power*level);
|
|
} else {
|
|
char damstr[BUFLEN];
|
|
int needgrab = B_FALSE;
|
|
objecttype_t *ot;
|
|
|
|
flag_t *af;
|
|
|
|
ot = findot(f->val[0]);
|
|
|
|
af = hasflag(ot->flags, F_XPVAL);
|
|
if (af) {
|
|
float thisamt = af->val[0];
|
|
if (f->val[2] == NA) {
|
|
if (db) dblog("canwill ability %s == %0.1f",ot->name, thisamt);
|
|
} else {
|
|
thisamt /= f->val[2];
|
|
if (db) dblog("canwill ability %s every %d turns == %0.1f",ot->name, f->val[2], thisamt);
|
|
}
|
|
spells += thisamt;
|
|
}
|
|
|
|
// other special cases
|
|
switch (f->val[0]) {
|
|
case OT_A_SWOOP:
|
|
if (db) dblog("canwill SWOOP - increasing avg dam from %0.1f to %0.1f.", avgdam, avgdam*1.1);
|
|
avgdam *= 1.1; // attack bonus!
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// get dam from text
|
|
texttospellopts(f->text, NULL, damstr, &needgrab, NULL);
|
|
if (strlen(damstr)) {
|
|
int dice,sides,mod,min,max;
|
|
float thisavg;
|
|
texttodice(damstr, &dice,&sides,&mod);
|
|
dicetotext(dice,sides,mod, &min, &max, damstr, NULL);
|
|
thisavg = ((min+max)/2);
|
|
|
|
if (db) dblog("canwill ability %s causes dam %0.1f",ot->name, thisavg);
|
|
// adjust if you have to grab first
|
|
if (needgrab) {
|
|
thisavg /= 2;
|
|
if (db) dblog(" (adjusted to %0.1f due to needing to grab)", thisavg);
|
|
}
|
|
// adjust based on how often we can do it
|
|
if (f->val[2] != NA) {
|
|
thisavg /= f->val[2];
|
|
if (db) dblog(" (can do every %d turns. --> %0.1f)", f->val[2], thisavg);
|
|
}
|
|
if (ot->id == OT_A_GRAB) {
|
|
// assume can only grab once in the 10 turns.
|
|
thisavg /= 10;
|
|
}
|
|
avgdam += thisavg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -- avg damage in 10 turns
|
|
if (db) dblog("calcxp: avg damage dealt (with abilities) is %0.1f",avgdam);
|
|
avgdam *= 10;
|
|
offense = avgdam;
|
|
if (db) dblog("calcxp: ATTACKVAL IS %0.1f",offense);
|
|
|
|
|
|
// extra 'spells'
|
|
if (hasflag(lf->race->flags, F_INDUCEFEAR)) {
|
|
spells += 10;
|
|
}
|
|
|
|
// TOTAL:
|
|
xpval = offense + defence + spells;
|
|
|
|
f = lfhasflag(lf, F_XPMOD);
|
|
if (f) {
|
|
xpval += f->val[0];
|
|
if (db) dblog("calcxp: F_XPMOD is %d",f->val[0]);
|
|
}
|
|
|
|
|
|
|
|
|
|
if (multiplier > 1) {
|
|
xpval *= multiplier;
|
|
if (db) dblog("calcxp: mulitplier takes val to %0.1f",xpval);
|
|
}
|
|
|
|
if (db) dblog("calcxp: xpval: %0.1f --> %0.1f",xpval, xpval * xpconstant);
|
|
xpval *= xpconstant;
|
|
|
|
if (db) dblog("calcxp: ------ FINAL XPVAL: %d ------",(int)xpval);
|
|
|
|
if (db) dblog("");
|
|
return (int) xpval;
|
|
}
|
|
|
|
int calcxprace(enum RACE rid) {
|
|
cell_t c;
|
|
int xpval;
|
|
map_t m;
|
|
lifeform_t *lf;
|
|
// set up fake map
|
|
m.lf = NULL;
|
|
m.lastlf = NULL;
|
|
// make a fake cell
|
|
setcelltype(&c, CT_CORRIDOR);
|
|
c.lf = NULL;
|
|
c.map = &m;
|
|
// make a fake lf
|
|
lf = addlf(&c, rid, 1);
|
|
xpval = calcxp(lf);
|
|
killlf(lf);
|
|
return xpval;
|
|
}
|
|
|
|
int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) {
|
|
int castable = B_FALSE;
|
|
flag_t *f;
|
|
objecttype_t *ot;
|
|
// TODO: check for mute?
|
|
|
|
if (isprone(lf)) {
|
|
reason = E_PRONE;
|
|
return B_FALSE;
|
|
}
|
|
if (isswimming(lf) && (getskill(lf, SK_SWIMMING) < PR_EXPERT)) {
|
|
reason = E_SWIMMING;
|
|
return B_FALSE;
|
|
}
|
|
|
|
reason = E_OK;
|
|
|
|
ot = findot(oid);
|
|
|
|
f = lfhasflagval(lf, F_CANWILL, oid, NA, NA, NULL);
|
|
if (f) {
|
|
int needgrab = B_FALSE;
|
|
|
|
// get canwill opts
|
|
texttospellopts(f->text, NULL, NULL, &needgrab, NULL);
|
|
|
|
// no mp cost.
|
|
if (mpcost) *mpcost = 0;
|
|
// ability ready?
|
|
if (f->val[1] == f->val[2]) {
|
|
castable = B_TRUE;
|
|
} else {
|
|
reason = E_NOTREADY;
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (needgrab || hasflag(ot->flags, F_NEEDSGRAB)) {
|
|
if (!lfhasflag(lf, F_GRABBING)) {
|
|
reason = E_NEEDGRAB;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
} else if (lfhasflagval(lf, F_CANCAST, oid, NA, NA, NULL)) {
|
|
int cost,power;
|
|
|
|
// need >animal intelligence to cast spells
|
|
if (ot->obclass->id == OC_SPELL) {
|
|
if (getiqname(getattr(lf, A_IQ), NULL) <= IQ_ANIMAL) {
|
|
reason = E_LOWIQ;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// how powerful is this spell?
|
|
power = getspellpower(lf, oid);
|
|
if (power <= 0) {
|
|
reason = E_TOOPOWERFUL;
|
|
return B_FALSE;
|
|
}
|
|
// how much mp does it take to cast this?
|
|
cost = getmpcost(lf, oid);
|
|
if (mpcost) *mpcost = cost;
|
|
if (lf->mp >= cost) {
|
|
castable = B_TRUE;
|
|
} else {
|
|
reason = E_NOMP;
|
|
return B_FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
return castable;
|
|
}
|
|
|
|
int candrink(lifeform_t *lf, object_t *o) {
|
|
// undead won't drink
|
|
if (getraceclass(lf) == RC_UNDEAD) {
|
|
reason = E_UNDEAD;
|
|
return B_FALSE;
|
|
}
|
|
if (!isdrinkable(o)) {
|
|
reason = E_WRONGOBTYPE;
|
|
return B_FALSE;
|
|
}
|
|
reason = E_OK;
|
|
return B_TRUE;
|
|
}
|
|
|
|
// if false, returns why you can't eat it in 'reason'
|
|
int caneat(lifeform_t *lf, object_t *o) {
|
|
// undead won't eat
|
|
if (getraceclass(lf) == RC_UNDEAD) {
|
|
reason = E_UNDEAD;
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (!isedible(o)) {
|
|
reason = E_WRONGOBTYPE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// ai won't eat bad food
|
|
if (!isplayer(lf) && isrotting(o)) {
|
|
reason = E_WONT;
|
|
return B_FALSE;
|
|
}
|
|
if ((o->type->id == OT_CORPSE) || (o->type->id == OT_HEAD)) {
|
|
flag_t *f;
|
|
f = hasflag(o->flags, F_CORPSEOF);
|
|
if (f) {
|
|
race_t *r;
|
|
r = findrace(f->val[0]);
|
|
// same race?
|
|
if ((r->id == lf->race->id) || (r->baseid == lf->race->baseid)) {
|
|
enum RACECLASS rc;
|
|
rc = getraceclass(lf);
|
|
// race which doens't eat its own?
|
|
if ((rc == RC_ANIMAL) || (rc == RC_HUMANOID)) {
|
|
// no cannibulism!
|
|
reason = E_NOCANNIBUL;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lfhasflag(lf, F_VEGETARIAN) && (o->material->id == MT_FLESH)) {
|
|
reason = E_VEGETARIAN;
|
|
return B_FALSE;
|
|
}
|
|
if (lfhasflag(lf, F_CARNIVORE) && (o->material->id != MT_FLESH)) {
|
|
reason = E_CARNIVORE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (lfhasflag(lf, F_PARTVEGETARIAN) && (o->material->id == MT_FLESH)) {
|
|
if (gethungerlevel(gethungerval(player)) < H_PECKISH) {
|
|
reason = E_PARTVEGETARIAN;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// ai lifeforms won't eat tainted food
|
|
if (!isplayer(lf)) {
|
|
if (hasflag(o->flags, F_TAINTED)) {
|
|
reason = E_WONT;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
int canhear(lifeform_t *lf, cell_t *dest) {
|
|
int numpixels;
|
|
int i;
|
|
int x1,y1;
|
|
int hleft;
|
|
int x2,y2;
|
|
map_t *map;
|
|
cell_t *retcell[MAXRETCELLS];
|
|
|
|
if (!lf) return B_FALSE;
|
|
if (!dest) return B_FALSE;
|
|
if (!lf->cell) return B_FALSE;
|
|
|
|
// can't hear when dead.
|
|
if (isdead(lf)) return B_FALSE;
|
|
|
|
// can't hear if you are deaf
|
|
if (lfhasflag(lf, F_DEAF)) return B_FALSE;
|
|
|
|
// can't hear when training
|
|
if (lfhasflag(lf, F_TRAINING)) return B_FALSE;
|
|
|
|
// can't hear noises from other maps
|
|
if (lf->cell->map != dest->map) return B_FALSE;
|
|
|
|
// for player only:
|
|
// can't hear if you have a hostile mosnter next to you
|
|
// and you're not blind.
|
|
// (you're too engrossed in the battle)
|
|
if (isplayer(lf) && isinbattle(lf)) {
|
|
if (getcelldist(lf->cell, dest) != 1)
|
|
return B_FALSE;
|
|
}
|
|
|
|
map = dest->map;
|
|
|
|
x1 = lf->cell->x;
|
|
y1 = lf->cell->y;
|
|
x2 = dest->x;
|
|
y2 = dest->y;
|
|
|
|
calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels );
|
|
|
|
// get max hearing range
|
|
hleft = gethearingrange(lf);
|
|
if (hleft <= 0) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
for (i = 0; i < numpixels ; i++) {
|
|
cell_t *cell;
|
|
|
|
cell = retcell[i];
|
|
|
|
// don't need to move out of the last one
|
|
if ((cell->x == x2) && (cell->y == y2)) {
|
|
break;
|
|
}
|
|
// you can always hear your own cell
|
|
if (i != 0) {
|
|
// solid cells decrease hearing range
|
|
if (cell->type->solid) {
|
|
hleft--;
|
|
}
|
|
|
|
// hearing range decreases by one
|
|
hleft--;
|
|
}
|
|
|
|
if (hleft <= 0) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
//
|
|
int cannotmove(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_PARALYZED) || lfhasflag(lf, F_FROZEN) || lfhasflag(lf, F_ASLEEP)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int canlearn(lifeform_t *lf, enum SKILL skid) {
|
|
if (lfhasflagval(lf, F_CANLEARN, skid, NA, NA, NULL)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int canpickup(lifeform_t *lf, object_t *o, int amt) {
|
|
reason = E_OK;
|
|
|
|
if (amt == ALL) {
|
|
amt = o->amt;
|
|
}
|
|
|
|
if (hasflag(o->flags, F_NOPICKUP)) {
|
|
reason = E_NOPICKUP;
|
|
return B_FALSE;
|
|
}
|
|
if (isimpassableob(o, lf)) {
|
|
reason = E_TOOBIG;
|
|
return B_FALSE;
|
|
}
|
|
if (lfhasflag(lf, F_NOPACK)) {
|
|
reason = E_NOPACK;
|
|
return B_FALSE;
|
|
}
|
|
if (lfhasflag(lf, F_GRAVBOOSTED)) {
|
|
reason = E_GRAVBOOSTED;
|
|
return B_FALSE;
|
|
}
|
|
if ((getlfmaterial(lf) == MT_GAS) || lfhasflag(lf, F_NONCORPOREAL)) {
|
|
reason = E_INSUBSTANTIAL;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// too heavy to lift?
|
|
//max = getlfweight(lf, B_NOOBS) * 2; // twice your body weight
|
|
if (getobunitweight(o) + getobpileweight(lf->pack) > (getmaxcarryweight(lf)*2)) {
|
|
reason = E_TOOHEAVY;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// space in pack?
|
|
if (countobs(lf->pack, B_FALSE) >= MAXPILEOBS) {
|
|
reason = E_NOSPACE;
|
|
return B_FALSE;
|
|
}
|
|
if (getnextletter(lf->pack, NULL) == '\0') {
|
|
reason = E_NOSPACE;
|
|
return B_FALSE;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// - can't turn into monsters which aren't randomly generated.
|
|
// - can't turn into unique monsters
|
|
// - can't turn into undead monsters
|
|
int canpolymorphto(enum RACE rid) {
|
|
race_t *r;
|
|
r = findrace(rid);
|
|
if (!r) return B_FALSE;
|
|
|
|
if (!appearsrandomly(rid)) return B_FALSE;
|
|
|
|
if (hasflag(r->flags, F_UNDEAD) || (r->raceclass->id == RC_UNDEAD)) return B_FALSE;
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
int canpush(lifeform_t *lf, object_t *o, int dir) {
|
|
cell_t *obcell, *dstcell;
|
|
reason = E_OK;
|
|
|
|
if ((getlfmaterial(lf) == MT_GAS) || lfhasflag(lf, F_NONCORPOREAL)) {
|
|
reason = E_INSUBSTANTIAL;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// check lf weight
|
|
if (getobweight(o) > getmaxpushweight(lf)) {
|
|
reason = E_TOOHEAVY;
|
|
return B_FALSE;
|
|
}
|
|
// check cell behind object
|
|
obcell = o->pile->where;
|
|
if (!obcell) {
|
|
reason = E_FAILED;
|
|
return B_FALSE;
|
|
}
|
|
dstcell = getcellindir(obcell, dir);
|
|
if (!cellwalkable(NULL, dstcell, NULL)) {
|
|
reason = E_FAILED;
|
|
return B_FALSE;
|
|
}
|
|
return B_TRUE;
|
|
|
|
}
|
|
|
|
int canquaff(lifeform_t *lf, object_t *o) {
|
|
if (!isdrinkable(o)) {
|
|
reason = E_WRONGOBTYPE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (getlfmaterial(lf) == MT_GAS) {
|
|
reason = E_INSUBSTANTIAL;
|
|
return B_FALSE;
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
int cansee(lifeform_t *viewer, lifeform_t *viewee) {
|
|
object_t *o;
|
|
flag_t *f;
|
|
int xray = 0;
|
|
int dist;
|
|
|
|
if (gamemode < GM_GAMESTARTED) {
|
|
return B_TRUE;
|
|
}
|
|
if (!viewee->cell || !viewer->cell) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
f = hasflag(viewer->flags, F_XRAYVIS);
|
|
if (f) {
|
|
xray = f->val[0];
|
|
} else {
|
|
xray = 0;
|
|
}
|
|
dist = getcelldist(viewer->cell, viewee->cell);
|
|
|
|
// viewer asleep?
|
|
if (lfhasflag(viewer, F_ASLEEP)) {
|
|
// can only 'see' yourself
|
|
if (viewee != viewer) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// no line of sight?
|
|
if (!haslos(viewer, viewee->cell)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
// viewee is invisible?
|
|
if (lfhasflag(viewee, F_INVISIBLE)) {
|
|
if (!lfhasflag(viewer, F_SEEINVIS)) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// viewee hiding?
|
|
if (lfhasflag(viewee, F_HIDING) && (viewee != viewer)) {
|
|
if (!lfhasflagval(viewer, F_SPOTTED, viewee->id, NA, NA, NULL)) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// something obscuring them?
|
|
for (o = viewee->cell->obpile->first ; o ; o = o->next) {
|
|
f = hasflag(o->flags, F_BLOCKSVIEW);
|
|
if (f) {
|
|
if (!lfhasflagval(viewer, F_CANSEETHROUGHMAT, o->material->id, NA, NA, NULL)) {
|
|
if (!xray || (xray < dist)) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
int cansleep(lifeform_t *lf) {
|
|
enum RACECLASS rc;
|
|
rc = getraceclass(lf);
|
|
if (rc == RC_PLANT) {
|
|
return B_FALSE;
|
|
} else if (rc == RC_UNDEAD) {
|
|
return B_FALSE;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// where == BP_NONE means "can i wear it anywhere?'
|
|
int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) {
|
|
object_t *oo;
|
|
flag_t *f;
|
|
|
|
reason = E_OK;
|
|
if ((where != BP_NONE) && !hasbp(lf, where)) {
|
|
reason = E_NOBP;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// already equipped?
|
|
if (hasflag(o->flags, F_EQUIPPED)) {
|
|
reason = E_ALREADYUSING;
|
|
return B_FALSE;
|
|
}
|
|
// wearable at all?
|
|
if (!iswearable(o) || !lfhasflag(lf, F_HUMANOID)) {
|
|
reason = E_IMPOSSIBLE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (gettechlevel(o) > getskill(lf, SK_TECHUSAGE)) {
|
|
reason = E_NOTKNOWN;
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (where == BP_NONE) {
|
|
// can we wear it ANYWHERE?
|
|
enum BODYPART possbp[MAXBODYPARTS];
|
|
int nparts = 0;
|
|
int i;
|
|
for (f = o->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_GOESON) {
|
|
possbp[nparts] = f->val[0];
|
|
nparts++;
|
|
}
|
|
}
|
|
|
|
if (nparts == 0) {
|
|
// can't wear anywhere!
|
|
reason = E_IMPOSSIBLE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// are any of these body parts free?
|
|
for (i = 0; i < nparts; i++) {
|
|
if (isfreebp(lf, possbp[i])) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
// no parts free
|
|
reason = E_WEARINGSOMETHINGELSE;
|
|
return B_FALSE;
|
|
|
|
} else {
|
|
// does this object go there?
|
|
f = hasflagval(o->flags, F_GOESON, where, NA, NA, NULL);
|
|
if (!f) {
|
|
// can't wear there!
|
|
reason = E_IMPOSSIBLE;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// anything else worn there?
|
|
for (oo = lf->pack->first ; oo ; oo = oo->next) {
|
|
f = hasflagval(oo->flags, F_EQUIPPED, where, -1, -1, NULL);
|
|
if (f) {
|
|
reason = E_WEARINGSOMETHINGELSE;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
int canweild(lifeform_t *lf, object_t *o) {
|
|
flag_t *f;
|
|
enum BODYPART weildloc,otherloc;
|
|
|
|
weildloc = getweildloc(o, &otherloc, NULL);
|
|
|
|
// already weilding it?
|
|
if (o && isequipped(o)) {
|
|
reason = E_ALREADYUSING;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// special case...
|
|
if (lf->race->id == R_DANCINGWEAPON) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
if (!lfhasflag(lf, F_HUMANOID)) {
|
|
reason = E_IMPOSSIBLE;
|
|
return B_FALSE;
|
|
}
|
|
if (!hasbp(lf, weildloc)) {
|
|
if (o && isfirearm(o) && !getequippedob(lf->pack, otherloc)) {
|
|
int temp;
|
|
// firearm can go in other hand.
|
|
// swap locations.
|
|
temp = weildloc;
|
|
weildloc = otherloc;
|
|
otherloc = temp;
|
|
} else {
|
|
reason = E_NOHANDS;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
if (o) {
|
|
for (f = o->flags->first ; f; f = f->next) {
|
|
if (f->id == F_ATTREQ) {
|
|
// meetsattreq will set 'reason' for us.
|
|
if (!meetsattreq(lf, f, o)) {
|
|
return B_FALSE;
|
|
}
|
|
} else if (f->id == F_TWOHANDED) {
|
|
// need both hands free...
|
|
if (lfhasflagval(lf, F_NOBODYPART, otherloc, NA, NA, NULL)) {
|
|
reason = E_NOHANDS;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
reason = E_OK;
|
|
|
|
// trying to fight unarmed, but no unarmed attack?
|
|
if (o == NULL) {
|
|
if (!hasflag(lf->flags, F_HASATTACK)) {
|
|
reason = E_NOUNARMEDATTACK;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
int cantakeoff(lifeform_t *lf, object_t *o) {
|
|
flag_t *f;
|
|
|
|
reason = E_OK;
|
|
f = hasflag(o->flags, F_EQUIPPED);
|
|
if (!f) {
|
|
reason = E_NOTEQUIPPED;
|
|
return B_FALSE;
|
|
}
|
|
|
|
// cursed?
|
|
if (o->blessed == B_CURSED) {
|
|
reason = E_CURSED;
|
|
return B_FALSE;
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell) {
|
|
int rv;
|
|
int cost;
|
|
flag_t *f,*willflag;
|
|
int power;
|
|
objecttype_t *sp;
|
|
// check whether we _can_ cast it.
|
|
// do we have this spell/ability?
|
|
// enough mp? etc
|
|
if (!cancast(lf, sid, &cost)) {
|
|
if (isplayer(lf)) {
|
|
// announce
|
|
switch (reason) {
|
|
case E_TOOPOWERFUL:
|
|
msg("That spell is too powerful for you to cast.");
|
|
break;
|
|
case E_NOMP:
|
|
msg("You don't have enough mana to cast that.");
|
|
break;
|
|
case E_LOWIQ:
|
|
msg("You are not smart enough to cast spells.");
|
|
break;
|
|
case E_PRONE:
|
|
msg("You can't cast spells while prone.");
|
|
break;
|
|
case E_SWIMMING:
|
|
msg("You can't cast spells while swimming.");
|
|
break;
|
|
default:
|
|
msg("For some reason, you can't cast that.");
|
|
break;
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
willflag = lfhasflagval(lf, F_CANWILL, sid, NA, NA, NULL);
|
|
|
|
// special case
|
|
if (!willflag) {
|
|
f = lfhasflag(lf, F_NEEDOBFORSPELLS);
|
|
if (f && !hasob(lf->pack, f->val[0])) {
|
|
objecttype_t *ot;
|
|
ot = findot(f->val[0]);
|
|
if (isplayer(lf)) {
|
|
msg("You can't cast spells without %s %s.",needan(ot->name) ? "an" : "a", ot->name);
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
power = getspellpower(lf, sid);
|
|
|
|
sp = findot(sid);
|
|
|
|
if (isplayer(lf) && (power > 1) && hasflag(sp->flags, F_VARPOWER)) {
|
|
if (!hasactivespell(lf, sp->id)) {
|
|
int max;
|
|
char buf[BUFLEN],desc[BUFLEN];
|
|
int i;
|
|
char ch;
|
|
// ask what power
|
|
max = power;
|
|
sprintf(buf, "Cast %s at what power level?", sp->name);
|
|
initprompt(&prompt, buf);
|
|
for (i = 1; i <= max; i++) {
|
|
sprintf(buf, "Power %s (%d MP)", roman(i), getmpcost(lf, sid) * i);
|
|
getvarpowerspelldesc(sp->id, i, desc);
|
|
if (strlen(desc)) {
|
|
strcat(buf, "\t");
|
|
strcat(buf, desc);
|
|
}
|
|
addchoice(&prompt, '0' + i, buf, buf, NULL);
|
|
}
|
|
ch = getchoice(&prompt);
|
|
power = ch - '0';
|
|
|
|
// modify cost
|
|
cost *= i;
|
|
}
|
|
}
|
|
|
|
// take time
|
|
taketime(lf, getspellspeed(lf));
|
|
|
|
// lose mp
|
|
losemp(lf, cost);
|
|
|
|
if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 20 + power, 0)) {
|
|
if (power > 1) {
|
|
// half strength
|
|
power /= 2;
|
|
if (power <= 1) power = 1;
|
|
|
|
if (isplayer(lf)) {
|
|
msg("Your magic resistance interferes with your spell!");
|
|
}
|
|
}
|
|
}
|
|
|
|
// announce
|
|
if (!isplayer(lf) && cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
// special case
|
|
f = lfhasflag(lf,F_SPELLCASTTEXT);
|
|
if (f) {
|
|
if (strlen(f->text)) {
|
|
msg("%s %s.", lfname, f->text);
|
|
}
|
|
} else {
|
|
msg("%s casts a spell.", lfname);
|
|
}
|
|
}
|
|
|
|
// boost power?
|
|
if (hasjob(lf, J_DRUID)) {
|
|
int n;
|
|
int boost = 0;
|
|
for (n = 0; n < lf->nlos; n++) {
|
|
if (lf->los[n]->lf && getraceclass(lf->los[n]->lf) == RC_PLANT) {
|
|
boost++;
|
|
} else if (hasobofclass(lf->los[n]->obpile, OC_FLORA)) {
|
|
boost++;
|
|
}
|
|
}
|
|
power += boost;
|
|
limit(&power, NA, 10);
|
|
}
|
|
|
|
// cast the spell
|
|
addflag(lf->flags, F_CASTINGSPELL, sid, NA, NA, NULL);
|
|
rv = dospelleffects(lf, sid, power, targlf, targob, targcell, B_UNCURSED, NULL);
|
|
f = lfhasflag(lf, F_CASTINGSPELL);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
|
|
// willing this spell? reset counter!
|
|
if (willflag) {
|
|
if (willflag->val[2] != NA) {
|
|
willflag->val[1] = -1;
|
|
}
|
|
}
|
|
|
|
// stop hiding
|
|
killflagsofid(lf->flags, F_HIDING);
|
|
|
|
return rv;
|
|
}
|
|
|
|
// returns TRUE if something happened.
|
|
int checkfordrowning(lifeform_t *lf, object_t *o) {
|
|
int depth,i;
|
|
int didsomething = B_FALSE;
|
|
flag_t *f;
|
|
enum SKILLLEVEL slev;
|
|
|
|
i = getskill(lf, SK_SWIMMING) - isburdened(lf);
|
|
limit(&i, 0, NA);
|
|
slev = i;
|
|
|
|
depth = getobdepth(o, lf);
|
|
|
|
// apply water damage (ie rust etc) to armour.
|
|
for (i = 0; i <= depth; i++) {
|
|
object_t *armour = NULL;
|
|
if (i == DP_FEET) {
|
|
armour = getouterequippedob(lf, BP_FEET); if (armour) takedamage(armour, 4, DT_WATER);
|
|
} else if (i == DP_WAIST) {
|
|
armour = getouterequippedob(lf, BP_LEGS); if (armour) takedamage(armour, 4, DT_WATER);
|
|
armour = getouterequippedob(lf, BP_WAIST); if (armour) takedamage(armour, 4, DT_WATER);
|
|
} else if (i == DP_SHOULDERS) {
|
|
armour = getouterequippedob(lf, BP_BODY); if (armour) takedamage(armour, 4, DT_WATER);
|
|
armour = getouterequippedob(lf, BP_SHOULDERS); if (armour) takedamage(armour, 4, DT_WATER);
|
|
} else if (i == DP_HEAD) {
|
|
armour = getouterequippedob(lf, BP_HEAD); if (armour) takedamage(armour, 4, DT_WATER);
|
|
}
|
|
}
|
|
|
|
// will you drown?
|
|
if (depth >= DP_HEAD) {
|
|
if (!slev && !lfhasflag(lf, F_BREATHWATER)) {
|
|
// you drown.
|
|
if (isplayer(lf)) {
|
|
msg("You drown.");
|
|
didsomething = B_TRUE;
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s drowns.",lfname);
|
|
didsomething = B_TRUE;
|
|
}
|
|
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
|
|
lf->hp = 0;
|
|
setlastdam(lf, "drowning");
|
|
}
|
|
}
|
|
|
|
if (!isdead(lf)) {
|
|
f = isvulnto(lf->flags, DT_WATER);
|
|
if (f) {
|
|
int dam;
|
|
if (strlen(f->text)) {
|
|
dam = roll(f->text);
|
|
} else {
|
|
dam = roll("1d6");
|
|
}
|
|
applywalkdam(lf, dam, DT_WATER, o);
|
|
}
|
|
}
|
|
|
|
return didsomething;
|
|
}
|
|
|
|
/*
|
|
void checkxp(enum RACE rid) {
|
|
int i,xp;
|
|
race_t *r;
|
|
|
|
r = findrace(rid);
|
|
if (!r) {
|
|
dblog("checkxp(): can't find race for rid %d",rid);
|
|
return;
|
|
}
|
|
xp = calcxprace(rid);
|
|
|
|
|
|
if (xp < xpposs[0]) {
|
|
dblog("** Recommended rarity for %s: 100 (before %s/%d)",
|
|
r->name,
|
|
raceposs[0]->name, getracerarity(raceposs[0]->id));
|
|
} else if (xp > xpposs[xplistlen-1]) {
|
|
dblog("** Recommended rarity for %s: above %d (after %s/%d)",
|
|
r->name, getracerarity(raceposs[xplistlen-1]->id),
|
|
raceposs[xplistlen-1]->name, getracerarity(raceposs[xplistlen-1]->id));
|
|
} else {
|
|
for (i = 0; i < xplistlen-1; i++) {
|
|
if ((raceposs[i]->d != r->id) && (raceposs[i+1] != r->id))
|
|
if ((xp >= xpposs[i]) && (xp <= xpposs[i+1])) {
|
|
dblog("** Recommended rarity for %s: %d (between %s/%d and %s/%d)",
|
|
r->name, (int)((float)xpposs[i] + (float)xpposs[i+1])/2,
|
|
raceposs[i]->name, getracerarity(raceposs[i]->id),
|
|
raceposs[i+1]->name, getracerarity(raceposs[i+1]->id)
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// how dangerous is lf2 to lf1?
|
|
// < 0 = harder
|
|
// > 0 = easier
|
|
float comparelfs(lifeform_t *lf1, lifeform_t *lf2) {
|
|
float avgdam[2];
|
|
lifeform_t *lf[2];
|
|
float turnstokill[2];
|
|
int i;
|
|
float ratio;
|
|
lf[0] = lf1;
|
|
lf[1] = lf2;
|
|
for (i = 0; i < 2; i++) {
|
|
float otherevasion;
|
|
// get avg damage
|
|
avgdam[i] = getavgdam(lf[i], B_FALSE);
|
|
// mod this by other lf's evasion
|
|
otherevasion = ((float)getevasion(lf[1-i]));
|
|
avgdam[i] -= pctof(otherevasion, avgdam[i]);
|
|
// divide other lf's hit points by this lf's avg dam
|
|
if (avgdam[i] == 0) {
|
|
turnstokill[1-i] = 9999;
|
|
} else {
|
|
turnstokill[1-i] = (float)lf[1-i]->hp / avgdam[i];
|
|
}
|
|
}
|
|
|
|
// compare turnstokill values
|
|
ratio = (turnstokill[0] / turnstokill[1]);
|
|
|
|
|
|
return ratio;
|
|
}
|
|
|
|
int countinnateattacks(lifeform_t *lf) {
|
|
int count = 0;
|
|
flag_t *f;
|
|
for (f = lf->flags->first ; f; f = f->next) {
|
|
if (f->id == F_HASATTACK) count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
int countmoney(lifeform_t *lf) {
|
|
object_t *o;
|
|
int amt = 0;
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (o->type->id == OT_GOLD) {
|
|
amt += o->amt;
|
|
}
|
|
}
|
|
return amt;
|
|
}
|
|
|
|
int countnearbyallies(lifeform_t *lf) {
|
|
lifeform_t *l;
|
|
int count = 0;
|
|
|
|
for (l = lf->cell->map->lf ; l ; l = l->next) {
|
|
if ((l != lf) && areallies(l, lf)) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int countnearbyhurtallies(lifeform_t *lf) {
|
|
lifeform_t *l;
|
|
int count = 0;
|
|
|
|
for (l = lf->cell->map->lf ; l ; l = l->next) {
|
|
if ((l != lf) && areallies(l, lf)) {
|
|
if (l->hp != l->maxhp) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// toggle debugging
|
|
void debug(lifeform_t *lf) {
|
|
char lfname[BUFLEN];
|
|
flag_t *f;
|
|
getlfname(lf, lfname);
|
|
|
|
f = hasflag(lf->flags, F_DEBUG);
|
|
if (f) {
|
|
killflag(f);
|
|
msg("%s - debugging is DISABLED.", lfname);
|
|
} else {
|
|
addflag(lf->flags, F_DEBUG, B_TRUE, NA, NA, NULL);
|
|
msg("%s - debugging is ON.", lfname);
|
|
}
|
|
}
|
|
|
|
// returns true if the player pays.
|
|
int demandbribe(lifeform_t *lf) {
|
|
char lfname[BUFLEN];
|
|
int amtwanted,amtgiven,totmoney;
|
|
int hd;
|
|
char buf[BUFLEN], answer[BUFLEN];
|
|
object_t *gold, *mongold;
|
|
int satisfied = B_FALSE;
|
|
int nminions;
|
|
int i,heard;
|
|
lifeform_t *minion[MAXCANDIDATES];
|
|
|
|
hd = gethitdice(lf);
|
|
gold = hasob(player->pack, OT_GOLD);
|
|
if (gold) {
|
|
totmoney = countmoney(player);
|
|
} else {
|
|
totmoney = 0;
|
|
}
|
|
mongold = hasob(lf->pack, OT_GOLD);
|
|
amtwanted = rnd(hd*25, hd*100);
|
|
|
|
getlfname(lf, lfname);
|
|
if (say(lf, "Hand over all your gold!", 2)) {
|
|
heard = B_TRUE;
|
|
} else {
|
|
heard = B_FALSE;
|
|
}
|
|
|
|
if (heard) {
|
|
int doagain = B_TRUE;
|
|
more();
|
|
while (doagain) {
|
|
sprintf(buf, "How much gold will you give %s (you have $%d)", lfname, totmoney);
|
|
askstring(buf, '?', answer, BUFLEN, NULL);
|
|
amtgiven = atoi(answer);
|
|
if (amtgiven > totmoney) {
|
|
msg("You don't have that much gold!"); more();
|
|
doagain = B_TRUE;
|
|
} else if (amtgiven < 0) {
|
|
msg("Please enter a valid number."); more();
|
|
doagain = B_TRUE;
|
|
} else {
|
|
doagain = B_FALSE;
|
|
}
|
|
}
|
|
limit(&amtgiven, 0, totmoney);
|
|
} else {
|
|
amtgiven = 0;
|
|
}
|
|
|
|
if (gold && (amtgiven > 0)) {
|
|
gold->amt -= amtgiven;
|
|
|
|
if (mongold) {
|
|
mongold->amt += amtgiven;
|
|
} else {
|
|
char gbuf[BUFLEN];
|
|
sprintf(gbuf, "%d gold", amtgiven);
|
|
mongold = addob(lf->pack, gbuf);
|
|
}
|
|
|
|
if ((amtgiven == totmoney) || (amtgiven >= amtwanted)) {
|
|
// always succeed
|
|
say(lf, "Pleasure doing business with you!", 2);
|
|
satisfied = B_TRUE;
|
|
} else {
|
|
say(lf, "Then die!", 3);
|
|
satisfied = B_FALSE;
|
|
}
|
|
} else {
|
|
// TODO: luck check to receive money ?
|
|
say(lf, "Then die!", 3);
|
|
satisfied = B_FALSE;
|
|
}
|
|
|
|
|
|
// if you gave the gold, mosnter becomes peaceful
|
|
if (satisfied) {
|
|
makepeaceful(lf);
|
|
// also make any of its minions peaceful
|
|
for (i = 0; i < nminions; i++) {
|
|
makepeaceful(minion[i]);
|
|
}
|
|
}
|
|
|
|
// either way, kill bribe flag
|
|
killflagsofid(lf->flags, F_DEMANDSBRIBE);
|
|
|
|
return satisfied;
|
|
}
|
|
|
|
void die(lifeform_t *lf) {
|
|
char buf[BUFLEN];
|
|
flag_t *f;
|
|
cell_t *where;
|
|
//int dropobs = B_TRUE;
|
|
int vaporised = B_FALSE;
|
|
int willbecomeghost = B_FALSE;
|
|
object_t *corpse = NULL;
|
|
|
|
if (cansee(player, lf)) {
|
|
needredraw = B_TRUE;
|
|
}
|
|
|
|
if (lfhasflag(lf, F_RISEASGHOST)) {
|
|
willbecomeghost = B_TRUE;
|
|
}
|
|
|
|
if (useringofmiracles(lf, 3)) {
|
|
int hunger;
|
|
// return to full health
|
|
lf->hp = lf->maxhp;
|
|
// cure poison
|
|
killflagsofid(lf->flags, F_POISONED);
|
|
// cure starvation
|
|
hunger = gethungerval(lf);
|
|
if (hunger > 0) {
|
|
modhunger(lf, -hunger);
|
|
}
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
if (!willbecomeghost) {
|
|
if (isplayer(lf) && hasjob(lf, J_GOD)) {
|
|
char ch;
|
|
msg("You die..."); more();
|
|
ch = askchar("Die", "yn", "n", B_TRUE);
|
|
if (ch == 'n') {
|
|
lf->hp = lf->maxhp;
|
|
msg("Not dying.");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// revert to your original form first.
|
|
if (lfhasflag(lf, F_POLYMORPHED)) {
|
|
if (lfhasflag(lf, F_ORIGRACE)) {
|
|
abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL);
|
|
// ... but you're still dead
|
|
lf->hp = 0;
|
|
}
|
|
}
|
|
|
|
|
|
if (!willbecomeghost) {
|
|
lf->alive = B_FALSE;
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
// force screen redraw so you see your hp = 0
|
|
drawscreen();
|
|
|
|
if (lf->lastdamtype == DT_EXPLOSIVE) {
|
|
msg("You are vaporised!");
|
|
vaporised = B_TRUE;
|
|
} else {
|
|
msg("You die.");
|
|
}
|
|
more();
|
|
// force msg redraw!
|
|
drawmsg();
|
|
} else {
|
|
if (!hasflag(lf->flags, F_NODEATHANNOUNCE)) {
|
|
if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
if (lf->lastdamtype == DT_EXPLOSIVE) {
|
|
msg("%s is vaporised!",buf);
|
|
vaporised = B_TRUE;
|
|
} else if (lf->lastdamtype == DT_MELT) {
|
|
msg("%s completely melts.",buf);
|
|
} else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) {
|
|
msg("%s shatters!",buf);
|
|
} else {
|
|
msg("%s dies.",buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lf->race->id == R_DANCINGWEAPON) {
|
|
if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s drops to the ground.", buf);
|
|
}
|
|
}
|
|
|
|
// award xp (but not if another monster killed it)
|
|
if (hasflag(lf->flags, F_KILLEDBYPLAYER)) {
|
|
awardxpfor(lf,100);
|
|
}
|
|
}
|
|
|
|
|
|
// drop/kill all objects
|
|
if (willbecomeghost || !isplayer(lf)) {
|
|
while (lf->pack->first) {
|
|
if (vaporised) {
|
|
killob(lf->pack->first);
|
|
} else {
|
|
if (!moveob(lf->pack->first, lf->cell->obpile, ALL)) {
|
|
killob(lf->pack->first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// drop corpse/splatter blood
|
|
if (vaporised) {
|
|
switch (rnd(1,2)) {
|
|
case 1:
|
|
fragments(lf->cell, "chunk of flesh", 2, UNLIMITED);
|
|
break;
|
|
case 2:
|
|
fragments(lf->cell, "pool of blood", 2, UNLIMITED);
|
|
break;
|
|
}
|
|
} else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) {
|
|
// shattered
|
|
fragments(lf->cell, "chunk of ice", 2, UNLIMITED);
|
|
} else {
|
|
if (lfhasflag(lf, F_NOCORPSE)) {
|
|
if (isundead(lf) && cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s crumbles to dust.", buf);
|
|
}
|
|
} else if (lf->lastdamtype == DT_MELT) {
|
|
// drop a pool of water
|
|
addob(lf->cell->obpile, "large puddle of water");
|
|
} else if (lf->lastdamtype == DT_NECROTIC) {
|
|
int n;
|
|
int numbones = 0;
|
|
char bonestring[BUFLEN];
|
|
for (n = 0; n < getlfsize(lf); n++) {
|
|
numbones += rnd(1,10);
|
|
}
|
|
// drop bones
|
|
sprintf(bonestring, "%d bones",numbones);
|
|
addob(lf->cell->obpile, bonestring);
|
|
} else {
|
|
char corpseprefix[BUFLEN];
|
|
char corpsename[BUFLEN];
|
|
|
|
strcpy(corpseprefix, "");
|
|
switch (lf->lastdamtype) {
|
|
case DT_FIRE:
|
|
strcat(corpseprefix, "flaming ");
|
|
break;
|
|
case DT_COLD:
|
|
strcat(corpseprefix, "frozen ");
|
|
break;
|
|
default:
|
|
if (lfhasflag(lf, F_FROZEN)) {
|
|
strcat(corpseprefix, "frozen ");
|
|
}
|
|
break;
|
|
}
|
|
if (lfhasflag(lf, F_BEHEADED)) {
|
|
strcat(corpseprefix, "headless ");
|
|
}
|
|
|
|
f = lfhasflag(lf, F_CORPSETYPE);
|
|
if (f) {
|
|
sprintf(corpsename, "%s%s", corpseprefix, f->text);
|
|
} else {
|
|
sprintf(corpsename, "%s%s corpse", corpseprefix, lf->race->name);
|
|
}
|
|
|
|
corpse = addob(lf->cell->obpile, corpsename);
|
|
if (corpse) {
|
|
if ((lf->lastdamtype == DT_FIRE) && isflammable(corpse)) {
|
|
addflag(corpse->flags, F_ONFIRE, B_TRUE, NA, NA, NULL);
|
|
}
|
|
|
|
// tainted?
|
|
if ((lf->lastdamtype == DT_POISONGAS) || lfhasflag(lf, F_POISONOUS) || lfhasflag(lf, F_POISONED)) {
|
|
addflag(corpse->flags, F_TAINTED, B_TRUE, NA, NA, NULL);
|
|
}
|
|
|
|
// set colour based on monster
|
|
if (corpse->type->id == OT_CORPSE) {
|
|
colourmatchob(corpse, lf);
|
|
}
|
|
|
|
// add extra flags ?
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_CORPSEFLAG) {
|
|
addflag(corpse->flags, f->val[0], f->val[1], f->val[2], NA, f->text);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (hasflag(corpse->flags, F_HEADLESS)) {
|
|
object_t *headob;
|
|
char headname[BUFLEN];
|
|
// drop head too
|
|
sprintf(headname, "%s head",lf->race->name);
|
|
headob = addob(lf->cell->obpile, headname);
|
|
colourmatchob(headob, lf);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// splatter
|
|
if (!vaporised) {
|
|
flag_t *f;
|
|
f = lfhasflag(lf, F_DIESPLATTER);
|
|
if (f) {
|
|
fragments(lf->cell, f->text, 1, f->val[0]);
|
|
}
|
|
}
|
|
|
|
|
|
if (willbecomeghost) {
|
|
flag_t *f, *nextf;
|
|
// remove all job flags
|
|
lf->born = B_FALSE;
|
|
for (f = lf->flags->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
if (f->lifetime == FROMJOB) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
killflagsofid(lf->flags, F_JOB);
|
|
lf->born = B_TRUE;
|
|
// turn into a ghost
|
|
setrace(lf, R_GHOST, B_TRUE);
|
|
lf->hp = lf->maxhp;
|
|
if (corpse) {
|
|
char cid[BUFLEN];
|
|
sprintf(cid, "%ld",corpse->id);
|
|
addflag(lf->flags, F_MYCORPSE, NA, NA, NA, cid);
|
|
}
|
|
} else {
|
|
where = lf->cell;
|
|
if (lf->controller != C_PLAYER) {
|
|
// kill lifeform
|
|
killlf(lf);
|
|
assert(where->lf == NULL);
|
|
}
|
|
}
|
|
|
|
if (needredraw) {
|
|
drawscreen();
|
|
}
|
|
}
|
|
|
|
void dumplf(void) {
|
|
lifeform_t *lf;
|
|
map_t *startmap;
|
|
int count = 0;
|
|
dblog("START LIFEFORM DUMP:");
|
|
if (player) {
|
|
startmap = player->cell->map;
|
|
} else {
|
|
startmap = firstmap;
|
|
}
|
|
for (lf = startmap->lf ; lf ; lf = lf->next) {
|
|
dblog(" timespent=%3d id %d race %s",lf->timespent, lf->id, lf->race->name);
|
|
count++;
|
|
}
|
|
dblog("END LIFEFORM DUMP (%d found)",count);
|
|
}
|
|
|
|
void genxplist(void) {
|
|
race_t *r;
|
|
race_t *racetemp;
|
|
int xptemp;
|
|
int count = 0;
|
|
int i;
|
|
int donesomething;
|
|
|
|
// count races
|
|
for (r = firstrace ; r; r = r->next) {
|
|
count++;
|
|
}
|
|
|
|
// allocate space
|
|
raceposs = malloc(count * sizeof(race_t *));
|
|
xpposs = malloc(count * sizeof(int));
|
|
|
|
// get xpval for all races
|
|
xplistlen = 0;
|
|
for (r = firstrace ; r; r = r->next) {
|
|
raceposs[xplistlen] = r;
|
|
xpposs[xplistlen] = calcxprace(r->id);
|
|
xplistlen++;
|
|
}
|
|
|
|
// bubblesort
|
|
donesomething = B_TRUE;
|
|
while (donesomething) {
|
|
donesomething = B_FALSE;
|
|
for (i = 0; i < (xplistlen-1); i++) {
|
|
if (xpposs[i] > xpposs[i+1]) {
|
|
// swap with next
|
|
xptemp = xpposs[i];
|
|
racetemp = raceposs[i];
|
|
xpposs[i] = xpposs[i+1];
|
|
raceposs[i] = raceposs[i+1];
|
|
xpposs[i+1] = xptemp;
|
|
raceposs[i+1] = racetemp;
|
|
donesomething = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void dumpxp(void) {
|
|
int i;
|
|
|
|
// dump
|
|
dblog("%-10s%-30s%s","XP", "Race", "Rarity");
|
|
for (i = 0; i < xplistlen; i++) {
|
|
dblog("%-10d%-30s%d",xpposs[i], raceposs[i]->name,getracerarity(NULL, raceposs[i]->id));
|
|
}
|
|
|
|
// free mem
|
|
free(xpposs);
|
|
free(raceposs);
|
|
|
|
// dump xp for levels
|
|
dblog("");
|
|
dblog("");
|
|
for (i = 2; i < 30; i++) {
|
|
char buf[BUFLEN];
|
|
sprintf(buf, "Lev %d",i);
|
|
dblog("%-10s%ld",buf, getxpforlev(i));
|
|
}
|
|
}
|
|
|
|
// dump which level random things will appear at
|
|
void dumplev(void) {
|
|
int i;
|
|
race_t *r;
|
|
objecttype_t *ot;
|
|
flag_t *f;
|
|
dblog("Start monster dump");
|
|
dblog("------------------\n");
|
|
// NOTE: this code copied from getrandomrace(), which is used by addmonster().
|
|
for (i = 1; i <= 25; i++) {
|
|
int min,max,prevmin,prevmax;
|
|
getrarity(i-1, &prevmin, &prevmax, RARITYVARIANCELF, B_FALSE);
|
|
getrarity(i, &min, &max, RARITYVARIANCELF, B_FALSE);
|
|
fprintf(logfile, "Dlev %d (rar >= %d): ",i,min);
|
|
for (r = firstrace ; r; r = r->next) {
|
|
int rarity = 0;
|
|
f = hasflag(r->flags, F_RARITY);
|
|
if (f) {
|
|
rarity = f->val[1];
|
|
// ok this lev?
|
|
if ((rarity >= min) && (rarity <= max)) {
|
|
char buf[BUFLEN];
|
|
strcpy(buf, "");
|
|
// ok on previous lev too?
|
|
if ((rarity >= prevmin) && (rarity <= prevmax)) {
|
|
// only print if dlev is 1
|
|
if (i == 1) {
|
|
sprintf(buf, "%s, ", r->name);
|
|
}
|
|
} else {
|
|
// ie. new mosnter for this lev
|
|
//sprintf(buf, "*%s*, ", r->name);
|
|
//makeuppercase(buf);
|
|
sprintf(buf, "%s, ", r->name);
|
|
}
|
|
fprintf(logfile, "%s", buf);
|
|
}
|
|
}
|
|
}
|
|
fprintf(logfile, "\n");
|
|
}
|
|
|
|
|
|
dblog("Start object dump");
|
|
dblog("------------------\n");
|
|
// NOTE: this code copied from getrandomrace(), which is used by addmonster().
|
|
for (i = 1; i <= 25; i++) {
|
|
int min,max,prevmin,prevmax;
|
|
getrarity(i-1, &prevmin, &prevmax, RARITYVARIANCEOB, B_FALSE);
|
|
getrarity(i, &min, &max, RARITYVARIANCEOB, B_FALSE);
|
|
fprintf(logfile, "Dlev %d (rar >= %d): ",i,min);
|
|
for (ot = objecttype ; ot; ot = ot->next) {
|
|
int rarity = 0;
|
|
f = hasflag(ot->flags, F_RARITY);
|
|
if (f) {
|
|
rarity = f->val[1];
|
|
// ok this lev?
|
|
if ((rarity >= min) && (rarity <= max)) {
|
|
char buf[BUFLEN];
|
|
strcpy(buf, "");
|
|
// ok on previous lev too?
|
|
if ((rarity >= prevmin) && (rarity <= prevmax)) {
|
|
// only print if dlev is 1
|
|
if (i == 1) {
|
|
sprintf(buf, "%s, ", ot->name);
|
|
}
|
|
} else {
|
|
// ie. new object for this lev
|
|
//sprintf(buf, "*%s*, ", r->name);
|
|
//makeuppercase(buf);
|
|
sprintf(buf, "%s, ", ot->name);
|
|
}
|
|
fprintf(logfile, "%s", buf);
|
|
}
|
|
}
|
|
}
|
|
fprintf(logfile, "\n");
|
|
}
|
|
|
|
fflush(logfile);
|
|
}
|
|
|
|
int eat(lifeform_t *lf, object_t *o) {
|
|
char lfname[BUFLEN];
|
|
char obname[BUFLEN];
|
|
char buf[BUFLEN];
|
|
flag_t *f;
|
|
double nutrition;
|
|
double turnstoeat;
|
|
double eateachturn;
|
|
double startpcteaten = 0;
|
|
double pcteaten;
|
|
int drinking = B_FALSE;
|
|
int amt;
|
|
int fullyeaten = B_FALSE;
|
|
flag_t *alreadyeating;
|
|
enum HUNGER hlev,posthlev;
|
|
|
|
if (hasflag(o->flags, F_DRINKABLE)) {
|
|
drinking = B_TRUE;
|
|
}
|
|
|
|
if (drinking) {
|
|
if (!candrink(lf, o)) {
|
|
if (isplayer(lf)) {
|
|
switch (reason) {
|
|
case E_UNDEAD:
|
|
msg("You are undead and don't need to drink.");
|
|
break;
|
|
default:
|
|
case E_WRONGOBTYPE:
|
|
msg("You can't drink that!");
|
|
break;
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
} else {
|
|
if (!caneat(lf, o)) {
|
|
if (isplayer(lf)) {
|
|
switch (reason) {
|
|
case E_NOCANNIBUL:
|
|
msg("The idea of eating your own race is abhorrent to you.");
|
|
break;
|
|
case E_UNDEAD:
|
|
msg("You are undead and don't need to eat.");
|
|
break;
|
|
case E_CARNIVORE:
|
|
msg("The thought of eating plant matter disgusts you.");
|
|
break;
|
|
case E_VEGETARIAN:
|
|
msg("The thought of eating flesh disgusts you.");
|
|
break;
|
|
case E_PARTVEGETARIAN:
|
|
msg("You aren't hungry enough to eat meat yet.");
|
|
break;
|
|
case E_WRONGOBTYPE:
|
|
default:
|
|
msg("You can't eat that!");
|
|
break;
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
getobname(o, obname, 1);
|
|
getlfname(lf, lfname);
|
|
|
|
// get total nutrition
|
|
nutrition = getnutrition(o);
|
|
|
|
if (nutrition == 0) {
|
|
// this might happen if you purposely try to eat a potion.
|
|
// technically a potion will pass above checks because you can
|
|
// drink it.
|
|
if (isplayer(lf)) {
|
|
msg("That doesn't seem very nutritious...");
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
// only do this check for the player - basically it should
|
|
// handle the case where we have poluymorphed into something
|
|
// which doesn't eat.
|
|
if (isplayer(lf)) {
|
|
f = hasflag(lf->flags, F_HUNGER);
|
|
if (!f) {
|
|
msg("You don't need to %s!", drinking ? "drink" : "eat");
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (touch(lf, o)) {
|
|
taketime(lf, getactspeed(lf));
|
|
return B_TRUE;
|
|
}
|
|
|
|
// how many turns to eat whole thing?
|
|
f = hasflag(o->flags, F_EDIBLE);
|
|
if (f && (f->val[2] != NA)) {
|
|
startpcteaten = f->val[2];
|
|
} else {
|
|
startpcteaten = 0;
|
|
}
|
|
|
|
if (drinking) {
|
|
// when drinking you can drink all of it.
|
|
turnstoeat = 1;
|
|
} else {
|
|
// time to eat entire food:
|
|
turnstoeat = getobunitweight(o) / (getlfweight(lf, B_NOOBS) / 10);
|
|
}
|
|
|
|
if (startpcteaten > 0) {
|
|
turnstoeat -= ((startpcteaten/100) * turnstoeat);
|
|
}
|
|
|
|
// now find out how much we'll eat in one turn.
|
|
if (turnstoeat <= 1) {
|
|
eateachturn = ((100 - startpcteaten)/100) * nutrition;
|
|
fullyeaten = B_TRUE;
|
|
} else {
|
|
eateachturn = nutrition / turnstoeat;
|
|
}
|
|
|
|
pcteaten = (eateachturn / nutrition) * 100;
|
|
|
|
// announce
|
|
/*
|
|
msg("totnutr:%0.0lf,startpcteaten:%0.0lf,endpcteaten:%0.0f,eatperturn:%0.0f,turnstoeat:%0.0lf,fullyeaten:%s",
|
|
nutrition,
|
|
startpcteaten,pcteaten,
|
|
eateachturn,turnstoeat,fullyeaten ? "YES" : "NO");
|
|
*/
|
|
sprintf(buf, "%ld",o->id);
|
|
alreadyeating = lfhasflagval(lf, F_EATING, NA, NA, NA, buf);
|
|
|
|
// announce
|
|
if (turnstoeat <= 1) {
|
|
if (alreadyeating) {
|
|
if (isplayer(lf)) {
|
|
msg("You finish %s.%s", drinking ? "drinking" : "eating",
|
|
(f->val[1] >= 20) ? " Yum!" : "");
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s finishes %s.", lfname, drinking ? "drinking" : "eating");
|
|
}
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
msg("You %s %s.%s", drinking ? "drink" : "eat", obname,
|
|
(f->val[1] >= 20) ? " Yum!" : "");
|
|
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s %s %s.", lfname, drinking ? "drinks" : "eats", obname);
|
|
}
|
|
}
|
|
} else {
|
|
if (alreadyeating) {
|
|
if (isplayer(lf)) {
|
|
msg("You continue %s.", drinking ? "drinking" : "eating");
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s continues %s.", lfname, drinking ? "drinking" : "eating");
|
|
}
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
msg("You start %s %s.", drinking ? "drinking" : "eating", obname);
|
|
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s starts %s %s.", lfname, drinking ? "drinking" : "eating", obname);
|
|
}
|
|
}
|
|
}
|
|
|
|
hlev = gethungerlevel(gethungerval(player));
|
|
if (alreadyeating) {
|
|
if (turnstoeat <= 1) {
|
|
killflag(alreadyeating);
|
|
}
|
|
} else if (!alreadyeating && (turnstoeat > 1)) {
|
|
addflag(lf->flags, F_EATING, NA, NA, NA, buf);
|
|
}
|
|
|
|
if (isrotting(o)) {
|
|
if (!isimmuneto(lf->flags, DT_POISON)) {
|
|
char dambuf[BUFLEN];
|
|
// lose hp
|
|
if (isplayer(lf)) {
|
|
msg("That %s was bad!", drinking ? "liquid" : "food");
|
|
}
|
|
// food poisoning for 20 turns
|
|
if (drinking) {
|
|
sprintf(dambuf, "%s",obname);
|
|
} else {
|
|
sprintf(dambuf, "a bad %s",noprefix(obname));
|
|
}
|
|
poison(lf, 20, P_FOOD, 1, dambuf);
|
|
}
|
|
}
|
|
|
|
// get less hungry
|
|
modhunger(lf, -eateachturn);
|
|
posthlev = gethungerlevel(gethungerval(player));
|
|
|
|
if (fullyeaten) {
|
|
// special cases
|
|
if (hasflagval(o->flags, F_CORPSEOF, R_GLOWBUG, NA, NA, NULL)) {
|
|
addtempflag(lf->flags, F_PRODUCESLIGHT, B_TRUE, NA, NA, NULL, 30);
|
|
}
|
|
if (hasflagval(o->flags, F_CORPSEOF, R_NEWT, NA, NA, NULL)) {
|
|
// think "eye of newt"
|
|
gainmp(lf, 2);
|
|
}
|
|
|
|
// special case for bananas
|
|
if (o->type->id == OT_BANANA) {
|
|
object_t *skin;
|
|
skin = addob(lf->pack, "banana skin");
|
|
if (skin) {
|
|
if (isplayer(lf)) {
|
|
char skinname[BUFLEN];
|
|
getobname(skin, skinname, 1);
|
|
msgnocap("%c - %s", skin->letter, skinname);
|
|
}
|
|
} else {
|
|
skin = addob(lf->cell->obpile, "banana skin");
|
|
if (skin && cansee(player, lf)) {
|
|
char skinname[BUFLEN];
|
|
getobname(skin, skinname, 1);
|
|
msg("%s drop%s %s on the ground.",lfname, isplayer(lf) ? "" : "s",
|
|
skinname);
|
|
}
|
|
}
|
|
}
|
|
} // end if fullyeaten
|
|
|
|
// take time
|
|
amt = getactspeed(lf);
|
|
if (o->pile->owner != lf) {
|
|
amt += SPEED_PICKUP;
|
|
}
|
|
taketime(lf, amt);
|
|
|
|
if (fullyeaten) {
|
|
// remove object
|
|
removeob(o, 1);
|
|
} else {
|
|
// mark how much we ate
|
|
f = hasflag(o->flags, F_EDIBLE);
|
|
if (f) {
|
|
f->val[2] = (int)(startpcteaten + pcteaten);
|
|
}
|
|
}
|
|
|
|
// stop eating if we are full
|
|
if (!fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) {
|
|
int stopeating = B_FALSE;
|
|
if (isplayer(lf)) {
|
|
int ch;
|
|
more();
|
|
ch = askchar("Stop eating?","yn","y", B_TRUE);
|
|
if (ch == 'y') {
|
|
stopeating = B_TRUE;
|
|
}
|
|
} else {
|
|
stopeating = B_TRUE;
|
|
}
|
|
if (stopeating) {
|
|
killflagsofid(lf->flags, F_EATING);
|
|
}
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
drawstatus();
|
|
wrefresh(statwin);
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void enhanceskills(lifeform_t *lf) {
|
|
enum SKILL whichsk;
|
|
flag_t *f;
|
|
skill_t *sk;
|
|
char ch = 'a';
|
|
int newskillcost = 1;
|
|
float hpratio,mpratio;
|
|
|
|
lf->level = lf->newlevel;
|
|
|
|
// update hp
|
|
hpratio = ((float)lf->hp / (float)lf->maxhp);
|
|
lf->maxhp += rollhitdice(lf);
|
|
lf->hp = hpratio * (float)lf->maxhp;
|
|
|
|
// update mp
|
|
if (lfhasflag(lf, F_MPDICE)) {
|
|
mpratio = ((float)lf->mp / (float)lf->maxmp);
|
|
lf->maxmp += rollmpdice(lf);
|
|
lf->mp = mpratio * (float)lf->maxmp;
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
drawstatus();
|
|
wrefresh(statwin);
|
|
msg("Welcome to level %d!",lf->level);
|
|
more();
|
|
}
|
|
|
|
// give job-based level rewards
|
|
f = levelabilityready(lf);
|
|
while (f) {
|
|
if (f->id == F_LEVABIL) {
|
|
addflag(lf->flags, F_CANWILL, f->val[1], f->val[2], f->val[2], f->text);
|
|
} else if (f->id == F_LEVFLAG) {
|
|
addflag(lf->flags, f->val[1], f->val[2], NA, NA, f->text);
|
|
} else if (f->id == F_LEVSKILL) {
|
|
giveskill(lf, f->val[1]);
|
|
} else if (f->id == F_LEVSPELL) {
|
|
addflag(lf->flags, F_CANCAST, f->val[1], NA, NA, NULL);
|
|
} else if (f->id == F_LEVSPELLSCHOOL) { // select a spell from school
|
|
if (isplayer(lf)) {
|
|
makespellchoicelist(&prompt, player, "Learn which new spell:","Describe which spell:", f->val[1], B_TRUE, B_FALSE);
|
|
if (prompt.nchoices > 0) {
|
|
objecttype_t *ot;
|
|
getchoicestr(&prompt, B_TRUE, B_TRUE);
|
|
ot = prompt.result;
|
|
if (ot) {
|
|
addflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL);
|
|
}
|
|
} else {
|
|
msg("There are no new spells for you to learn at this time.");
|
|
}
|
|
} else {
|
|
makespellchoicelist(&prompt, player, "xx","xx:", f->val[1], B_FALSE, B_FALSE);
|
|
if (prompt.nchoices > 0) {
|
|
objecttype_t *ot;
|
|
// pick one randomly
|
|
ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices)].data;
|
|
if (ot) {
|
|
addflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
f->lifetime = LEVABILITYDONE; // mark as done.
|
|
|
|
// get next one
|
|
f = levelabilityready(lf);
|
|
}
|
|
// now refresh them all for next level.
|
|
refreshlevelabilities(lf);
|
|
|
|
// increase str/int etc if we can
|
|
f = lfhasflag(lf, F_STATGAINREADY);
|
|
while (f && (f->val[2] > 0)) {
|
|
enum ATTRIB att;
|
|
if (isplayer(lf)) {
|
|
char ch;
|
|
ch = askchar("Increase your Strength, Dexterity, Constitution or Intelligence?", "sdci",NULL, B_TRUE);
|
|
switch (ch) {
|
|
case 's': att = A_STR; break;
|
|
case 'd': att = A_DEX; break;
|
|
case 'c': att = A_CON; break;
|
|
case 'i': att = A_IQ; break;
|
|
}
|
|
} else {
|
|
// pick randomly
|
|
att = rnd(0,MAXATTS-1);
|
|
}
|
|
modattr(lf, att, 1);
|
|
f->val[2]--;
|
|
if (f->val[2] <= 0) {
|
|
killflag(f);
|
|
}
|
|
if (isplayer(lf)) {
|
|
// update status bar with new stats
|
|
drawstatus();
|
|
wrefresh(statwin);
|
|
// wait for player to acknowledge 'you feel stronger' etc
|
|
more();
|
|
}
|
|
f = lfhasflag(lf, F_STATGAINREADY);
|
|
}
|
|
|
|
// now ask about learning/enhancing skills
|
|
if (isplayer(lf)) {
|
|
char eorl = 'e';
|
|
int skillstoenhance = 0;
|
|
int skillstolearn = 0;
|
|
int done = B_FALSE;
|
|
|
|
skillstoenhance = 0;
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if ((f->id == F_HASSKILL) && (f->val[1] != PR_MASTER)) {
|
|
skillstoenhance++;
|
|
}
|
|
}
|
|
|
|
skillstolearn = 0;
|
|
for (sk = firstskill ; sk ; sk = sk->next) {
|
|
if (!getskill(player, sk->id) && canlearn(player, sk->id)) {
|
|
skillstolearn++;
|
|
}
|
|
}
|
|
|
|
|
|
while (!done && lf->skillpoints && (skillstolearn || skillstoenhance)) {
|
|
if (skillstolearn && (lf->skillpoints >= newskillcost)) {
|
|
if (skillstoenhance) {
|
|
char buf[BUFLEN];
|
|
sprintf(buf, "Enhance existing skills or Learn a new one (%d points left)?",lf->skillpoints);
|
|
eorl = askchar(buf,"eln","e", B_TRUE);
|
|
} else {
|
|
ch = askchar("Learn a new skill?","yn","y", B_TRUE);
|
|
if (ch == 'y') eorl = 'l';
|
|
else eorl = 'n';
|
|
}
|
|
} else if (skillstoenhance) {
|
|
ch = askchar("Enhance your current skills?","yn","y", B_TRUE);
|
|
if (ch == 'y') eorl = 'e';
|
|
else eorl = 'n';
|
|
} else {
|
|
eorl = 'n';
|
|
}
|
|
|
|
if (eorl == 'e') {
|
|
// enhance an existing skill
|
|
|
|
// any skills to get?
|
|
if (skillstoenhance) {
|
|
char ques[BUFLEN];
|
|
sprintf(ques, "Enhance which skill (%d left)?", lf->skillpoints);
|
|
initprompt(&prompt, ques);
|
|
|
|
ch = 'a';
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if ((f->id == F_HASSKILL) && (f->val[1] != PR_MASTER)) {
|
|
char buf[BUFLEN];
|
|
sprintf(buf, "%s (%s -> %s)", getskillname(f->val[0]),
|
|
getskilllevelname(f->val[1]), getskilllevelname(f->val[1] + 1));
|
|
addchoice(&prompt, ch++, getskillname(f->val[0]), buf, f);
|
|
}
|
|
}
|
|
addchoice(&prompt, '-', "None", "None", NULL);
|
|
|
|
getchoicestr(&prompt, B_FALSE, B_TRUE);
|
|
f = (flag_t *)prompt.result;
|
|
if (f) {
|
|
whichsk = f->val[0];
|
|
giveskill(lf, whichsk);
|
|
lf->skillpoints--;
|
|
}
|
|
} else {
|
|
msg("You have already mastered all your current skills.");
|
|
}
|
|
} else if (eorl == 'l') {
|
|
// learn a new skill
|
|
|
|
// enough points?
|
|
if (player->skillpoints < newskillcost) {
|
|
msg("You need at least %d skill points to learn a new skill.", newskillcost);
|
|
} else {
|
|
|
|
if (skillstolearn) {
|
|
char ques[BUFLEN];
|
|
sprintf(ques, "Learn which new skill (%d left)?", player->skillpoints);
|
|
initprompt(&prompt, ques);
|
|
|
|
ch = 'a';
|
|
for (sk = firstskill ; sk ; sk = sk->next) {
|
|
if (!getskill(player, sk->id) && canlearn(player, sk->id)) {
|
|
char buf[BUFLEN];
|
|
sprintf(buf, "%-18s(%s)", getskillname(sk->id), getskilldesc(sk->id));
|
|
addchoice(&prompt, ch++, getskillname(sk->id), buf, sk);
|
|
}
|
|
}
|
|
addchoice(&prompt, '-', "None", "None", NULL);
|
|
getchoicestr(&prompt, B_FALSE, B_TRUE);
|
|
sk = (skill_t *)prompt.result;
|
|
if (sk) {
|
|
giveskill(player, sk->id);
|
|
player->skillpoints -= newskillcost;
|
|
}
|
|
} else {
|
|
msg("There is nothing more that you can learn.");
|
|
}
|
|
}
|
|
} else if (eorl == 'n') {
|
|
done = B_TRUE;
|
|
} // end enhance/learnnew
|
|
} // whiel skillstolearn || skillstoenhance
|
|
statdirty = B_TRUE;
|
|
} else {
|
|
// monsters will just enhance a random skill, they never learn new ones.
|
|
enum SKILL poss[MAXSKILLS];
|
|
int nposs = 0;
|
|
int sel;
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if ((f->id == F_HASSKILL) && (f->val[1] != PR_MASTER)) {
|
|
poss[nposs] = f->val[0];
|
|
nposs++;
|
|
}
|
|
}
|
|
sel = rnd(0,nposs-1);
|
|
|
|
giveskill(lf, poss[sel]);
|
|
lf->skillpoints--;
|
|
} // end if isplayer
|
|
|
|
killflagsofid(lf->flags, F_HASNEWLEVEL);
|
|
|
|
// ready for another level?
|
|
if (lf->xp >= getxpforlev(lf->level + 1)) {
|
|
gainlevel(lf); // this will increment 'newlevel'
|
|
}
|
|
}
|
|
|
|
|
|
// if the lf wearing something which shades their eyes?
|
|
object_t *eyesshaded(lifeform_t *lf) {
|
|
object_t *glasses;
|
|
glasses = getarmour(lf, BP_EYES);
|
|
if (glasses && hasflag(glasses->flags, F_TINTED)) {
|
|
return glasses;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) {
|
|
char lfname[BUFLEN];
|
|
|
|
if (isdead(lf)) return B_TRUE;
|
|
if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
getlfname(lf,lfname);
|
|
|
|
if (announce) {
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
if (fromlf) {
|
|
char fromlfname[BUFLEN];
|
|
getlfname(fromlf, fromlfname);
|
|
msg("%s knock%s %s to the ground!",fromlfname, isplayer(fromlf) ? "" : "s", lfname);
|
|
} else {
|
|
msg("%s fall%s to the ground.",lfname, isplayer(lf) ? "" : "s");
|
|
}
|
|
}
|
|
}
|
|
taketime(lf, SP_NORMAL*2);
|
|
|
|
addflag(lf->flags, F_PRONE, B_TRUE, NA, NA, NULL);
|
|
loseconcentration(lf);
|
|
return B_FALSE;
|
|
}
|
|
|
|
int fallasleep(lifeform_t *lf, int howlong) {
|
|
if (lfhasflag(lf, F_ASLEEP)) {
|
|
return B_TRUE;
|
|
}
|
|
loseconcentration(lf);
|
|
interrupt(lf);
|
|
|
|
killflagsofid(lf->flags, F_RAGE);
|
|
killflagsofid(lf->flags, F_TRAINING);
|
|
|
|
addtempflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL, howlong);
|
|
return B_FALSE;
|
|
}
|
|
|
|
// make 'lf' respond to damage
|
|
void fightback(lifeform_t *lf, lifeform_t *attacker) {
|
|
interrupt(lf);
|
|
|
|
// special cases
|
|
if ((lf->race->id == R_STIRGE) || (lf->race->id == R_LEECH)) {
|
|
if (ispeaceful(lf)) {
|
|
// rest our sated counter
|
|
killflagsofid(lf->flags, F_COUNTER);
|
|
}
|
|
}
|
|
|
|
if (attacker) {
|
|
// wake up
|
|
killflagsofid(lf->flags, F_ASLEEP);
|
|
// monsters might flee, fight back, etc
|
|
if (!isplayer(lf)) {
|
|
if (willflee(lf)) {
|
|
scare(lf, attacker, PERMENANT, 0);
|
|
} else {
|
|
lifeform_t *l;
|
|
|
|
aiattack(lf, attacker, AI_FOLLOWTIME);
|
|
|
|
// any nearby monsters which will help out?
|
|
if (getallegiance(lf) != AL_FRIENDLY) {
|
|
for (l = lf->cell->map->lf ; l ; l = l->next) {
|
|
if (!isdead(l) && areallies(l,lf)) {
|
|
if (cansee(l, attacker)) {
|
|
aiattack(l, attacker, AI_FOLLOWTIME);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// special cases (which will only happen if not retreating)
|
|
}
|
|
// special cases (which will happen whether retreating or not)
|
|
if (lf->race->id == R_DARKMANTLE) {
|
|
cell_t *poss[MAXCANDIDATES];
|
|
int i, nposs = 0;
|
|
// darkjump
|
|
for (i = 0; i < lf->nlos; i++) {
|
|
if (cellwalkable(lf, lf->los[i], NULL) && isdark(lf->los[i])) {
|
|
poss[nposs] = lf->los[i];
|
|
nposs++;
|
|
}
|
|
}
|
|
if (nposs) {
|
|
//teleportto(lf, poss[rnd(0,nposs-1)], B_FALSE); // no smoke
|
|
abilityeffects(lf, OT_A_DARKWALK, poss[rnd(0,nposs-1)], NULL, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
job_t *findjob(enum JOB jobid) {
|
|
job_t *j;
|
|
for (j = firstjob ; j ; j = j->next) {
|
|
if (j->id == jobid) return j;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
job_t *findjobbyname(char *name) {
|
|
job_t *j;
|
|
for (j = firstjob ; j ; j = j->next) {
|
|
if (!strcasecmp(j->name, name)) return j;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
lifeform_t *findlf(map_t *m, int lfid) {
|
|
lifeform_t *lf;
|
|
map_t *thismap;
|
|
if (m) {
|
|
for (lf = m->lf ; lf ; lf = lf->next) {
|
|
if (lf->id == lfid) return lf;
|
|
}
|
|
} else {
|
|
for (thismap = firstmap ; thismap ; thismap = thismap->next) {
|
|
for (lf = thismap->lf ; lf ; lf = lf->next) {
|
|
if (lf->id == lfid) return lf;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
race_t *findrace(enum RACE id) {
|
|
race_t *r;
|
|
for (r = firstrace; r ; r = r->next) {
|
|
if (r->id == id) {
|
|
return r;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
race_t *findracebyname(char *name) {
|
|
race_t *r;
|
|
// first check for exact matches
|
|
for (r = firstrace; r ; r = r->next) {
|
|
if (!strcmp(r->name, name)) {
|
|
return r;
|
|
}
|
|
}
|
|
// ...then partial matches
|
|
for (r = firstrace; r ; r = r->next) {
|
|
if (strstr(r->name, name)) {
|
|
return r;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
raceclass_t *findraceclass(enum RACECLASS id) {
|
|
raceclass_t *r;
|
|
for (r = firstraceclass; r ; r = r->next) {
|
|
if (r->id == id) {
|
|
return r;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
skill_t *findskill(enum SKILL id) {
|
|
skill_t *r;
|
|
for (r = firstskill; r ; r = r->next) {
|
|
if (r->id == id) {
|
|
return r;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
skill_t *findskillbyname(char *name) {
|
|
skill_t *s;
|
|
for (s = firstskill ; s ; s = s->next) {
|
|
if (!strcasecmp(s->name, name)) return s;
|
|
}
|
|
for (s = firstskill ; s ; s = s->next) {
|
|
if (!strcasestr(s->name, name)) return s;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
enum SKILLLEVEL findskilllevbyname(char *name) {
|
|
enum SKILLLEVEL slev;
|
|
for (slev = PR_INEPT; slev <= PR_MASTER; slev++) {
|
|
if (!strcasecmp(getskilllevelname(slev), name)) {
|
|
return slev;
|
|
}
|
|
}
|
|
return PR_INEPT;
|
|
}
|
|
|
|
// try to actually do the 'run away' action for
|
|
// anyone we are fleeing from.
|
|
// returns TRUE if we ran away from something
|
|
int flee(lifeform_t *lf) {
|
|
flag_t *f, *nextf;
|
|
lifeform_t *fleefrom = NULL;
|
|
|
|
// are we fleeing?
|
|
for (f = lf->flags->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
if (f->id == F_FLEEFROM) {
|
|
lifeform_t *thisone;
|
|
thisone = findlf(lf->cell->map, f->val[0]);
|
|
if (thisone) {
|
|
if (cansee(lf, thisone)) {
|
|
// if not fleeing from anyone, or this one is closer...
|
|
if (!fleefrom || getcelldist(lf->cell, thisone->cell) < getcelldist(lf->cell, fleefrom->cell)) {
|
|
fleefrom = thisone;
|
|
}
|
|
} else {
|
|
// if we can't see the person we're running from, and it's not enforced for
|
|
// a certain time period (ie. f->lifetime == PERMENANT), we can now stop fleeing.
|
|
if (f->lifetime == PERMENANT) {
|
|
killflag(f);
|
|
}
|
|
// if the flag is temporary, wait for it to time out normally
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// found someone who we are fleeing from?
|
|
if (fleefrom) {
|
|
object_t *stairs;
|
|
// ways of fleeing other than movement?
|
|
if (!isplayer(lf)) {
|
|
enum OBTYPE spell;
|
|
// if AI, try to use specific spells like teleport self
|
|
spell = aigetfleespell(lf);
|
|
if (spell != OT_NONE) {
|
|
lifeform_t *targlf;
|
|
cell_t *targcell;
|
|
object_t *targob;
|
|
|
|
aigetspelltarget(lf, findot(spell), fleefrom, &targlf, &targcell, &targob, F_AICASTTOFLEE);
|
|
return castspell(lf, spell, targlf, targob, targcell);
|
|
}
|
|
// if AI, use helpful fleeing items
|
|
if (!useitemwithflag(lf, F_AIFLEEITEM)) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// announce
|
|
if (isplayer(lf)) {
|
|
char buf[BUFLEN];
|
|
drawscreen();
|
|
getlfname(fleefrom, buf);
|
|
msg("You flee from %s!",buf);
|
|
}
|
|
|
|
// can we flee via stairs?
|
|
stairs = hasobwithflag(lf->cell->obpile, F_CLIMBABLE);
|
|
if (stairs) {
|
|
if (!usestairs(lf, stairs)) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
// move away from them
|
|
if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH)) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
// if we get here, it means we didn't need to or couldn't flee
|
|
return B_FALSE;
|
|
}
|
|
|
|
// start fleeing from 'enemy'
|
|
void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong) {
|
|
flag_t *f;
|
|
|
|
// in recovery from fleeing?
|
|
// this is to prevent constant usage of war cry!
|
|
f = hasflagval(lf->flags, F_NOFLEEFROM, enemy->id, NA, NA, NULL);
|
|
if (f) {
|
|
if (f->lifetime > 0) {
|
|
f->lifetime -= 5;
|
|
if (f->lifetime <= 0) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
if (isplayer(lf)) {
|
|
msg("You flinch.");
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s flinches.",lfname);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// already fleeing?
|
|
f = hasflagval(lf->flags, F_FLEEFROM, enemy->id, NA, NA, NULL);
|
|
if (f) {
|
|
// update time
|
|
if (f->lifetime != PERMENANT) {
|
|
if (f->lifetime < howlong) {
|
|
f->lifetime = howlong;
|
|
}
|
|
}
|
|
} else {
|
|
addtempflag(lf->flags, F_FLEEFROM, enemy->id, NA, NA, NULL, howlong);
|
|
}
|
|
}
|
|
|
|
int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong) {
|
|
if (isimmuneto(freezee->flags, DT_COLD)) {
|
|
if (isplayer(freezee)) {
|
|
msg("You feel a slight chill.");
|
|
}
|
|
return B_TRUE;
|
|
} else if (isresistantto(freezee->flags, DT_COLD)) {
|
|
char buf[BUFLEN];
|
|
// note: damage value here will be halved due to resistance
|
|
// so this really means rnd( 5,10)
|
|
if (isplayer(freezee)) {
|
|
msg("You feel freezing cold!");
|
|
}
|
|
if (freezer) {
|
|
char lfname[BUFLEN];
|
|
getlfname(freezer, lfname);
|
|
sprintf(buf, "being frozen by %s",lfname);
|
|
} else {
|
|
strcpy(buf, "being frozen");
|
|
}
|
|
losehp(freezee, rnd(10,20), DT_COLD, freezer, buf);
|
|
return B_TRUE;
|
|
}
|
|
|
|
// turn to ice
|
|
addtempflag(freezee->flags, F_FROZEN, B_TRUE, NA, NA, NULL, howlong);
|
|
return B_FALSE;
|
|
}
|
|
|
|
void gainhp(lifeform_t *lf, int amt) {
|
|
int gained = B_FALSE;
|
|
int maxed = B_FALSE;
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
if (lf->hp < lf->maxhp) {
|
|
lf->hp += amt;
|
|
gained = B_TRUE;
|
|
}
|
|
|
|
if (lf->hp >= lf->maxhp) {
|
|
lf->hp = lf->maxhp;
|
|
if (gained) maxed = B_TRUE;
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
if (maxed) {
|
|
msg("You are now fully healed.");
|
|
}
|
|
// update screen
|
|
drawstatus();
|
|
updatestatus();
|
|
}
|
|
}
|
|
|
|
void gainlevel(lifeform_t *lf) {
|
|
flag_t *f;
|
|
race_t *mybaserace;
|
|
int skillready = B_FALSE;
|
|
//int preready,postready;
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
drawstatus();
|
|
wrefresh(statwin);
|
|
}
|
|
|
|
//preready = readytotrain(lf);
|
|
|
|
addflag(lf->flags, F_HASNEWLEVEL, B_TRUE, NA, NA, NULL);
|
|
|
|
lf->newlevel++;
|
|
|
|
|
|
// stat gain (str etc) every 3 levels
|
|
if ((lf->newlevel % 3) == 0) {
|
|
flag_t *f;
|
|
f = lfhasflag(lf, F_STATGAINREADY);
|
|
if (f) {
|
|
// TODO: should never happen now.
|
|
f->val[2]++;
|
|
} else {
|
|
f = addflag(lf->flags, F_STATGAINREADY, NA, NA, 1, NULL);
|
|
}
|
|
}
|
|
|
|
// skill gain
|
|
// new skill at level 2, 4, 6, etc
|
|
//if ((lf->newlevel % 2) == 0) {
|
|
lf->skillpoints++;
|
|
skillready = B_TRUE;
|
|
// }
|
|
|
|
//if (postready && !preready) {
|
|
/*
|
|
} else {
|
|
killflagsofid(lf->flags, F_HASNEWLEVEL);
|
|
}
|
|
*/
|
|
|
|
if (isplayer(lf)) {
|
|
if (skillready) {
|
|
msg("You feel ready to learn a new skill!");
|
|
} else {
|
|
msg("You feel ready for a training session!");
|
|
}
|
|
more();
|
|
} else if (cansee(player, lf)) {
|
|
//getlfname(lf, buf);
|
|
//msg("%s looks more confident!",buf);
|
|
}
|
|
|
|
|
|
// you can now re-attempt identification of objects
|
|
killflagsofid(lf->flags, F_FAILEDINSPECT);
|
|
|
|
// monster races can be promoted...
|
|
if (lf->race->baseid) {
|
|
mybaserace = findrace(lf->race->baseid);
|
|
} else {
|
|
mybaserace = lf->race;
|
|
}
|
|
f = hasflagval(mybaserace->flags, F_LEVRACE, lf->newlevel, NA, NA, NULL);
|
|
if (f && (lf->race->id != f->val[1])) {
|
|
// promotion!
|
|
setrace(lf, f->val[1], B_FALSE);
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
needredraw = B_TRUE;
|
|
statdirty = B_TRUE;
|
|
drawscreen();
|
|
}
|
|
}
|
|
|
|
|
|
void gainmp(lifeform_t *lf, int amt) {
|
|
int gained = B_FALSE;
|
|
int maxed = B_FALSE;
|
|
int max;
|
|
|
|
max = getmaxmp(lf);
|
|
|
|
// magic resistance means you can't regenerate mana!
|
|
if (skillcheck(lf, SC_RESISTMAG, 20, 0)) {
|
|
return;
|
|
}
|
|
|
|
if (lf->mp < max) {
|
|
lf->mp += amt;
|
|
gained = B_TRUE;
|
|
}
|
|
|
|
if (lf->mp >= max) {
|
|
lf->mp = max;
|
|
if (gained) maxed = B_TRUE;
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
if (maxed) {
|
|
msg("Your mana is now fully restored.");
|
|
}
|
|
if (gained) {
|
|
statdirty = B_TRUE;
|
|
drawstatus();
|
|
updatestatus();
|
|
}
|
|
}
|
|
}
|
|
|
|
void gainxp(lifeform_t *lf, long amt) {
|
|
if (lfhasflag(lf, F_HASNEWLEVEL)) {
|
|
// can't gain any more xp until you do training
|
|
return;
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
// level 0 lifeforms can't gain xp
|
|
if (lf->level == 0) return;
|
|
|
|
lf->xp += amt;
|
|
|
|
// ready for next level? can only go up ONE level.
|
|
if (lf->xp >= getxpforlev(lf->level + 1)) {
|
|
gainlevel(lf); // this will increment 'newlevel'
|
|
}
|
|
}
|
|
|
|
int getactspeed(lifeform_t *lf) {
|
|
int speed = 0;
|
|
flag_t *f;
|
|
|
|
f = lfhasflag(lf, F_ACTIONSPEED);
|
|
if (f) {
|
|
speed = f->val[0];
|
|
} else {
|
|
speed = SPEED_ACTION; // default
|
|
}
|
|
|
|
// modifier?
|
|
for (f = lf->flags->first ; f ; f = f->next ){
|
|
if ((f->id == F_SLOWACT) || (f->id == F_SLOWACTMOVE)) {
|
|
speed += f->val[0];
|
|
} else if ((f->id == F_FASTACT) || (f->id == F_FASTACTMOVE)) {
|
|
speed -= f->val[0];
|
|
}
|
|
}
|
|
|
|
switch (isburdened(lf)) {
|
|
case BR_NONE:
|
|
break;
|
|
case BR_BURDENED:
|
|
speed += 5;
|
|
break;
|
|
case BR_STRAINED:
|
|
case BR_OVERLOADED:
|
|
speed += 10;
|
|
break;
|
|
}
|
|
|
|
adjustspeedforwater(lf, &speed);
|
|
|
|
if (speed < 1) speed = 1;
|
|
|
|
return speed;
|
|
}
|
|
|
|
void getadjallies(lifeform_t *lf, lifeform_t **adjally, int *nadjallies) {
|
|
int d;
|
|
for (d = DC_N; d <= DC_NW; d++) {
|
|
cell_t *c;
|
|
c = getcellindir(lf->cell, d);
|
|
if (c && c->lf) {
|
|
if (areallies(lf, c->lf) || areenemies(lf, c->lf)) {
|
|
if (!isimmobile(c->lf)) {
|
|
adjally[*nadjallies] = c->lf;
|
|
(*nadjallies)++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum ALLEGIENCE getallegiance(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = lfhasflag(lf, F_CHARMEDBY);
|
|
if (f) {
|
|
lifeform_t *cb;
|
|
cb = findlf(NULL, f->val[0]);
|
|
if (cb) {
|
|
return getallegiance(cb);
|
|
} else {
|
|
killflag(f);
|
|
}
|
|
}
|
|
if (isplayer(lf) || isfriendly(lf)) {
|
|
return AL_FRIENDLY;
|
|
} else if (ispeaceful(lf)) {
|
|
return AL_PEACEFUL;
|
|
}
|
|
return AL_HOSTILE;
|
|
}
|
|
|
|
int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs) {
|
|
object_t *o;
|
|
enum BODYPART bp;
|
|
*nobs = 0;
|
|
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
|
|
o = getouterequippedob(lf, bp);
|
|
if (o) {
|
|
int n,found = B_FALSE;
|
|
// already got htis one?
|
|
for (n = 0; n < *nobs; n++) {
|
|
if (ob[n]->id == o->id) {
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
if (!found) {
|
|
ob[*nobs] = o;
|
|
(*nobs)++;
|
|
}
|
|
}
|
|
}
|
|
return *nobs;
|
|
}
|
|
|
|
object_t *getarmour(lifeform_t *lf, enum BODYPART bp) {
|
|
object_t *o;
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isarmour(o) && isequippedon(o, bp)) {
|
|
return o;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int getarmourrating(lifeform_t *lf) {
|
|
object_t *o;
|
|
flag_t *f;
|
|
int ar = 0;
|
|
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_ARMOURRATING) {
|
|
ar += f->val[0];
|
|
}
|
|
if (f->id == F_MAGICARMOUR) {
|
|
ar += f->val[0];
|
|
}
|
|
if (f->id == F_PHALANX) {
|
|
int dir;
|
|
cell_t *c;
|
|
int nmatched = 0;
|
|
// count adjacent allies of name xx
|
|
for (dir = DC_N; dir <= DC_NW; dir++) {
|
|
c = getcellindir(lf->cell, dir);
|
|
if (c && c->lf) {
|
|
if (strcasestr(c->lf->race->name, f->text)) {
|
|
nmatched++;
|
|
}
|
|
}
|
|
}
|
|
if (nmatched >= f->val[2]) {
|
|
ar += f->val[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (hasflag(o->flags, F_EQUIPPED)) {
|
|
f = hasflag(o->flags, F_ARMOURRATING);
|
|
if (f) {
|
|
float thisar;
|
|
|
|
thisar = f->val[0];
|
|
|
|
// adjust for skill
|
|
if (hasflag(o->flags, F_SHIELD)) {
|
|
switch (getskill(lf, SK_SHIELDS)) {
|
|
case PR_INEPT:
|
|
thisar *= 0.5;
|
|
break;
|
|
case PR_NOVICE:
|
|
break;
|
|
case PR_BEGINNER:
|
|
thisar *= 1.2;
|
|
break;
|
|
case PR_ADEPT:
|
|
thisar *= 1.4;
|
|
break;
|
|
case PR_SKILLED:
|
|
thisar *= 1.6;
|
|
break;
|
|
case PR_EXPERT:
|
|
thisar *= 1.8;
|
|
break;
|
|
case PR_MASTER:
|
|
thisar *= 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// adjust for condition
|
|
thisar = pctof(getobhppct(o), thisar);
|
|
|
|
ar += thisar;
|
|
|
|
ar += getobbonus(o);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ar;
|
|
}
|
|
|
|
// how far away should we be before attacking?
|
|
|
|
int getattackspeed(lifeform_t *lf) {
|
|
object_t *w;
|
|
float speed;
|
|
speed = getactspeed(lf);
|
|
|
|
w = getweapon(lf);
|
|
if (w) {
|
|
speed *= ((float)getobattackdelay(w) / 100.0);
|
|
}
|
|
|
|
return (int)speed;
|
|
}
|
|
|
|
int getattpoints(lifeform_t *lf) {
|
|
flag_t *f;
|
|
int attpoints = 0;
|
|
f = lfhasflag(lf, F_STATGAINREADY);
|
|
if (f) {
|
|
attpoints = f->val[2];
|
|
}
|
|
return attpoints;
|
|
}
|
|
|
|
int getattr(lifeform_t *lf, enum ATTRIB attr) {
|
|
return real_getattr(lf, attr, B_FALSE);
|
|
}
|
|
|
|
int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) {
|
|
int val = 0;
|
|
flag_t *f;
|
|
|
|
// override?
|
|
if (!ignoreattrset) {
|
|
f = lfhasflagval(lf, F_ATTRSET, attr, NA, NA, NULL);
|
|
if (f) {
|
|
return f->val[1];
|
|
}
|
|
}
|
|
|
|
// base attribute
|
|
val = lf->att[attr];
|
|
// modified?
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if ((f->id == F_ATTRMOD) && (f->val[0] == attr)) {
|
|
val += f->val[1];
|
|
}
|
|
}
|
|
|
|
if (val < 0) val = 0;
|
|
|
|
return val;
|
|
}
|
|
|
|
// returns average damage per turn, modified by accuracy
|
|
int getavgdam(lifeform_t *lf, int forxp) {
|
|
obpile_t *op;
|
|
int avgdam = 0;
|
|
int db = B_FALSE;
|
|
flag_t *f;
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
db = B_TRUE;
|
|
}
|
|
|
|
op = addobpile(NULL, NULL);
|
|
for (f = lf->race->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_HASATTACK) {
|
|
int min,max;
|
|
float thisavg;
|
|
object_t *o;
|
|
float acc;
|
|
flag_t *of;
|
|
|
|
objecttype_t *ot;
|
|
ot = findot(f->val[0]);
|
|
o = addob(op, ot->name);
|
|
|
|
getdamrange(f, &min,&max);
|
|
thisavg = ((float)min + (float)max) / 2.0;
|
|
|
|
// confers anything?
|
|
for (of = o->flags->first ; of ; of = of->next) {
|
|
if (of->id == F_HITCONFER) {
|
|
flag_t *valflag;
|
|
int maxlifetime;
|
|
// get max lifetime
|
|
gethitconferlifetime(f->text, NULL, &maxlifetime);
|
|
valflag = hasflag(o->flags, F_HITCONFERVALS);
|
|
assert(valflag);
|
|
// assign xp based on what is conferred
|
|
switch (of->val[0]) {
|
|
case F_POISONED:
|
|
// sum up poison power
|
|
thisavg += (maxlifetime * valflag->val[1]);
|
|
break;
|
|
default:
|
|
thisavg += 10;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// modify for accuracy
|
|
acc = getlfaccuracy(lf, o);
|
|
thisavg = pctof(acc, thisavg);
|
|
|
|
avgdam += thisavg;
|
|
if (db) {
|
|
char obname[BUFLEN];
|
|
getobname(o,obname,1);
|
|
if (db) dblog("getavgdam: %s: == %d-%d dam, avg is %0.1f",obname, min, max, thisavg);
|
|
}
|
|
} else if (forxp && (f->id == F_STARTOB)) {
|
|
object_t *o;
|
|
int min,max;
|
|
float thisavg;
|
|
float acc;
|
|
flag_t *of;
|
|
obpile_t *op2;
|
|
|
|
op2 = addobpile(NULL,NULL);
|
|
|
|
o = addob(op2, f->text);
|
|
|
|
getdamrange(hasflag(o->flags, F_DAM), &min,&max);
|
|
thisavg = ((float)min + (float)max) / 2.0;
|
|
|
|
// confers anything?
|
|
for (of = o->flags->first ; of ; of = of->next) {
|
|
if (of->id == F_HITCONFER) {
|
|
thisavg += 10;
|
|
}
|
|
}
|
|
|
|
// modify for accuracy
|
|
acc = getlfaccuracy(lf, o);
|
|
thisavg = pctof(acc, thisavg);
|
|
|
|
avgdam += thisavg;
|
|
if (db) {
|
|
char obname[BUFLEN];
|
|
getobname(o,obname,1);
|
|
if (db) dblog("getavgdam: %s: == %d-%d dam, avg is %0.1f",obname, min, max, thisavg);
|
|
}
|
|
|
|
killobpile(op2);
|
|
}
|
|
}
|
|
|
|
|
|
if (!forxp) {
|
|
object_t *w;
|
|
// current weapon...
|
|
w = getweapon(lf);
|
|
if (w) {
|
|
float thisavg,acc;
|
|
float dammod;
|
|
int bonus = 0,mindam,maxdam;
|
|
// damage
|
|
f = hasflag(w->flags, F_BONUS);
|
|
if (f) {
|
|
// only tell player about bonuses if they are known.!
|
|
bonus = f->val[0];
|
|
} else {
|
|
bonus = 0;
|
|
}
|
|
|
|
f = hasflag(w->flags, F_DAM);
|
|
if (f) {
|
|
getdamrange(f, &mindam, &maxdam);
|
|
} else {
|
|
mindam = 0;
|
|
maxdam = 0;
|
|
}
|
|
|
|
mindam += bonus;
|
|
maxdam += bonus;
|
|
|
|
dammod = getstrdammod(lf);
|
|
// apply damage mod for strength
|
|
if (!hasflag(w->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) {
|
|
mindam = (int)((float)mindam * dammod);
|
|
maxdam = (int)((float)maxdam * dammod);
|
|
}
|
|
|
|
if (mindam < 0) mindam = 0;
|
|
if (maxdam < 0) maxdam = 0;
|
|
|
|
thisavg = (((float)(mindam + maxdam)) / 2);
|
|
acc = getlfaccuracy(lf, w);
|
|
thisavg = pctof(acc, thisavg);
|
|
|
|
avgdam += thisavg;
|
|
}
|
|
}
|
|
|
|
if (op) killobpile(op);
|
|
|
|
return (int)avgdam;
|
|
}
|
|
|
|
float getequippedweight(lifeform_t *lf) {
|
|
object_t *o;
|
|
float total = 0;
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isequipped(o) && isarmour(o)) {
|
|
total += getobweight(o);
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int getevasion(lifeform_t *lf) {
|
|
object_t *o;
|
|
flag_t *f;
|
|
int ev = 0;
|
|
|
|
// no evasion if you can't move!
|
|
if (isimmobile(lf)) {
|
|
return 0;
|
|
}
|
|
|
|
// natural evasion
|
|
f = hasflag(lf->flags, F_EVASION);
|
|
if (f) {
|
|
// evasion 10 means -10% penalty to hit you
|
|
ev += (f->val[0]);
|
|
if (ev < 0) ev = 0;
|
|
}
|
|
|
|
// now get object penalties/bonuses
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
// armour/weapons must be worn to do anything
|
|
if (hasflag(o->flags, F_EQUIPPED)) {
|
|
f = hasflag(o->flags, F_EVASION);
|
|
if (f) {
|
|
if (isarmour(o)) {
|
|
// adjust penalties based on armour skill.
|
|
ev += adjustarmourpenalty(lf, f->val[0]);
|
|
} else {
|
|
ev += (f->val[0]);
|
|
}
|
|
if (ev < 0) ev = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// dexterity mod
|
|
ev += (getstatmod(lf, A_DEX) / 2);
|
|
if (ev < 0) ev = 0;
|
|
|
|
// you are easier to hit if you're glowing
|
|
if (hasflag(lf->flags, F_PRODUCESLIGHT)) {
|
|
ev -= 5;
|
|
if (ev < 0) ev = 0;
|
|
}
|
|
|
|
// modify for stickiness
|
|
if (hasobwithflag(lf->cell->obpile, F_RESTRICTMOVEMENT)) {
|
|
ev -= 50;
|
|
}
|
|
if (ev < 0) ev = 0;
|
|
|
|
// modify for blindness
|
|
if (isblind(lf)) {
|
|
ev -= 15;
|
|
}
|
|
if (ev < 0) ev = 0;
|
|
|
|
|
|
return ev;
|
|
|
|
}
|
|
|
|
object_t *getbestthrowmissile(lifeform_t *lf) {
|
|
object_t *bestwep = NULL;
|
|
int bestdam = -1;
|
|
object_t *o;
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (!isequipped(o) && isthrowmissile(o) ) {
|
|
int thisdam;
|
|
// better than last one?
|
|
thisdam = getthrowdam(o) + getshatterdam(o);
|
|
if ((bestwep == NULL) || (thisdam > bestdam)) {
|
|
bestwep = o;
|
|
bestdam = thisdam;
|
|
}
|
|
|
|
}
|
|
}
|
|
return bestwep;
|
|
}
|
|
|
|
object_t *getbestfirearm(lifeform_t *lf) {
|
|
object_t *bestgun = NULL;
|
|
object_t *o;
|
|
int bestfirespeed = -1;
|
|
|
|
|
|
bestgun = NULL;
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
// if it is a gun and we can weild it...
|
|
if (isfirearm(o) && (isequipped(o) || canweild(lf, o))) {
|
|
int thisfirespeed;
|
|
thisfirespeed = getfirearmspeed(o);
|
|
if (thisfirespeed > bestfirespeed) {
|
|
bestgun = o;
|
|
bestfirespeed = thisfirespeed;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bestgun;
|
|
}
|
|
|
|
|
|
object_t *getbestweapon(lifeform_t *lf) {
|
|
//obpile_t *op = NULL;
|
|
object_t *bestwep = NULL;
|
|
//int bestmaxdam = -999;
|
|
object_t *o;
|
|
|
|
bestwep = getweapon(lf);
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
// if it does damage and we can weild it...
|
|
if (isweapon(o) && !isfirearm(o) && canweild(lf, o)) {
|
|
if (isbetterwepthan(o, bestwep)) {
|
|
bestwep = o;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (op && (bestwep == op->first)) {
|
|
// ie. use no weapon
|
|
bestwep = NULL;
|
|
}
|
|
|
|
if (op) {
|
|
killobpile(op);
|
|
}
|
|
*/
|
|
|
|
return bestwep;
|
|
}
|
|
|
|
|
|
int getbodyparthitchance(enum BODYPART bp) {
|
|
switch (bp) {
|
|
case BP_EYES: return 1;
|
|
case BP_HEAD: return 2;
|
|
case BP_WAIST: return 3;
|
|
case BP_HANDS: return 3;
|
|
case BP_FEET: return 3;
|
|
case BP_LEGS: return 4;
|
|
case BP_SHOULDERS: return 4;
|
|
case BP_BODY: return 5;
|
|
default: break;
|
|
}
|
|
return 0; // ie rings, weapon
|
|
}
|
|
|
|
char *getbodypartname(enum BODYPART bp) {
|
|
switch (bp) {
|
|
case BP_WEAPON:
|
|
return "right hand";
|
|
case BP_SECWEAPON:
|
|
return "left hand";
|
|
case BP_RIGHTHAND:
|
|
return "right finger";
|
|
case BP_LEFTHAND:
|
|
return "left finger";
|
|
case BP_HANDS:
|
|
return "hands";
|
|
case BP_EYES:
|
|
return "eyes";
|
|
case BP_HEAD:
|
|
return "head";
|
|
case BP_BODY:
|
|
return "body";
|
|
case BP_SHOULDERS:
|
|
return "shoulders";
|
|
case BP_WAIST:
|
|
return "waist";
|
|
case BP_LEGS:
|
|
return "legs";
|
|
case BP_FEET:
|
|
return "feet";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
char *getbodypartequipname(enum BODYPART bp) {
|
|
switch (bp) {
|
|
case BP_WEAPON:
|
|
case BP_SECWEAPON:
|
|
return "in"; // ie. 'in right hand'
|
|
case BP_RIGHTHAND:
|
|
case BP_LEFTHAND:
|
|
case BP_HANDS:
|
|
case BP_HEAD:
|
|
case BP_BODY:
|
|
case BP_LEGS:
|
|
case BP_FEET:
|
|
return "on";
|
|
case BP_EYES:
|
|
case BP_SHOULDERS:
|
|
return "over";
|
|
case BP_WAIST:
|
|
return "around";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
object_t *getequippedob(obpile_t *op, enum BODYPART bp) {
|
|
object_t *o;
|
|
for (o = op->first; o ; o = o->next) {
|
|
if (hasflagval(o->flags, F_EQUIPPED, bp, NA, NA, NULL)) {
|
|
return o;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
object_t *getfirearm(lifeform_t *lf) {
|
|
object_t *o;
|
|
o = getequippedob(lf->pack, BP_SECWEAPON);
|
|
if (o && isfirearm(o)) {
|
|
return o;
|
|
}
|
|
o = getequippedob(lf->pack, BP_WEAPON);
|
|
if (o && hasflag(o->flags, F_FIREARM)) {
|
|
return o;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int getfootprinttime(lifeform_t *lf) {
|
|
int time;
|
|
|
|
time = FOOTPRINTTIME;
|
|
switch (getlfsize(lf)) {
|
|
case SZ_MINI: time = 1; break;
|
|
case SZ_TINY: time -= 15; break;
|
|
case SZ_SMALL: time -= 10; break;
|
|
default: break;
|
|
case SZ_LARGE: time += 10; break;
|
|
case SZ_HUGE: time += 20; break;
|
|
case SZ_ENORMOUS: time += 30; break;
|
|
}
|
|
|
|
if (time > 0) {
|
|
if (getskill(lf, SK_TRACKING) == PR_EXPERT) {
|
|
time /= 2;
|
|
limit(&time, 1, NA);
|
|
}
|
|
}
|
|
return time;
|
|
}
|
|
|
|
lifeform_t *getguntarget(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = hasflag(lf->flags, F_GUNTARGET);
|
|
if (!f) {
|
|
return NULL;
|
|
}
|
|
return findlf(NULL, f->val[0]);
|
|
}
|
|
|
|
int getguntargetid(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = hasflag(lf->flags, F_GUNTARGET);
|
|
if (!f) {
|
|
return -1;
|
|
}
|
|
return f->val[0];
|
|
}
|
|
|
|
|
|
/*
|
|
// get time to heal 1 hp
|
|
int gethealtime(lifeform_t *lf) {
|
|
int healtime;
|
|
flag_t *f;
|
|
f = lfhasflag(lf, F_HEALTIME);
|
|
if (f) {
|
|
healtime = f->val[0];
|
|
} else {
|
|
healtime = DEF_HEALTIME;
|
|
}
|
|
return healtime;
|
|
}
|
|
*/
|
|
|
|
int gethearingrange(lifeform_t *lf) {
|
|
int range = 8; // deafult
|
|
range = 2 + (getskill(lf, SK_LISTEN)*2);
|
|
return range;
|
|
}
|
|
|
|
int gethidemodifier(lifeform_t *lf) {
|
|
int modifier = 0;
|
|
|
|
reason = E_OK;
|
|
if (!safetorest(lf)) {
|
|
if (getskill(lf, SK_STEALTH) == PR_EXPERT) {
|
|
// can still hide, but with a modifier
|
|
modifier = -4;
|
|
} else if (getskill(lf, SK_STEALTH) == PR_MASTER) {
|
|
// can still hide, but with a modifier
|
|
modifier = -2;
|
|
} else {
|
|
reason = E_IMPOSSIBLE;
|
|
modifier = -100; // special case
|
|
}
|
|
}
|
|
|
|
// no stealth skill?
|
|
if (!getskill(lf, SK_STEALTH)) {
|
|
modifier = -5;
|
|
}
|
|
return modifier;
|
|
}
|
|
|
|
int gethitdice(lifeform_t *lf) {
|
|
if (isplayer(lf) || lfhasflag(lf, F_VARLEVEL)) {
|
|
return lf->level;
|
|
}
|
|
return (lf->maxhp / 4);
|
|
}
|
|
|
|
int gethppct(lifeform_t *lf) {
|
|
float pct;
|
|
pct = (int)(((float)lf->hp / (float)lf->maxhp) * 100);
|
|
return pct;
|
|
}
|
|
|
|
enum HUNGER gethungerlevel(int hunger) {
|
|
int thresh = HUNGERCONST;
|
|
if (hunger < -thresh) {
|
|
return H_STUFFED;
|
|
} else if (hunger < 0) {
|
|
return H_FULL;
|
|
} else if (hunger <= thresh) {
|
|
return H_NONE;
|
|
} else if (hunger <= (thresh*2)) {
|
|
return H_PECKISH;
|
|
} else if (hunger <= (thresh*3)) {
|
|
return H_HUNGRY;
|
|
} else if (hunger <= (thresh*4)) {
|
|
return H_VHUNGRY;
|
|
} else if (hunger <= (thresh*5)) {
|
|
return H_STARVING;
|
|
}
|
|
return H_STARVED;
|
|
}
|
|
|
|
char *gethungername(enum HUNGER hunger, char *buf) {
|
|
switch (hunger) {
|
|
case H_STUFFED:
|
|
strcpy(buf, "stuffed");
|
|
break;
|
|
case H_FULL:
|
|
strcpy(buf, "full");
|
|
break;
|
|
case H_NONE:
|
|
strcpy(buf, "not hungry");
|
|
break;
|
|
case H_PECKISH:
|
|
strcpy(buf, "peckish");
|
|
break;
|
|
case H_HUNGRY:
|
|
strcpy(buf, "hungry");
|
|
break;
|
|
case H_VHUNGRY:
|
|
strcpy(buf, "very hungry");
|
|
break;
|
|
case H_STARVING:
|
|
strcpy(buf, "starving");
|
|
break;
|
|
case H_STARVED:
|
|
strcpy(buf, "starved");
|
|
break;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
int gethungerval(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = hasflag(lf->flags, F_HUNGER);
|
|
if (f) {
|
|
return f->val[0];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
job_t *getjob(lifeform_t *lf) {
|
|
flag_t *f;
|
|
|
|
// no job if polymorphed
|
|
if (lfhasflag(lf, F_POLYMORPHED)) {
|
|
return NULL;
|
|
}
|
|
|
|
f = hasflag(lf->flags, F_JOB);
|
|
if (f) {
|
|
return findjob(f->val[0]);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int getlastdir(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = lfhasflag(lf, F_LASTDIR);
|
|
if (f) {
|
|
return f->val[0];
|
|
}
|
|
return D_NONE;
|
|
}
|
|
|
|
int getlfaccuracy(lifeform_t *lf, object_t *wep) {
|
|
flag_t *f;
|
|
int acc = 0;
|
|
|
|
// get weapon
|
|
if (wep) {
|
|
acc = getobaccuracy(wep, lf);
|
|
}
|
|
|
|
// dual weilding?
|
|
if (isdualweilding(lf)) {
|
|
switch (getskill(lf, SK_TWOWEAPON)) {
|
|
case PR_INEPT: acc -= 100; break;
|
|
case PR_NOVICE: acc -= 20; break;
|
|
case PR_BEGINNER: acc -= 10; break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
|
|
for (f = lf->flags->first ;f ; f = f->next) {
|
|
if (f->id == F_ACCURACYMOD) {
|
|
acc += f->val[0];
|
|
} else if (f->id == F_SHIELDPENALTY) {
|
|
acc -= adjustshieldpenalty(lf, f->val[0]);
|
|
}
|
|
}
|
|
|
|
// modify for weilder's level
|
|
acc += (lf->level * 2);
|
|
|
|
if (lfhasflag(lf, F_RAGE)) {
|
|
// assume maximum dex
|
|
acc += 50;
|
|
} else {
|
|
int dexmod;
|
|
// modify with dexterity
|
|
dexmod = getstatmod(lf, A_DEX);
|
|
// double dex penalties when dual weilding
|
|
if (isdualweilding(lf) && (dexmod < 0)) {
|
|
dexmod *= 2;
|
|
}
|
|
acc += dexmod;
|
|
}
|
|
|
|
// modify for blindness
|
|
if (isblind(lf)) {
|
|
acc -= 50;
|
|
}
|
|
// modify for being on the ground
|
|
if (isprone(lf)) {
|
|
acc -= 30;
|
|
}
|
|
// modify for swimming
|
|
if (isswimming(lf) && !isaquatic(lf)) {
|
|
switch (getskill(lf, SK_SWIMMING)) {
|
|
// you can't attack until you are at
|
|
// expert or better.
|
|
default: acc = 0; break;
|
|
case PR_EXPERT: acc -= 20; break;
|
|
case PR_MASTER: break; // no penalty
|
|
}
|
|
}
|
|
|
|
// modify for drunkenness
|
|
f = isdrunk(lf);
|
|
if (f) {
|
|
int amt;
|
|
amt = (f->lifetime/DRUNKTIME)+1;
|
|
if (hasjob(lf, J_PIRATE)) {
|
|
acc += (10*amt);
|
|
} else {
|
|
acc -= (10*amt);
|
|
}
|
|
}
|
|
|
|
// modify for nausea
|
|
if (lfhasflag(lf, F_NAUSEATED)) {
|
|
acc -= 25;
|
|
}
|
|
|
|
// modify for stickiness
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
if (hasobwithflag(lf->cell->obpile, F_RESTRICTMOVEMENT)) {
|
|
acc -= 25;
|
|
}
|
|
}
|
|
|
|
if (acc < 0) acc = 0;
|
|
return acc;
|
|
}
|
|
|
|
|
|
enum LFCONDITION getlfcondition(lifeform_t *lf) {
|
|
float hp,maxhp;
|
|
int pct;
|
|
hp = lf->hp;
|
|
maxhp = lf->maxhp;
|
|
pct = (int)((hp / maxhp) * 100.0);
|
|
if (pct == 100) {
|
|
return C_HEALTHY;
|
|
} else if (pct >= 80) {
|
|
return C_HURT;
|
|
} else if (pct >= 50) {
|
|
return C_WOUNDED;
|
|
} else if (pct >= 25) {
|
|
return C_SERIOUS;
|
|
} else if (pct > 0) {
|
|
return C_CRITICAL;
|
|
}
|
|
// ie. <= 0
|
|
return C_DEAD;
|
|
}
|
|
|
|
int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions) {
|
|
flag_t *f;
|
|
lifeform_t *min;
|
|
*nminions = 0;
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_MINION) {
|
|
min = findlf(lf->cell->map, f->val[0]);
|
|
if (min) {
|
|
(minion[*nminions]) = min;
|
|
(*nminions)++;
|
|
}
|
|
}
|
|
}
|
|
return *nminions;
|
|
}
|
|
|
|
int getnightvisrange(lifeform_t *lf) {
|
|
int range = -1; // default
|
|
flag_t *f;
|
|
|
|
f = lfhasflag(lf, F_SEEINDARK);
|
|
if (f && !isblind(lf)) {
|
|
if (f->val[0] == UNLIMITED) {
|
|
range = getvisrange(lf);
|
|
} else {
|
|
range = f->val[0];
|
|
}
|
|
} else {
|
|
f = lfhasflag(lf, F_TREMORSENSE);
|
|
if (f) {
|
|
return f->val[0];
|
|
}
|
|
}
|
|
|
|
return range;
|
|
}
|
|
|
|
char *getlfconditionname(enum LFCONDITION cond) {
|
|
switch (cond) {
|
|
case C_CRITICAL:
|
|
return "critically wounded";
|
|
case C_SERIOUS:
|
|
return "seriously wounded";
|
|
case C_WOUNDED:
|
|
return "wounded";
|
|
case C_HURT:
|
|
return "hurt";
|
|
case C_HEALTHY:
|
|
return "healthy";
|
|
case C_DEAD:
|
|
return "dead";
|
|
}
|
|
return "?unknown condition?";
|
|
}
|
|
|
|
object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp) {
|
|
object_t *o;
|
|
switch (bp) {
|
|
case BP_RIGHTHAND:
|
|
case BP_LEFTHAND:
|
|
o = getequippedob(lf->pack, BP_HANDS);
|
|
if (o) return o;
|
|
else return getequippedob(lf->pack, bp);
|
|
break;
|
|
case BP_BODY:
|
|
o = getequippedob(lf->pack, BP_SHOULDERS);
|
|
if (o) return o;
|
|
else return getequippedob(lf->pack, bp);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return getequippedob(lf->pack, bp);
|
|
}
|
|
|
|
// return the healthiest possible hurt condition that 'lf' will
|
|
// recognise when looking at someone else.
|
|
//
|
|
// this is based on intelligence and firstaid skill
|
|
enum LFCONDITION getseenlfconditioncutoff(lifeform_t *lf) {
|
|
enum IQBRACKET iqb;
|
|
enum SKILLLEVEL slev;
|
|
enum LFCONDITION cutoff;
|
|
|
|
// intelligence higher than 'average' doesn't count.
|
|
iqb = getiqname(getattr(lf, A_IQ), NULL);
|
|
if (iqb > IQ_AVERAGE) iqb = IQ_AVERAGE;
|
|
|
|
// adjust for firstaid skill
|
|
slev = getskill(lf, SK_FIRSTAID);
|
|
iqb += slev;
|
|
|
|
// figure out health cutoff - condition > cutoff gets no description
|
|
if (iqb >= IQ_GENIUS) {
|
|
cutoff = C_HEALTHY; //
|
|
} else if (iqb >= IQ_AVERAGE) {
|
|
cutoff = C_HURT; // ie. no real cutoff
|
|
} else if (iqb >= IQ_DOPEY) {
|
|
cutoff = C_WOUNDED;
|
|
} else if (iqb >= IQ_ANIMAL) {
|
|
cutoff = C_SERIOUS;
|
|
} else {
|
|
cutoff = C_DEAD;
|
|
}
|
|
return cutoff;
|
|
}
|
|
|
|
char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer) {
|
|
enum LFCONDITION cond,cutoff;
|
|
|
|
cutoff = getseenlfconditioncutoff(viewer);
|
|
|
|
cond = getlfcondition(lf);
|
|
if (cond > cutoff) {
|
|
return "";
|
|
}
|
|
return getlfconditionname(cond);
|
|
}
|
|
|
|
glyph_t *getlfglyph(lifeform_t *lf) {
|
|
flag_t *f;
|
|
/*
|
|
if (isplayer(lf) && !ispolymorphed(lf)) {
|
|
return &playerglyph;
|
|
}
|
|
*/
|
|
|
|
f = lfhasflag(lf, F_GLYPH);
|
|
if (f) {
|
|
tempglyph.ch = f->text[0];
|
|
return &tempglyph;
|
|
}
|
|
|
|
return &lf->race->glyph;
|
|
}
|
|
|
|
enum MATERIAL getlfmaterial(lifeform_t *lf) {
|
|
if (lf->race->id == R_DANCINGWEAPON) {
|
|
object_t *wep;
|
|
wep = getweapon(lf);
|
|
if (wep) {
|
|
return wep->material->id;
|
|
}
|
|
}
|
|
|
|
return lf->race->material->id;
|
|
}
|
|
|
|
enum SKILLLEVEL getlorelevel(lifeform_t *lf, enum RACECLASS rcid) {
|
|
enum SKILLLEVEL slev = PR_INEPT;
|
|
raceclass_t *rc;
|
|
rc = findraceclass(rcid);
|
|
if (rc) {
|
|
slev = getskill(lf, rc->skill);
|
|
}
|
|
return slev;
|
|
}
|
|
|
|
int getmaxattacks(lifeform_t *lf) {
|
|
flag_t *f;
|
|
int maxattacks;
|
|
f = lfhasflag(lf, F_MAXATTACKS);
|
|
if (f) {
|
|
maxattacks = f->val[0];
|
|
} else {
|
|
maxattacks = countinnateattacks(lf);
|
|
}
|
|
|
|
// if we have high unarmed skill and our second hand is free,
|
|
// we get one more attack
|
|
if (getskill(lf, SK_UNARMED) >= PR_ADEPT) {
|
|
if (!getequippedob(lf->pack, BP_SECWEAPON)) {
|
|
maxattacks++;
|
|
}
|
|
}
|
|
|
|
if (getskill(lf, SK_TWOWEAPON) && isdualweilding(lf)) {
|
|
maxattacks++;
|
|
}
|
|
return maxattacks;
|
|
}
|
|
|
|
float getmaxcarryweight(lifeform_t *lf) {
|
|
float max;
|
|
float mod;
|
|
enum STRBRACKET sbrack;
|
|
|
|
sbrack = getstrname(getattr(lf, A_STR), NULL);
|
|
switch (sbrack) {
|
|
case ST_HELPLESS:
|
|
mod = 0.1; break;
|
|
case ST_FEEBLE:
|
|
mod = 0.25; break;
|
|
case ST_VWEAK:
|
|
mod = 0.5; break;
|
|
case ST_WEAK:
|
|
mod = 0.75; break;
|
|
case ST_AVERAGE:
|
|
mod = 1; break; // your body weight
|
|
case ST_STRONG:
|
|
mod = 1.25; break;
|
|
case ST_MIGHTY:
|
|
mod = 1.5; break;
|
|
case ST_TITANIC:
|
|
mod = 2; break; // twice your own body weight
|
|
default:
|
|
mod = 1; break; // your body weight
|
|
}
|
|
|
|
max = getlfweight(lf, B_NOOBS) * mod;
|
|
|
|
return max;
|
|
}
|
|
|
|
/*
|
|
float getmaxliftweight(lifeform_t *lf) {
|
|
float max;
|
|
float mod;
|
|
enum STRBRACKET sbrack;
|
|
|
|
sbrack = getstrname(getattr(lf, A_STR), NULL);
|
|
switch (sbrack) {
|
|
case ST_HELPLESS:
|
|
mod = 0.05; break;
|
|
case ST_FEEBLE:
|
|
mod = 0.1; break;
|
|
case ST_VWEAK:
|
|
mod = 0.25; break;
|
|
case ST_WEAK:
|
|
mod = 0.4; break;
|
|
case ST_AVERAGE:
|
|
mod = 0.5; break; // half your body weight
|
|
case ST_STRONG:
|
|
mod = 0.75; break;
|
|
case ST_MIGHTY:
|
|
mod = 1; break; // your own body weight
|
|
case ST_TITANIC:
|
|
mod = 1.5; break; // more than your own body weight
|
|
}
|
|
|
|
max = getlfweight(lf, B_NOOBS) * mod;
|
|
|
|
return max;
|
|
}
|
|
*/
|
|
|
|
int getmaxmp(lifeform_t *lf) {
|
|
flag_t *f;
|
|
int activemp = 0;
|
|
int maxmp;
|
|
int extrapct = 0;
|
|
|
|
// base
|
|
maxmp = lf->maxmp;
|
|
|
|
// extras
|
|
sumflags(lf->flags, F_EXTRAMP, &extrapct, NULL, NULL);
|
|
maxmp += pctof(maxmp, extrapct);
|
|
|
|
// losses
|
|
activemp = 0;
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_BOOSTSPELL) {
|
|
activemp += f->val[1];
|
|
}
|
|
}
|
|
maxmp -= activemp;
|
|
//if (maxmp < 0) maxmp = 0; // ????
|
|
|
|
return maxmp;
|
|
}
|
|
|
|
float getmaxpushweight(lifeform_t *lf) {
|
|
float max;
|
|
max = getlfweight(lf, B_NOOBS) * 2; // twice your body weight
|
|
return max;
|
|
}
|
|
|
|
int getmr(lifeform_t *lf) {
|
|
int amt = 0;
|
|
|
|
sumflags(lf->flags, F_RESISTMAG, &amt, NULL, NULL);
|
|
|
|
return amt;
|
|
}
|
|
|
|
|
|
int getvisrange(lifeform_t *lf) {
|
|
int range;
|
|
flag_t *f;
|
|
|
|
if (isblind(lf)) {
|
|
return 0;
|
|
}
|
|
|
|
f = lfhasflag(lf, F_VISRANGE);
|
|
if (f) {
|
|
range = f->val[0];
|
|
} else {
|
|
range = MAXVISRANGE;
|
|
}
|
|
|
|
// modify for darkness outside ?
|
|
if ((range > 0) && isoutdoors(lf->cell->map)) {
|
|
int hours,mins,secs;
|
|
float pct;
|
|
splittime(&hours,&mins,&secs);
|
|
pct = ((float)mins/59.0) * 100.0;
|
|
if (hours == 6) { // ie. 6am - 7am
|
|
// getting lighter. as minutes approach 59,
|
|
// visrange gets closer to maximum.
|
|
range = pctof( pct, range);
|
|
limit(&range, 1, NA);
|
|
} else if (hours == 18) { // ie. 6pm-7pm
|
|
// getting darker. as minutes approach 59,
|
|
// visrange gets closer to zero.
|
|
range = pctof( 100 - pct, range);
|
|
limit(&range, 1, NA);
|
|
}
|
|
}
|
|
|
|
// modifications?
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_VISRANGEMOD) {
|
|
range += f->val[0];
|
|
}
|
|
}
|
|
|
|
if (range < 0) range = 0;
|
|
return range;
|
|
}
|
|
|
|
int getmovespeed(lifeform_t *lf) {
|
|
int speed = 0;
|
|
flag_t *f;
|
|
|
|
f = lfhasflag(lf, F_MOVESPEED);
|
|
if (f) {
|
|
speed = f->val[0];
|
|
} else {
|
|
speed = SPEED_MOVE; // default
|
|
}
|
|
|
|
// modifier?
|
|
for (f = lf->flags->first ; f ; f = f->next ){
|
|
if ((f->id == F_SLOWMOVE) || (f->id == F_SLOWACTMOVE)) {
|
|
speed += f->val[0];
|
|
} else if ((f->id == F_FASTMOVE) || (f->id == F_FASTACTMOVE)) {
|
|
speed -= f->val[0];
|
|
} else if (f->id == F_SPRINTING) {
|
|
if (f->val[0]) {
|
|
speed -= 10;
|
|
} else {
|
|
speed += 5;
|
|
}
|
|
} else if (f->id == F_TIRED) {
|
|
speed += 5;
|
|
}
|
|
}
|
|
|
|
switch (isburdened(lf)) {
|
|
case BR_NONE:
|
|
break;
|
|
case BR_BURDENED:
|
|
speed += 5;
|
|
break;
|
|
case BR_STRAINED:
|
|
case BR_OVERLOADED:
|
|
speed += 10;
|
|
break;
|
|
}
|
|
|
|
|
|
if (lfhasflag(lf, F_SNEAK)) {
|
|
speed *= 2;
|
|
}
|
|
|
|
if (speed < 1) speed = 1;
|
|
|
|
adjustspeedforwater(lf, &speed);
|
|
|
|
|
|
return speed;
|
|
}
|
|
|
|
char *getmoveverb(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_FLYING)) {
|
|
return "fly";
|
|
} else if (lfhasflag(lf, F_LEVITATING)) {
|
|
return "float";
|
|
}
|
|
if (lfhasflag(lf, F_FLEEFROM)) {
|
|
return "flee";
|
|
}
|
|
if (isswimming(lf)) {
|
|
return "swim";
|
|
}
|
|
return "walk";
|
|
}
|
|
|
|
char *getmoveverbother(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_FLYING)) {
|
|
return "flies";
|
|
} else if (lfhasflag(lf, F_LEVITATING)) {
|
|
return "floats";
|
|
}
|
|
|
|
if (lfhasflag(lf, F_FLEEFROM)) {
|
|
return "flees";
|
|
}
|
|
return "walks";
|
|
}
|
|
|
|
lifeform_t *getnearbypeaceful(lifeform_t *lf) {
|
|
int i;
|
|
lifeform_t *poss[MAXCANDIDATES];
|
|
lifeform_t *l;
|
|
int nposs = 0;
|
|
// peaceful enemy in los ?
|
|
for (i = 0; i < lf->nlos; i++) {
|
|
l = lf->los[i]->lf;
|
|
if (l && (getallegiance(l) == AL_PEACEFUL)) {
|
|
poss[nposs] = l;
|
|
}
|
|
}
|
|
if (nposs) {
|
|
return poss[rnd(0,nposs-1)];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char *getlfname(lifeform_t *lf, char *buf) {
|
|
return real_getlfname(lf, buf, B_TRUE);
|
|
}
|
|
|
|
char *real_getlfname(lifeform_t *lf, char *buf, int usevis) {
|
|
char descstring[BUFLEN];
|
|
char jobstring[BUFLEN];
|
|
char the[5];
|
|
job_t *j;
|
|
flag_t *f;
|
|
|
|
// 'the' or 'your' ?
|
|
if (ispetof(lf, player)) {
|
|
strcpy(the, "your");
|
|
} else {
|
|
strcpy(the, "the");
|
|
}
|
|
|
|
// construct description string
|
|
strcpy(descstring, "");
|
|
if (lfhasflag(lf, F_FROZEN)) {
|
|
strcat(descstring, "frozen ");
|
|
}
|
|
if (lfhasflag(lf, F_HEADLESS)) {
|
|
strcat(descstring, "headless ");
|
|
}
|
|
|
|
// construct job string
|
|
strcpy(jobstring, "");
|
|
if (!lfhasflag(lf, F_NOJOBTEXT)) {
|
|
j = getjob(lf);
|
|
if (j) {
|
|
sprintf(jobstring, " %s", j->name);
|
|
jobstring[1] = tolower(jobstring[1]);
|
|
}
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
sprintf(buf, "you");
|
|
} else {
|
|
//if (isblind(player)) {
|
|
if (usevis && !cansee(player, lf)) {
|
|
sprintf(buf, "something");
|
|
} else {
|
|
if (lf->race->id == R_DANCINGWEAPON) {
|
|
object_t *wep;
|
|
wep = getweapon(lf);
|
|
if (wep) {
|
|
char obname[BUFLEN];
|
|
real_getobname(wep, obname, 1, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_FALSE);
|
|
sprintf(buf, "%s %s%s",the,descstring,noprefix(obname));
|
|
} else {
|
|
sprintf(buf, "%s %s%s%s",the,descstring,lf->race->name,jobstring);
|
|
}
|
|
} else {
|
|
char zombiestring[BUFLEN];
|
|
f = hasflag(lf->flags, F_LFSUFFIX);
|
|
|
|
strcpy(zombiestring, "");
|
|
if (f) {
|
|
sprintf(zombiestring, " %s", f->text);
|
|
}
|
|
|
|
sprintf(buf, "%s %s%s%s%s",the,descstring,lf->race->name,jobstring,zombiestring);
|
|
}
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
char *getlfnamea(lifeform_t *lf, char *buf) {
|
|
return real_getlfnamea(lf, buf, B_TRUE);
|
|
}
|
|
|
|
char *real_getlfnamea(lifeform_t *lf, char *buf, int usevis) {
|
|
if (isplayer(lf)) {
|
|
sprintf(buf, "you");
|
|
} else {
|
|
char buf2[BUFLEN];
|
|
char the[5];
|
|
|
|
real_getlfname(lf, buf2, usevis);
|
|
|
|
|
|
if (ispetof(lf, player)) {
|
|
strcpy(the, "your");
|
|
} else {
|
|
if (isvowel(lf->race->name[0])) {
|
|
strcpy(the, "an");
|
|
} else {
|
|
strcpy(the, "a");
|
|
}
|
|
}
|
|
|
|
sprintf(buf, "%s %s", the, noprefix(buf2));
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
enum LFSIZE getlfsize(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = hasflag(lf->flags, F_SIZE);
|
|
assert(f);
|
|
return f->val[0];
|
|
}
|
|
|
|
float getlfweight(lifeform_t *lf, int withobs) {
|
|
float weight = 0;
|
|
weight = lf->race->weight;
|
|
|
|
if (lfhasflag(lf, F_OBESE)) {
|
|
weight *= 2;
|
|
}
|
|
|
|
if (withobs) {
|
|
weight += getobpileweight(lf->pack);
|
|
}
|
|
return weight;
|
|
}
|
|
|
|
object_t *getsecmeleeweapon(lifeform_t *lf) {
|
|
object_t *o;
|
|
o = getequippedob(lf->pack, BP_SECWEAPON);
|
|
if (o && ismeleeweapon(o)) {
|
|
return o;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
object_t *getshield(lifeform_t *lf) {
|
|
object_t *o;
|
|
o = getequippedob(lf->pack, BP_SECWEAPON);
|
|
if (o && isshield(o)) {
|
|
return o;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int getspellspeed(lifeform_t *lf) {
|
|
int speed = 0;
|
|
flag_t *f;
|
|
|
|
f = lfhasflag(lf, F_SPELLSPEED);
|
|
if (f) {
|
|
speed = f->val[0];
|
|
} else {
|
|
f = lfhasflag(lf, F_MOVESPEED);
|
|
if (f) {
|
|
speed = f->val[0];
|
|
} else {
|
|
speed = SPEED_MOVE; // default
|
|
}
|
|
}
|
|
|
|
// don't use movement speed modifier!
|
|
return speed;
|
|
}
|
|
|
|
char *getplayername(char *buf) {
|
|
flag_t *f;
|
|
f = hasflag(player->flags, F_NAME);
|
|
if (f) {
|
|
strcpy(buf, f->text);
|
|
} else{
|
|
// should never happen!
|
|
strcpy(buf, "");
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
char *getplayernamefull(char *buf) {
|
|
char pname[BUFLEN];
|
|
job_t *j;
|
|
|
|
getplayername(pname);
|
|
|
|
j = getjob(player);
|
|
if (j) {
|
|
sprintf(buf, "%s the %s", pname, j->name);
|
|
} else {
|
|
sprintf(buf, "%s the %s", pname, player->race->name);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
|
|
int getpoisondamchance(enum POISONTYPE ptype) {
|
|
int chance = 0;
|
|
switch (ptype) {
|
|
case P_FOOD:
|
|
case P_GAS:
|
|
case P_VENOM:
|
|
case P_COLD:
|
|
chance = 33;
|
|
break;
|
|
default:
|
|
chance = 0;
|
|
break;
|
|
}
|
|
return chance;
|
|
}
|
|
|
|
char *getpoisondamverb(enum POISONTYPE ptype) {
|
|
switch (ptype) {
|
|
case P_FOOD:
|
|
case P_VENOM:
|
|
return "vomit";
|
|
case P_GAS:
|
|
case P_COLD:
|
|
return "cough";
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
char *getpoisondesc(enum POISONTYPE ptype) {
|
|
switch (ptype) {
|
|
case P_FOOD:
|
|
case P_VENOM:
|
|
case P_GAS:
|
|
case P_WEAKNESS:
|
|
return "Poisoned";
|
|
case P_COLD:
|
|
return "Sick";
|
|
default:
|
|
break;
|
|
}
|
|
return "Poisoned";
|
|
}
|
|
|
|
char *getpoisonname(enum POISONTYPE ptype) {
|
|
switch (ptype) {
|
|
case P_COLD:
|
|
return "hypothermia";
|
|
case P_FOOD:
|
|
return "food poisoning";
|
|
case P_GAS:
|
|
return "gas inhalation";
|
|
case P_VENOM:
|
|
return "venom poisoning";
|
|
case P_WEAKNESS:
|
|
return "weakening poison";
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
int getraceclass(lifeform_t *lf) {
|
|
return lf->race->raceclass->id;
|
|
}
|
|
|
|
int getracerarity(map_t *map, enum RACE rid) {
|
|
race_t *r;
|
|
int rarity = -1;
|
|
r = findrace(rid);
|
|
if (r) {
|
|
flag_t *f;
|
|
|
|
f = hasflagval(r->flags, F_RARITY, H_ALL, NA, NA, NULL);
|
|
if (!f) {
|
|
if (map) {
|
|
f = hasflagval(r->flags, F_RARITY, map->habitat, NA, NA, NULL);
|
|
} else {
|
|
f = hasflagval(r->flags, F_RARITY, NA, NA, NA, NULL);
|
|
}
|
|
}
|
|
|
|
if (f) {
|
|
// ignore habitat for now!
|
|
rarity = f->val[1];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return rarity;
|
|
}
|
|
|
|
object_t *getrandomarmour(lifeform_t *lf) {
|
|
object_t *o;
|
|
flag_t *f;
|
|
object_t *poss[MAXBODYPARTS];
|
|
object_t **hitposition;
|
|
int hitchance[MAXBODYPARTS];
|
|
int nposs = 0;
|
|
int maxroll = 0;
|
|
int i,n,idx;
|
|
int sel;
|
|
int anyfound = B_FALSE;
|
|
|
|
// make a list of all valid armour
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (hasflag(o->flags, F_ARMOURRATING)) {
|
|
f = hasflag(o->flags, F_EQUIPPED);
|
|
if (f) {
|
|
anyfound = B_TRUE;
|
|
poss[nposs] = o;
|
|
if (hasflag(o->flags, F_SHIELD)) {
|
|
hitchance[nposs] = getbodyparthitchance(BP_BODY);
|
|
} else {
|
|
hitchance[nposs] = getbodyparthitchance(f->val[0]);
|
|
}
|
|
maxroll += hitchance[nposs];
|
|
nposs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (anyfound == B_FALSE) return NULL;
|
|
|
|
// now figure out chances of each one getting hit
|
|
hitposition = malloc(maxroll * sizeof(object_t *));
|
|
idx = 0;
|
|
for (i = 0; i < nposs; i++) {
|
|
for (n = 0; n < hitchance[i]; n++) {
|
|
hitposition[idx] = poss[i];
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
sel = rnd(0, maxroll-1);
|
|
o = hitposition[sel];
|
|
|
|
free(hitposition);
|
|
|
|
return o;
|
|
}
|
|
|
|
int getrandommonlevel(race_t *r, map_t *m) {
|
|
flag_t *f;
|
|
int wantlev = 1;
|
|
f = hasflag(r->flags, F_VARLEVEL);
|
|
if (f) {
|
|
wantlev = rnd(1, getmapdifficulty(m));
|
|
if (f->val[0] > 0) {
|
|
limit(&wantlev, 1, f->val[0]);
|
|
}
|
|
}
|
|
return wantlev;
|
|
}
|
|
|
|
race_t *getrandomrace(cell_t *c, int forcedepth) {
|
|
//int rarity;
|
|
race_t *r;
|
|
race_t *poss[MAXRANDOMLFCANDIDATES];
|
|
int nposs = 0;
|
|
int selidx;
|
|
int db = B_FALSE;
|
|
int depth;
|
|
int raritymin,raritymax;
|
|
|
|
// determine rarity of lf to generate
|
|
if (forcedepth != NA) {
|
|
depth = forcedepth;
|
|
} else {
|
|
depth = getmapdifficulty(c ? c->map : NULL);
|
|
}
|
|
|
|
getrarity(depth, &raritymin, &raritymax, RARITYVARIANCELF, B_TRUE);
|
|
|
|
if (db) dblog("finding random lf with rarity val %d-%d\n",raritymin,raritymax);
|
|
|
|
|
|
// try to find a lf of this type which will
|
|
// fit in the map's habitat
|
|
nposs = 0;
|
|
while (nposs == 0) {
|
|
for (r = firstrace ; r ; r = r->next) {
|
|
int valid = B_FALSE;
|
|
flag_t *rarflag = NULL;
|
|
|
|
// correct rarity?
|
|
rarflag = hasflagval(r->flags, F_RARITY, H_ALL, NA, NA, NULL);
|
|
if (!rarflag) {
|
|
if (c) {
|
|
rarflag = hasflagval(r->flags, F_RARITY, c->map->habitat, NA, NA, NULL);
|
|
} else {
|
|
rarflag = hasflagval(r->flags, F_RARITY, NA, NA, NA, NULL);
|
|
}
|
|
}
|
|
|
|
if (rarflag) {
|
|
if ((rarflag->val[1] >= raritymin) && (rarflag->val[1] <= raritymax)) {
|
|
valid = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (valid && c) {
|
|
// can it go into the cell?
|
|
if (hasobwithflag(c->obpile, F_DEEPWATER)) {
|
|
// water
|
|
if (!hasflag(r->flags, F_AQUATIC) && (r->raceclass->id != RC_AQUATIC)) {
|
|
// not aquatic
|
|
valid = B_FALSE;
|
|
}
|
|
} else {
|
|
// no water
|
|
if (hasflag(r->flags, F_NEEDSWATER)) {
|
|
valid = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (valid) {
|
|
if (db) dblog("-> possibility: %s, rarity=%d",r->name, rarflag->val[1]);
|
|
poss[nposs] = r;
|
|
nposs++;
|
|
if (nposs >= MAXRANDOMLFCANDIDATES) break;
|
|
}
|
|
}
|
|
|
|
// nothing found?
|
|
if (nposs == 0) {
|
|
// already at lowest rarity?
|
|
if ((raritymax >= 100) && (raritymin <= 0)) {
|
|
// give up
|
|
if (db) dblog("no possible lf at all! giving up.");
|
|
return NULL;
|
|
}
|
|
|
|
// expand range and try again
|
|
raritymax += 10; if (raritymax > 100) raritymax = 100;
|
|
raritymin -= 10; if (raritymin < 0) raritymin = 0;
|
|
if (db) dblog("no possible lfs like this. trying again with rarity %d-%d\n",raritymin,raritymax);
|
|
}
|
|
}
|
|
|
|
if (db) dblog("got %d possibilities.",nposs);
|
|
// pick a random lf from our possiblities
|
|
selidx = rnd(0,nposs-1);
|
|
r = poss[selidx];
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
race_t *getreallyrandomrace(void) {
|
|
race_t **poss;
|
|
race_t *r;
|
|
int nposs = 0;
|
|
int sel;
|
|
int count = 0;
|
|
|
|
// count races
|
|
for (r = firstrace ; r ; r = r->next) {
|
|
count++;
|
|
}
|
|
|
|
|
|
poss = malloc(count * sizeof(race_t *));
|
|
|
|
for (r = firstrace ; r ; r = r->next) {
|
|
if (appearsrandomly(r->id)) {
|
|
poss[nposs] = r;
|
|
nposs++;
|
|
}
|
|
}
|
|
sel = rnd(0,nposs-1);
|
|
r = poss[sel];
|
|
free(poss);
|
|
return r;
|
|
}
|
|
|
|
enum SKILL getrandomskill(void) {
|
|
int sel,count = 0;
|
|
skill_t *sk;
|
|
sel = rnd(0,MAXSKILLS-1);
|
|
for (sk = firstskill ; sk ; sk = sk->next) {
|
|
if (count == sel) return sk->id;
|
|
count++;
|
|
}
|
|
return SK_NONE;
|
|
}
|
|
|
|
object_t *getrestob(lifeform_t *lf) {
|
|
object_t *o,*bestob = NULL;
|
|
int bestval = -1;
|
|
flag_t *f;
|
|
for (o = lf->pack->first; o ; o = o->next) {
|
|
f = hasflag(o->flags, F_HELPSREST);
|
|
if (f) {
|
|
if (!bestob && (f->val[0] > bestval)) {
|
|
bestval = f->val[0];
|
|
bestob = o;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bestob;
|
|
}
|
|
|
|
// returns proficiency level in a given skill
|
|
enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id) {
|
|
flag_t *f;
|
|
f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL);
|
|
if (f) {
|
|
return f->val[1];
|
|
}
|
|
return PR_INEPT;
|
|
}
|
|
|
|
char *getspeedname(int speed, char *buf) {
|
|
sprintf(buf, "unknownspeed");
|
|
if (speed <= SP_GODLIKE) {
|
|
sprintf(buf, "insanely fast");
|
|
} else if (speed <= SP_ULTRAFAST) {
|
|
sprintf(buf, "extremely fast");
|
|
} else if (speed <= SP_VERYFAST) {
|
|
sprintf(buf, "very fast");
|
|
} else if (speed <= SP_FAST) {
|
|
sprintf(buf, "fast");
|
|
} else if (speed <= SP_NORMAL) {
|
|
sprintf(buf, "normal");
|
|
} else if (speed <= SP_SLOW) {
|
|
sprintf(buf, "slow");
|
|
} else if (speed <= SP_VERYSLOW) {
|
|
sprintf(buf, "very slow");
|
|
} else if (speed <= SP_ULTRASLOW) {
|
|
sprintf(buf, "extremely slow");
|
|
} else {
|
|
sprintf(buf, "insanely slow");
|
|
}
|
|
return buf;
|
|
}
|
|
char *getspeednameshort(int speed, char *buf) {
|
|
sprintf(buf, "unknownspeed");
|
|
if (speed <= SP_GODLIKE) {
|
|
sprintf(buf, "fast+++");
|
|
} else if (speed <= SP_ULTRAFAST) {
|
|
sprintf(buf, "fast++");
|
|
} else if (speed <= SP_VERYFAST) {
|
|
sprintf(buf, "fast+");
|
|
} else if (speed <= SP_FAST) {
|
|
sprintf(buf, "fast");
|
|
} else if (speed <= SP_NORMAL) {
|
|
sprintf(buf, "normal");
|
|
} else if (speed <= SP_SLOW) {
|
|
sprintf(buf, "slow");
|
|
} else if (speed <= SP_VERYSLOW) {
|
|
sprintf(buf, "slow+");
|
|
} else if (speed <= SP_ULTRASLOW) {
|
|
sprintf(buf, "slow++");
|
|
} else {
|
|
sprintf(buf, "slow+++");
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
// ie. intelligence level: xxx
|
|
enum IQBRACKET getiqname(int iq, char *buf) {
|
|
if (iq <= 0) {
|
|
if (buf) strcpy(buf, "mindless");
|
|
return IQ_MINDLESS;
|
|
} else if (iq == 1) {
|
|
if (buf) strcpy(buf, "vegetable");
|
|
return IQ_VEGETABLE;
|
|
} else if (iq <= 3) {
|
|
if (buf) strcpy(buf, "animal");
|
|
return IQ_ANIMAL;
|
|
} else if (iq <= 6) {
|
|
if (buf) strcpy(buf, "dim-witted");
|
|
return IQ_DIMWITTED;
|
|
} else if (iq <= 9) {
|
|
if (buf) strcpy(buf, "dopey");
|
|
return IQ_DOPEY;
|
|
} else if (iq <= 12) {
|
|
if (buf) strcpy(buf, "average");
|
|
return IQ_AVERAGE;
|
|
} else if (iq <= 15) {
|
|
if (buf) strcpy(buf, "smart");
|
|
return IQ_SMART;
|
|
} else if (iq <= 17) {
|
|
if (buf) strcpy(buf, "enlightened");
|
|
return IQ_ENLIGHTENED;
|
|
}
|
|
|
|
if (buf) strcpy(buf, "genius");
|
|
return IQ_GENIUS;
|
|
}
|
|
|
|
enum DEXBRACKET getdexname(int dex, char *buf) {
|
|
if (dex <= 0) {
|
|
if (buf) strcpy(buf, "incompetent");
|
|
return DX_INCOMPETENT;
|
|
} else if (dex <= 2) {
|
|
if (buf) strcpy(buf, "oafish");
|
|
return DX_OAFISH;
|
|
} else if (dex <= 4) {
|
|
if (buf) strcpy(buf, "inept");
|
|
return DX_INEPT;
|
|
} else if (dex <= 6) {
|
|
if (buf) strcpy(buf, "clumsy");
|
|
return DX_CLUMSY;
|
|
} else if (dex <= 8) {
|
|
if (buf) strcpy(buf, "awkward");
|
|
return DX_AWKWARD;
|
|
} else if (dex == 9) {
|
|
if (buf) strcpy(buf, "average");
|
|
return DX_AVERAGE;
|
|
} else if (dex <= 11) {
|
|
if (buf) strcpy(buf, "dextrous");
|
|
return DX_DEXTROUS;
|
|
} else if (dex <= 13) {
|
|
if (buf) strcpy(buf, "nimble");
|
|
return DX_NIMBLE;
|
|
} else if (dex <= 15) {
|
|
if (buf) strcpy(buf, "agile");
|
|
return DX_AGILE;
|
|
} else if (dex <= 17) {
|
|
if (buf) strcpy(buf, "swift");
|
|
return DX_SWIFT;
|
|
}
|
|
|
|
if (buf) strcpy(buf, "supersonic");
|
|
return DX_SUPERSONIC;
|
|
}
|
|
|
|
// returns a pct addition for things like:
|
|
// accuracy, evasion, lockpicking
|
|
// result will be between -50 and 50
|
|
float getstatmod(lifeform_t *lf, enum ATTRIB att) {
|
|
float mod = 0;
|
|
float base;
|
|
// <9 = penalty
|
|
// 9 = average
|
|
// >9 = bonus up to 50%
|
|
base = getattr(lf, att) - 9;
|
|
mod = (int)((base / 9.0) * 50.0);
|
|
return mod;
|
|
}
|
|
|
|
enum CONBRACKET getconname(int str, char *buf) {
|
|
if (str <= 2) {
|
|
if (buf) strcpy(buf, "frail");
|
|
return CN_FRAIL;
|
|
} else if (str <= 4) {
|
|
if (buf) strcpy(buf, "sickly");
|
|
return CN_SICKLY;
|
|
} else if (str <= 6) {
|
|
if (buf) strcpy(buf, "unhealthy");
|
|
return CN_UNHEALTHY;
|
|
} else if (str <= 8) {
|
|
if (buf) strcpy(buf, "unfit");
|
|
return CN_UNFIT;
|
|
} else if (str <= 11) {
|
|
if (buf) strcpy(buf, "average");
|
|
return CN_AVERAGE;
|
|
} else if (str <= 14) {
|
|
if (buf) strcpy(buf, "healthy");
|
|
return CN_HEALTHY;
|
|
} else if (str <= 16) {
|
|
if (buf) strcpy(buf, "very fit");
|
|
return CN_FIT;
|
|
} else if (str <= 18) {
|
|
if (buf) strcpy(buf, "hardy");
|
|
return CN_HARDY;
|
|
}
|
|
|
|
if (buf) strcpy(buf, "hardy");
|
|
return CN_HARDY;
|
|
}
|
|
|
|
enum STRBRACKET getstrname(int str, char *buf) {
|
|
if (str <= 0) {
|
|
if (buf) strcpy(buf, "helpless");
|
|
return ST_HELPLESS;
|
|
} else if (str <= 3) {
|
|
if (buf) strcpy(buf, "feeble");
|
|
return ST_FEEBLE;
|
|
} else if (str <= 6) {
|
|
if (buf) strcpy(buf, "very weak");
|
|
return ST_VWEAK;
|
|
} else if (str <= 8) {
|
|
if (buf) strcpy(buf, "weak");
|
|
return ST_WEAK;
|
|
} else if (str <= 12) {
|
|
if (buf) strcpy(buf, "average");
|
|
return ST_AVERAGE;
|
|
} else if (str <= 15) {
|
|
if (buf) strcpy(buf, "strong");
|
|
return ST_STRONG;
|
|
} else if (str <= 17) {
|
|
if (buf) strcpy(buf, "mighty");
|
|
return ST_MIGHTY;
|
|
}
|
|
|
|
if (buf) strcpy(buf, "titanic");
|
|
return ST_TITANIC;
|
|
}
|
|
|
|
char *getskilldesc(enum SKILL id) {
|
|
skill_t *s;
|
|
s = findskill(id);
|
|
if (s) {
|
|
return s->desc;
|
|
}
|
|
return "?unknownskilldesc?";
|
|
}
|
|
|
|
char *getskillname(enum SKILL id) {
|
|
skill_t *s;
|
|
s = findskill(id);
|
|
if (s) {
|
|
return s->name;
|
|
}
|
|
return "?unknownskill?";
|
|
}
|
|
|
|
char *getskilllevelname(enum SKILLLEVEL sl) {
|
|
switch (sl) {
|
|
case PR_INEPT:
|
|
return "Inept";
|
|
case PR_NOVICE:
|
|
return "Novice";
|
|
case PR_BEGINNER:
|
|
return "Beginner";
|
|
case PR_ADEPT:
|
|
return "Adept";
|
|
case PR_SKILLED:
|
|
return "Skilled";
|
|
case PR_EXPERT:
|
|
return "Expert";
|
|
case PR_MASTER:
|
|
return "Master";
|
|
}
|
|
return "?Unknownskilllevel?";
|
|
}
|
|
|
|
|
|
// get throw speed (ie. damage multiplier)
|
|
// based on strength.
|
|
//
|
|
// cube the number to get km/h.
|
|
// ie. 1 = 1km/h
|
|
// ie. 2 = 16km/h
|
|
// ie. 3 = 27km/h
|
|
// ie. 4 = 64km/h
|
|
// ie. 5 = 125km/h
|
|
// ie. 10 = 1000km/h
|
|
int getthrowspeed(int str) {
|
|
enum STRBRACKET sb;
|
|
int speed = 0;
|
|
sb = getstrname(str, NULL);
|
|
switch (sb) {
|
|
case ST_HELPLESS:
|
|
case ST_FEEBLE:
|
|
speed = 1;
|
|
break;
|
|
case ST_VWEAK:
|
|
case ST_WEAK:
|
|
speed = 2;
|
|
break;
|
|
case ST_AVERAGE:
|
|
speed = 3;
|
|
break;
|
|
case ST_STRONG:
|
|
speed = 4;
|
|
break;
|
|
case ST_MIGHTY:
|
|
speed = 5;
|
|
break;
|
|
default:
|
|
case ST_TITANIC:
|
|
speed = 6;
|
|
break;
|
|
// gun is 10
|
|
}
|
|
return speed;
|
|
}
|
|
|
|
void getwantdistance(lifeform_t *lf, int *min, int *max, int attacking) {
|
|
flag_t *f;
|
|
// default - run into them
|
|
*min = 0;
|
|
*max = 0;
|
|
if (attacking) {
|
|
f = lfhasflag(lf, F_ATTACKRANGE);
|
|
if (f) {
|
|
*min = f->val[0];
|
|
*max = f->val[1];
|
|
}
|
|
} else {
|
|
*min = 1;
|
|
*max = 3;
|
|
}
|
|
}
|
|
|
|
|
|
object_t *getweapon(lifeform_t *lf) {
|
|
object_t *o;
|
|
o = getequippedob(lf->pack, BP_WEAPON);
|
|
if (o) {
|
|
return o;
|
|
}
|
|
// no primary weapon. do we have a secondary one?
|
|
o = getequippedob(lf->pack, BP_SECWEAPON);
|
|
if (o && ismeleeweapon(o)) {
|
|
return o;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
long getxpforlev(int level) {
|
|
long needxp = 0;
|
|
// 2.8
|
|
float multiplier = 10;
|
|
float constant = 3.1;
|
|
|
|
// no xp needed for level 1
|
|
/*
|
|
for (i = 0; i < level - 1; i++) {
|
|
//needxp += (20 * pow(2,i));
|
|
needxp += (20 * (pow(i,2.8)));
|
|
}
|
|
*/
|
|
needxp = (multiplier * (pow(level,constant) - 1));
|
|
return needxp;
|
|
}
|
|
|
|
void givejob(lifeform_t *lf, enum JOB jobid) {
|
|
job_t *j;
|
|
flag_t *f;
|
|
int i;
|
|
int condition = NOCONDITION;
|
|
int rollhp = B_FALSE, rollmp = B_FALSE;
|
|
int rollatt[MAXATTS];
|
|
int ignorenext;
|
|
int ignoredprev;
|
|
int db = B_FALSE;
|
|
|
|
if (db) dblog("givejob() starting.\n");
|
|
|
|
for (i = 0; i < MAXATTS; i++) {
|
|
rollatt[i] = B_FALSE;
|
|
}
|
|
|
|
// give the job
|
|
addflag(lf->flags, F_JOB, jobid, NA, NA, NULL);
|
|
j = findjob(jobid);
|
|
|
|
// override hitdice from race
|
|
if (hasflag(j->flags, F_HITDICE)) {
|
|
rollhp = B_TRUE;
|
|
f = lfhasflag(lf, F_HITDICE);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
// override mpdice from race
|
|
if (hasflag(j->flags, F_MPDICE)) {
|
|
rollmp = B_TRUE;
|
|
f = lfhasflag(lf, F_MPDICE);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
|
|
// inherit all flags except startob ones
|
|
ignorenext = B_FALSE;
|
|
ignoredprev = B_FALSE;
|
|
for (f = j->flags->first ; f ; f = f->next) {
|
|
if (condition == IFPLAYER) {
|
|
if (f->id == F_ENDIFPLAYER) {
|
|
if (db) dblog("ending ifplayer condition");
|
|
condition = NOCONDITION;
|
|
} else if (!isplayer(lf)) {
|
|
if (db) dblog("setting ignorenext cause of ifplayer");
|
|
ignorenext = B_TRUE; // ie. ignore this one.
|
|
}
|
|
} else if (condition == IFMONSTER) {
|
|
if (f->id == F_ENDIFMONSTER) {
|
|
if (db) dblog("ending ifmonster condition");
|
|
condition = NOCONDITION;
|
|
} else if (isplayer(lf)) {
|
|
if (db) dblog("setting ignorenext cause of ifmonster");
|
|
ignorenext = B_TRUE; // ie. ignore this one.
|
|
}
|
|
}
|
|
|
|
if (ignorenext) {
|
|
if (db) dblog("ignoring this flag: %d",f->id);
|
|
ignorenext = B_FALSE;
|
|
ignoredprev = B_TRUE;
|
|
} else {
|
|
if (f->id == F_IFPCT) {
|
|
if (db) dblog("ifpct flag...");
|
|
if (rnd(0,100) > f->val[0]) {
|
|
if (db) dblog(" failed.");
|
|
ignorenext = B_TRUE;
|
|
} else {
|
|
if (db) dblog(" passed.");
|
|
}
|
|
/*
|
|
if ((f->val[2] == IFMONSTER) && isplayer(lf)) {
|
|
ignorenext = B_TRUE;
|
|
} else if ((f->val[2] == IFPLAYER) && !isplayer(lf)) {
|
|
ignorenext = B_TRUE;
|
|
}
|
|
*/
|
|
} else if (f->id == F_IFPLAYER) {
|
|
if (db) dblog("starting ifplayer condition");
|
|
condition = IFPLAYER;
|
|
} else if (f->id == F_IFMONSTER) {
|
|
if (db) dblog("starting ifmonster condition");
|
|
condition = IFMONSTER;
|
|
} else if (f->id == F_ELSE) {
|
|
if (db) dblog("else flag...");
|
|
if (ignoredprev) {
|
|
if (db) dblog("... MATCHED.");
|
|
} else {
|
|
if (db) dblog("... ignoring next.");
|
|
ignorenext = B_TRUE;
|
|
}
|
|
} else {
|
|
addflag_real(lf->flags, f->id, f->val[0], f->val[1], f->val[2], f->text, FROMJOB,B_TRUE, -1);
|
|
if (f->id == F_STARTATT) {
|
|
rollatt[f->val[0]] = B_TRUE;
|
|
}
|
|
}
|
|
ignoredprev = B_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// now give start obs/skills from it
|
|
givestartobs(lf, lf->flags);
|
|
givestartskills(lf, lf->flags);
|
|
autoskill(lf);
|
|
|
|
|
|
// override hp/mp from race
|
|
if (rollhp) {
|
|
lf->maxhp = 0;
|
|
for (i = 0; i < lf->level; i++) {
|
|
lf->maxhp += rollhitdice(lf);
|
|
assert(lf->maxhp > 0);
|
|
}
|
|
lf->hp = lf->maxhp;
|
|
}
|
|
|
|
if (rollmp) {
|
|
f = hasflag(lf->flags, F_MPDICE);
|
|
if (f) {
|
|
lf->maxmp = f->val[0] * 4;
|
|
if (f->val[1] != NA) lf->maxmp += f->val[1];
|
|
for (i = 0; i < lf->level-1; i++) {
|
|
lf->maxmp += rollmpdice(lf);
|
|
}
|
|
lf->mp = lf->maxmp;
|
|
}
|
|
}
|
|
|
|
// re-roll attributes if required
|
|
for (i = 0; i < MAXATTS; i++) {
|
|
if (rollatt[i]) {
|
|
rollstat(lf, i);
|
|
lf->baseatt[i] = lf->att[i];
|
|
}
|
|
}
|
|
|
|
if ((gamemode != GM_GAMESTARTED)) {
|
|
autoweild(lf);
|
|
}
|
|
}
|
|
|
|
|
|
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 lifetimeval;
|
|
|
|
if (o->pile->owner == lf) held = B_TRUE;
|
|
|
|
if (held && hasflag(o->flags, F_EQUIPPED)) {
|
|
equipped = B_TRUE;
|
|
}
|
|
if (held && hasflag(o->flags, F_ACTIVATED)) {
|
|
activated = B_TRUE;
|
|
}
|
|
|
|
if (whattype == F_EQUIPCONFER) {
|
|
if (!equipped) {
|
|
return;
|
|
} else {
|
|
lifetimeval = FROMOBEQUIP;
|
|
}
|
|
} else if (whattype == F_HOLDCONFER) {
|
|
if (!held) {
|
|
return;
|
|
} else {
|
|
lifetimeval = FROMOBHOLD;
|
|
}
|
|
} else if (whattype == F_ACTIVATECONFER) {
|
|
if (!activated) {
|
|
return;
|
|
} else {
|
|
lifetimeval = FROMOBACTIVATE;
|
|
}
|
|
}
|
|
|
|
for (f = o->flags->first ; f ; f = f->next) {
|
|
if (f->id == whattype) {
|
|
int known = B_FALSE;
|
|
int addit = B_FALSE;
|
|
|
|
if (isknown(o) || !isplayer(lf)) {
|
|
known = B_TRUE;
|
|
}
|
|
|
|
if (f->val[2] == IFKNOWN) {
|
|
// only confer if known
|
|
if (known) {
|
|
addit = B_TRUE;
|
|
}
|
|
} else {
|
|
addit = B_TRUE;
|
|
}
|
|
|
|
|
|
if (addit) {
|
|
newflag = addflag_real(lf->flags, f->val[0], f->val[1], f->val[2], NA, f->text, lifetimeval, known, o->id);
|
|
if (newflag->known) { // ie. if we found out about it through it being announced
|
|
flagsknown++;
|
|
}
|
|
flagsfound++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if all conferred flags now known, object is known
|
|
if (flagsfound && (flagsknown == flagsfound)) {
|
|
makeknown(o->type->id);
|
|
// in some cases, identify the object fully
|
|
// (ie. make +xxx bonuses known too)
|
|
if (isplayer(lf)) {
|
|
if (hasflag(o->flags, F_IDWHENUSED)) {
|
|
identify(o);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int giveskill(lifeform_t *lf, enum SKILL id) {
|
|
flag_t *f, *newf;
|
|
skill_t *sk;
|
|
|
|
sk = findskill(id);
|
|
if (!sk) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL);
|
|
if (f) {
|
|
// already have the skill - make it better
|
|
if (f->val[1] < PR_MASTER) {
|
|
f->val[1]++;
|
|
}
|
|
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {
|
|
msg("You have learned the %s %s skill!", getskilllevelname(f->val[1]), getskillname(sk->id));
|
|
}
|
|
statdirty = B_TRUE; // in case skill changes your stats
|
|
} else {
|
|
// gaining a new skill
|
|
f = addflag(lf->flags, F_HASSKILL, id, PR_NOVICE, NA, NULL);
|
|
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {
|
|
msg("You have learned the %s %s skill!", getskilllevelname(PR_NOVICE), getskillname(sk->id));
|
|
more();
|
|
}
|
|
|
|
// special effects for gaining a skill.
|
|
|
|
// there aren't REALLY "from job", but mark them as such anyway, so that
|
|
// they are invalidated if we get polymorphed.
|
|
|
|
// NOTE: this WILL be a problem if i ever add code to allow change of jobs!
|
|
if (id == SK_ATHLETICS) {
|
|
newf = addflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL);
|
|
newf->lifetime = FROMJOB;
|
|
} else if (id == SK_ATHLETICS) {
|
|
makeknown(OT_POT_WATER);
|
|
} else if (id == SK_LORE_ARCANA) {
|
|
newf = addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL);
|
|
newf->lifetime = FROMJOB;
|
|
} else if (id == SK_TRAPS) {
|
|
newf = addflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL);
|
|
newf->lifetime = FROMJOB;
|
|
}
|
|
statdirty = B_TRUE; // in case skill changes your stats
|
|
|
|
}
|
|
|
|
|
|
// special effects based on skill level
|
|
if (id == SK_ATHLETICS) {
|
|
if (f->val[1] == PR_ADEPT) {
|
|
newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL);
|
|
newf->lifetime = FROMJOB;
|
|
}
|
|
} else if (id == SK_CARTOGRAPHY) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_NOVICE) {
|
|
msg("You now make basic maps of your surroundings.");
|
|
} else if (f->val[1] == PR_BEGINNER) {
|
|
msg("Your map will now show the location of staircases.");
|
|
} else if (f->val[1] == PR_ADEPT) {
|
|
msg("Your map will now show the location of doors.");
|
|
} else if (f->val[1] == PR_SKILLED) {
|
|
msg("You will no longer forget your surroundings.");
|
|
} else if (f->val[1] == PR_EXPERT) {
|
|
msg("Your map will now show the location of objects.");
|
|
}
|
|
}
|
|
if (f->val[1] == PR_MASTER) {
|
|
newf = addflag(lf->flags, F_CANWILL, OT_S_MAPPING, 50, 50, "pw:1;");
|
|
newf->lifetime = FROMJOB;
|
|
}
|
|
} else if (id == SK_COOKING) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_NOVICE) {
|
|
msg("You can now recognise rotting food.");
|
|
} else if (f->val[1] == PR_BEGINNER) {
|
|
msg("You can now recognise all kinds of bad food.");
|
|
} else if (f->val[1] == PR_ADEPT) {
|
|
newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL);
|
|
newf->lifetime = FROMJOB;
|
|
}
|
|
}
|
|
} else if (id == SK_FIRSTAID) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_ADEPT) {
|
|
msg("You can now recgonise when poison is potentially fatal.");
|
|
statdirty = B_TRUE;
|
|
}
|
|
}
|
|
} else if (id == SK_LISTEN) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_BEGINNER) {
|
|
msg("You can now gauge the distance of sounds.");
|
|
} else if (f->val[1] == PR_ADEPT) {
|
|
msg("You can now determine the direction sounds are coming from.");
|
|
} else if (f->val[1] == PR_EXPERT) {
|
|
msg("You can now identify monsters based on sound.");
|
|
} else if (f->val[1] == PR_MASTER) {
|
|
msg("You can now locate monsters based on sound.");
|
|
}
|
|
}
|
|
} else if (id == SK_RANGED) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_MASTER) {
|
|
msg("Your no longer suffer ranged-based accuracy penalties when firing.");
|
|
}
|
|
}
|
|
} else if (id == SK_STEALTH) {
|
|
if (f->val[1] == PR_BEGINNER) {
|
|
newf = addflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
|
|
newf->lifetime = FROMJOB;
|
|
} else if (f->val[1] == PR_EXPERT) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
msg("You can now hide even when monsters are nearby.");
|
|
}
|
|
}
|
|
} else if (id == SK_SWIMMING) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_NOVICE) {
|
|
msg("You can now swim.");
|
|
} else if ((f->val[1] >= PR_BEGINNER) && (f->val[1] <= PR_SKILLED)) {
|
|
msg("You can now swim a bit faster.");
|
|
} else if (f->val[1] == PR_EXPERT) {
|
|
msg("You can now attack awkwardly and cast spells while swimming.");
|
|
} else if (f->val[1] == PR_MASTER) {
|
|
msg("You can now attack while swimming with no penalty.");
|
|
}
|
|
}
|
|
} else if (id == SK_TECHUSAGE) {
|
|
objecttype_t *ot;
|
|
// automatically make known all tech <= our skill level
|
|
for (ot = objecttype ; ot ; ot = ot->next) {
|
|
// if objecttype is not known...
|
|
if (!isknownot(ot)) {
|
|
flag_t *tf;
|
|
tf = hasflag(ot->flags, F_TECHLEVEL);
|
|
// if objecttype has a tech level , and it is
|
|
// lower (or equal to) our tech knowledge...
|
|
if (tf && !isknownot(ot) && (tf->val[0] <= f->val[1])) {
|
|
// then make it known!
|
|
makeknown(ot->id);
|
|
if (isplayer(lf)) {
|
|
object_t *o;
|
|
o = hasob(lf->pack, ot->id);
|
|
if (o) {
|
|
char buf[BUFLEN];
|
|
getobname(o, buf, o->amt);
|
|
msgnocap("%c - %s", o->letter, buf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (id == SK_TRACKING) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_NOVICE) {
|
|
msg("You can now see footprints.");
|
|
} else if (f->val[1] == PR_BEGINNER) {
|
|
msg("You can now determine how recently footprints were made.");
|
|
} else if (f->val[1] == PR_ADEPT) {
|
|
msg("You can now identify creatures from their footprints.");
|
|
} else if (f->val[1] == PR_SKILLED) {
|
|
msg("You can now recognise the direction of footprints.");
|
|
} else if (f->val[1] == PR_EXPERT) {
|
|
msg("You can now partially obscure your own footprints.");
|
|
} else if (f->val[1] == PR_MASTER) {
|
|
msg("You can now move without leaving footprints.");
|
|
}
|
|
}
|
|
} else if (id == SK_TWOWEAPON) {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
if (f->val[1] == PR_NOVICE) {
|
|
msg("You can now weild two weapons at once.");
|
|
} else if (f->val[1] == PR_ADEPT) {
|
|
msg("You no longer suffer an accuracy penalty when weilding two weapons.");
|
|
} else if (f->val[1] == PR_SKILLED) {
|
|
msg("Follow-up attacks with your second weapon are now more accurate.");
|
|
} else if (f->val[1] == PR_EXPERT) {
|
|
addflag(lf->flags, F_CANWILL, OT_A_FLURRY, 3, 3, "pw:1;");
|
|
} else if (f->val[1] == PR_MASTER) {
|
|
msg("You can now deflect attacks with your second weapon.");
|
|
}
|
|
}
|
|
} else if (id == SK_SS_ALLOMANCY) {
|
|
// give all allomantic spells
|
|
mayusespellschool(lf->flags, SS_ALLOMANCY, F_CANCAST);
|
|
} else if (id == SK_SS_MENTAL) {
|
|
// give a spell
|
|
if (!lfhasflagval(lf, F_CANCAST, OT_S_MINDSCAN, NA, NA, NULL)) {
|
|
addflag(lf->flags, F_CANCAST, OT_S_MINDSCAN, NA, NA, NULL);
|
|
}
|
|
} else if (isloreskill(id) && (gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
raceclass_t *rc;
|
|
// find raceclass for this one
|
|
for (rc = firstraceclass ; rc ; rc = rc->next) {
|
|
if (rc->skill == id) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (rc) {
|
|
// announce.
|
|
if (f->val[1] >= PR_MASTER) {
|
|
msg("You now know everything there is to know about %s.", rc->pluralname);
|
|
} else if (f->val[1] >= PR_SKILLED) {
|
|
msg("You can now anticipate how %s will react.", rc->pluralname);
|
|
} else if (f->val[1] >= PR_ADEPT) {
|
|
msg("You can now determine how dangerous %s are.", rc->pluralname);
|
|
} else if (f->val[1] >= PR_BEGINNER) {
|
|
msg("You can now determine how much damage %s will deal.", rc->pluralname);
|
|
} else if (f->val[1] >= PR_NOVICE) {
|
|
msg("You now know basic information about %s.", rc->pluralname);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ((gamemode == GM_GAMESTARTED) && statdirty) {
|
|
// redraw it right away.
|
|
drawstatus();
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int giveskilllev(lifeform_t *lf, enum SKILL id, enum SKILLLEVEL slev) {
|
|
flag_t *f;
|
|
f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL);
|
|
if (!f) {
|
|
// give one rank of the skill
|
|
giveskill(lf, id);
|
|
f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL);
|
|
}
|
|
|
|
if (f) {
|
|
f->val[1] = slev;
|
|
} else {
|
|
assert(1 == 0);
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
// give start objects from a particular flagpile
|
|
void givestartobs(lifeform_t *lf, flagpile_t *fp) {
|
|
object_t *o;
|
|
flag_t *f;
|
|
char buf[BUFLEN],buf2[BUFLEN];
|
|
int ignorenext = B_FALSE;
|
|
int ignoredprev = B_FALSE;
|
|
int db = B_FALSE;
|
|
|
|
if (db) {
|
|
sprintf(buf2, "calling givestartobs for %s",lf->race->name);
|
|
}
|
|
|
|
// give start objects and id them
|
|
ignorenext = B_FALSE;
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
o = NULL;
|
|
if (ignorenext) {
|
|
ignorenext = B_FALSE;
|
|
ignoredprev = B_TRUE;
|
|
continue;
|
|
}
|
|
if (f->id == F_IFPCT) {
|
|
if (rnd(0,100) > f->val[0]) {
|
|
ignorenext = B_TRUE;
|
|
}
|
|
if ((f->val[2] == IFMONSTER) && isplayer(lf)) {
|
|
ignorenext = B_TRUE;
|
|
} else if ((f->val[2] == IFPLAYER) && !isplayer(lf)) {
|
|
ignorenext = B_TRUE;
|
|
}
|
|
} else if (f->id == F_ELSE) {
|
|
if (ignoredprev) {
|
|
} else {
|
|
ignorenext = B_TRUE;
|
|
}
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
// if this is the player, DONT inherit any STARTOB* flags from race
|
|
if (f->lifetime == FROMRACE) {
|
|
continue;
|
|
}
|
|
} else {
|
|
// if this is a monster, DONT inherit specific STARTOB flags from race
|
|
if ((f->lifetime == FROMJOB) && (f->id == F_STARTOB)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (f->id == F_STARTOB) {
|
|
assert(strlen(f->text) > 0);
|
|
if (rnd(1,100) <= f->val[0]) {
|
|
o = addob(lf->pack, f->text);
|
|
}
|
|
} else if (f->id == F_STARTOBDT) {
|
|
if (rnd(1,100) <= f->val[0]) {
|
|
int counter = 0;
|
|
if (db) {
|
|
sprintf(buf2, "calling startobdt");
|
|
}
|
|
while (!getrandomobwithdt(lf->cell->map, f->val[1], buf)) {
|
|
counter++;
|
|
}
|
|
if (db) {
|
|
sprintf(buf2, "finished startobdt (needed %d tries)", counter);
|
|
}
|
|
//assert(strlen(buf) > 0);
|
|
o = addob(lf->pack, buf);
|
|
}
|
|
} else if (f->id == F_STARTOBCLASS) {
|
|
if (rnd(1,100) <= f->val[0]) {
|
|
int counter = 0;
|
|
if (db) {
|
|
sprintf(buf2, "calling startobclass");
|
|
}
|
|
//obdb = B_TRUE;
|
|
while (!getrandomobwithclass(lf->cell->map, f->val[1], buf, f->val[2])) {
|
|
counter++;
|
|
}
|
|
//obdb = B_FALSE;
|
|
if (db) {
|
|
sprintf(buf2, "finished startobclass (needed %d tries)", counter);
|
|
}
|
|
//if (strlen(buf) <= 0);
|
|
o = addob(lf->pack, buf);
|
|
}
|
|
}
|
|
|
|
|
|
// added an object?
|
|
if (o) {
|
|
// undead can't have cursed objecst
|
|
if (isundead(lf)) {
|
|
if (o->blessed == B_BLESSED) setblessed(o, B_CURSED);
|
|
}
|
|
// player knows the objects they start with
|
|
if (isplayer(lf)) {
|
|
identify(o);
|
|
}
|
|
}
|
|
}
|
|
ignoredprev = B_FALSE;
|
|
}
|
|
|
|
// now remove startob flags so we don't get them again!
|
|
killflagsofid(fp, F_STARTOB);
|
|
killflagsofid(fp, F_STARTOBDT);
|
|
killflagsofid(fp, F_STARTOBCLASS);
|
|
|
|
// make sure lf doesn't start off burdened!
|
|
while (isburdened(lf)) {
|
|
modattr(lf, A_STR, 1); // get stronger
|
|
}
|
|
}
|
|
|
|
void givestartskills(lifeform_t *lf, flagpile_t *fp) {
|
|
flag_t *f;
|
|
for (f = fp->first ; f ; f = f->next) {
|
|
if (f->id == F_STARTSKILL) {
|
|
int wantval;
|
|
wantval = f->val[1];
|
|
while (getskill(lf, f->val[0]) < wantval) {
|
|
giveskill(lf, f->val[0]);
|
|
}
|
|
}
|
|
}
|
|
// now remove startskill flags so we don't get them again!
|
|
killflagsofid(fp, F_STARTSKILL);
|
|
}
|
|
|
|
|
|
job_t *hasjob(lifeform_t *lf, enum JOB job) {
|
|
job_t *j = NULL;
|
|
if (lfhasflagval(lf, F_JOB, job, NA, NA, NULL)) {
|
|
j = findjob(job);
|
|
}
|
|
return j;
|
|
}
|
|
|
|
|
|
|
|
int lfcanbestoned(lifeform_t *lf) {
|
|
switch (getlfmaterial(lf)) {
|
|
case MT_GAS:
|
|
case MT_STONE:
|
|
return B_FALSE;
|
|
default:
|
|
break;
|
|
}
|
|
if (lfhasflag(lf, F_NONCORPOREAL)) {
|
|
return B_FALSE;
|
|
}
|
|
if (isimmuneto(lf->flags, DT_PETRIFY)) {
|
|
return B_FALSE;
|
|
}
|
|
if (isdead(lf)) {
|
|
return B_FALSE;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// does the lf has this flag, either internally or
|
|
// conferred by a held/equipped object?
|
|
flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid) {
|
|
flag_t *f;
|
|
|
|
// note: we check conferred flags first because we want
|
|
// these to override ones direclty on the player.
|
|
|
|
// does a held object give us this flag?
|
|
/*
|
|
o = hasobwithflagval(lf->pack, F_HOLDCONFER, fid, NA, NA, NULL);
|
|
if (o) {
|
|
// return the flag, not the objcet
|
|
f = hasflagval(o->flags, F_HOLDCONFER, fid, NA, NA, NULL);
|
|
if (f) return f;
|
|
}
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
f = hasflagval(o->flags, F_HOLDCONFER, fid, NA, NA, NULL);
|
|
if (f) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
// does an equipped object give us this flag?
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (hasflag(o->flags, F_EQUIPPED)) {
|
|
f = hasflagval(o->flags, F_EQUIPCONFER, fid, NA, NA, NULL);
|
|
if (f) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// do we have this flag directly?
|
|
f = hasflag(lf->flags, fid);
|
|
if (f) return f;
|
|
return NULL;
|
|
}
|
|
|
|
flag_t *lfhasflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text) {
|
|
flag_t *f;
|
|
f = hasflagval(lf->flags, fid, val0, val1, val2, text);
|
|
if (f) return f;
|
|
|
|
// does a held object give us this flag?
|
|
/*
|
|
o = hasobwithflagval(lf->pack, F_HOLDCONFER, fid, val0, val1, text);
|
|
if (o) {
|
|
// return the flag, not the objcet
|
|
f = hasflagval(o->flags, F_HOLDCONFER, fid, val0, val1, text);
|
|
if (f) return f;
|
|
}
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
f = hasflagval(o->flags, F_HOLDCONFER, fid, val0, val1, text);
|
|
if (f) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// does an equipped object give us this flag?
|
|
/*
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (hasflag(o->flags, F_EQUIPPED)) {
|
|
f = hasflagval(o->flags, F_EQUIPCONFER, fid, val0, val1, NULL);
|
|
if (f) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
flag_t *lfhasknownflag(lifeform_t *lf, enum FLAG fid) {
|
|
flag_t *f;
|
|
|
|
// note: we check conferred flags first because we want
|
|
// these to override ones direclty on the player.
|
|
|
|
/*
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isknown(o)) {
|
|
f = hasflagval(o->flags, F_HOLDCONFER, fid, NA, NA, NULL);
|
|
if (f && f->known) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*/
|
|
// does an equipped object give us this flag?
|
|
/*
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isknown(o)) {
|
|
if (hasflag(o->flags, F_EQUIPPED)) {
|
|
f = hasflagval(o->flags, F_EQUIPCONFER, fid, NA, NA, NULL);
|
|
if (f && f->known) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// do we have this flag directly?
|
|
f = hasflagknown(lf->flags, fid);
|
|
if (f && f->known) return f;
|
|
return NULL;
|
|
}
|
|
|
|
flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text) {
|
|
flag_t *f;
|
|
|
|
/*
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isknown(o)) {
|
|
f = hasflagval(o->flags, F_HOLDCONFER, fid, val0, val1, text);
|
|
if (f && f->known) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// does an equipped object give us this flag?
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isknown(o)) {
|
|
if (hasflag(o->flags, F_EQUIPPED)) {
|
|
f = hasflagval(o->flags, F_EQUIPCONFER, fid, val0, val1, NULL);
|
|
if (f && f->known) {
|
|
if (f->val[2] == B_IFIDENT) {
|
|
if (isknown(o)) return f;
|
|
} else {
|
|
return f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// got the flag directly?
|
|
f = hasflagvalknown(lf->flags, fid, val0, val1, val2, text);
|
|
if (f && f->known) return f;
|
|
return NULL;
|
|
}
|
|
|
|
// returns radius of light produces
|
|
int lfproduceslight(lifeform_t *lf) {
|
|
int temp = 0;
|
|
int radius = 0;
|
|
object_t *o;
|
|
|
|
// lf producing light itself?
|
|
sumflags(lf->flags, F_PRODUCESLIGHT, &temp, NULL, NULL);
|
|
if (temp) radius = temp;
|
|
|
|
// objects in hands or on body...
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isequipped(o)) {
|
|
temp = obproduceslight(o);
|
|
if (temp > radius) {
|
|
radius = temp;
|
|
}
|
|
}
|
|
}
|
|
return radius;
|
|
}
|
|
|
|
// return true on failure
|
|
int lockpick(lifeform_t *lf, object_t *target, object_t *device) {
|
|
flag_t *f,*lockflag;
|
|
char lfname[BUFLEN];
|
|
char obname[BUFLEN];
|
|
int faileffect;
|
|
int difficulty = 20; // default, never used though
|
|
|
|
lockflag = hasflag(target->flags, F_LOCKED);
|
|
if (lockflag) {
|
|
difficulty = lockflag->val[1];
|
|
} else {
|
|
// should never happen
|
|
if (isplayer(lf)) {
|
|
msg("That isn't locked!");
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
getlfname(lf,lfname);
|
|
getobname(target,obname, 1);
|
|
|
|
f = hasflag(device->flags, F_PICKLOCKS);
|
|
assert(f);
|
|
faileffect = f->val[1];
|
|
|
|
// take time
|
|
taketime(lf, getactspeed(lf) );
|
|
|
|
// TODO: different difficulty based on doors (maybe part of F_LOCKED flag)
|
|
if (skillcheck(lf, SC_OPENLOCKS, difficulty, f->val[0])) {
|
|
// success!
|
|
// announce
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
msg("%s unlock%s %s.",lfname, isplayer(lf) ? "" : "s", obname);
|
|
}
|
|
// unlock it
|
|
killflagsofid(target->flags, F_LOCKED);
|
|
// xp
|
|
if (isplayer(lf)) {
|
|
if (hasjob(lf, J_ROGUE)) {
|
|
gainxp(lf, difficulty);
|
|
} else {
|
|
gainxp(lf, difficulty/3);
|
|
}
|
|
}
|
|
} else {
|
|
// failed!
|
|
if (faileffect == B_DIEONFAIL) {
|
|
char devname[BUFLEN];
|
|
getobname(device,devname, 1);
|
|
// kill object
|
|
if (isplayer(lf)) {
|
|
msg("Your %s breaks!",noprefix(devname));
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s%s %s breaks!",lfname, getpossessive(lfname), noprefix(devname));
|
|
}
|
|
removeob(device, 1);
|
|
} else if (faileffect == B_BLUNTONFAIL) {
|
|
if (!makeduller(device, 1)) {
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
msg("%s fail%s to unlock %s.",lfname, isplayer(lf) ? "" : "s", obname);
|
|
}
|
|
}
|
|
} else {
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
msg("%s fail%s to unlock %s.",lfname, isplayer(lf) ? "" : "s", obname);
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
void loseobflags(lifeform_t *lf, object_t *o, int kind) {
|
|
flag_t *f,*ff,*nextff;
|
|
for (f = o->flags->first ; f ; f = f->next) {
|
|
int checkthis = B_FALSE;
|
|
if (kind == ALLCONFERRED) {
|
|
if ((f->id == F_EQUIPCONFER) || (f->id == F_HOLDCONFER) || (f->id == F_ACTIVATECONFER)) {
|
|
checkthis = B_TRUE;
|
|
}
|
|
} else {
|
|
if (f->id == kind) {
|
|
checkthis = B_TRUE;
|
|
}
|
|
}
|
|
if (checkthis) {
|
|
int lifetimecheck;
|
|
// probably don't need this now that we are using
|
|
// flag->obfrom...
|
|
if (f->id == F_EQUIPCONFER) {
|
|
lifetimecheck = FROMOBEQUIP;
|
|
} else if (f->id == F_ACTIVATECONFER) {
|
|
lifetimecheck = FROMOBACTIVATE;
|
|
} else { // ie. F_HOLDCONFER
|
|
lifetimecheck = FROMOBHOLD;
|
|
}
|
|
|
|
// not using killflagsofid() because we only want
|
|
// to kill flags which came from this object
|
|
for (ff = lf->flags->first ; ff ; ff = nextff) {
|
|
nextff = ff->next;
|
|
if ( (ff->id == f->val[0]) &&
|
|
(ff->val[0] == f->val[1]) &&
|
|
(ff->val[1] == f->val[2]) &&
|
|
(ff->lifetime == lifetimecheck) ) {
|
|
if (ff->obfrom == o->id) {
|
|
killflag(ff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int hasbp(lifeform_t *lf, enum BODYPART bp) {
|
|
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
|
|
return B_FALSE;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
flag_t *hasactivespell(lifeform_t *lf, enum OBTYPE sid) {
|
|
return lfhasflagval(lf, F_BOOSTSPELL, sid, NA, NA, NULL);
|
|
}
|
|
|
|
// got line of fire to dest? if lof is blocked, return last cell in 'newdest'
|
|
//int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) {
|
|
int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) {
|
|
int numpixels;
|
|
int i;
|
|
int x1,y1,x2,y2;
|
|
map_t *map;
|
|
cell_t *retcell[MAXRETCELLS];
|
|
|
|
reason = E_OK;
|
|
if (newdest) *newdest = src;
|
|
|
|
//if (!viewer) return B_FALSE;
|
|
if (!src) return B_FALSE;
|
|
|
|
if (src->map != dest->map) {
|
|
reason = E_NOLOS;
|
|
return B_FALSE;
|
|
}
|
|
map = dest->map;
|
|
|
|
|
|
x1 = src->x;
|
|
y1 = src->y;
|
|
x2 = dest->x;
|
|
y2 = dest->y;
|
|
|
|
// can always fire at your own cell
|
|
if ((x1 == x2) && (y1 == y2)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels);
|
|
|
|
|
|
for (i = 0; i < numpixels ; i++) {
|
|
cell_t *cell;
|
|
object_t *blockob;
|
|
|
|
cell = retcell[i];
|
|
|
|
// we _DO_ need to move out of last cell for line of fire.
|
|
|
|
// if walls don't stop lof, this is now a valid cell.
|
|
if (!(loftype & LOF_WALLSTOP)) {
|
|
if (newdest) *newdest = cell;
|
|
}
|
|
|
|
// solid cells stop lof
|
|
if (loftype & LOF_WALLSTOP) {
|
|
if (cell->type->solid) {
|
|
reason = E_NOLOF;
|
|
return B_FALSE;
|
|
}
|
|
// certain objects block lof
|
|
blockob = hasobwithflag(cell->obpile, F_BLOCKSLOF);
|
|
if (blockob) {
|
|
int blocked = B_TRUE; // default
|
|
int isopen;
|
|
if (isdoor(blockob, &isopen)) {
|
|
if (isopen) {
|
|
// open doors don't block line of fire
|
|
blocked = B_FALSE;
|
|
}
|
|
}
|
|
if (blocked) {
|
|
reason = E_NOLOF;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
// if lifeforms don't stop lof, this is now a valid cell.
|
|
// if (!(loftype & LOF_LFSSTOP)) {
|
|
if (newdest) *newdest = cell;
|
|
// }
|
|
|
|
// lifeforms block lof unless they're in our destination
|
|
if (cell->lf && (!isprone(cell->lf)) && (loftype & LOF_LFSSTOP)) {
|
|
// if not in first cell...
|
|
if (i != 0) {
|
|
// if not in last cell...
|
|
if (i != (numpixels-1)) {
|
|
reason = E_NOLOF;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
// cell is now valid
|
|
if (newdest) *newdest = cell;
|
|
}
|
|
|
|
// made it to the target cell!
|
|
return B_TRUE;
|
|
}
|
|
|
|
int haslos(lifeform_t *viewer, cell_t *dest) {
|
|
int numpixels;
|
|
int i;
|
|
int x1,y1;
|
|
int maxvisrange;
|
|
int nightvisrange;
|
|
int xray = 0;
|
|
//int wentuphill = B_FALSE;
|
|
//int origheight;
|
|
//int shopwall;
|
|
flag_t *f;
|
|
int x2,y2;
|
|
map_t *map;
|
|
object_t *o;
|
|
int currange;
|
|
cell_t *retcell[MAXRETCELLS];
|
|
|
|
if (!viewer) return B_FALSE;
|
|
if (!dest) return B_FALSE;
|
|
if (!viewer->cell) return B_FALSE;
|
|
|
|
// let the player see when dead, otherwise the screen wil
|
|
// go black when "You die" appears.
|
|
if (isdead(viewer) && !isplayer(viewer)) return B_FALSE;
|
|
|
|
if (viewer->cell->map != dest->map) return B_FALSE;
|
|
|
|
map = dest->map;
|
|
|
|
x1 = viewer->cell->x;
|
|
y1 = viewer->cell->y;
|
|
x2 = dest->x;
|
|
y2 = dest->y;
|
|
|
|
|
|
f = hasflag(viewer->flags, F_XRAYVIS);
|
|
if (f) {
|
|
xray = f->val[0];
|
|
} else {
|
|
xray = 0;
|
|
}
|
|
|
|
// can't see if you're blind
|
|
if (isblind(viewer)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels);
|
|
|
|
maxvisrange = getvisrange(viewer);
|
|
nightvisrange = getnightvisrange(viewer);
|
|
|
|
//origheight = getheight(x1,y1,z);
|
|
|
|
// too far away
|
|
if (maxvisrange != UNLIMITED) {
|
|
if (getcelldist(viewer->cell, dest) > maxvisrange) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// outside the range of our light, and not lit
|
|
if (nightvisrange != UNLIMITED) {
|
|
if (getcelldist(viewer->cell, dest) > nightvisrange) {
|
|
if (!islit(dest)) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//shopwall = B_FALSE;
|
|
currange = 0;
|
|
|
|
for (i = 0; i < numpixels ; i++) {
|
|
cell_t *cell;
|
|
|
|
cell = retcell[i];
|
|
// don't need to move out of the last one
|
|
if ((cell->x == x2) && (cell->y == y2)) {
|
|
break;
|
|
}
|
|
|
|
// you can always see your own cell
|
|
if (i != 0) {
|
|
currange++;
|
|
if (currange > maxvisrange) {
|
|
return B_FALSE;
|
|
}
|
|
// if we went uphill, stop here
|
|
/*
|
|
if (wentuphill) {
|
|
return B_FALSE;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
if (debug) {
|
|
printf("checking LOS at %d,%d going (%d,%d)\n",x,y,xinc,yinc);
|
|
fflush(stdout);
|
|
}
|
|
*/
|
|
|
|
// solid cells stop los - but if you are standing on a solid
|
|
// cell you can still see out.
|
|
if (!cell->type->transparent) {
|
|
if (xray) xray--;
|
|
else return B_FALSE;
|
|
}
|
|
|
|
// check for objects which block view
|
|
for (o = cell->obpile->first ; o ; o = o->next) {
|
|
f = hasflag(o->flags, F_BLOCKSVIEW);
|
|
if (f) {
|
|
if (!lfhasflagval(viewer, F_CANSEETHROUGHMAT, o->material->id, NA, NA, NULL)) {
|
|
if (xray) {
|
|
xray--;
|
|
} else {
|
|
if (f->val[0] == B_TRUE) {
|
|
return B_FALSE;
|
|
} else {
|
|
currange += f->val[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// xray vision decreases by one
|
|
if (xray) xray--;
|
|
|
|
// if you went uphill, can't see any further
|
|
/*
|
|
if (getheight(x,y,z) > origheight) {
|
|
wentuphill = B_TRUE;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
void initjobs(void) {
|
|
int i;
|
|
// job definitions
|
|
// NOTE: try to always make the job's weapon be the first object defined.
|
|
// this will make sure that they have the letter 'a'.
|
|
addjob(J_GOD, "Diety");
|
|
//addflag(lastjob->flags, F_OMNIPOTENT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_MPDICE, 100, NA, NA, NULL);
|
|
//addflag(lastjob->flags, F_MPREGEN, 100, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "short sword of pyromania");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "hand of god");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blocks of chocolate");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 vials of ambrosia");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather boots");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather gloves");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "graph paper");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "a digital watch");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blessed scrolls of create monster");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blessed potions of experience");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "ring of miracles");
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_MASTER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_MASTER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_MASTER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_MASTER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SS_MENTAL, PR_MASTER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_MASTER, NA, NULL);
|
|
addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf");
|
|
for (i = 1; i < MAXSKILLS; i++) {
|
|
addflag(lastjob->flags, F_CANLEARN, i, NA, NA, NULL);
|
|
}
|
|
// gods may use all abilities and cast any spell at will
|
|
for (i = SS_NONE+1; i < SS_LAST; i++) {
|
|
if ((i == SS_ABILITY) || (i == SS_DIVINE)) {
|
|
mayusespellschool(lastjob->flags, i, F_CANWILL);
|
|
} else {
|
|
mayusespellschool(lastjob->flags, i, F_CANCAST);
|
|
}
|
|
}
|
|
|
|
addjob(J_ADVENTURER, "Adventurer");
|
|
addflag(lastjob->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "short sword");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 bananas");
|
|
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");
|
|
addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_UNDEAD, PR_NOVICE, NA, NULL);
|
|
for (i = 1; i < MAXSKILLS; i++) {
|
|
addflag(lastjob->flags, F_CANLEARN, i, NA, NA, NULL);
|
|
}
|
|
addjob(J_ALLOMANCER, "Allomancer");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "1 gold coins");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "club");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "cloak");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "potion of magic");
|
|
addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL);
|
|
//addflag(lastjob->flags, F_MPDICE, 5, 6, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_ABSORBMETAL, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_DETECTMETAL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SS_ALLOMANCY, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_NOVICE, NA, NULL);
|
|
mayusespellschool(lastjob->flags, SS_ALLOMANCY, F_CANCAST);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL);
|
|
// TODO skill: court knowledge ??
|
|
// TODO skill: bartering 2
|
|
addjob(J_BARBARIAN, "Barbarian");
|
|
addflag(lastjob->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_CON, CN_FIT, NA, NULL);
|
|
addflag(lastjob->flags, F_HITDICE, 1, 6, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "axe");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler");
|
|
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_STARTSKILL, SK_AXES, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_TRACKING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LOCKPICKING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_LEVABIL, 3, OT_A_HEAVYBLOW, 3, NULL);
|
|
addflag(lastjob->flags, F_LEVABIL, 4, OT_A_WARCRY, 4, NULL);
|
|
addflag(lastjob->flags, F_LEVABIL, 5, OT_A_CHARGE, 5, NULL);
|
|
addflag(lastjob->flags, F_LEVABIL, 6, OT_A_RAGE, 50, NULL);
|
|
addflag(lastjob->flags, F_LEVABIL, 10, OT_A_HURRICANESTRIKE, 5, NULL);
|
|
addjob(J_COMMANDO, "Commando");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "combat knife");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "revolver");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "helmet");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "flak jacket");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "combat pants");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather boots");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "nightvis goggles");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "1-2 blocks of c4");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "1-3 grenades");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "1-3 flashbangs");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "digital watch");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 bullets");
|
|
addflag(lastjob->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_CON, CN_HEALTHY, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_ADEPT, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_FIRSTAID, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_TRACKING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL);
|
|
addjob(J_DRUID, "Druid");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "quarterstaff");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of sandals");
|
|
addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL);
|
|
// skills
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_ADEPT, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_TRACKING, 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);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL);
|
|
// gained skills
|
|
addflag(lastjob->flags, F_LEVSKILL, 5, SK_LORE_NATURE, NA, NULL);
|
|
addflag(lastjob->flags, F_LEVSKILL, 10, SK_LORE_NATURE, NA, NULL);
|
|
addflag(lastjob->flags, F_LEVSKILL, 15, SK_LORE_NATURE, NA, NULL);
|
|
// abilities
|
|
mayusespellschool(lastjob->flags, SS_NATURE, F_CANCAST);
|
|
addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf");
|
|
addflag(lastjob->flags, F_PARTVEGETARIAN, B_TRUE, NA, NA, NULL);
|
|
|
|
addjob(J_PLUMBER, "Plumber");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "spanner");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "overalls");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "cap");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3-5 mushrooms");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "rubber boots");
|
|
addflag(lastjob->flags, F_EVASION, 30, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_OBESE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SPELLCASTING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_COLD, NA, NA, NULL);
|
|
addjob(J_PRINCE, "Prince");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "blessed ornamental sword");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "100 gold coins");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "golden crown");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "ornamental dagger");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "velvet robe");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "silk shirt");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "riding trousers");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather boots");
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL);
|
|
|
|
addjob(J_PIRATE, "Pirate");
|
|
// stats
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_CON, CN_HEALTHY, NA, NULL);
|
|
// abilities
|
|
addflag(lastjob->flags, F_STABILITY, B_TRUE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_EXTRALUCK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young hawk");
|
|
addflag(lastjob->flags, F_MAXATTACKS, 2, NA, NA, NULL);// this is so that our hookhand works
|
|
addflag(lastjob->flags, F_VISRANGEMOD, -4, NA, NA, NULL);
|
|
// also: has a hook instead of fists.
|
|
// startobjects
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "cutlass");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "silk shirt");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "cloth trousers");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "eyepatch");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "tricorne");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "300-350 gold coins");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 potions of rum");
|
|
// skills
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_UNARMED, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_ADEPT, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL);
|
|
|
|
addjob(J_ROGUE, "Rogue");
|
|
addflag(lastjob->flags, F_STARTATT, A_STR, ST_WEAK, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_NIMBLE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_CON, CN_UNFIT, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "dagger");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins");
|
|
addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LISTEN, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_BACKSTAB, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SPOTHIDDEN, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_TRACKING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_GRAVITY, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_MODIFICATION, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_MENTAL, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, NA, NA, NULL);
|
|
|
|
addjob(J_WIZARD, "Wizard");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "knife");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe");
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic");
|
|
/*
|
|
addflag(lastjob->flags, F_IFPLAYER, NA, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 50, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "spellbook of flame dart");
|
|
addflag(lastjob->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "spellbook of cone of cold");
|
|
addflag(lastjob->flags, F_ENDIFPLAYER, NA, NA, NA, NULL);
|
|
*/
|
|
|
|
addflag(lastjob->flags, F_IFMONSTER, NA, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 50, NA, NA, NULL); // monsters sometimes start with a random book
|
|
addflag(lastjob->flags, F_STARTOBCLASS, 100, OC_BOOK, NA, NULL);
|
|
addflag(lastjob->flags, F_ENDIFMONSTER, NA, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_HITDICE, 1, 1, NA, NULL); // low hp
|
|
addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_STR, ST_WEAK, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL);
|
|
// wizard heals slowly, but regenerates mp
|
|
addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL);
|
|
//addflag(lastjob->flags, F_MPREGEN, 1, SK_SPELLCASTING, 35, NULL);
|
|
// can detect magic objects
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_STARTSKILL, SK_SS_WILD, PR_NOVICE, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL);
|
|
// wizards can learn all spell schools except psionics and allomancy
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_DEATH, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_COLD, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_GRAVITY, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_MODIFICATION, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_SUMMONING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LORE_DEMONS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANLEARN, SK_LORE_UNDEAD, NA, NA, NULL);
|
|
// gained skills
|
|
addflag(lastjob->flags, F_LEVFLAG, 3, F_DETECTMAGIC, B_TRUE, NULL);
|
|
addflag(lastjob->flags, F_LEVFLAG, 7, F_DETECTAURAS, B_TRUE, NULL);
|
|
addflag(lastjob->flags, F_LEVFLAG, 10, F_CONTROL, B_TRUE, NULL);
|
|
addflag(lastjob->flags, F_LEVSPELLSCHOOL, 101, SS_NONE, B_TRUE, NULL); // new spell every 1 level
|
|
|
|
// for monster wizards only:
|
|
addflag(lastjob->flags, F_IFMONSTER, NA, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 50, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_FIREDART, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 50, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_COLDRAY, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 33, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_HEALINGMIN, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 33, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_BLINK, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 33, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 20, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_HASTE, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_IFPCT, 20, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_CANCAST, OT_S_HEALING, NA, NA, NULL);
|
|
addflag(lastjob->flags, F_ENDIFMONSTER, NA, NA, NA, NULL);
|
|
}
|
|
|
|
void initrace(void) {
|
|
// race classes
|
|
addraceclass(RC_OTHER, "misc. creature", "miscellaneous creatures", SK_NONE);
|
|
addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE);
|
|
addraceclass(RC_AQUATIC, "aquatic creature", "aquatic creatures", SK_LORE_NATURE);
|
|
addraceclass(RC_DEMON, "demon", "demons", SK_LORE_DEMONS);
|
|
addraceclass(RC_HUMANOID, "humanoid", "humanoid creatures", SK_LORE_HUMANOID);
|
|
addraceclass(RC_INSECT, "insect", "insects and animals", SK_LORE_NATURE);
|
|
addraceclass(RC_MAGIC, "magical creature", "magical creatures", SK_LORE_ARCANA);
|
|
addraceclass(RC_PLANT, "plant", "plants", SK_LORE_NATURE);
|
|
addraceclass(RC_SLIME, "slime", "slimes", SK_NONE);
|
|
addraceclass(RC_UNDEAD, "undead", "the undead", SK_LORE_UNDEAD);
|
|
|
|
// races / monsters
|
|
addrace(R_HUMAN, "human", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, 2, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
|
|
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "1-50 gold coins");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 65, OC_WEAPON, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 65, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 65, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 65, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL);
|
|
// TODO: humans start with a random job sometimes?
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
// addflag(lastrace->flags, F_RESTHEALMPAMT, 1, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
// human monsters...
|
|
addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL);
|
|
addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEMANDSBRIBE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, 2, NA, NULL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "1-100 gold coins");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_WEAPON, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_SCROLL, NA, NULL);
|
|
//addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOJOBTEXT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTJOB, 15, J_WIZARD, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTJOB, 50, J_ROGUE, NA, NULL);
|
|
|
|
// monsters
|
|
addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_GENIUS, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 12, 4, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 8, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, 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_CANWILL, OT_S_FIREDART, NA, NA, "pw:5;");
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_WEAKEN, NA, NA, "pw:2;");
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_SLEEP, NA, NA, "pw:2;");
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_PULL, NA, NA, "pw:2;");
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_PARALYZE, NA, NA, "pw:2;");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "2d4");
|
|
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "gazes at you");
|
|
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_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 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);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 4, 5, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, 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, "2d4+1");
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "heavy flail");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roars");
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, 2, 2, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "goblin");
|
|
addflag(lastrace->flags, F_MINIONS, 20, 1, 3, "goblin warrior");
|
|
|
|
addrace(R_COCKATRICE, "cockatrice", 5, 'c', C_YELLOW, MT_FLESH, RC_MAGIC);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_SWIFT, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "splash of cockatrice blood");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 7, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 8, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
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_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTIMMUNE, DT_PETRIFY, B_TRUE, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6+3");
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
// special attack handled in attack.c
|
|
|
|
addrace(R_CREEPINGCLAW, "creeping claw", 3, 'x', C_YELLOW, MT_FLESH, RC_MAGIC);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, -2, 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_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, 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_EYES, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_BODY, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, 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;");
|
|
|
|
addrace(R_DARKMANTLE, "darkmantle", 70, 'U', C_BLUE, MT_FLESH, RC_MAGIC);
|
|
addflag(lastrace->flags, F_STARTHIDDENPCT, 80, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_SUPERSONIC, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 9, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 15, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SPELLSPEED, SP_VERYSLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, "");
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_DARKNESS, 7, 7, "pw:3;");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:0d0+5;");
|
|
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "waves its tentacles");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TENTACLE, NA, NA, "2d6");
|
|
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_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "0d6+5");
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_EYEBAT, "eyebat", 5, 'e', C_BLUE, MT_FLESH, RC_MAGIC);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_VWEAK, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 20, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
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_SPELLCASTTEXT, NA, NA, NA, "gazes at you");
|
|
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_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings");
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
|
|
addrace(R_GIANTHILL, "hill giant", 160, 'H', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 55, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 19, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -20, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "2d5");
|
|
addflag(lastrace->flags, F_STARTOB, 90, NA, NA, "25-100 gold coins");
|
|
addflag(lastrace->flags, F_STARTOB, 70, NA, NA, "1-2 boulders");
|
|
addflag(lastrace->flags, F_IFPCT, 70, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "great club");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 70, NA, NA, "club");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 65, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 65, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow");
|
|
addflag(lastrace->flags, F_WANTS, OT_BOULDER, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_GIANTFIRE, "fire giant", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 21, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 13, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -20, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "2d5+3");
|
|
addflag(lastrace->flags, F_STARTOB, 90, NA, NA, "25-100 gold coins");
|
|
addflag(lastrace->flags, F_IFPCT, 70, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flaming greatsword");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flaming longsword");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "javelin");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "javelin");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "javelin");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "javelin");
|
|
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "plate mail");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 70, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, 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_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_GIANTFIREFC, "fire giant forgecaller", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_GIANTFIRE;
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "fire giant corpse");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 48, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 17, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -20, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "2d5+3");
|
|
addflag(lastrace->flags, F_STARTOB, 90, NA, NA, "25-100 gold coins");
|
|
addflag(lastrace->flags, F_IFPCT, 70, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flaming morningstar");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flaming mace");
|
|
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "plate mail");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 70, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, 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);
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_FLAMEBURST, 4, 4, "pw:4;");
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SS_FIRE, PR_ADEPT, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_GIANTFIRETITAN, "fire titan", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 40, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_ENORMOUS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 49, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 20, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -30, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "2d5+8");
|
|
addflag(lastrace->flags, F_STARTOB, 90, NA, NA, "100-300 gold coins");
|
|
addflag(lastrace->flags, F_IFPCT, 65, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flaming greatsword of pyromania");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flaming greatsword");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_TITANIC, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_SWIFT, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 3, NA, "^crackling flames.");
|
|
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_BURNINGWAVE, 3, 3, "pw:6;");
|
|
addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
// TODO: storm giant
|
|
// TODO: storm titan
|
|
|
|
addrace(R_GNOLL, "gnoll", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 2, 3, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 8, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-40 gold coins");
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_GNOLLHM, "gnoll huntmaster", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_GNOLL;
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 6, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 0, 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_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "longbow");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10-20 arrows");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "hand axe");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-40 gold coins");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL);
|
|
addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll");
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_GNOLLMR, "gnoll marauder", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_GNOLL;
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 0, 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_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4+2");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "spear");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "buckler");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_QUICKBITE, 1, 6, 2, NULL);
|
|
addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL);
|
|
addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll");
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_GOBLIN, "goblin", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-25 gold coins");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "short sword");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 40, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
//addflag(lastrace->flags, F_STARTJOB, 25, J_WIZARD, 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_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
|
|
addrace(R_GOBLINWAR, "goblin warrior", 30, 'g', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_GOBLIN;
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 3, 5, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4+2");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "spear");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "1-5 javelins");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-50 gold coins");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, 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_MINIONS, 90, 1, 2, "goblin");
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_GOBLINSHOOTER, "goblin sharpshooter", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_GOBLIN;
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 3, 7, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "short sword");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "hand crossbow");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "1-15 bolts");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-25 gold coins");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
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_MINIONS, 70, 1, 2, "goblin");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTHIDDENPCT, 75, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_GOBLINHEXER, "goblin hexer", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_GOBLIN;
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 5, 6, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
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_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "club");
|
|
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
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_HASSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin");
|
|
|
|
addrace(R_HOBGOBLIN, "hobgoblin", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 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, 2, 3, NA, NULL);
|
|
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);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+2");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "longsword");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "buckler");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-50 gold coins");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_PHALANX, 5, NA, 1, "hobgoblin");
|
|
addflag(lastrace->flags, F_MINIONS, 50, 1, 2, "goblin");
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_HOBGOBLINWAR, "hobgoblin warrior", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_HOBGOBLIN;
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, 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, 2, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "flail");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-75 gold coins");
|
|
addflag(lastrace->flags, F_STARTOB, 90, NA, NA, "large shield");
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "scale armour");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_PHALANX, 8, NA, 1, "hobgoblin");
|
|
addflag(lastrace->flags, F_MINIONS, 50, 1, 4, "goblin");
|
|
addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
// TODO: hobgoblin archer
|
|
// TODO: hobgoblin warcaster
|
|
|
|
addrace(R_KOBOLD, "kobold", 18, 'k', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL);
|
|
addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL);
|
|
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_STARTATT, A_STR, ST_WEAK, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_NIMBLE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBDT, 20, DT_PIERCE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 40, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-3 darts");
|
|
addflag(lastrace->flags, F_STARTOB, 33, NA, NA, "javelin");
|
|
addflag(lastrace->flags, F_STARTOB, 33, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 33, NA, NA, "buckler");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-10 gold coins");
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_TROGLODYTE, "troglodyte", 20, 'z', C_GREY, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DIMWITTED, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_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_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");
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, B_TRUE, NA, NULL);
|
|
addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STENCH, 3, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_LIZARDMAN, "lizardman", 100, 'z', C_GREEN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 6, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d5+1");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TAIL, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-50 gold coins");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "spear");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-2 javelins");
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, B_TRUE, NA, NULL);
|
|
addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "spits");
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_POISONBOLT, 5, 5, "pw:5;");
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_LURKINGHORROR, "lurking horror", 100, 'U', C_MAGENTA, MT_FLESH, RC_DEMON);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 3, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, 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_NOBODYPART, BP_WEAPON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_EYES, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, 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_TREMORSENSE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_INDUCEFEAR, B_TRUE, NA, 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_DEAF, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_OGRE, "ogre", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 66, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 7, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "2d4");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "2d4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_STUPID, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_IFPCT, 80, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "great club");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "morningstar");
|
|
addflag(lastrace->flags, F_STARTOB, 70, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-70 gold coins");
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MINIONS, 50, 1, 5, "orc");
|
|
addflag(lastrace->flags, F_MINIONS, 20, 1, 2, "orc warrior");
|
|
addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL);
|
|
|
|
addrace(R_OGRESAVAGE, "ogre savage", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_OGRE;
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 55, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 13, 8, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 11, 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_FISTS, NA, NA, "3d4");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "3d4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_STUPID, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_IFPCT, 80, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed great club");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "great club");
|
|
addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-70 gold coins");
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MINIONS, 50, 1, 5, "orc");
|
|
addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "orc warrior");
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_OGREWARHULK, "ogre warhulk", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_OGRE;
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 50, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 35, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 11, 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_FISTS, NA, NA, "4d4");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "4d4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_STUPID, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_IFPCT, 80, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "heavy flail");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "great club");
|
|
addflag(lastrace->flags, F_STARTOB, 70, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-100 gold coins");
|
|
addflag(lastrace->flags, F_HEAVYBLOW, B_TRUE, NA, 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_MINIONS, 25, 1, 8, "orc");
|
|
addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "orc warrior");
|
|
|
|
addrace(R_ORC, "orc", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 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_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_IFPCT, 70, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "club");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBDT, 50, DT_SLASH, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "bone helmet");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-50 gold coins");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
|
|
//addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_ORCWARRIOR, "orc warrior", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
lastrace->baseid = R_ORC;
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 10, 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_STARTATT, A_IQ, IQ_DOPEY, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_IFPCT, 70, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "battleaxe");
|
|
addflag(lastrace->flags, F_ELSE, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBDT, 50, DT_CHOP, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour");
|
|
addflag(lastrace->flags, F_STARTOB, 75, NA, NA, "buckler");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "bone helmet");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-50 gold coins");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL);
|
|
//addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_ORK, "ork", 90, 'o', C_BROWN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "orc corpse");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 81, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 81, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 3, 3, 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, "1d4");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBDT, 100, DT_SLASH, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBDT, 30, DT_BASH, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "flak jacket");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "leather boots");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "football helmet");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-25 gold coins");
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_TECH, 10, NULL);
|
|
addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_OPERABLE, B_COVETS, NA, NULL); // ie. tech
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_PEGASUS, "pegasus", 130, 'Q', C_GREY, MT_FLESH, RC_MAGIC);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 57, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 57, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 6, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_HOOF, NA, NA, "1d8");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_HOOF, NA, NA, "1d8");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 3, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 2, 2, NULL);
|
|
addflag(lastrace->flags, F_SWOOPRANGE, 4, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 4, NA, "screams in pain^screams of pain");
|
|
addflag(lastrace->flags, F_RESISTMAG, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 25, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_POLTERGEIST, "poltergeist", 50, 'p', C_GREEN, MT_FLESH, RC_UNDEAD); // sPirit
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
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, NA, "gestures");
|
|
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_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SS_MENTAL, PR_EXPERT, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL);
|
|
|
|
addrace(R_SATYR, "satyr", 80, 'h', C_GREEN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_BUTT, NA, NA, "2d4");
|
|
addflag(lastrace->flags, F_STARTOBDT, 50, DT_SLASH, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "panpipes");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "bow");
|
|
addflag(lastrace->flags, F_STARTOB, 75, NA, NA, "1-10 arrows");
|
|
addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-30 gold coins");
|
|
addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout");
|
|
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);
|
|
addflag(lastrace->flags, F_CANCAST, OT_S_FEAR, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SS_MENTAL, PR_ADEPT, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTHIDDENPCT, 60, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_TRACKING, PR_SKILLED, NA, NULL);
|
|
|
|
addrace(R_SHADOWCAT, "shadowcat", 5, 'f', C_BLUE, MT_FLESH, RC_MAGIC);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, 3, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 40, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "hisses^a hiss");
|
|
addflag(lastrace->flags, F_SEEINDARK, 8, NA, NA, NULL);
|
|
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);
|
|
|
|
addrace(R_OOZEGREY, "grey ooze", 10, 'j', C_GREY, MT_SLIME, RC_SLIME);
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pool of slime");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 5, 0, NA, NULL);
|
|
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_NOBODYPART, BP_WEAPON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_EYES, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, 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_HASATTACK, OT_ACIDATTACK, NA, NA, "1d6+5");
|
|
addflag(lastrace->flags, F_TREMORSENSE, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slurping");
|
|
addflag(lastrace->flags, F_DTIMMUNE, DT_ACID, B_TRUE, NA, NULL);
|
|
addflag(lastrace->flags, F_AUTOCREATEOB, 0, NA, NA, "puddle of acid");
|
|
addflag(lastrace->flags, F_DIESPLATTER, 3, NA, NA, "splash of acid");
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
|
|
addrace(R_SPRITEFIRE, "fire sprite", 5, 'n', C_RED, MT_FIRE, RC_MAGIC);
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "small fire");
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_VWEAK, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 15, NA, NA, NULL);
|
|
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, NA, "gestures");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^crackling flames");
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL);
|
|
addflag(lastrace->flags, F_HASSKILL, SK_SS_FIRE, PR_BEGINNER, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
|
|
|
|
addrace(R_TROLL, "troll", 100, 't', C_GREEN, MT_FLESH, RC_HUMANOID);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 70, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 3, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DIMWITTED, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_REGENERATES, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
|
|
|
|
addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, 0, 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_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DIMWITTED, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_WEAK, 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_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
|
|
|
|
// fish
|
|
addrace(R_CRAB, "giant crab", 250, ';', C_ORANGE, MT_FLESH, RC_AQUATIC);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 20, NA, NA, NULL); // very high armour
|
|
addflag(lastrace->flags, F_HITDICE, 4, 4, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, "");
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4");
|
|
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_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, 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);
|
|
addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, -2, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, "");
|
|
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_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
|
|
addrace(R_PIRANHAKING, "king piranha", 1, ';', 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);
|
|
addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, 2, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, "");
|
|
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_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;");
|
|
addrace(R_EELELEC, "electric eel", 120, ';', C_CYAN, MT_FLESH, RC_AQUATIC);
|
|
addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 73, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, 0, 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_TREMORSENSE, 10, 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_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_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL);
|
|
addrace(R_EELGIANT, "giant eel", 150, ';', C_BLUE, MT_FLESH, RC_AQUATIC);
|
|
addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 5, 0, 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_TREMORSENSE, 10, 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_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_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;");
|
|
|
|
// plants
|
|
addrace(R_CACTUS, "cactus", 30, 'F', C_YELLOW, MT_PLANT, RC_PLANT);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 76, NA, "");
|
|
addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
|
|
addflag(lastrace->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp spines");
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 4, NA, NA, "");
|
|
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_EYES, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, 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_NOBODYPART, BP_WAIST, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addrace(R_DREAMFUNGUS, "dreamfungus", 0.5, 'F', C_MAGENTA, MT_METAL, RC_PLANT);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 70, NA, "");
|
|
addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_VEGETABLE, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, 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_EYES, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, 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_NOBODYPART, BP_WAIST, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addrace(R_SAWGRASS, "sawgrass", 1, 'F', C_GREY, MT_METAL, RC_PLANT);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_VEGETABLE, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, 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_EYES, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, 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_NOBODYPART, BP_WAIST, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
// end plants
|
|
|
|
// animals
|
|
addrace(R_BAT, "giant bat", 3, 'B', C_BROWN, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 88, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 95, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 0, 2, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings");
|
|
addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 73, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 3, 3, 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_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars");
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d4;");
|
|
addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_BROWN, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 52, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 62, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 5, 5, 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_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d8");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars");
|
|
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;");
|
|
addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_BLEEDABIL, OT_A_RAGE, NA, NA, NULL);
|
|
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);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, "");
|
|
addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, "");
|
|
addflag(lastrace->flags, F_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_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1+4");
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL);
|
|
lastrace->baseid = R_ANT;
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 65, NA, "");
|
|
addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 4, 4, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, "");
|
|
addflag(lastrace->flags, F_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_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1+4");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:1d8+3;");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:1d6+3;needgrab:1;");
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "giant worker ant");
|
|
addrace(R_ANTLION, "giant antlion", 30, 'a', C_YELLOW, MT_FLESH, RC_ANIMAL);
|
|
lastrace->baseid = R_ANT;
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 60, NA, "");
|
|
addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 6, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, "");
|
|
addflag(lastrace->flags, F_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_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "5d4");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:2d4;");
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars");
|
|
addrace(R_DOGBLINK, "blink dog", 35, 'd', C_YELLOW, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, "");
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 77, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 77, NA, "");
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 4, 0, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, 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_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);
|
|
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_BLINK, 2, 2, "pw:1;");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 1, NA, "whines in pain^whining");
|
|
addrace(R_DOGDEATH, "death hound", 40, 'd', C_BLUE, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 60, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, 1, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d10");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d10");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, 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_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, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
|
|
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);
|
|
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, "");
|
|
addflag(lastrace->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 83, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 83, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, 2, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "2d4");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 5, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, 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, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
|
|
|
|
addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian
|
|
lastrace->baseid = R_HAWK;
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, IQ_AVERAGE, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, 4, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d2");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL);
|
|
addflag(lastrace->flags, F_SWOOPRANGE, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_LEVRACE, 4, R_HAWK, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain");
|
|
|
|
addrace(R_HAWK, "hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian
|
|
lastrace->baseid = R_HAWK;
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 77, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, 4, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL);
|
|
addflag(lastrace->flags, F_SWOOPRANGE, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_LEVRACE, 8, R_HAWKBLOOD, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain");
|
|
|
|
addrace(R_HAWKBLOOD, "blood hawk", 1, 'A', C_RED, MT_FLESH, RC_ANIMAL); // 'A' for Avian
|
|
lastrace->baseid = R_HAWK;
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 65, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 3, 4, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3+3");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4+3");
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL);
|
|
addflag(lastrace->flags, F_SWOOPRANGE, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 7, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain");
|
|
addrace(R_HAWKFROST, "frost hawk", 1, 'A', C_CYAN, MT_FLESH, RC_ANIMAL); // 'A' for Avian
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 10, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+5");
|
|
addflag(lastrace->flags, F_EXTRADAM, DT_COLD, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL);
|
|
addflag(lastrace->flags, F_SWOOPRANGE, 8, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_COLDBURST, 2, 2, "pw:2;");
|
|
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "screeches");
|
|
addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain");
|
|
addrace(R_LEECH, "giant leech", 10, 'j', C_MAGENTA, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 81, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 84, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 3, 1, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
|
|
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_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:4;");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:0d1+4;");
|
|
addrace(R_NEWT, "giant newt", 4, ':', C_BROWN, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_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);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTRESIST, DT_FIRE, B_TRUE, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addrace(R_PORCUPINE, "giant porcupine", 10, 'r', C_GREY, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HATESRACE, R_ANT, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, 1, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, 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_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_RETALIATE, 1, 4, DT_PIERCE, "sharp spines");
|
|
addflag(lastrace->flags, F_CORPSEFLAG, F_SHARP, 1, 4, NULL);
|
|
addrace(R_RAT, "giant rat", 3, 'r', C_BROWN, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_VWEAK, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 0, 1, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ENHANCESMELL, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
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);
|
|
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, "");
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 20, "5-10");
|
|
addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing");
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addrace(R_SNAKECARPET, "carpet snake", 3, 's', C_GREY, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 88, NA, "");
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3+1");
|
|
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_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing");
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addrace(R_SNAKETREE, "tree snake", 3, 's', C_GREEN, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, "");
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3+1");
|
|
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_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
|
|
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_TREMORSENSE, 10, NA, NA, NULL);
|
|
addrace(R_SNAKECOBRA, "giant cobra", 3, 's', C_BLUE, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 78, NA, "");
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 3, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3+1");
|
|
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_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing");
|
|
addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "spits");
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_POISONBOLT, 4, 4, "pw:3;");
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addrace(R_SNAKECONSTRICTOR, "constrictor", 3, 's', C_MAGENTA, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 68, NA, "");
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 4, 3, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1");
|
|
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_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
|
|
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_GRAB, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;");
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addrace(R_SNAKEWATER, "water snake", 3, 's', C_BLUE, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, "");
|
|
addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4+1");
|
|
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_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing");
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
|
|
addrace(R_SPIDER, "giant spider", 5, 'S', C_GREY, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 87, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, 1, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4");
|
|
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_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:1;");
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_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");
|
|
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, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 63, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 3, 1, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 26, "10-20");
|
|
addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 3, NA, NULL); // strong!
|
|
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_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:5;");
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_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");
|
|
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, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 78, NA, "");
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 3, 1, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_HITCONFER, F_PAIN, SC_POISON, 26, "5-15");
|
|
addflag(lastrace->flags, F_HITCONFERVALS, DT_POISON, NA, NA, "1d2");
|
|
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_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:7;");
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_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");
|
|
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);
|
|
addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 97, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, 2, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, 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_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_CARNIVORE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 8, 8, NULL);
|
|
addflag(lastrace->flags, F_LEVRACE, 5, R_WOLF, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
|
|
addrace(R_WOLF, "wolf", 25, 'd', C_GREY, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 90, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 3, 3, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d5");
|
|
addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 10, 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_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_CARNIVORE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
|
|
|
|
// insects
|
|
addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL);
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 100, NA, "");
|
|
addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 0, 1, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, 60, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addrace(R_GIANTFLY, "giant fly", 1, 'i', C_GREY, MT_FLESH, RC_INSECT);
|
|
lastrace->baseid = R_GIANTFLY;
|
|
addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 3, 3, NA, "");
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, 0, NA, "");
|
|
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
|
|
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_NOISETEXT, N_GETANGRY, 2, NA, "buzzes angrily^an angry buzzing");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing");
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addrace(R_GIANTBLOWFLY, "giant blowfly", 2, 'i', C_WHITE, MT_FLESH, RC_INSECT);
|
|
lastrace->baseid = R_GIANTFLY;
|
|
addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "giant fly corpse");
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 1, 2, NA, "");
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, 1, NA, "");
|
|
addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
|
|
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_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "buzzes angrily^an angry buzzing");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing");
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addrace(R_STIRGE, "stirge", 10, 'i', C_BROWN, MT_FLESH, RC_INSECT);
|
|
addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, 1, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
|
|
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_NOBODYPART, BP_LEGS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "buzzes angrily^an angry buzzing");
|
|
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing");
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:1d4;");
|
|
|
|
addrace(R_CENTIPEDE, "giant centipede", 3, 'w', C_GREEN, MT_FLESH, RC_INSECT);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, "");
|
|
addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 3, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6");
|
|
addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 25, "10-15");
|
|
addflag(lastrace->flags, F_HITCONFERVALS, P_WEAKNESS, 3, 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_SHOULDERS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
|
|
addflag(lastrace->flags, F_TREMORSENSE, 3, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addrace(R_GLOWBUG, "glowbug", 1, 'i', C_WHITE, MT_FLESH, RC_INSECT);
|
|
addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, "");
|
|
addflag(lastrace->flags, F_RARITY, H_FOREST, 97, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, 0, NA, "");
|
|
addflag(lastrace->flags, F_EVASION, 60, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, NA, NA, "1d2-1");
|
|
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_NOPACK, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing");
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
|
|
// undead
|
|
addrace(R_ZOMBIE, "zombie", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, 4, 1, NULL);
|
|
addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5");
|
|
addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
|
|
addrace(R_SKELETON, "skeleton", 20, 'Z', C_GREY, MT_BONE, RC_UNDEAD);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
|
|
addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "5-20 bones");
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL);
|
|
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_STARTOBDT, 50, DT_CHOP, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTOB, 25, DT_CHOP, NA, "buckler");
|
|
addflag(lastrace->flags, F_DTVULN, DT_BASH, 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);
|
|
|
|
addrace(R_GHAST, "ghast", 50, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL);
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 55, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 4, 2, NA, NULL);
|
|
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_TOUCHPARALYZE2, NA, NA, "0d1+0");
|
|
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
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);
|
|
|
|
addrace(R_GHOST, "ghost", 50, 'p', C_BLUE, MT_MAGIC, RC_UNDEAD); // p for sPirit
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL);
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 4, 2, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
|
|
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);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_INDUCEFEAR, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_CANWILL, OT_S_INVISIBILITY, 40, 40, "pw:1;");
|
|
// special: ghosts gain canwill->possession if they are near
|
|
// their previous corpse. use f_mycorpse->oid for this.
|
|
|
|
addrace(R_GHOUL, "ghoul", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_HITDICE, 3, 2, NA, NULL);
|
|
addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, "");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5+3");
|
|
addflag(lastrace->flags, F_HASATTACK, OT_TOUCHPARALYZE, NA, NA, "0d1+0");
|
|
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL);
|
|
addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL);
|
|
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);
|
|
|
|
// special monsters
|
|
addrace(R_GASCLOUD, "cloud of gas", 0.1, '}', C_GREY, MT_GAS, RC_OTHER);
|
|
addflag(lastrace->flags, F_MOVESPEED, SP_ULTRAFAST, NA, NA, "");
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL);
|
|
addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 1, 1, NA, "");
|
|
addflag(lastrace->flags, F_EVASION, 300, 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_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_BODY, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, 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_NOSPELLS, 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);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
|
|
addrace(R_DANCINGWEAPON, "dancing weapon", 0, ')', C_GREY, MT_METAL, RC_OTHER);
|
|
addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, "");
|
|
addflag(lastrace->flags, F_HITDICE, 2, NA, NA, "");
|
|
addflag(lastrace->flags, F_EVASION, 50, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_BODY, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, 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_NOSPELLS, 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);
|
|
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
|
|
addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL);
|
|
}
|
|
|
|
int isairborne(lifeform_t *lf) {
|
|
if (!lf) return B_FALSE;
|
|
if (lfhasflag(lf, F_FLYING)) {
|
|
return B_TRUE;
|
|
} else if (lfhasflag(lf, F_LEVITATING)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isaquatic(lifeform_t *lf) {
|
|
if (lf->race->raceclass->id == RC_AQUATIC) {
|
|
return B_TRUE;
|
|
} else if (lfhasflag(lf, F_AQUATIC)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isbleeding(lifeform_t *lf) {
|
|
float hppct;
|
|
hppct = ((float)lf->hp / (float) lf->maxhp) * 100;
|
|
|
|
if (hppct <= 40) return B_TRUE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isblind(lifeform_t *lf) {
|
|
if (!lf) return B_FALSE;
|
|
|
|
if (lfhasflag(lf, F_ASLEEP)) {
|
|
return B_TRUE;
|
|
}
|
|
if (lfhasflag(lf, F_BLIND)) {
|
|
return B_TRUE;
|
|
}
|
|
if (lfhasflagval(lf, F_NOBODYPART, BP_EYES, NA, NA, NULL)) {
|
|
if (!lfhasflag(lf, F_TREMORSENSE)) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
enum BURDENED isburdened(lifeform_t *lf) {
|
|
float cur,max;
|
|
float ratio;
|
|
// monsters can't be burdened!
|
|
if (!isplayer(lf)) {
|
|
return BR_NONE;
|
|
}
|
|
max = getmaxcarryweight(lf);
|
|
cur = getobpileweight(lf->pack);
|
|
ratio = cur / max;
|
|
if (ratio >= 2) {
|
|
return BR_OVERLOADED;
|
|
} else if (ratio > 1.5) {
|
|
return BR_STRAINED;
|
|
} else if (ratio > 1) {
|
|
return BR_BURDENED;
|
|
}
|
|
return BR_NONE;
|
|
}
|
|
|
|
int ischarmable(lifeform_t *lf) {
|
|
if (getiqname(getattr(lf, A_IQ), NULL) <= IQ_VEGETABLE) {
|
|
reason = E_LOWIQ;
|
|
return B_FALSE;
|
|
}
|
|
if (isundead(lf)) {
|
|
reason = E_UNDEAD;
|
|
return B_FALSE;
|
|
}
|
|
if (hasflag(lf->flags, F_DRUNK)) {
|
|
reason = E_DRUNK;
|
|
return B_FALSE;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
int isdead(lifeform_t *lf) {
|
|
if (!lf->alive) return B_TRUE;
|
|
if (lf->hp <= 0) return B_TRUE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
void killlf(lifeform_t *lf) {
|
|
lifeform_t *nextone, *lastone, *l;
|
|
map_t *m;
|
|
flag_t *f;
|
|
|
|
if ((gamemode == GM_GAMESTARTED)) {
|
|
if (cansee(player, lf)) {
|
|
needredraw = B_TRUE;
|
|
}
|
|
}
|
|
|
|
m = lf->cell->map;
|
|
|
|
// remove references
|
|
lf->cell->lf = NULL;
|
|
|
|
// shouldn't need this...
|
|
lf->cell = NULL;
|
|
|
|
// remove impossible flags...
|
|
// check if anyone is targetting us.
|
|
// if so, stop targetting us now that
|
|
// we are dead.
|
|
// also: does anyone have us as a master?
|
|
// TODO: check on all maps?
|
|
if ((gamemode == GM_GAMESTARTED)) {
|
|
for (l = m->lf ; l ; l = l->next) {
|
|
f = lfhasflagval(l, F_TARGETLF, lf->id, NA, NA, NULL);
|
|
if (f) killflag(f);
|
|
f = lfhasflagval(l, F_ATTACHEDTO, lf->id, NA, NA, NULL);
|
|
if (f) killflag(f);
|
|
f = lfhasflagval(l, F_GRABBEDBY, lf->id, NA, NA, NULL);
|
|
if (f) killflag(f);
|
|
f = lfhasflagval(l, F_GRABBING, lf->id, NA, NA, NULL);
|
|
if (f) killflag(f);
|
|
f = lfhasflagval(l, F_PETOF, lf->id, NA, NA, NULL);
|
|
if (f) killflag(f);
|
|
}
|
|
}
|
|
|
|
// free mem
|
|
if (lf->lastdam) free(lf->lastdam);
|
|
|
|
// kill any remaining obs
|
|
while (lf->pack->first) {
|
|
killob(lf->pack->first);
|
|
}
|
|
// kill object pile
|
|
free(lf->pack);
|
|
|
|
// kill flags
|
|
killflagpile(lf->flags);
|
|
|
|
// remove from list
|
|
nextone = lf->next;
|
|
if (nextone != NULL) {
|
|
nextone->prev = lf->prev;
|
|
} else { /* last */
|
|
m->lastlf = lf->prev;
|
|
}
|
|
|
|
if (lf->prev == NULL) {
|
|
/* first */
|
|
nextone = lf->next;
|
|
free(m->lf);
|
|
m->lf = nextone;
|
|
} else {
|
|
lastone = lf->prev;
|
|
free (lastone->next );
|
|
lastone->next = nextone;
|
|
}
|
|
}
|
|
|
|
flag_t *isdrunk(lifeform_t *lf) {
|
|
return lfhasflag(lf, F_DRUNK);
|
|
}
|
|
|
|
// returns second weapon if you are dual weilding
|
|
object_t *isdualweilding(lifeform_t *lf) {
|
|
object_t *priwep,*secwep;
|
|
// dual weilding?
|
|
priwep = getweapon(lf);
|
|
secwep = getsecmeleeweapon(lf);
|
|
if (priwep && secwep) {
|
|
if (priwep != secwep) { // twohanded weapons dont count
|
|
return secwep;
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isfleeing(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_FLEEFROM)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isfreebp(lifeform_t *lf, enum BODYPART bp) {
|
|
if (hasobwithflagval(lf->pack, F_EQUIPPED, bp, NA, NA, NULL)) return B_FALSE;
|
|
|
|
if (!hasbp(lf, bp)) return B_FALSE;
|
|
|
|
if ((bp == BP_WEAPON) || (bp == BP_SECWEAPON)) {
|
|
object_t *o;
|
|
enum BODYPART otherbp;
|
|
// check for 2handed weapons in other hand too
|
|
if (bp == BP_WEAPON) otherbp = BP_SECWEAPON;
|
|
else otherbp = BP_WEAPON;
|
|
|
|
|
|
o = hasobwithflagval(lf->pack, F_EQUIPPED, otherbp, NA, NA, NULL);
|
|
if (o && hasflag(o->flags, F_TWOHANDED)) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
int isfriendly(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_FRIENDLY)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isgenius(lifeform_t *lf) {
|
|
enum IQBRACKET iqb;
|
|
iqb = getiqname(getattr(lf, A_IQ), NULL);
|
|
|
|
if (lfhasflag(lf, F_OMNIPOTENT) ||
|
|
lfhasflag(lf, F_EXTRAINFO) ||
|
|
iqb >= IQ_GENIUS) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt) {
|
|
flag_t *f;
|
|
f = hasflagval(fp, F_DTIMMUNE, dt, NA, NA, NULL);
|
|
if (f) return f;
|
|
f = hasflagval(fp, F_DTIMMUNE, DT_ALL, NA, NA, NULL);
|
|
if (f) return f;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int isinbattle(lifeform_t *lf) {
|
|
int dir;
|
|
if (isblind(lf)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
for (dir = DC_N; dir <= DC_NW; dir++) {
|
|
cell_t *c;
|
|
c = getcellindir(lf->cell, dir);
|
|
if (c && c->lf && areenemies(lf, c->lf)) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
int isingunrange(lifeform_t *lf, cell_t *where) {
|
|
object_t *gun;
|
|
int range;
|
|
gun = getfirearm(lf);
|
|
if (!gun) return B_FALSE;
|
|
range = getfirearmrange(gun);
|
|
if (getcelldist(lf->cell, where) <= range) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
// cannot voluntarily move _at all_.
|
|
int isimmobile(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_ASLEEP)) {
|
|
return B_TRUE;
|
|
}
|
|
if (lfhasflag(lf, F_FROZEN)) {
|
|
return B_TRUE;
|
|
}
|
|
if (lfhasflag(lf, F_PARALYZED)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isloreskill(enum SKILL skid) {
|
|
switch (skid) {
|
|
case SK_LORE_ARCANA:
|
|
case SK_LORE_DEMONS:
|
|
case SK_LORE_HUMANOID:
|
|
case SK_LORE_NATURE:
|
|
case SK_LORE_UNDEAD:
|
|
return B_TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int ismaxedskill(lifeform_t *lf, enum SKILL skid) {
|
|
// TODO: implement skill maximums per job
|
|
if (getskill(lf, skid) == PR_MASTER) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int ispeaceful(lifeform_t *lf) {
|
|
if (isplayer(lf)) return B_FALSE;
|
|
if (lfhasflag(lf, F_HOSTILE)) {
|
|
return B_FALSE;
|
|
}
|
|
if (lfhasflagval(lf, F_TARGETLF, player->id, NA, NA, NULL)) {
|
|
return B_FALSE;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
int ispetof(lifeform_t *lf, lifeform_t *owner) {
|
|
if (!lf || !owner) return B_FALSE;
|
|
if (lfhasflagval(lf, F_PETOF, owner->id, NA, NA, NULL)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
flag_t *ispetortarget(lifeform_t *lf, lifeform_t *ownertarget) {
|
|
flag_t *f;
|
|
if (!lf || !ownertarget) return B_FALSE;
|
|
f = lfhasflagval(lf, F_PETOF, ownertarget->id, NA, NA, NULL);
|
|
if (f) return f;
|
|
f = lfhasflagval(lf, F_TARGETLF, ownertarget->id, NA, NA, NULL);
|
|
if (f) return f;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int isplayer(lifeform_t *lf) {
|
|
if (lf && (lf->controller == C_PLAYER)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
// returns poison flag with longest remaining lifetime
|
|
flag_t *ispoisoned(lifeform_t *lf) {
|
|
flag_t *f,*max = NULL;
|
|
for (f = lf->flags->first ;f ; f = f->next) {
|
|
if (f->id == F_POISONED) {
|
|
if (f->lifetime == PERMENANT) {
|
|
return f;
|
|
} else if ((max == NULL) || (f->lifetime > max->lifetime)) {
|
|
max = f;
|
|
}
|
|
}
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
flag_t *ispoisonedwith(lifeform_t *lf, enum POISONTYPE pt) {
|
|
return lfhasflagval(lf, F_POISONED, pt, NA, NA, NULL);
|
|
}
|
|
|
|
int ispolymorphed(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_POLYMORPHED)) {
|
|
return B_TRUE;
|
|
} else {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
int isprone(lifeform_t *lf) {
|
|
if (lfhasflag(lf, F_PRONE)) {
|
|
return B_TRUE;
|
|
}
|
|
if (lfhasflag(lf, F_ASLEEP)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt) {
|
|
flag_t *f;
|
|
f = hasflagval(fp, F_DTRESIST, dt, NA, NA, NULL);
|
|
if (f) return f;
|
|
f = hasflagval(fp, F_DTRESIST, DT_ALL, NA, NA, NULL);
|
|
if (f) return f;
|
|
if (dt == DT_FIRE) {
|
|
f = hasflag(fp, F_WET);
|
|
if (f) return f;
|
|
f = hasflag(fp, F_DRUNK);
|
|
if (f) return f;
|
|
}
|
|
if (dt == DT_COLD) {
|
|
f = hasflag(fp, F_DRUNK);
|
|
if (f) return f;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
flag_t *isresting(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = lfhasflag(lf, F_ASLEEP);
|
|
if (f && (f->val[2] != NA)) {
|
|
return f;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
object_t *isstuck(lifeform_t *lf) {
|
|
object_t *o;
|
|
|
|
for (o = lf->cell->obpile->first ; o ; o = o->next) {
|
|
if ((o->type->id == OT_WEB) && (lf->race->baseid == R_SPIDER)) {
|
|
continue;
|
|
}
|
|
if (hasflag(o->flags, F_RESTRICTMOVEMENT)) {
|
|
return o;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
job_t *addjob(enum JOB id, char *name) {
|
|
job_t *a;
|
|
|
|
// add to the end of the list
|
|
if (firstjob == NULL) {
|
|
firstjob = malloc(sizeof(job_t));
|
|
a = firstjob;
|
|
a->prev = NULL;
|
|
} else {
|
|
// go to end of list
|
|
a = lastjob;
|
|
a->next = malloc(sizeof(job_t));
|
|
a->next->prev = a;
|
|
a = a->next;
|
|
}
|
|
lastjob = a;
|
|
a->next = NULL;
|
|
|
|
// props
|
|
a->id = id;
|
|
a->name = strdup(name);
|
|
|
|
a->flags = addflagpile(NULL, NULL);
|
|
return a;
|
|
}
|
|
|
|
lifeform_t *addlf(cell_t *cell, enum RACE rid, int level) {
|
|
return real_addlf(cell, rid, level, C_AI);
|
|
}
|
|
|
|
lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
|
|
map_t *m;
|
|
lifeform_t *a;
|
|
int i;
|
|
//int db = B_FALSE;
|
|
|
|
assert(cell);
|
|
if (cell->type != (celltype_t *) DUMMYCELLTYPE) {
|
|
assert(!cell->type->solid);
|
|
}
|
|
|
|
|
|
m = cell->map;
|
|
|
|
// add to the end of the list
|
|
if (m->lf == NULL) {
|
|
m->lf = malloc(sizeof(lifeform_t));
|
|
a = m->lf;
|
|
a->prev = NULL;
|
|
} else {
|
|
// go to end of list
|
|
a = m->lastlf;
|
|
a->next = malloc(sizeof(lifeform_t));
|
|
a->next->prev = a;
|
|
a = a->next;
|
|
}
|
|
|
|
if (controller == C_PLAYER) {
|
|
player = a;
|
|
}
|
|
|
|
m->lastlf = a;
|
|
a->next = NULL;
|
|
|
|
a->born = B_FALSE; // will set this back to true later
|
|
|
|
// props
|
|
a->id = nextlfid; nextlfid++;
|
|
a->controller = controller;
|
|
a->level = level;
|
|
a->newlevel = level;
|
|
a->xp = getxpforlev(a->level);
|
|
a->skillpoints = 0;
|
|
a->cell = cell;
|
|
a->alive = B_TRUE;
|
|
a->lastdam = strdup("nothing");
|
|
a->lastdamtype = DT_NONE;
|
|
if ((gamemode == GM_GAMESTARTED) && a->prev) {
|
|
a->timespent = a->prev->timespent + 1;
|
|
} else {
|
|
a->timespent = 0;
|
|
}
|
|
a->sorted = B_FALSE;
|
|
a->forgettimer = 0;
|
|
|
|
a->polyrevert = B_FALSE;
|
|
|
|
// for precalcing line of sight
|
|
a->nlos = 0;
|
|
a->los = NULL;
|
|
|
|
// for ai
|
|
|
|
// avoid messages when equipping initial obs
|
|
a->created = B_FALSE;
|
|
|
|
a->pack = addobpile(a, NOLOC);
|
|
|
|
a->turnsskipped = 0;
|
|
|
|
// clear laoding variables
|
|
for (i = 0; i < MAXPILEOBS; i++) {
|
|
a->oblist[i] = -1;
|
|
}
|
|
a->x = -1;
|
|
a->y = -1;
|
|
|
|
// defaults
|
|
a->hp = 1;
|
|
a->maxhp = a->hp;
|
|
a->mp = 0;
|
|
a->maxmp = a->mp;
|
|
|
|
// init flags
|
|
a->flags = addflagpile(a, NULL);
|
|
|
|
//addflag(a->flags, F_DEBUG, B_TRUE, NA, NA, NULL); // ooooooooooo
|
|
|
|
// set race - this will inherit race flags
|
|
a->race = NULL;
|
|
|
|
setrace(a, rid, B_FALSE);
|
|
|
|
|
|
// update other things
|
|
cell->lf = a;
|
|
|
|
// give start objetcs
|
|
if ((gamemode != GM_LOADING) && (gamemode != GM_VALIDATION)) {
|
|
outfitlf(a);
|
|
}
|
|
a->created = B_TRUE;
|
|
a->born = B_TRUE; // now finished creating it.
|
|
if ((gamemode == GM_GAMESTARTED) && cansee(player, a)) {
|
|
needredraw = B_TRUE;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
|
|
|
|
race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass) {
|
|
race_t *a;
|
|
|
|
assert(!findrace(id));
|
|
|
|
// add to the end of the list
|
|
if (firstrace == NULL) {
|
|
firstrace = malloc(sizeof(race_t));
|
|
a = firstrace;
|
|
a->prev = NULL;
|
|
} else {
|
|
// go to end of list
|
|
a = lastrace;
|
|
a->next = malloc(sizeof(race_t));
|
|
a->next->prev = a;
|
|
a = a->next;
|
|
}
|
|
lastrace = a;
|
|
a->next = NULL;
|
|
|
|
|
|
// props
|
|
a->id = id;
|
|
a->baseid = id; // default
|
|
a->raceclass = findraceclass(raceclass);
|
|
|
|
a->material = findmaterial(mat);
|
|
assert(a->material);
|
|
a->name = strdup(name);
|
|
a->weight = weight;
|
|
a->glyph.ch = glyph;
|
|
a->glyph.colour = glyphcolour;
|
|
|
|
a->flags = addflagpile(NULL, NULL);
|
|
return a;
|
|
}
|
|
|
|
raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill) {
|
|
raceclass_t *a;
|
|
|
|
assert(!findraceclass(id));
|
|
|
|
// add to the end of the list
|
|
if (firstraceclass == NULL) {
|
|
firstraceclass = malloc(sizeof(raceclass_t));
|
|
a = firstraceclass;
|
|
a->prev = NULL;
|
|
} else {
|
|
// go to end of list
|
|
a = lastraceclass;
|
|
a->next = malloc(sizeof(raceclass_t));
|
|
a->next->prev = a;
|
|
a = a->next;
|
|
}
|
|
lastraceclass = a;
|
|
a->next = NULL;
|
|
|
|
|
|
// props
|
|
a->id = id;
|
|
a->name = strdup(name);
|
|
a->pluralname = strdup(pluralname);
|
|
a->skill = skill;
|
|
|
|
return a;
|
|
}
|
|
|
|
skill_t *addskill(enum SKILL id, char *name, char *desc) {
|
|
skill_t *a;
|
|
|
|
assert(!findskill(id));
|
|
|
|
// add to the end of the list
|
|
if (firstskill == NULL) {
|
|
firstskill = malloc(sizeof(skill_t));
|
|
a = firstskill;
|
|
a->prev = NULL;
|
|
} else {
|
|
// go to end of list
|
|
a = lastskill;
|
|
a->next = malloc(sizeof(skill_t));
|
|
a->next->prev = a;
|
|
a = a->next;
|
|
}
|
|
lastskill = a;
|
|
a->next = NULL;
|
|
|
|
|
|
// props
|
|
a->id = id;
|
|
a->name = strdup(name);
|
|
a->desc = strdup(desc);
|
|
|
|
return a;
|
|
}
|
|
|
|
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
|
|
return;
|
|
}
|
|
// footprints first
|
|
if (!isairborne(lf)) {
|
|
int fpdir;
|
|
enum SKILLLEVEL slev;
|
|
|
|
slev = getskill(lf, SK_TRACKING);
|
|
if (slev == PR_MASTER) {
|
|
// no footprints!
|
|
return;
|
|
} else if (slev == PR_EXPERT) {
|
|
fpdir = D_NONE;
|
|
} else {
|
|
fpdir = dir;
|
|
}
|
|
|
|
|
|
footprint = hastrailof(lf->cell->obpile, lf, OT_FOOTPRINT, &fpflag, NULL);
|
|
if (footprint) {
|
|
assert(fpflag);
|
|
fpflag->lifetime = getfootprinttime(lf);
|
|
fpflag->val[1] = fpdir;
|
|
} else {
|
|
char buf[BUFLENTINY];
|
|
sprintf(buf, "%d", lf->id);
|
|
footprint = addob(lf->cell->obpile, "footprint");
|
|
addtempflag(footprint->flags, F_TRAIL, lf->race->id, fpdir, S_SIGHT, buf, getfootprinttime(lf));
|
|
}
|
|
}
|
|
|
|
// now smell
|
|
scent = hastrailof(lf->cell->obpile, lf, OT_SCENT, &fpflag, NULL);
|
|
if (scent) {
|
|
assert(fpflag);
|
|
fpflag->lifetime = SCENTTIME;
|
|
} else {
|
|
char buf[BUFLENTINY];
|
|
sprintf(buf, "%d", lf->id);
|
|
scent = addob(lf->cell->obpile, "scent");
|
|
addtempflag(scent->flags, F_TRAIL, lf->race->id, dir, S_SMELL, buf, SCENTTIME);
|
|
}
|
|
}
|
|
|
|
void adjustspeedforwater(lifeform_t *lf, int *speed) {
|
|
object_t *o;
|
|
flag_t *f;
|
|
if (!isairborne(lf)) {
|
|
for (o = lf->cell->obpile->first ; o ; o = o->next) {
|
|
f = hasflag(o->flags, F_REDUCEMOVEMENT);
|
|
if (f) {
|
|
if (hasflag(o->flags, F_DEEPWATER)) {
|
|
int modamt = 0;
|
|
// water
|
|
if (isaquatic(lf)) {
|
|
modamt = 0;
|
|
} else {
|
|
switch (getskill(lf, SK_SWIMMING)) {
|
|
default:
|
|
case PR_NOVICE:
|
|
case PR_INEPT: modamt = f->val[0]; break; // normal penalty
|
|
case PR_BEGINNER: modamt = f->val[0] - 2; break;
|
|
case PR_ADEPT: modamt = 0; break;
|
|
case PR_SKILLED: modamt = -1; break;
|
|
case PR_EXPERT: modamt = -2; break;
|
|
case PR_MASTER: modamt = -2; break;
|
|
}
|
|
}
|
|
limit(&modamt, 0, 5);
|
|
*speed += (modamt * SPEEDUNIT);
|
|
} else {
|
|
// something else
|
|
*speed += (f->val[0] * SPEEDUNIT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) {
|
|
flag_t *f;
|
|
if (isimmuneto(lf->flags, damtype)) {
|
|
*amt = 0;
|
|
return;
|
|
}
|
|
|
|
if ((damtype == DT_MAGIC) && getmr(lf) && skillcheck(lf, SC_RESISTMAG, 10 + (*amt * 2), 0)) {
|
|
*amt = 0;
|
|
return;
|
|
}
|
|
|
|
// water normally doesn't hurt.
|
|
if ((damtype == DT_WATER) && !isvulnto(lf->flags, damtype)) {
|
|
*amt = 0;
|
|
return;
|
|
}
|
|
|
|
if (lfhasflag(lf, F_INVULNERABLE)) {
|
|
switch (damtype) {
|
|
case DT_DIRECT:
|
|
case DT_NONE:
|
|
break;
|
|
default:
|
|
*amt = 0;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ((damtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) {
|
|
(*amt) *= 2;
|
|
}
|
|
|
|
if ((damtype == DT_ELECTRIC) && hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
|
|
(*amt) *= 2;
|
|
}
|
|
if ((damtype == DT_COLD) && hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
|
|
(*amt) = pctof(150, *amt);
|
|
}
|
|
|
|
if (isresistantto(lf->flags, damtype)) {
|
|
(*amt) /= 2;
|
|
}
|
|
f = isvulnto(lf->flags, damtype);
|
|
if (f) {
|
|
if ((*amt == 0) && strlen(f->text)) {
|
|
int ndice,nsides,bonus;
|
|
texttodice(f->text, &ndice,&nsides,&bonus);
|
|
*amt = rolldie(ndice,nsides) + bonus;
|
|
} else {
|
|
(*amt) *= 2;
|
|
}
|
|
}
|
|
|
|
|
|
// adjust for lifeform material
|
|
//adjustdammaterial(amt, damtype, getlfmaterial(lf));
|
|
|
|
if (*amt < 0) *amt = 0;
|
|
}
|
|
|
|
void makepeaceful(lifeform_t *who) {
|
|
char lfname[BUFLEN];
|
|
|
|
getlfname(who, lfname);
|
|
if (lfhasflag(who, F_DEBUG)) {
|
|
msg("Making %s friendly.",lfname);
|
|
}
|
|
|
|
if (lfhasflag(who, F_HOSTILE)) {
|
|
if (cansee(player, who)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(who, lfname);
|
|
msg("%s calms down.", lfname);
|
|
}
|
|
}
|
|
|
|
killflagsofid(who->flags, F_HOSTILE);
|
|
killflagsofid(who->flags, F_TARGETLF); // stop targetting anyone
|
|
|
|
}
|
|
|
|
lifeform_t *makezombie(object_t *o) {
|
|
flag_t *f;
|
|
race_t *r;
|
|
lifeform_t *lf;
|
|
cell_t *where;
|
|
char obname[BUFLEN];
|
|
|
|
if (o->type->id != OT_CORPSE) return NULL;
|
|
|
|
f = hasflag(o->flags, F_CORPSEOF);
|
|
if (!f) return NULL;
|
|
|
|
r = findrace(f->val[0]);
|
|
if (!r) return NULL;
|
|
|
|
where = getoblocation(o);
|
|
getobname(o, obname, 1);
|
|
|
|
lf = addlf(where, r->id, 1);
|
|
|
|
addflag(lf->flags, F_LFSUFFIX, B_TRUE, NA, NA, "zombie");
|
|
addflag(lf->flags, F_GLYPH, C_GREY, NA, NA, "Z");
|
|
addflag(lf->flags, F_UNDEAD, B_TRUE, NA, NA, NULL);
|
|
addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
addflag(lf->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL);
|
|
addflag(lf->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(lf->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL);
|
|
addflag(lf->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL);
|
|
addflag(lf->flags, F_DTVULN, DT_HOLY, NA, NA, NULL);
|
|
|
|
if (hasflag(o->flags, F_HEADLESS)) {
|
|
// remove the head
|
|
addflag(lf->flags, F_NOBODYPART, BP_HEAD, NA, NA, NULL);
|
|
// remove the eyes (this will make the creature blind)
|
|
addflag(lf->flags, F_NOBODYPART, BP_EYES, NA, NA, NULL);
|
|
// need HEADLESS too to show that this monster normally
|
|
// _does_ have a head. this will cause getlfname
|
|
// to add "headless " to the description.
|
|
addflag(lf->flags, F_HEADLESS, B_TRUE, NA, NA, NULL);
|
|
}
|
|
|
|
killflagsofid(lf->flags, F_WANTSBETTERWEP);
|
|
killflagsofid(lf->flags, F_WANTSBETTERARM);
|
|
killflagsofid(lf->flags, F_WANTSOBFLAG);
|
|
killflagsofid(lf->flags, F_WANTS);
|
|
killflagsofid(lf->flags, F_NOISETEXT);
|
|
killflagsofid(lf->flags, F_SEEINDARK);
|
|
killflagsofid(lf->flags, F_TREMORSENSE);
|
|
|
|
killflagsofid(lf->flags, F_MOVESPEED);
|
|
addflag(lf->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL);
|
|
killflagsofid(lf->flags, F_ACTIONSPEED);
|
|
addflag(lf->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL);
|
|
lf->baseatt[A_IQ] = rolliq(IQ_MINDLESS);
|
|
lf->att[A_IQ] = lf->baseatt[A_IQ];
|
|
|
|
// no magic
|
|
lf->maxmp = 0;
|
|
lf->mp = 0;
|
|
|
|
// no objects
|
|
while (lf->pack->first) {
|
|
killob(lf->pack->first);
|
|
}
|
|
|
|
// no abilities
|
|
killflagsofid(lf->flags, F_CANCAST);
|
|
killflagsofid(lf->flags, F_CANWILL);
|
|
|
|
// remove the object
|
|
removeob(o,o->amt);
|
|
|
|
// redraw & announce
|
|
if (haslos(player, where)) {
|
|
needredraw = B_TRUE;
|
|
drawscreen();
|
|
msg("%s rises from the dead!", obname);
|
|
}
|
|
|
|
return lf;
|
|
}
|
|
|
|
int areenemies(lifeform_t *lf1, lifeform_t *lf2) {
|
|
reason = E_OK;
|
|
|
|
if (hasjob(lf1, J_DRUID) && (getraceclass(lf2) == RC_PLANT)) {
|
|
return B_FALSE;
|
|
} else if (hasjob(lf2, J_DRUID) && (getraceclass(lf1) == RC_PLANT)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
switch (getallegiance(lf1)) {
|
|
case AL_HOSTILE:
|
|
switch (getallegiance(lf2)) {
|
|
case AL_HOSTILE:
|
|
return B_FALSE;
|
|
case AL_PEACEFUL:
|
|
return B_FALSE;
|
|
case AL_FRIENDLY:
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case AL_PEACEFUL:
|
|
return B_FALSE;
|
|
case AL_FRIENDLY:
|
|
switch (getallegiance(lf2)) {
|
|
case AL_HOSTILE:
|
|
return B_TRUE;
|
|
case AL_PEACEFUL:
|
|
return B_FALSE;
|
|
case AL_FRIENDLY:
|
|
return B_FALSE;
|
|
}
|
|
break;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) {
|
|
flag_t *fromlfflag;
|
|
lifeform_t *fromlf = NULL;
|
|
char damstring[BUFLEN],buf[BUFLEN];
|
|
|
|
getobname(o, buf, o->amt);
|
|
|
|
fromlfflag = hasflag(o->flags, F_CREATEDBY);
|
|
if (fromlfflag) {
|
|
sprintf(damstring, "%s^created by %s",buf, fromlfflag->text);
|
|
} else {
|
|
strcpy(damstring, buf);
|
|
}
|
|
|
|
dam = losehp(lf, dam, damtype, fromlf, damstring);
|
|
if (dam > 0) {
|
|
if (damtype == DT_POISONGAS) {
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s choke%s on %s!", lfname, isplayer(lf) ? "" : "s", buf);
|
|
}
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
msg("%s %ss you!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp));
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s %ss %s!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int areallies(lifeform_t *lf1, lifeform_t *lf2) {
|
|
// UNCOMMENT THIS TO GO BACK TO ONLY HAVING MONSTERS
|
|
// OF THE SAME BASE RACE COUNTING AS ALLIES.
|
|
if (getallegiance(lf1) == getallegiance(lf2)) {
|
|
if (isplayer(lf1) || isplayer(lf2)) {
|
|
// if one of them is the player
|
|
return B_TRUE;
|
|
} else {
|
|
if (lf1->race->baseid == lf2->race->baseid) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
if (getallegiance(lf1) == getallegiance(lf2)) {
|
|
return B_TRUE;
|
|
}
|
|
*/
|
|
return B_FALSE;
|
|
}
|
|
|
|
// make sure player has at least novice skill in all their start weapons/armour
|
|
void autoskill(lifeform_t *lf) {
|
|
skill_t *sk;
|
|
object_t *o;
|
|
enum SKILLLEVEL slev;
|
|
int nweps = 0;
|
|
|
|
if (isplayer(lf)) {
|
|
slev = PR_NOVICE;
|
|
} else {
|
|
slev = PR_ADEPT;
|
|
}
|
|
|
|
if (!hasjob(lf, J_WIZARD)) {
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if (isweapon(o) && canweild(lf, o)) {
|
|
sk = getobskill(o);
|
|
if (sk && !getskill(lf, sk->id)) {
|
|
giveskilllev(lf, sk->id, slev);
|
|
}
|
|
nweps++;
|
|
}
|
|
if (isfirearm(o) && canweild(lf, o)) {
|
|
giveskilllev(lf, SK_RANGED, slev);
|
|
}
|
|
if (isarmour(o) && canwear(lf, o, BP_NONE)) {
|
|
flag_t *f;
|
|
// evasion penalty?
|
|
f = hasflag(o->flags, F_EVASION);
|
|
if (f && (f->val[0] < 0)) {
|
|
giveskilllev(lf, SK_ARMOUR, slev);
|
|
}
|
|
}
|
|
if (isshield(o) && canwear(lf, o, BP_NONE)) {
|
|
giveskilllev(lf, SK_SHIELDS, slev);
|
|
}
|
|
}
|
|
}
|
|
|
|
// monsters must get unarmed skill!
|
|
if (!nweps && !isplayer(lf)) {
|
|
giveskilllev(lf, SK_UNARMED, slev);
|
|
}
|
|
|
|
}
|
|
|
|
void autotarget(lifeform_t *lf) {
|
|
object_t *gun;
|
|
lifeform_t *targ,*newtarg;
|
|
int closest;
|
|
int i;
|
|
int gunrange;
|
|
int targid;
|
|
|
|
gun = getfirearm(lf);
|
|
if (!gun) return;
|
|
|
|
if (!getammo(lf)) return;
|
|
|
|
gunrange = getfirearmrange(gun);
|
|
|
|
// already got a target?
|
|
targid = getguntargetid(lf);
|
|
|
|
if (targid == -1) {
|
|
targ = NULL;
|
|
} else {
|
|
targ = findlf(NULL, targid);
|
|
if (targ) {
|
|
// dead? remove target and keep going.
|
|
if (isdead(targ)) {
|
|
// clear target ?
|
|
targ = NULL;
|
|
} else if (!haslof(lf->cell, targ->cell, B_FALSE, NULL)) {
|
|
// clear target ?
|
|
targ = NULL;
|
|
} else {
|
|
// already got a valid target. return.
|
|
return;
|
|
}
|
|
} else {
|
|
// target no longer exists?
|
|
// clear target ?
|
|
}
|
|
}
|
|
|
|
// find new target
|
|
newtarg = NULL;
|
|
closest = 9999;
|
|
for (i = 0; i < lf->nlos; i++) {
|
|
cell_t *c;
|
|
c = lf->los[i];
|
|
if (c->lf && (c->lf != lf) && cansee(lf, c->lf) && isingunrange(lf, c)) {
|
|
int valid = B_TRUE;
|
|
if (!areenemies(lf, c->lf)) {
|
|
valid = B_FALSE;
|
|
}
|
|
if (valid) {
|
|
int thisdist;
|
|
thisdist = getcelldist(lf->cell, c);
|
|
if (thisdist < closest) {
|
|
newtarg = c->lf;
|
|
closest = thisdist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (newtarg && (newtarg != targ)) {
|
|
setguntarget(lf, newtarg);
|
|
}
|
|
}
|
|
|
|
int isswimming(lifeform_t *lf) {
|
|
if (!lf) return B_FALSE;
|
|
if (gamemode != GM_GAMESTARTED) {
|
|
return B_FALSE;
|
|
}
|
|
if (!isairborne(lf) &&
|
|
hasobwithflag(lf->cell->obpile, F_DEEPWATER) &&
|
|
getskill(lf, SK_SWIMMING)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isundead(lifeform_t *lf) {
|
|
if (lf->race->raceclass->id == RC_UNDEAD) {
|
|
return B_TRUE;
|
|
}
|
|
if (lfhasflag(lf, F_UNDEAD)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt) {
|
|
flag_t *f;
|
|
f = hasflagval(fp, F_DTVULN, dt, NA, NA, NULL);
|
|
if (f) return f;
|
|
f = hasflagval(fp, F_DTVULN, DT_ALL, NA, NA, NULL);
|
|
if (f) return f;
|
|
return NULL;
|
|
}
|
|
|
|
void killjob(job_t *job) {
|
|
job_t *nextone, *lastone;
|
|
|
|
// free mem
|
|
free(job->name);
|
|
killflagpile(job->flags);
|
|
|
|
// remove from list
|
|
nextone = job->next;
|
|
if (nextone != NULL) {
|
|
nextone->prev = job->prev;
|
|
} else { /* last */
|
|
lastjob = job->prev;
|
|
}
|
|
|
|
if (job->prev == NULL) {
|
|
/* first */
|
|
nextone = job->next;
|
|
free(job);
|
|
job = nextone;
|
|
} else {
|
|
lastone = job->prev;
|
|
free (lastone->next );
|
|
lastone->next = nextone;
|
|
}
|
|
}
|
|
|
|
|
|
void killrace(race_t *race) {
|
|
race_t *nextone, *lastone;
|
|
|
|
// free mem
|
|
free(race->name);
|
|
killflagpile(race->flags);
|
|
|
|
// remove from list
|
|
nextone = race->next;
|
|
if (nextone != NULL) {
|
|
nextone->prev = race->prev;
|
|
} else { /* last */
|
|
lastrace = race->prev;
|
|
}
|
|
|
|
if (race->prev == NULL) {
|
|
/* first */
|
|
nextone = race->next;
|
|
free(race);
|
|
race = nextone;
|
|
} else {
|
|
lastone = race->prev;
|
|
free (lastone->next );
|
|
lastone->next = nextone;
|
|
}
|
|
}
|
|
|
|
|
|
flag_t *levelabilityready(lifeform_t *lf) {
|
|
flag_t *f;
|
|
|
|
if (!lfhasflag(lf, F_HASNEWLEVEL)) return NULL;
|
|
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
// we'll set lifetime to -1 while actually assigning these.
|
|
if (f->lifetime == FROMJOB) {
|
|
switch (f->id) {
|
|
case F_LEVFLAG:
|
|
if (lf->newlevel == f->val[0]) {
|
|
return f;
|
|
}
|
|
break;
|
|
case F_LEVABIL:
|
|
case F_LEVSKILL:
|
|
case F_LEVSPELL:
|
|
case F_LEVSPELLSCHOOL:
|
|
if ((f->val[0] < 100) && (lf->newlevel == f->val[0])) {
|
|
return f;
|
|
} else if ((f->val[0] >= 100) && (lf->newlevel % (f->val[0] - 100) == 0) ) {
|
|
return f;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void loseconcentration(lifeform_t *lf) {
|
|
flag_t *f;
|
|
// stop sprinting
|
|
f = lfhasflag(lf, F_SPRINTING);
|
|
if (f && f->val[0]) {
|
|
killflag(f);
|
|
}
|
|
// boost spells end
|
|
stopallspells(lf);
|
|
|
|
// stop hiding
|
|
killflagsofid(lf->flags, F_HIDING);
|
|
|
|
interrupt(lf);
|
|
}
|
|
|
|
// lose hp, and adjust damage based on resistances
|
|
int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc) {
|
|
return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE);
|
|
}
|
|
|
|
int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam) {
|
|
char buf[BUFLEN];
|
|
char buf2[BUFLEN];
|
|
char lfname[BUFLEN];
|
|
int prebleed = B_FALSE,postbleed = B_FALSE;
|
|
flag_t *f;
|
|
|
|
getlfname(lf, lfname);
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
if (isbleeding(lf)) {
|
|
prebleed = B_TRUE;
|
|
}
|
|
|
|
// check for psychic armour etc
|
|
if (amt > 0) {
|
|
if (isphysicaldam(damtype)) {
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_MAGICARMOUR) {
|
|
int damtaken;
|
|
damtaken = amt;
|
|
if (damtaken > f->val[0]) {
|
|
damtaken = f->val[0];
|
|
}
|
|
f->val[0] -= damtaken;
|
|
if (f->val[0] <= 0) {
|
|
// from a spell?
|
|
if (f->lifetime == FROMSPELL) {
|
|
flag_t *spellflag;
|
|
spellflag = hasactivespell(lf, f->obfrom);
|
|
if (spellflag) {
|
|
killflag(spellflag);
|
|
}
|
|
}
|
|
killflag(f);
|
|
} else {
|
|
if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s%s %s pulses!", lfname, getpossessive(lfname), f->text);
|
|
}
|
|
}
|
|
|
|
// reduce damage
|
|
amt -= damtaken;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// adjust damage!
|
|
if (reducedam) {
|
|
adjustdamlf(lf, &amt, damtype);
|
|
}
|
|
|
|
// stop resting/running!
|
|
interrupt(lf);
|
|
|
|
// stop hiding
|
|
killflagsofid(lf->flags, F_HIDING);
|
|
|
|
// large damage?
|
|
if ((amt >= (lf->maxhp / 2)) && (amt >= 20)) {
|
|
if (useringofmiracles(lf, 1)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// occasionally drop blood
|
|
switch (damtype) {
|
|
case DT_POISON:
|
|
case DT_POISONGAS:
|
|
case DT_WATER:
|
|
break;
|
|
default:
|
|
if (onein(3)) {
|
|
bleed(lf);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (hasflag(lf->flags, F_DEBUG)) {
|
|
msg("[%s takes %d dam]",lfname, amt);
|
|
}
|
|
|
|
// take damage
|
|
lf->hp -= amt;
|
|
|
|
// fill in lastdam...
|
|
lf->lastdamtype = damtype;
|
|
|
|
// if they died
|
|
if (lf->hp <= 0) {
|
|
//if (!fromlf || (fromlf == player)) {
|
|
if (fromlf && (getallegiance(fromlf) == AL_FRIENDLY)) {
|
|
addflag(lf->flags, F_KILLEDBYPLAYER, B_TRUE, NA, NA, NULL);
|
|
}
|
|
} else {
|
|
// effects based on damage
|
|
if ((damtype == DT_COLD) && lfhasflag(lf, F_COLDBLOOD)) {
|
|
// slow them
|
|
addtempflag(lf->flags, F_SLOWMOVE, 5, NA, NA, NULL, 10);
|
|
} else if ((damtype == DT_POISONGAS) && (amt > 0)) {
|
|
if (!skillcheck(lf, SC_POISON, 25, 0)) {
|
|
poison(lf, rnd(5,10), P_GAS, 2, "poison gas");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isbleeding(lf)) {
|
|
postbleed = B_TRUE;
|
|
}
|
|
|
|
// replace 'the' at start of damsrc with 'a'
|
|
if (strstr(damsrc, "the ") == damsrc) {
|
|
sprintf(buf, "a %s", (damsrc+4));
|
|
} else {
|
|
strcpy(buf, damsrc);
|
|
}
|
|
|
|
|
|
// fill in damage amount
|
|
sprintf(buf2, "^%d damage",amt);
|
|
strcat(buf, buf2);
|
|
|
|
setlastdam(lf, buf);
|
|
|
|
|
|
// special case
|
|
if (lf->race->id == R_DREAMFUNGUS) {
|
|
if (cansee(player, lf)) {
|
|
animradialorth(lf->cell, 4, '}', C_MAGENTA);
|
|
msg("%s releases a cloud of purple spores!", lfname);
|
|
drawscreen();
|
|
}
|
|
spellcloud(lf->cell, 3, '\0', C_MAGENTA, OT_S_SLEEP, 8);
|
|
}
|
|
|
|
|
|
|
|
// further effects if not dead...
|
|
if (!isdead(lf)) {
|
|
// fight back if required
|
|
if (fromlf) {
|
|
fightback(lf, fromlf);
|
|
}
|
|
|
|
// low hitpoint warning
|
|
if (amt > 0) {
|
|
if (isplayer(lf)) {
|
|
int warnthresh;
|
|
warnthresh = (int)((float)0.25 * (float)lf->maxhp);
|
|
if (lf->hp <= warnthresh) {
|
|
warn("*** LOW HITPOINT WARNING ***");
|
|
more();
|
|
}
|
|
} else if (prebleed != postbleed) {
|
|
if (ispetof(lf, player) && !canhear(player, lf->cell)) {
|
|
char realname[BUFLEN];
|
|
real_getlfname(lf, realname, B_FALSE);
|
|
warn("You feel worried about your %s.", noprefix(realname));
|
|
} else {
|
|
makenoise(lf, N_LOWHP);
|
|
}
|
|
if (ispetof(lf, player)) {
|
|
more();
|
|
}
|
|
}
|
|
}
|
|
// you wake up if you were hit!
|
|
killflagsofid(lf->flags, F_ASLEEP);
|
|
|
|
|
|
// automatic onbleed abilities?
|
|
if (postbleed && !prebleed) {
|
|
f = lfhasflag(lf, F_BLEEDABIL);
|
|
if (f) {
|
|
flag_t *notime;
|
|
notime = addflag(lf->flags, F_NOTIME, B_TRUE, NA, NA, NULL);
|
|
abilityeffects(lf, f->val[0], lf->cell, lf, NULL);
|
|
killflag(notime);
|
|
}
|
|
}
|
|
}
|
|
|
|
// update screen
|
|
drawstatus();
|
|
updatestatus();
|
|
return amt;
|
|
}
|
|
|
|
void losemp(lifeform_t *lf, int amt) {
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
lf->mp -= amt;
|
|
|
|
if (lf->mp < 0) {
|
|
lf->mp = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void makefriendly(lifeform_t *who, int howlong) {
|
|
char lfname[BUFLEN];
|
|
|
|
getlfname(who, lfname);
|
|
if (lfhasflag(who, F_DEBUG)) {
|
|
msg("Making %s friendly.",lfname);
|
|
}
|
|
|
|
if (howlong == PERMENANT) {
|
|
killflagsofid(who->flags, F_HOSTILE);
|
|
} // if not unlimited, they'll revert back.
|
|
|
|
if (!hasflag(who->flags, F_FRIENDLY)) {
|
|
addtempflag(who->flags, F_FRIENDLY, B_TRUE, NA, NA, NULL, howlong);
|
|
}
|
|
killflagsofid(who->flags, F_TARGETLF); // stop targetting anyone
|
|
|
|
}
|
|
|
|
int makenauseated(lifeform_t *lf, int amt, int howlong) {
|
|
flag_t *f;
|
|
|
|
if (isundead(lf)) return B_TRUE;
|
|
|
|
if (!hasbp(lf, BP_HEAD)) return B_TRUE; // can't smell with no head
|
|
|
|
if (!lfhasflag(lf, F_HUMANOID)) return B_TRUE;
|
|
|
|
f = lfhasflag(lf, F_NAUSEATED);
|
|
if (f) {
|
|
if ((f->lifetime >= 0) && (f->lifetime < howlong)) {
|
|
f->lifetime = howlong;
|
|
f->val[0] = MAXOF(f->val[0], amt);
|
|
}
|
|
} else {
|
|
addtempflag(lf->flags, F_NAUSEATED, amt, NA, NA, NULL, howlong);
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
void makenoise(lifeform_t *lf, enum NOISETYPE nid) {
|
|
flag_t *f;
|
|
char *verb = NULL, *noun = NULL;
|
|
int volume;
|
|
|
|
if (lfhasflag(lf, F_FROZEN)) {
|
|
// can't make noise if frozen!
|
|
return;
|
|
}
|
|
|
|
f = hasflagval(lf->flags, F_NOISETEXT, nid, NA, NA, NULL);
|
|
if (f) {
|
|
char *dummy;
|
|
char noisetext[BUFLEN];
|
|
|
|
volume = f->val[1];
|
|
|
|
if (f->text[0] == '^') {
|
|
verb = NULL;
|
|
noun = strtok_r(f->text, "^", &dummy);
|
|
} else {
|
|
verb = strtok_r(f->text, "^", &dummy);
|
|
noun = strtok_r(NULL, "^", &dummy);
|
|
}
|
|
|
|
sprintf(noisetext, "%s.",noun);
|
|
noise(lf->cell, lf, volume, noisetext, verb);
|
|
} else {
|
|
// some defaults
|
|
if (nid == N_WALK) {
|
|
enum LFSIZE sz;
|
|
char movetext[BUFLEN];
|
|
strcpy(movetext, "");
|
|
sz = getlfsize(lf);
|
|
switch (sz) {
|
|
case SZ_MINI:
|
|
case SZ_TINY:
|
|
volume = 0;
|
|
break;
|
|
case SZ_SMALL:
|
|
volume = 1;
|
|
strcpy(movetext, "light footsteps.");
|
|
break;
|
|
case SZ_MEDIUM:
|
|
case SZ_HUMAN:
|
|
volume = 2;
|
|
strcpy(movetext, "footsteps.");
|
|
break;
|
|
case SZ_LARGE:
|
|
volume = 3;
|
|
strcpy(movetext, "heavy footsteps.");
|
|
break;
|
|
case SZ_HUGE:
|
|
volume = 4;
|
|
strcpy(movetext, "heavy footsteps.");
|
|
break;
|
|
case SZ_ENORMOUS:
|
|
volume = 5;
|
|
strcpy(movetext, "very heavy footsteps.");
|
|
break;
|
|
case SZ_MAX:
|
|
volume = 6;
|
|
strcpy(movetext, "extremely loud thumping.");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (strlen(movetext)) {
|
|
noise(lf->cell, lf, volume, movetext, NULL);
|
|
}
|
|
} else if (nid == N_WARCRY) {
|
|
noise(lf->cell, lf, 4, "a blood-curdling war cry!", "shouts a blood-curdling war-cry!");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) {
|
|
objecttype_t *ot;
|
|
skill_t *sk;
|
|
|
|
sk = findskill(getschoolskill(ss));
|
|
|
|
if (sk) {
|
|
if (!hasflagval(fp, F_STARTSKILL, sk->id, NA, NA, NULL)) {
|
|
addflag(fp, F_STARTSKILL, sk->id, PR_NOVICE, NA, NULL);
|
|
}
|
|
}
|
|
|
|
for (ot = objecttype ; ot ; ot = ot->next) {
|
|
//if (ot->obclass->id == OC_SPELL) {
|
|
if (hasflagval(ot->flags, F_SPELLSCHOOL, ss, NA, NA, NULL)) {
|
|
if (!hasflagval(fp, how, ot->id, NA, NA, NULL)) {
|
|
addflag(fp, how, ot->id, NA, NA, NULL);
|
|
}
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
|
|
|
|
// if you don't meet it, return why not in 'reason'
|
|
int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o) {
|
|
enum ATTRIB att;
|
|
int valneeded;
|
|
int myval;
|
|
att = f->val[0];
|
|
valneeded = f->val[1];
|
|
|
|
// modify for masterwork
|
|
if (o) {
|
|
if (hasflag(o->flags, F_MASTERWORK)) {
|
|
valneeded -= 3;
|
|
if (valneeded < 0) valneeded = 0;
|
|
}
|
|
}
|
|
|
|
myval = getattr(lf, att);
|
|
|
|
if (myval < valneeded) {
|
|
switch (att) {
|
|
case A_DEX:
|
|
reason = E_LOWDEX;
|
|
break;
|
|
case A_CON:
|
|
reason = E_LOWCON;
|
|
break;
|
|
case A_IQ:
|
|
reason = E_LOWIQ;
|
|
break;
|
|
case A_STR:
|
|
reason = E_LOWSTR;
|
|
break;
|
|
case A_NONE:
|
|
break;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
reason = E_OK;
|
|
return B_TRUE;
|
|
}
|
|
|
|
int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) {
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
// already at max/min?
|
|
if ((amt > 0) && (lf->att[attr] >= 18)) {
|
|
return B_TRUE;
|
|
}
|
|
if ((amt < 0) && (lf->att[attr] <= 0)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
lf->att[attr] += amt;
|
|
|
|
// increase base if required
|
|
if (lf->att[attr] > lf->baseatt[attr]) {
|
|
lf->baseatt[attr] = lf->att[attr];
|
|
}
|
|
|
|
// enforce limits
|
|
limit(&lf->att[attr], 0, 18);
|
|
|
|
if ((gamemode == GM_GAMESTARTED) && (amt != 0) && (isplayer(lf) || cansee(player, lf))) {
|
|
char lfname[BUFLEN], verb[BUFLEN], adverb[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
if (isplayer(lf)) strcpy(verb, "feel");
|
|
else strcpy(verb, "looks");
|
|
if (amt > 0) {
|
|
switch (attr) {
|
|
case A_STR:
|
|
strcpy(adverb, "stronger");
|
|
break;
|
|
case A_CON:
|
|
strcpy(adverb, "healthier");
|
|
break;
|
|
case A_DEX:
|
|
strcpy(adverb, "more agile");
|
|
break;
|
|
case A_IQ:
|
|
strcpy(adverb, "smarter");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else { // ie. amt < 0
|
|
switch (attr) {
|
|
case A_STR:
|
|
strcpy(adverb, "weaker");
|
|
break;
|
|
case A_CON:
|
|
strcpy(adverb, "frail");
|
|
break;
|
|
case A_DEX:
|
|
strcpy(adverb, "sluggish");
|
|
break;
|
|
case A_IQ:
|
|
strcpy(adverb, "foolish");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
msg("%s %s %s!", lfname, verb, adverb);
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
void modhunger(lifeform_t *lf, int amt) {
|
|
flag_t *f;
|
|
int prehlev, posthlev;
|
|
int multiplier;
|
|
f = hasflag(lf->flags, F_HUNGER);
|
|
if (!f) {
|
|
return;
|
|
}
|
|
|
|
// modify for effects
|
|
if (amt > 0) {
|
|
sumflags(lf->flags, F_FASTMETAB, &multiplier, NULL, NULL);
|
|
if (multiplier > 0) {
|
|
amt *= multiplier;
|
|
}
|
|
}
|
|
|
|
prehlev = gethungerlevel(f->val[0]);
|
|
f->val[0] += amt;
|
|
posthlev = gethungerlevel(f->val[0]);
|
|
|
|
if (posthlev == H_STARVED) {
|
|
if (isplayer(lf)) {
|
|
msg("You collapse from starvation.");
|
|
}
|
|
setlastdam(lf, "starvation");
|
|
lf->hp = 0;
|
|
} else if (prehlev != posthlev) {
|
|
if (posthlev != H_NONE) {
|
|
char buf[BUFLEN];
|
|
int needfeeling = B_FALSE;
|
|
int needexclam = B_FALSE;
|
|
switch (posthlev) {
|
|
case H_PECKISH:
|
|
case H_HUNGRY:
|
|
case H_VHUNGRY:
|
|
needfeeling = B_TRUE;
|
|
break;
|
|
default:
|
|
needfeeling = B_FALSE;
|
|
break;
|
|
}
|
|
switch (posthlev) {
|
|
case H_STUFFED:
|
|
case H_STARVING:
|
|
needexclam = B_TRUE;
|
|
break;
|
|
default:
|
|
needexclam = B_FALSE;
|
|
break;
|
|
}
|
|
|
|
|
|
if (isplayer(lf)) {
|
|
gethungername(posthlev, buf);
|
|
msg("You are %s%s%s%c",
|
|
((amt < 0) && (posthlev > H_NONE)) ? "still " : "",
|
|
needfeeling ? "feeling " : "",
|
|
buf,
|
|
(needexclam) ? '!' : '.');
|
|
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
if ((posthlev >= H_VHUNGRY) && (amt > 0)) {
|
|
stopresting(lf);
|
|
}
|
|
if (posthlev > H_STARVING) {
|
|
useringofmiracles(lf, 2);
|
|
// reset hunger
|
|
f->val[0] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
float modifybystat(float num, lifeform_t *lf, enum ATTRIB att) {
|
|
int newnum;
|
|
newnum = num + ( num * (getstatmod(lf, att) / 100.0) );
|
|
return newnum;
|
|
}
|
|
|
|
// if validchars is set, we will populate it with a list of valid
|
|
// choice letters for asking the player how to rest.
|
|
int needstorest(lifeform_t *lf, char *validchars) {
|
|
int need = B_FALSE;
|
|
if (validchars) strcpy(validchars, "");
|
|
|
|
if (lf->hp < lf->maxhp) {
|
|
if (validchars) strcat(validchars, "h");
|
|
need = B_TRUE;
|
|
}
|
|
if ((getmaxmp(lf) > 0) && (lf->mp < getmaxmp(lf))) {
|
|
if (validchars) strcat(validchars, "m");
|
|
need = B_TRUE;
|
|
}
|
|
return need;
|
|
}
|
|
|
|
// returns TRUE if the player heard it.
|
|
int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seetext) {
|
|
lifeform_t *l;
|
|
int sounddist;
|
|
int rv = B_FALSE;
|
|
if (gamemode != GM_GAMESTARTED) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
// sound will travel 2*volume cells
|
|
sounddist = 2 * volume;
|
|
|
|
// if anything nearby hears it, it might respond
|
|
for (l = c->map->lf; l ; l = l->next) {
|
|
int dist;
|
|
|
|
// ie. if this lf is in the process of swapping places
|
|
if (!l->cell) continue;
|
|
|
|
// if you make a noise while swapping position with
|
|
// something, its ->cell will be null here!
|
|
dist = getcelldist(l->cell, c);
|
|
|
|
if ((l != noisemaker) && (l->cell)) {
|
|
int difficulty;
|
|
//if (canhear(l, c) && haslos(l, c)) {
|
|
|
|
// listen check difficulty is based on sound distance vs max hearing distance
|
|
difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20);
|
|
// listen bonus is the sound volume
|
|
|
|
if (canhear(l, c) &&
|
|
(haslos(l, c) ||
|
|
((dist <= sounddist) && skillcheck(l, SC_LISTEN, difficulty, volume)))) {
|
|
flag_t *f;
|
|
// announce?
|
|
if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) {
|
|
// never say "you hear xxx" if you can see the lf that caused the noise.
|
|
if (noisemaker && cansee(l, noisemaker)) {
|
|
if (seetext) {
|
|
char lfname[BUFLEN];
|
|
getlfname(noisemaker, lfname);
|
|
msg("%s %s.", lfname, seetext);
|
|
rv = B_TRUE;
|
|
}
|
|
} else if (text && !lfhasflag(l, F_DONELISTEN)) {
|
|
char textnopunc[BUFLEN];
|
|
char punc;
|
|
int dist;
|
|
|
|
punc = text[strlen(text)-1];
|
|
strncpy(textnopunc, text, strlen(text)-1);
|
|
|
|
dist = getcelldist(l->cell, c);
|
|
|
|
// listen skill gives you more info about monsters
|
|
if (noisemaker) {
|
|
enum SKILLLEVEL slev;
|
|
char lfname[BUFLEN];
|
|
char distbuf[BUFLEN];
|
|
char dirbuf[BUFLEN];
|
|
int dir;
|
|
|
|
real_getlfnamea(noisemaker, lfname, B_FALSE);
|
|
if (dist >= 20) {
|
|
strcpy(distbuf, " far away");
|
|
} else if (dist >= 10) {
|
|
strcpy(distbuf, "");
|
|
} else if (dist >= 5) {
|
|
strcpy(distbuf, " nearby");
|
|
} else {
|
|
strcpy(distbuf, " very nearby");
|
|
}
|
|
|
|
dir = getdirtowards(l->cell, c, NULL, B_FALSE, DT_COMPASS);
|
|
strcpy(dirbuf, getdirname(dir));
|
|
dirbuf[0] = tolower(dirbuf[0]);
|
|
|
|
slev = getskill(l, SK_LISTEN);
|
|
//
|
|
// high listen skill lets you know more info.
|
|
//
|
|
// beginner = distance
|
|
// adept = distance and direction
|
|
// expert = monstername and distance and direction
|
|
// master = temporary scan of where they are!
|
|
if (slev >= PR_MASTER) {
|
|
flag_t *f;
|
|
f = lfhasflagval(l, F_CANHEARLF, noisemaker->id, NA, NA, NULL);
|
|
if (f) {
|
|
if (f->lifetime > 0) f->lifetime = 2;
|
|
} else {
|
|
addtempflag(l->flags, F_CANHEARLF, noisemaker->id, NA, NA, NULL, 2);
|
|
}
|
|
} else if (slev >= PR_EXPERT) {
|
|
msg("You hear %s%s to the %s%c", lfname, distbuf, dirbuf, punc);
|
|
rv = B_TRUE;
|
|
} else if (slev >= PR_ADEPT) {
|
|
msg("You hear %s%s to the %s%c", textnopunc, distbuf, dirbuf, punc);
|
|
rv = B_TRUE;
|
|
} else if (slev >= PR_BEGINNER) {
|
|
msg("You hear %s%s%c", textnopunc, distbuf, punc);
|
|
rv = B_TRUE;
|
|
} else {
|
|
msg("You hear %s", text);
|
|
rv = B_TRUE;
|
|
}
|
|
} else {
|
|
msg("You hear %s", text);
|
|
rv = B_TRUE;
|
|
}
|
|
// only hear one thing per turn.
|
|
addflag(l->flags, F_DONELISTEN, B_TRUE, NA, NA, NULL);
|
|
}
|
|
}
|
|
// wake up a little
|
|
f = lfhasflag(l, F_ASLEEP);
|
|
if (f) {
|
|
if (f->lifetime > 0) { // ie. temporary
|
|
timeeffectsflag(f, rnd(1,10));
|
|
} else if (f->lifetime == PERMENANT) {
|
|
if (f->val[2] == NA) { // ie asleep rather than 'resting'
|
|
// wake up!
|
|
if (isplayer(l)) {
|
|
msg("A nearby noise awakens you!");
|
|
rv = B_TRUE;
|
|
}
|
|
killflag(f);
|
|
} else {
|
|
// ie resting on purpose via 'r'
|
|
// only wake up if the sound if very close
|
|
if (getcelldist(c, l->cell) == 1) {
|
|
// wake up!
|
|
if (isplayer(l)) {
|
|
msg("A nearby noise awakens you!");
|
|
rv = B_TRUE;
|
|
}
|
|
killflag(f);
|
|
}
|
|
}
|
|
// make it temporary
|
|
//f->lifetime = rnd(1,10);
|
|
}
|
|
|
|
// still asleep?
|
|
if (lfhasflag(l, F_ASLEEP) && cansee(player, l)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(l, lfname);
|
|
msg("%s stir%s in %s slumber...", lfname,
|
|
isplayer(l) ? "" : "s",
|
|
isplayer(l) ? "your" : "its");
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
// give initial equiment / skills to a lifeform
|
|
void outfitlf(lifeform_t *lf) {
|
|
//int db = B_FALSE;
|
|
givestartobs(lf, lf->flags);
|
|
givestartskills(lf, lf->flags);
|
|
autoskill(lf);
|
|
|
|
// weild/wear stuff
|
|
autoweild(lf);
|
|
}
|
|
|
|
|
|
int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) {
|
|
char obname[BUFLEN];
|
|
object_t *o;
|
|
//flag_t *f;
|
|
int failed = B_FALSE;
|
|
|
|
if (!what) {
|
|
return B_TRUE;
|
|
}
|
|
if (howmany == 0) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
// in case we get burduned
|
|
if (isplayer(lf)) statdirty = B_TRUE;
|
|
|
|
getobname(what, obname, howmany);
|
|
if (howmany == ALL) howmany = what->amt;
|
|
|
|
if (fromground) {
|
|
if (lfhasflag(lf, F_LEVITATING)) {
|
|
if (isplayer(lf)) {
|
|
msg("You can't reach the ground from up here!");
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
if (!canpickup(lf, what,howmany)){
|
|
// tell the player why!
|
|
if (isplayer(lf)) {
|
|
switch (reason) {
|
|
case E_INSUBSTANTIAL:
|
|
msg("Your hand passes straight through %s.",obname);
|
|
break;
|
|
case E_NOSPACE:
|
|
msg("Your pack is too full to fit any more objects.");
|
|
break;
|
|
case E_NOPACK:
|
|
msg("You lack the ability to carry things!");
|
|
break;
|
|
case E_NOPICKUP:
|
|
msg("You can't pick up %s!",obname);
|
|
break;
|
|
case E_TOOBIG:
|
|
msg("%s %s too large for you to lift.",obname, (what->amt == 1) ? "is" : "are");
|
|
break;
|
|
case E_TOOHEAVY:
|
|
msg("%s %s too heavy to lift!",obname, (what->amt == 1) ? "is" : "are");
|
|
break;
|
|
case E_GRAVBOOSTED:
|
|
msg("The %s feels too heavy to lift!",noprefix(obname));
|
|
break;
|
|
default:
|
|
msg("For some reason, you cannot pick up %s!",obname);
|
|
break;
|
|
}
|
|
}
|
|
failed = B_TRUE;
|
|
}
|
|
|
|
if (!failed) {
|
|
if (touch(lf, what)) {
|
|
taketime(lf, SPEED_PICKUP);
|
|
return B_TRUE;
|
|
}
|
|
if (hasflag(what->flags, F_DEAD)) {
|
|
taketime(lf, SPEED_PICKUP);
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
// special case
|
|
|
|
if (!failed) {
|
|
// try to move whatever was selected
|
|
o = moveob(what, lf->pack, howmany);
|
|
if (o) { // if pickup was successful...
|
|
if (isplayer(lf)) {
|
|
// refresh obname to copd with stacking
|
|
getobname(o, obname, o->amt);
|
|
msgnocap("%c - %s",o->letter, obname);
|
|
} else if (cansee(player, lf)) {
|
|
char buf[BUFLEN];
|
|
getlfname(lf, buf);
|
|
msg("%s picks up %s.",buf, obname);
|
|
}
|
|
/*
|
|
taketime(lf, (SPEED_PICKUP * howmany));
|
|
*/
|
|
taketime(lf, SPEED_PICKUP);
|
|
|
|
// TODO: update burdened status
|
|
|
|
// use ammo rightaway if required.
|
|
testammo(lf, o);
|
|
} else {
|
|
// tell the player why!
|
|
if (isplayer(lf)) {
|
|
switch (reason) {
|
|
case E_NOSPACE:
|
|
msg("Your pack is too full to fit any more objects.");
|
|
break;
|
|
default:
|
|
msg("For some reason, you cannot pick up %s!",obname);
|
|
break;
|
|
}
|
|
}
|
|
failed = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (failed) {
|
|
// if object isn't where player is, move it to player's pile
|
|
// for example, if obejct was being picked up via telekenesis
|
|
if (what->pile->where != lf->cell) {
|
|
moveob(what, lf->cell->obpile, howmany);
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat) {
|
|
flag_t *f;
|
|
int found = B_FALSE;
|
|
|
|
// adjust time based on first aid skill
|
|
howlong -= getskill(lf, SK_FIRSTAID);
|
|
if (howlong <= 0) {
|
|
return;
|
|
}
|
|
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if ( (f->id == F_POISONED) && (f->val[0] == ptype) &&
|
|
(f->lifetime > 0) ) {
|
|
// extend duration
|
|
f->lifetime += howlong;
|
|
// announce - announceflaggain won't be called
|
|
// since this isn't a new flag.
|
|
if (isplayer(lf)) {
|
|
msg("You feel more sick.");
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s looks even more sick.", lfname);
|
|
}
|
|
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
addtempflag(lf->flags, F_POISONED, ptype, power, NA, fromwhat, howlong);
|
|
|
|
// also apply specific poison effect
|
|
switch (ptype) {
|
|
case P_FOOD:
|
|
case P_GAS:
|
|
case P_VENOM:
|
|
default:
|
|
break;
|
|
case P_WEAKNESS:
|
|
f = addtempflag(lf->flags, F_ATTRMOD, A_STR, -power, NA, NULL, FROMPOISON);
|
|
f->obfrom = ptype; // poison type
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int poisoncausesvomit(enum POISONTYPE ptype) {
|
|
switch (ptype) {
|
|
case P_FOOD:
|
|
case P_VENOM:
|
|
return B_TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int poisonthreatenslife(lifeform_t *lf, flag_t *f) {
|
|
float time,dam,totaldam;
|
|
|
|
if (!f) return B_FALSE;
|
|
|
|
time = f->lifetime;
|
|
dam = f->val[1];
|
|
|
|
totaldam = time * dam;
|
|
totaldam = pctof(getpoisondamchance(f->val[0]), totaldam);
|
|
|
|
if (totaldam >= lf->hp) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void practice(lifeform_t *lf, enum SKILL skid) {
|
|
flag_t *f;
|
|
|
|
// already got the skill?
|
|
if (getskill(lf, skid)) {
|
|
return;
|
|
}
|
|
// practice a little bit...
|
|
f = lfhasflagval(lf, F_PRACTICINGSKILL, skid, NA, NA, NULL);
|
|
if (f) {
|
|
f->val[1]++;
|
|
if (f->val[1] >= PRACTICETIME) {
|
|
// learnt it!
|
|
giveskill(lf, skid);
|
|
}
|
|
} else {
|
|
addflag(lf->flags, F_PRACTICINGSKILL, skid, 1, NA, NULL);
|
|
}
|
|
}
|
|
|
|
void precalclos(lifeform_t *lf) {
|
|
int x,y;
|
|
cell_t *c;
|
|
int maxvisrange;
|
|
cell_t *los[MAX_MAPW * MAX_MAPH];
|
|
int nlos;
|
|
int i;
|
|
|
|
// free existing structures
|
|
if (lf->los) {
|
|
free(lf->los);
|
|
}
|
|
|
|
|
|
nlos = 0;
|
|
|
|
maxvisrange = getvisrange(lf);
|
|
for (y = lf->cell->y - maxvisrange; y <= lf->cell->y + maxvisrange ; y++) {
|
|
for (x = lf->cell->x - maxvisrange; x <= lf->cell->x + maxvisrange ; x++) {
|
|
c = getcellat(lf->cell->map, x, y);
|
|
//
|
|
if ((c != lf->cell) && haslos(lf, c)) {
|
|
los[nlos] = c;
|
|
nlos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now fill in lifeform structure
|
|
lf->los = malloc(sizeof(cell_t *) * nlos);
|
|
for (i = 0; i < nlos; i++) {
|
|
lf->los[i] = los[i];
|
|
}
|
|
lf->nlos = nlos;
|
|
}
|
|
|
|
int push(lifeform_t *lf, object_t *o, int dir) {
|
|
cell_t *obcell, *dstcell;
|
|
char obname[BUFLEN];
|
|
getobname(o, obname, o->amt);
|
|
|
|
// remember cells
|
|
obcell = o->pile->where;
|
|
dstcell = getcellindir(obcell, dir);
|
|
|
|
// take time (even if it will fail) - twice normal
|
|
taketime(lf, getactspeed(lf) * 2);
|
|
|
|
if (!obcell || !dstcell) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
if (touch(lf, o)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
// move object
|
|
o = moveob(o, dstcell->obpile, o->amt);
|
|
if (!o) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
// move player
|
|
moveto(lf, obcell, B_TRUE, B_FALSE);
|
|
|
|
// announce
|
|
if (isplayer(lf)) {
|
|
msg("You push %s.", obname);
|
|
} else if (haslos(player, dstcell)) {
|
|
char buf[BUFLEN];
|
|
getlfname(lf, buf);
|
|
capitalise(buf);
|
|
msg("%s pushes %s.", cansee(player, lf) ? buf : "Something", obname);
|
|
}
|
|
|
|
touch(lf, o);
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
int readytotrain(lifeform_t *lf) {
|
|
if (lf->skillpoints || getattpoints(lf) || levelabilityready(lf)) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
void refreshlevelabilities(lifeform_t *lf) {
|
|
flag_t *f;
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
// we'll set timeleft to -1 while actually assigning these.
|
|
switch (f->id) {
|
|
case F_LEVFLAG:
|
|
case F_LEVABIL:
|
|
case F_LEVSKILL:
|
|
case F_LEVSPELL:
|
|
case F_LEVSPELLSCHOOL:
|
|
f->lifetime = FROMJOB;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// move lf to the _START_ of the destination map list
|
|
void relinklf(lifeform_t *src, map_t *dst) {
|
|
map_t *srcmap;
|
|
|
|
srcmap = src->cell->map;
|
|
|
|
// unlink this player from the current list
|
|
if (src->prev == NULL) {
|
|
// first
|
|
srcmap->lf = src->next;
|
|
} else {
|
|
// not first
|
|
src->prev->next = src->next;
|
|
}
|
|
if (src->next == NULL) {
|
|
// last
|
|
srcmap->lastlf = src->prev;
|
|
} else {
|
|
// not last
|
|
src->next->prev = src->prev;
|
|
}
|
|
|
|
// add this lf to the START of the list on the new map
|
|
if (dst->lf == NULL) {
|
|
// first (and only) element in new list
|
|
dst->lf = src;
|
|
src->prev = NULL;
|
|
src->next = NULL;
|
|
dst->lastlf = src;
|
|
} else {
|
|
lifeform_t *aa;
|
|
|
|
// go to start of list
|
|
aa = dst->lf;
|
|
|
|
dst->lf = src;
|
|
src->prev = NULL;
|
|
src->next = aa;
|
|
|
|
aa->prev = src;
|
|
}
|
|
|
|
// note this function will NOT set the lifeform's cell to one on the new map.
|
|
|
|
// now rise up
|
|
sortlf(dst, src);
|
|
}
|
|
|
|
// strat resting...
|
|
void startresting(lifeform_t *lf, int willtrain) {
|
|
int traincounter;
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
needredraw = B_TRUE;
|
|
}
|
|
|
|
if (willtrain) {
|
|
traincounter = 50;
|
|
traincounter = modifybystat(traincounter, player, A_IQ);
|
|
} else {
|
|
traincounter = NA;
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
lf->turnsskipped = 0;
|
|
}
|
|
|
|
// stop hiding
|
|
killflagsofid(lf->flags, F_HIDING);
|
|
|
|
if (willtrain) {
|
|
addflag(lf->flags, F_TRAINING, B_TRUE, NA, traincounter, NULL);
|
|
} else {
|
|
addflag(lf->flags, F_ASLEEP, B_TRUE, NA, B_TRUE, NULL);
|
|
}
|
|
|
|
// stop movement for all allies
|
|
if (isplayer(lf)) {
|
|
lifeform_t *l;
|
|
for (l = lf->cell->map->lf ; l ; l = l->next) {
|
|
if ((l != lf) && areallies(l, lf)) {
|
|
killflagsofid(l->flags, F_TARGETCELL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
if (willtrain) {
|
|
msg("You start training...");
|
|
}
|
|
drawmsg();
|
|
drawcursor();
|
|
}
|
|
}
|
|
|
|
int rolliq(enum IQBRACKET bracket) {
|
|
int roll = 0;
|
|
switch (bracket) {
|
|
case IQ_MINDLESS:
|
|
roll = 0;
|
|
break;
|
|
case IQ_VEGETABLE:
|
|
roll = rnd(1,3);
|
|
break;
|
|
case IQ_ANIMAL:
|
|
roll = rnd(4,6);
|
|
break;
|
|
case IQ_DIMWITTED:
|
|
roll = rnd(4,6);
|
|
break;
|
|
case IQ_DOPEY:
|
|
roll = rnd(7,9);
|
|
break;
|
|
case IQ_AVERAGE:
|
|
roll = rnd(10,12);
|
|
break;
|
|
case IQ_SMART:
|
|
roll = rnd(13,15);
|
|
break;
|
|
case IQ_ENLIGHTENED:
|
|
roll = rnd(16,17);
|
|
break;
|
|
case IQ_GENIUS:
|
|
roll = 18;
|
|
break;
|
|
default:
|
|
roll = rolldie(3,6);
|
|
break;
|
|
}
|
|
return roll;
|
|
}
|
|
|
|
int rollcon(enum CONBRACKET bracket) {
|
|
int roll = 0;
|
|
switch (bracket) {
|
|
case CN_FRAIL:
|
|
roll = rnd(1,2);
|
|
break;
|
|
case CN_SICKLY:
|
|
roll = rnd(3,4);
|
|
break;
|
|
case CN_UNHEALTHY:
|
|
roll = rnd(5,6);
|
|
break;
|
|
case CN_UNFIT:
|
|
roll = rnd(7,8);
|
|
break;
|
|
case CN_AVERAGE:
|
|
roll = rnd(9,11);
|
|
break;
|
|
case CN_HEALTHY:
|
|
roll = rnd(12,14);
|
|
break;
|
|
case CN_FIT:
|
|
roll = rnd(15,16);
|
|
break;
|
|
case CN_HARDY:
|
|
roll = rnd(17,18);
|
|
break;
|
|
default:
|
|
roll = rolldie(3,6);
|
|
break;
|
|
}
|
|
return roll;
|
|
}
|
|
|
|
int rolldex(enum DEXBRACKET bracket) {
|
|
int roll = 0;
|
|
switch (bracket) {
|
|
case DX_INCOMPETENT:
|
|
roll = 0;
|
|
break;
|
|
case DX_OAFISH:
|
|
roll = rnd(1,2);
|
|
break;
|
|
case DX_INEPT:
|
|
roll = rnd(3,4);
|
|
break;
|
|
case DX_CLUMSY:
|
|
roll = rnd(5,6);
|
|
break;
|
|
case DX_AWKWARD:
|
|
roll = rnd(7,8);
|
|
break;
|
|
case DX_AVERAGE:
|
|
roll = 9;
|
|
break;
|
|
case DX_DEXTROUS:
|
|
roll = rnd(10,11);
|
|
break;
|
|
case DX_NIMBLE:
|
|
roll = rnd(12,13);
|
|
break;
|
|
case DX_AGILE:
|
|
roll = rnd(14,15);
|
|
break;
|
|
case DX_SWIFT:
|
|
roll = rnd(16,17);
|
|
break;
|
|
case DX_SUPERSONIC:
|
|
roll = 18;
|
|
break;
|
|
default:
|
|
roll = rolldie(3,6);
|
|
break;
|
|
}
|
|
return roll;
|
|
}
|
|
|
|
int rollstr(enum STRBRACKET bracket) {
|
|
int roll = 0;
|
|
switch (bracket) {
|
|
case ST_HELPLESS:
|
|
roll = 0;
|
|
break;
|
|
case ST_FEEBLE:
|
|
roll = rnd(1,3);
|
|
break;
|
|
case ST_VWEAK:
|
|
roll = rnd(4,6);
|
|
break;
|
|
case ST_WEAK:
|
|
roll = rnd(7,9);
|
|
break;
|
|
case ST_AVERAGE:
|
|
roll = rnd(10,12);
|
|
break;
|
|
case ST_STRONG:
|
|
roll = rnd(13,15);
|
|
break;
|
|
case ST_MIGHTY:
|
|
roll = rnd(16,17);
|
|
break;
|
|
case ST_TITANIC:
|
|
roll = 18;
|
|
break;
|
|
default:
|
|
roll = rolldie(3,6);
|
|
break;
|
|
}
|
|
return roll;
|
|
}
|
|
|
|
int rollstat(lifeform_t *lf, enum ATTRIB attr) {
|
|
flag_t *f;
|
|
int bracket;
|
|
|
|
f = hasflagval(lf->flags, F_STARTATT, attr, NA, NA, NULL);
|
|
if (f) {
|
|
bracket = f->val[1];
|
|
} else {
|
|
switch (attr) {
|
|
case A_STR:
|
|
bracket = ST_RANDOM; break;
|
|
case A_CON:
|
|
bracket = CN_RANDOM; break;
|
|
case A_DEX:
|
|
bracket = DX_RANDOM; break;
|
|
case A_IQ:
|
|
bracket = IQ_RANDOM; break;
|
|
default:
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
switch (attr) {
|
|
case A_STR:
|
|
lf->att[attr] = rollstr(bracket);
|
|
break;
|
|
case A_DEX:
|
|
lf->att[attr] = rolldex(bracket);
|
|
break;
|
|
case A_IQ:
|
|
lf->att[attr] = rolliq(bracket);
|
|
break;
|
|
case A_CON:
|
|
lf->att[attr] = rollcon(bracket);
|
|
break;
|
|
default:
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
// safe to rest?
|
|
int safetorest(lifeform_t *lf) {
|
|
lifeform_t *l;
|
|
reason = E_OK;
|
|
|
|
for (l = lf->cell->map->lf ; l ; l = l->next) {
|
|
if ((l != lf) && cansee(lf, l) && areenemies(lf, l) ) {
|
|
if (!lfhasflag(l, F_HARMLESS)) {
|
|
reason = E_MONSTERNEARBY;
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
int say(lifeform_t *lf, char *text, int volume) {
|
|
char buf[BUFLEN];
|
|
char verb[BUFLEN];
|
|
char noun[BUFLEN];
|
|
if (volume < 2) {
|
|
strcpy(verb, "whispers");
|
|
strcpy(noun, "whispering.");
|
|
} else if (volume == 2) {
|
|
strcpy(verb, "says");
|
|
strcpy(noun, "voices.");
|
|
} else if (volume == 3) {
|
|
strcpy(verb, "shouts");
|
|
strcpy(noun, "raised voices.");
|
|
} else if (volume == 4) {
|
|
strcpy(verb, "roars");
|
|
strcpy(noun, "roaring voices!");
|
|
} else if (volume > 4) {
|
|
strcpy(verb, "bellows");
|
|
strcpy(noun, "bellowing voices!");
|
|
}
|
|
|
|
sprintf(buf, "%s \"%s\"", verb, text);
|
|
|
|
return noise(lf->cell, lf, volume, noun, buf);
|
|
}
|
|
|
|
// returns TRUE if something happened
|
|
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus) {
|
|
int nfailures = 0;
|
|
int i;
|
|
int penalty = 0;
|
|
if (!scarer) return B_FALSE;
|
|
|
|
// immune to fear?
|
|
if (lfhasflag(lf, F_UNDEAD)) return B_FALSE;
|
|
|
|
if (lfhasflag(lf, F_ASLEEP)) {
|
|
return B_FALSE;
|
|
}
|
|
// not intelligent enough to be scared?
|
|
if (getiqname(getattr(scarer, A_IQ), NULL) <= IQ_VEGETABLE) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
// determine morale check penalty
|
|
if (isbleeding(lf)) {
|
|
penalty += 5;
|
|
}
|
|
if (lfhasflag(lf, F_HUMANOID)) {
|
|
object_t *o;
|
|
for (o = scarer->pack->first ; o; o = o->next) {
|
|
flag_t *f;
|
|
f = isequipped(o);
|
|
// ie. equipped, but not primary or secondary weapon
|
|
if (f && (f->val[0] > BP_SECWEAPON)) {
|
|
f = hasflag(o->flags, F_SCARY);
|
|
if (f) {
|
|
scarerbonus += f->val[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// three checks
|
|
nfailures = 0;
|
|
for (i = 0; i < 3; i++) {
|
|
if (!skillcheckvs(lf, SC_MORALE, -penalty, scarer, SC_MORALE, scarerbonus)) {
|
|
nfailures++;
|
|
}
|
|
}
|
|
|
|
if (nfailures == 1) {
|
|
// cower
|
|
fleefrom(lf, scarer, rnd(1,3));
|
|
return B_TRUE;
|
|
} else if (nfailures == 2) {
|
|
// flee for given time
|
|
fleefrom(lf, scarer, howlong);
|
|
return B_TRUE;
|
|
} else if (nfailures == 3) {
|
|
object_t *wep;
|
|
// drop weapon and flee for given time
|
|
fleefrom(lf, scarer, howlong);
|
|
wep = getweapon(lf);
|
|
if (wep) {
|
|
drop(wep, ALL);
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
int setammo(lifeform_t *lf, object_t *ammo) {
|
|
object_t *gun;
|
|
object_t *o;
|
|
char gunname[BUFLEN],ammoname[BUFLEN];
|
|
|
|
if (ammo) {
|
|
getobname(ammo, ammoname, ammo->amt);
|
|
}
|
|
|
|
gun = getfirearm(lf);
|
|
if (!gun) {
|
|
if (isplayer(lf)) {
|
|
msg("You have no firearm weilded!");
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
getobname(gun, gunname, gun->amt);
|
|
|
|
|
|
if (ammo && !isammofor(ammo, gun)) {
|
|
if (isplayer(lf)) {
|
|
msg("You can't load %s with %s!", gunname, ammoname);
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
// remove current ammo
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
flag_t *f;
|
|
f = hasflag(o->flags, F_CURAMMO);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
|
|
|
|
if (ammo) {
|
|
addflag(ammo->flags, F_CURAMMO, B_TRUE, NA, NA, NULL);
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
msg("Using %s as ammo for %s.", ammoname, gunname);
|
|
}
|
|
} else {
|
|
if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) {
|
|
msg("No ammo equipped for %s.", gunname);
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
void setattr(lifeform_t *lf, enum ATTRIB attr, int val) {
|
|
lf->att[attr] = val;
|
|
if (lf->att[attr] > lf->baseatt[attr]) {
|
|
lf->baseatt[attr] = lf->att[attr];
|
|
}
|
|
}
|
|
|
|
void setguntarget(lifeform_t *lf, lifeform_t *targ) {
|
|
flag_t *f;
|
|
f = hasflag(lf->flags, F_GUNTARGET);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
|
|
if (targ) {
|
|
addflag(lf->flags, F_GUNTARGET, targ->id, NA, NA, NULL);
|
|
if (isplayer(lf)) {
|
|
// announce
|
|
char targname[BUFLEN];
|
|
getlfname(targ, targname);
|
|
msg("Targetted: %s.",noprefix(targname)); // remove 'the '
|
|
} else {
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
char lfname[BUFLEN];
|
|
char targname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
getlfname(targ, targname);
|
|
dblog("%s targetted %s.",lfname,targname);
|
|
}
|
|
}
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
// announce
|
|
msg("Targetted: nothing.");
|
|
} else {
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
dblog("%s target set to nothing.",lfname);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) {
|
|
flag_t *f,*nextf;
|
|
int i;
|
|
race_t *newrace;
|
|
char buf[BUFLEN];
|
|
|
|
newrace = findrace(rid);
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
if (frompolymorph && (gamemode == GM_GAMESTARTED) && lf->race) {
|
|
race_t *origrace;
|
|
|
|
// remove 'become a ghost' flag
|
|
killflagsofid(lf->flags, F_RISEASGHOST);
|
|
|
|
// were we already polymorphed?
|
|
f = lfhasflag(lf, F_ORIGRACE);
|
|
if (f) {
|
|
origrace = findrace(f->val[0]);
|
|
}
|
|
// announce
|
|
if (origrace && (newrace == origrace)) {
|
|
// reverting to original form....
|
|
if (!isdead(lf)) {
|
|
if (isplayer(lf)) {
|
|
msg("You revert to your original form!");
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("The %s transforms back to its original form!", newrace->name);
|
|
}
|
|
}
|
|
|
|
f = lfhasflagval(lf, F_CANWILL, OT_A_POLYREVERT, NA, NA, NULL);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
killflagsofid(lf->flags, F_ORIGRACE);
|
|
killflagsofid(lf->flags, F_POLYMORPHED);
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
msg("You transform into %s %s!", isvowel(newrace->name[0]) ? "an" : "a", newrace->name);
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// stop stoning.
|
|
killflagsofid(lf->flags, F_BEINGSTONED);
|
|
|
|
// first remove flags from existing race, or temporary ones
|
|
lf->born = B_FALSE;
|
|
for (f = lf->flags->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
if (f->lifetime == FROMRACE) {
|
|
killflag(f);
|
|
} else if ((f->lifetime > 0) && (f->id != F_POLYMORPHED)) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
|
|
// set race
|
|
lf->race = newrace;
|
|
|
|
// inherit flags from race
|
|
copyflags(lf->flags, lf->race->flags, FROMRACE);
|
|
// don't want certain race only flags...
|
|
killflagsofid(lf->flags, F_RARITY);
|
|
|
|
// generate stats
|
|
for (i = 0; i < MAXATTS; i++) {
|
|
rollstat(lf, i);
|
|
lf->baseatt[i] = lf->att[i];
|
|
}
|
|
|
|
// generate hp/maxhp from hit dice
|
|
lf->maxhp = 0;
|
|
for (i = 0; i < lf->level; i++) {
|
|
lf->maxhp += rollhitdice(lf);
|
|
assert(lf->maxhp > 0);
|
|
}
|
|
lf->hp = lf->maxhp;
|
|
|
|
// generate mp, if you have it.
|
|
f = hasflag(lf->flags, F_MPDICE);
|
|
if (f) {
|
|
lf->maxmp = f->val[0] * 4;
|
|
if (f->val[1] != NA) lf->maxmp += f->val[1];
|
|
for (i = 0; i < lf->level-1; i++) {
|
|
lf->maxmp += rollmpdice(lf);
|
|
}
|
|
} else {
|
|
lf->maxmp = 0;
|
|
}
|
|
lf->mp = lf->maxmp;
|
|
|
|
|
|
lf->born = B_TRUE;
|
|
|
|
// check whether:
|
|
// new race can equip things (F_NOBODYPART xx)
|
|
// new race can hold objects (F_NOPACK xx)
|
|
// TODO: new race can use magic (F_NOSPELLS)
|
|
// new race can still hold all the items which you have
|
|
if ((gamemode == GM_GAMESTARTED)) {
|
|
enum BODYPART bp;
|
|
object_t *o,*nexto;
|
|
|
|
// no pack?
|
|
if (lfhasflag(lf, F_NOPACK)) {
|
|
// drop everything
|
|
if (countobs(lf->pack, B_FALSE)) {
|
|
if (isplayer(lf)) {
|
|
msg("Your possessions drop to the ground!");
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s%s possessions drop to the ground!",buf, getpossessive(buf));
|
|
}
|
|
}
|
|
for (o = lf->pack->first ; o ; o = nexto) {
|
|
nexto = o->next;
|
|
|
|
moveob(o, lf->cell->obpile, o->amt);
|
|
}
|
|
}
|
|
|
|
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
|
|
if (lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) {
|
|
for (o = lf->pack->first; o ; o = nexto ) {
|
|
nexto = o->next;
|
|
if (hasflagval(o->flags, F_EQUIPPED, bp, NA, NA, NULL)) {
|
|
char obname[BUFLEN];
|
|
getobname(o, obname, o->amt);
|
|
// drop it!
|
|
if (isplayer(lf)) {
|
|
msg("Your %s drops to the ground!",noprefix(obname));
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s%s %s drop to the ground!",buf, getpossessive(buf),
|
|
noprefix(obname));
|
|
}
|
|
moveob(o, lf->cell->obpile, o->amt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (o = lf->pack->first ; o ; o = nexto) {
|
|
nexto = o->next;
|
|
|
|
if (!canpickup(lf, o, o->amt)) {
|
|
char obname[BUFLEN];
|
|
getobname(o, obname, o->amt);
|
|
// drop it!
|
|
if (isplayer(lf)) {
|
|
msg("Your %s drops to the ground!",noprefix(obname));
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s%s %s drop to the ground!",buf, getpossessive(buf),
|
|
noprefix(obname));
|
|
}
|
|
moveob(o, lf->cell->obpile, o->amt);
|
|
}
|
|
}
|
|
} // end if gamestarted
|
|
|
|
}
|
|
|
|
void setlastdam(lifeform_t *lf, char *buf) {
|
|
if (lf->lastdam) {
|
|
free(lf->lastdam);
|
|
}
|
|
lf->lastdam = strdup(buf);
|
|
}
|
|
|
|
void initskills(void) {
|
|
addskill(SK_ARMOUR, "Armour", "Helps maintain armour, reducing evasion penalties and armour damage.");
|
|
addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery.");
|
|
addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen.");
|
|
addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps.");
|
|
addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.");
|
|
addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison.");
|
|
addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds.");
|
|
addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.");
|
|
addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.");
|
|
addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.");
|
|
addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block projectiles.");
|
|
addskill(SK_SPELLCASTING, "Sorcery", "Determines your ability to cast spells from all schools.");
|
|
addskill(SK_SPOTHIDDEN, "Searching", "Helps you to spot hidden traps or creatures.");
|
|
addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.");
|
|
addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.");
|
|
addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items.");
|
|
addskill(SK_TRACKING, "Tracking", "Allows you to track enemies by their footprints.");
|
|
addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps.");
|
|
addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once.");
|
|
// knowledge
|
|
addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising magical objects and creatures.");
|
|
addskill(SK_LORE_DEMONS, "Lore:Demonology", "Determines your knowledge about demons.");
|
|
addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.");
|
|
addskill(SK_LORE_NATURE, "Lore:Nature", "Determines your knowledge of plants, animals and insects.");
|
|
addskill(SK_LORE_UNDEAD, "Lore:Undead", "Determines your knowledge of the undead.");
|
|
// weaponry
|
|
addskill(SK_AXES, "Axes", "Helps you use chopping weapons like axes.");
|
|
addskill(SK_CLUBS, "Clubs", "Helps you use bashing weapons like maces or clubs.");
|
|
addskill(SK_LONGBLADES, "Long Blades", "Helps you use long swords, scimitars, etc.");
|
|
addskill(SK_POLEARMS, "Polearms", "Helps you use long bladed weapons like halberds.");
|
|
addskill(SK_SHORTBLADES, "Short Blades", "Helps you use daggers, short swords, etc.");
|
|
addskill(SK_STAVES, "Staves", "Helps you use quarterstaffs, staffs, etc.");
|
|
addskill(SK_UNARMED, "Unarmed Combat", "Helps you fight using your bare hands.");
|
|
// spell schools
|
|
addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_AIR, "Air Magic", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_DEATH, "Necromancy", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_DIVINATION, "Divination", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_FIRE, "Fire Magic", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_COLD, "Cold Magic", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_GRAVITY, "Gravitation Magic", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_LIFE, "Life Magic", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_MODIFICATION, "Modification", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_MENTAL, "Psionics", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_NATURE, "Nature Magic", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_SUMMONING, "Summoning", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_TRANSLOCATION, "Translocation", "Boosts casting of spells from this school.");
|
|
addskill(SK_SS_WILD, "Wild Magic", "Boosts casting of spells from this school.");
|
|
}
|
|
|
|
void interrupt(lifeform_t *lf) {
|
|
stopeating(lf);
|
|
stopresting(lf);
|
|
stoprunning(lf);
|
|
killflagsofid(lf->flags, F_AUTOCMD);
|
|
}
|
|
|
|
/*j
|
|
void setlftarget(lifeform_t *lf, lifeform_t *victim) {
|
|
// first remove existing targets
|
|
killflagsofid(lf->flags, F_TARGET);
|
|
killflagsofid(lf->flags, F_TARGETCELL);
|
|
|
|
// set new target
|
|
addflag(lf->flags, F_TARGET, victim->id, victim->cell->x, victim->cell->x, NULL);
|
|
|
|
if (!areenemies(lf, victim)) {
|
|
if (getallegiance(victim) == AL_FRIENDLY) {
|
|
if (!hasflag(lf->flags, F_HOSTILE)) {
|
|
addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
int shoot(lifeform_t *lf) {
|
|
object_t *gun,*ammo;
|
|
lifeform_t *targ;
|
|
int firespeed;
|
|
|
|
reason = E_OK;
|
|
gun = getfirearm(lf);
|
|
if (!gun) {
|
|
reason = E_NOTEQUIPPED;
|
|
return B_TRUE;
|
|
}
|
|
// get target
|
|
targ = getguntarget(lf);
|
|
if (!targ) {
|
|
reason = E_NOTARGET;
|
|
return B_TRUE;
|
|
}
|
|
// get ammo
|
|
ammo = getammo(lf);
|
|
if (!ammo) {
|
|
reason = E_NOAMMO;
|
|
return B_TRUE;
|
|
}
|
|
|
|
// get fire speed
|
|
firespeed = getfirearmspeed(gun);
|
|
|
|
taketime(lf, getattackspeed(lf));
|
|
|
|
fireat(lf, ammo, 1, targ->cell, firespeed, gun);
|
|
return B_FALSE;
|
|
}
|
|
|
|
int skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod) {
|
|
return real_skillcheck(lf, ct, diff, mod, NULL);
|
|
}
|
|
|
|
// positive mod makes it easier, negative makes it harder
|
|
int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *result) {
|
|
int attrib;
|
|
int levmod;
|
|
int othermod = 0;
|
|
int db = B_FALSE;
|
|
int roll;
|
|
int modroll;
|
|
int luckmod = 0;
|
|
char mbuf[BUFLEN];
|
|
flag_t *f;
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
if (ct != SC_STEALTH) { // dont show debug info for stealth checks
|
|
db = B_TRUE;
|
|
}
|
|
}
|
|
|
|
switch (ct) {
|
|
case SC_STR:
|
|
attrib = getattr(lf, A_STR);
|
|
break;
|
|
case SC_CON:
|
|
attrib = getattr(lf, A_CON);
|
|
break;
|
|
case SC_DEX:
|
|
attrib = getattr(lf, A_DEX);
|
|
break;
|
|
case SC_OPENLOCKS:
|
|
attrib = getattr(lf, A_DEX);
|
|
break;
|
|
case SC_IQ:
|
|
case SC_WILL:
|
|
attrib = getattr(lf, A_IQ);
|
|
break;
|
|
case SC_MORALE: // based on level/hitdice and size.
|
|
attrib = (lf->hp / 4);
|
|
attrib += ((float)getlfsize(lf) * 1.5);
|
|
f = lfhasflag(lf, F_MORALE);
|
|
if (f) attrib += f->val[0];
|
|
break;
|
|
case SC_SLIP:
|
|
case SC_FALL:
|
|
attrib = getattr(lf, A_DEX);
|
|
break;
|
|
case SC_SHIELDBLOCK:
|
|
attrib = (getattr(lf, A_DEX) / 4);
|
|
break;
|
|
case SC_POISON:
|
|
attrib = getattr(lf, A_CON);
|
|
break;
|
|
case SC_DISARM:
|
|
attrib = (getskill(lf, SK_TRAPS)*3);
|
|
if (attrib) {
|
|
attrib += (getattr(lf, A_DEX)/4);
|
|
}
|
|
break;
|
|
case SC_DODGE:
|
|
// getevasion returns 0-100 (ie. pct chance)
|
|
// convert this to 0-20
|
|
attrib = getevasion(lf) / 5;
|
|
break;
|
|
case SC_LISTEN:
|
|
// if you are asleep, listen check doesn't help.
|
|
if (lfhasflag(lf, F_ASLEEP)) {
|
|
attrib = 0;
|
|
} else {
|
|
attrib = getskill(lf, SK_LISTEN);
|
|
}
|
|
break;
|
|
case SC_RESISTMAG:
|
|
attrib = (getattr(lf, A_CON)/4) + (getattr(lf, A_IQ)/4) + getmr(lf);
|
|
break;
|
|
case SC_SEARCH:
|
|
attrib = (getskill(lf, SK_SPOTHIDDEN)*4);
|
|
break;
|
|
case SC_STEALTH:
|
|
attrib = (getskill(lf, SK_STEALTH)*4);
|
|
break;
|
|
}
|
|
|
|
// level modifier
|
|
levmod = (lf->level / 3);
|
|
|
|
// other modifiers
|
|
if (ct == SC_SLIP) {
|
|
if (getequippedob(lf->pack, BP_FEET)) {
|
|
othermod += 5;
|
|
}
|
|
if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) {
|
|
othermod += 20;
|
|
}
|
|
} else if (ct == SC_FALL) {
|
|
if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) {
|
|
othermod += 10;
|
|
}
|
|
} else if (ct == SC_SHIELDBLOCK) {
|
|
switch (getskill(lf, SK_SHIELDS)) {
|
|
case PR_NOVICE: othermod = 4; break;
|
|
case PR_BEGINNER: othermod = 7; break;
|
|
case PR_ADEPT: othermod = 10; break;
|
|
case PR_SKILLED: othermod = 13; break;
|
|
case PR_EXPERT: othermod = 16; break;
|
|
case PR_MASTER: othermod = 20; break;
|
|
default:
|
|
othermod = 0;
|
|
break;
|
|
}
|
|
} else if (ct == SC_OPENLOCKS) {
|
|
enum SKILLLEVEL slev;
|
|
slev = getskill(lf, SK_LOCKPICKING);
|
|
if (slev == PR_INEPT) {
|
|
othermod -= 10;
|
|
} else {
|
|
othermod += (5 * slev);
|
|
}
|
|
} else if (ct == SC_POISON) {
|
|
// auto pass if we are immune
|
|
if (isimmuneto(lf->flags, DT_POISON)) {
|
|
othermod += (diff*2);
|
|
} else if (isresistantto(lf->flags, DT_POISON)) {
|
|
othermod += 5;
|
|
} else if (isvulnto(lf->flags, DT_POISON)) {
|
|
othermod -= 10;
|
|
}
|
|
} else if (ct == SC_SEARCH) {
|
|
int bonus = 0;
|
|
sumflags(lf->flags, F_ENHANCESEARCH, &bonus, NULL, NULL);
|
|
othermod += bonus;
|
|
} else if (ct == SC_STEALTH) {
|
|
if (attrib > 0) {
|
|
if (lfhasflag(lf, F_SNEAK)) {
|
|
othermod += 3;
|
|
}
|
|
}
|
|
if (isairborne(lf)) {
|
|
othermod += 5;
|
|
}
|
|
} else if (ct == SC_WILL) {
|
|
// level counts for more
|
|
levmod *= 2;
|
|
}
|
|
|
|
|
|
// luck
|
|
sumflags(lf->flags, F_EXTRALUCK, &luckmod, NULL, NULL);
|
|
othermod += luckmod;
|
|
|
|
roll = rolldie(1, 20);
|
|
|
|
if (db) {
|
|
sprintf(mbuf, "%s skillcheck - need %d, got %d(rll)+%d(attr)+%d(lvm)+%d(othmod)+%d(mod)=",lf->race->name, diff, roll, attrib,levmod, othermod,mod);
|
|
}
|
|
modroll = roll;
|
|
modroll += attrib;
|
|
modroll += mod;
|
|
modroll += levmod;
|
|
modroll += othermod;
|
|
if (db) {
|
|
msg("%s%d.",mbuf,modroll);
|
|
}
|
|
|
|
|
|
// natural 20 will pass some checks
|
|
if (roll == 20) {
|
|
if (db) {
|
|
msg("%s skillcheck passed with natural 20.", lf->race->name);
|
|
}
|
|
switch (ct) {
|
|
case SC_DODGE:
|
|
case SC_SEARCH:
|
|
case SC_STEALTH:
|
|
modroll = diff;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
*result = modroll;
|
|
}
|
|
|
|
if (modroll >= diff) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
// returns TRUE if lf1 succeeded, FALSE if lf1 failed.
|
|
int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, enum CHECKTYPE ct2, int mod2) {
|
|
int roll1,roll2;
|
|
int db = B_FALSE;
|
|
|
|
if (lfhasflag(lf1, F_DEBUG)) {
|
|
db = B_TRUE;
|
|
}
|
|
|
|
// bonus for knowledge about the other lf's race
|
|
if (getlorelevel(lf1, lf2->race->raceclass->id) >= PR_SKILLED) {
|
|
mod1 += 5;
|
|
}
|
|
if (getlorelevel(lf2, lf1->race->raceclass->id) >= PR_SKILLED) {
|
|
mod2 += 5;
|
|
}
|
|
|
|
|
|
real_skillcheck(lf1, ct1, 0, mod1, &roll1);
|
|
real_skillcheck(lf2, ct2, 0, mod2, &roll2);
|
|
if (db) {
|
|
char lfname1[BUFLEN];
|
|
char lfname2[BUFLEN];
|
|
getlfname(lf1, lfname1);
|
|
getlfname(lf2, lfname2);
|
|
msg("%s:%d %s %s:%d, %s.",
|
|
lfname1,roll1,
|
|
(roll1 > roll2) ? ">" : "<=",
|
|
lfname2,roll2,
|
|
(roll1 > roll2) ? "pass" : "fail"
|
|
);
|
|
}
|
|
|
|
if (roll1 > roll2) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
int slipon(lifeform_t *lf, object_t *o) {
|
|
char obname[BUFLEN];
|
|
char lfname[BUFLEN];
|
|
|
|
if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET) ||
|
|
lfhasflag(lf, F_NONCORPOREAL) || isairborne(lf)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
getlfname(lf,lfname);
|
|
getobname(o, obname, 1);
|
|
// slip!
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
char damstring[BUFLEN];
|
|
msg("%s slip%s on %s and fall%s to the ground.",lfname, isplayer(lf) ? "" : "s", obname,
|
|
isplayer(lf) ? "" : "s");
|
|
sprintf(damstring, "slipping on %s",obname);
|
|
losehp(lf, 1, DT_FALL, NULL, damstring);
|
|
}
|
|
|
|
fall(lf, NULL, B_FALSE);
|
|
|
|
// object gets damaged?
|
|
if (hasflag(o->flags, F_DAMAGABLE)) {
|
|
takedamage(o, 1, DT_DIRECT);
|
|
}
|
|
// object moves?
|
|
if (hasflag(o->flags, F_SLIPMOVE)) {
|
|
cell_t *cur, *new;
|
|
cur = getoblocation(o);
|
|
new = getrandomadjcell(cur, WE_WALKABLE, B_NOEXPAND);
|
|
if (new) {
|
|
if (haslos(player, cur) || haslos(player, new)) {
|
|
msg("%s slips across the floor.", obname);
|
|
}
|
|
moveob(o, new->obpile, 1);
|
|
}
|
|
}
|
|
loseconcentration(lf);
|
|
return B_FALSE;
|
|
}
|
|
|
|
void sortlf(map_t *map, lifeform_t *lf) {
|
|
if ((lf->next) && lf->timespent >= lf->next->timespent) {
|
|
lifeform_t *temp;
|
|
// remember next element
|
|
temp = lf->next;
|
|
|
|
// remove this element from list
|
|
// don't bother checking if (l->next == NULL) as we know
|
|
// this won't be true due to the for loop condition
|
|
if (lf->prev == NULL) {
|
|
// first
|
|
map->lf = lf->next;
|
|
lf->next->prev = NULL;
|
|
} else {
|
|
// not first
|
|
lf->prev->next = lf->next;
|
|
lf->next->prev = lf->prev;
|
|
}
|
|
|
|
// TESTING: re-add at correct position.
|
|
while (temp->next && (temp->next->timespent <= lf->timespent)) {
|
|
//dblog("moving past %d %s (timespend=%d)...",temp->next->id, temp->next->race->name, temp->next->timespent);
|
|
temp = temp->next;
|
|
}
|
|
|
|
// re-add element afterwards
|
|
lf->next = temp->next;
|
|
lf->prev = temp;
|
|
temp->next = lf;
|
|
if (lf->next == NULL) {
|
|
map->lastlf = lf;
|
|
} else {
|
|
lf->next->prev = lf;
|
|
}
|
|
} else if ((lf->prev) && (lf->timespent < lf->prev->timespent)) {
|
|
lifeform_t *temp;
|
|
// remember previous element
|
|
temp = lf->prev;
|
|
|
|
// remove this element from list
|
|
// don't bother checking if (l->prev == NULL) as we know
|
|
// this won't be true due to the for loop condition
|
|
if (lf->next == NULL) {
|
|
// last
|
|
map->lastlf = lf->prev;
|
|
lf->prev->next = NULL;
|
|
} else {
|
|
// not last
|
|
lf->prev->next = lf->next;
|
|
lf->next->prev = lf->prev;
|
|
}
|
|
|
|
// re-add at correct position.
|
|
while (temp->prev && (temp->prev->timespent > lf->timespent)) {
|
|
//dblog("moving past %d %s (timespend=%d)...",temp->next->id, temp->next->race->name, temp->next->timespent);
|
|
temp = temp->prev;
|
|
}
|
|
|
|
// re-add element before
|
|
lf->next = temp;
|
|
lf->prev = temp->prev;
|
|
temp->prev = lf;
|
|
if (lf->prev == NULL) {
|
|
map->lf = lf;
|
|
} else {
|
|
lf->prev->next = lf;
|
|
}
|
|
}
|
|
}
|
|
|
|
int stone(lifeform_t *lf) {
|
|
char lfname[BUFLEN];
|
|
char statname[BUFLEN];
|
|
int failed = B_FALSE;
|
|
|
|
if (!lfcanbestoned(lf)) {
|
|
failed = B_TRUE;
|
|
}
|
|
if (failed) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
getlfname(lf, lfname);
|
|
|
|
|
|
sprintf(statname, "statue of a %s", lf->race->name);
|
|
addob(lf->cell->obpile, statname);
|
|
|
|
// kill lifeform
|
|
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
|
|
addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
|
|
if (cansee(player, lf)) {
|
|
msg("%s %s to stone!", lfname, isplayer(lf) ? "turn" : "turns");
|
|
}
|
|
setlastdam(lf, "petrification");
|
|
die(lf);
|
|
return B_FALSE;
|
|
}
|
|
|
|
void stopeating(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = lfhasflag(lf, F_EATING);
|
|
if (f) {
|
|
if (isplayer(lf)){
|
|
msg("You stop eating.");
|
|
}
|
|
killflagsofid(lf->flags, F_EATING);
|
|
}
|
|
|
|
}
|
|
|
|
void stopresting(lifeform_t *lf) {
|
|
flag_t *f;
|
|
|
|
// stop training
|
|
f = hasflag(lf->flags, F_TRAINING);
|
|
if (f) {
|
|
killflag(f);
|
|
if (isplayer(lf)) {
|
|
msg("Your training is interrupted!");
|
|
} else if (cansee(player, lf)) {
|
|
char buf[BUFLEN];
|
|
getlfname(lf, buf);
|
|
capitalise(buf);
|
|
msg("%s stops training.",buf);
|
|
}
|
|
statdirty = B_TRUE;
|
|
}
|
|
// stop resting!
|
|
f = isresting(lf);
|
|
if (f) {
|
|
killflag(f);
|
|
if (isplayer(lf)) {
|
|
msg("Your rest is interrupted!");
|
|
} else if (cansee(player, lf)) {
|
|
char buf[BUFLEN];
|
|
getlfname(lf, buf);
|
|
msg("%s stops resting.",buf);
|
|
}
|
|
statdirty = B_TRUE;
|
|
}
|
|
}
|
|
|
|
void stoprunning(lifeform_t *lf) {
|
|
flag_t *f;
|
|
f = hasflag(lf->flags, F_RUNNING);
|
|
if (f) {
|
|
killflag(f);
|
|
}
|
|
f = lfhasflag(lf, F_SPRINTING);
|
|
if (f && f->val[0]) {
|
|
killflag(f);
|
|
}
|
|
|
|
}
|
|
|
|
// if this object is ammo, and we are using a gun
|
|
// with no ammo, then equip it.
|
|
int testammo(lifeform_t *lf, object_t *o) {
|
|
object_t *gun;
|
|
gun = getfirearm(lf);
|
|
if (gun) {
|
|
if (isammofor(o, gun)) {
|
|
object_t *curammo;
|
|
curammo = getammo(lf);
|
|
if (!curammo) {
|
|
setammo(lf, o);
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int takeoff(lifeform_t *lf, object_t *o) {
|
|
flag_t *f;
|
|
char obname[BUFLEN];
|
|
char buf[BUFLEN];
|
|
|
|
if (!isarmour(o)) {
|
|
return unweild(lf, o);
|
|
}
|
|
|
|
getobname(o, obname, 1);
|
|
|
|
if (!cantakeoff(lf, o)) {
|
|
switch (reason) {
|
|
case E_CURSED:
|
|
if (isplayer(lf)) {
|
|
msg("Your %s appears to be stuck to you!", noprefix(obname));
|
|
o->blessknown = B_TRUE;
|
|
}
|
|
// still take time
|
|
taketime(lf, getactspeed(lf));
|
|
break;
|
|
case E_NOTEQUIPPED:
|
|
if (isplayer(lf)) {
|
|
msg("You are not wearing that!");
|
|
}
|
|
break;
|
|
default:
|
|
if (isplayer(lf)) {
|
|
msg("For some reason, you cannot remove your %s!", noprefix(obname));
|
|
}
|
|
// still take time
|
|
taketime(lf, getactspeed(lf));
|
|
break;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// remove the equipped flag
|
|
f = hasflag(o->flags, F_EQUIPPED);
|
|
killflag(f);
|
|
|
|
taketime(lf, getactspeed(lf));
|
|
if ((gamemode == GM_GAMESTARTED)) {
|
|
if (isplayer(lf)) {
|
|
msg("You take off %s.", obname);
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
capitalise(buf);
|
|
msg("%s takes off %s.", buf, obname);
|
|
}
|
|
|
|
}
|
|
|
|
// lose flags
|
|
loseobflags(lf, o, F_EQUIPCONFER);
|
|
|
|
if (obproduceslight(o)) {
|
|
calclight((getoblocation(o))->map);
|
|
precalclos(lf);
|
|
drawscreen();
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void taketime(lifeform_t *lf, long howlong) {
|
|
int db = B_FALSE;
|
|
map_t *map;
|
|
|
|
|
|
if (lfhasflag(lf, F_NOTIME)) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
*/
|
|
|
|
map = lf->cell->map;
|
|
|
|
assert(howlong > 0);
|
|
|
|
if (db && (gamemode == GM_GAMESTARTED) && cansee(player, lf)) {
|
|
dblog("lfid %d (%s) spending %d time\n",lf->id,lf->race->name, howlong);
|
|
}
|
|
// inc timespent
|
|
lf->timespent += howlong;
|
|
assert(lf->timespent >= 0);
|
|
|
|
// time-based effects on lifeforms (eg hp regeneration) go here...
|
|
|
|
// TODO: decrement lifeform's (or their object's) temporary flags
|
|
|
|
|
|
// if you don't have a map, start forgetting the dungeon
|
|
if (isplayer(lf)) {
|
|
if (!lfhasflag(lf, F_PHOTOMEM) && (getskill(lf, SK_CARTOGRAPHY) < PR_SKILLED)) {
|
|
lf->forgettimer += ((float)howlong / 500.0);
|
|
if (lf->forgettimer > 1) {
|
|
int amt;
|
|
|
|
// TODO: modify using race memory
|
|
amt = (int)floor(lf->forgettimer);
|
|
forgetcells(lf->cell->map, amt);
|
|
lf->forgettimer -= amt;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now move player up in linked list...
|
|
sortlf(map, lf);
|
|
}
|
|
|
|
int throwat(lifeform_t *thrower, object_t *o, cell_t *where) {
|
|
if (!hasbp(thrower, BP_HANDS)) {
|
|
if (isplayer(thrower)) msg("You have no hands to throw with!");
|
|
return B_TRUE;
|
|
}
|
|
taketime(thrower, getactspeed(thrower));
|
|
return fireat(thrower, o, 1, where, getthrowspeed(getattr(thrower, A_STR)), NULL);
|
|
}
|
|
|
|
// lf effects which happen every xx ticks
|
|
// IMPORTANT - don't call taketime() during this function.
|
|
void timeeffectslf(lifeform_t *lf) {
|
|
object_t *o, *nexto;
|
|
flag_t *f,*nextf;
|
|
|
|
// decrement flags
|
|
timeeffectsflags(lf->flags);
|
|
|
|
// remove effects from expired poison
|
|
for (f = lf->flags->first ; f; f = nextf) {
|
|
nextf = f->next;
|
|
if (f->lifetime == FROMPOISON) {
|
|
if (!lfhasflagval(lf, F_POISONED, f->obfrom, NA, NA, NULL)) {
|
|
killflag(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
f = lfhasflag(lf, F_INTERRUPTED);
|
|
if (f) {
|
|
interrupt(lf);
|
|
killflag(f);
|
|
}
|
|
|
|
if (isdead(lf)) {
|
|
return;
|
|
}
|
|
|
|
// revert to original form if a polymorph just expired
|
|
if (lf->polyrevert) {
|
|
enum RACE rid = R_NONE;
|
|
race_t *r;
|
|
flag_t *ff;
|
|
// change back
|
|
ff = lfhasflag(lf, F_ORIGRACE);
|
|
if (ff) {
|
|
rid = ff->val[0];
|
|
} else {
|
|
rid = R_NONE; // should never happen!
|
|
}
|
|
r = findrace(rid);
|
|
if (r) {
|
|
setrace(lf, r->id, B_TRUE);
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
msg("For some reason, you are unable to revert to your original form!");
|
|
}
|
|
}
|
|
lf->polyrevert = B_FALSE;
|
|
}
|
|
|
|
|
|
// time effects on lifeform's objects
|
|
for (o = lf->pack->first ; o ; o = nexto) {
|
|
nexto = o->next;
|
|
|
|
if ((o->type->id == OT_ENERGYBLADE) && !hasactivespell(lf, OT_S_SUMMONWEAPON)) {
|
|
killob(o);
|
|
continue;
|
|
}
|
|
timeeffectsob(o);
|
|
}
|
|
|
|
}
|
|
|
|
//////////////////////////////////
|
|
// effects which happen before every TURN
|
|
// (ie. the faster the player is, the faster they happen)
|
|
// eg. damage from walking on things
|
|
//////////////////////////////////
|
|
void turneffectslf(lifeform_t *lf) {
|
|
int db = B_FALSE;
|
|
map_t *map;
|
|
enum ERROR error;
|
|
object_t *o;
|
|
flag_t *f, *nextf;
|
|
flag_t *asp;
|
|
char buf[BUFLEN];
|
|
lifeform_t *l;
|
|
int i;
|
|
int willvanish = B_FALSE;
|
|
|
|
map = lf->cell->map;
|
|
|
|
if (db) dblog("starting turneffectslf for lf id %d %s", lf->id, lf->race->name);
|
|
|
|
if (isplayer(lf) && isdrunk(lf)) statdirty = B_TRUE;
|
|
|
|
// clear one-turn-only flags
|
|
killflagsofid(lf->flags, F_DONELISTEN);
|
|
killflagsofid(lf->flags, F_NOSWAP);
|
|
|
|
// update where player knows
|
|
// (but without a map you will then slowly forget it)
|
|
if (isplayer(lf)) {
|
|
updateknowncells();
|
|
} else {
|
|
// ai start of turn code
|
|
killflagsofid(lf->flags, F_IGNORECELL);
|
|
}
|
|
|
|
// stuck inside solid cells?
|
|
if (!cellwalkable(lf, lf->cell, &error)) {
|
|
if (error == E_WALLINWAY) {
|
|
if (isplayer(lf)) {
|
|
msg("You reintegrate inside a solid object!");
|
|
}
|
|
losehp(lf, 9999, DT_DIRECT, NULL, "re-integration inside a solid object");
|
|
//}
|
|
}
|
|
}
|
|
// drown?
|
|
o = hasobwithflag(lf->cell->obpile, F_DEEPWATER);
|
|
if (o) {
|
|
if (checkfordrowning(lf, o)) {
|
|
if (isdead(lf)) return;
|
|
}
|
|
}
|
|
// suffocate?
|
|
if (lfhasflag(lf, F_NEEDSWATER) && !hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
|
|
if (isplayer(lf)) {
|
|
msg("You are suffocating without water to breath!");
|
|
} else if (cansee(player, lf)) {
|
|
int dam;
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s is suffocating!", lfname);
|
|
dam = lf->maxhp / 3;
|
|
limit(&dam, 1, NA);
|
|
losehp(lf, dam, DT_DIRECT, NULL, "suffocation");
|
|
if (isdead(lf)) return;
|
|
}
|
|
}
|
|
|
|
// get more hungry
|
|
modhunger(lf, 1);
|
|
|
|
// regeneration
|
|
sumflags(lf->flags, F_REGENERATES, &i, NULL, NULL);
|
|
if (i > 0) {
|
|
// heal hp
|
|
gainhp(lf, i);
|
|
}
|
|
|
|
// MP regeneration
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_MPREGEN) {
|
|
gainmp(lf, f->val[0]);
|
|
}
|
|
}
|
|
|
|
|
|
if (hasactivespell(lf, OT_S_SUMMONWEAPON)) {
|
|
if (!hasob(lf->pack, OT_ENERGYBLADE)) {
|
|
stopspell(lf, OT_S_SUMMONWEAPON);
|
|
}
|
|
}
|
|
|
|
if (lfhasflag(lf, F_MAGSHIELD)) {
|
|
object_t *nexto;
|
|
// metal weapons?
|
|
for (o = lf->pack->first ; o ; o = nexto) {
|
|
nexto = o->next;
|
|
if (ismetal(o->material->id)) {
|
|
f = isequipped(o);
|
|
if (f && ((f->val[0] == BP_WEAPON) || (f->val[0] == BP_SECWEAPON))) {
|
|
cell_t *c;
|
|
// weapon flies away
|
|
c = getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND);
|
|
if (!c) c = lf->cell;
|
|
moveob(o, c->obpile, o->amt);
|
|
if (isplayer(lf)) {
|
|
getobname(o, buf, o->amt);
|
|
msg("Your %s flies out of your hands!",noprefix(buf), (o->amt == 1) ? "flies" : "fly");
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getobname(o, buf, o->amt);
|
|
getlfname(lf, lfname);
|
|
msg("%s%s %s flies out of its hands!",lfname, getpossessive(lfname),
|
|
noprefix(buf), (o->amt == 1) ? "flies" : "fly");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// objects on the ground?
|
|
for (o = lf->cell->obpile->first ; o ; o = nexto) {
|
|
nexto = o->next;
|
|
if (ismetal(o->material->id)) {
|
|
cell_t *c;
|
|
// object flies away
|
|
c = getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND);
|
|
if (!c) c = lf->cell;
|
|
moveob(o, c->obpile, o->amt);
|
|
if (isplayer(lf)) {
|
|
getobname(o, buf, o->amt);
|
|
msg("%s is repelled away from you!",buf);
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getobname(o, buf, o->amt);
|
|
getlfname(lf, lfname);
|
|
msg("%s is repelled away from %s!",buf, lfname);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// special effects
|
|
f = lfhasflag(lf, F_AUTOCREATEOB);
|
|
if (f) {
|
|
int radius;
|
|
radius = f->val[0];
|
|
addobsinradius(lf->cell, f->val[0], DT_COMPASS, f->text, B_FALSE);
|
|
}
|
|
|
|
// handle ghosts
|
|
if (lf->race->id == R_GHOST) {
|
|
f = lfhasflag(lf, F_MYCORPSE);
|
|
if (f) {
|
|
long corpseid;
|
|
cell_t *corpseloc = NULL;
|
|
object_t *corpse;
|
|
|
|
corpseid = atol(f->text);
|
|
|
|
corpse = findobidinmap(lf->cell->map, corpseid);
|
|
if (corpse) {
|
|
corpseloc = corpse->pile->where;
|
|
}
|
|
// can we see our corpse?
|
|
if (corpseloc && haslos(lf, corpseloc)) {
|
|
// give possession ability
|
|
if (!lfhasflagval(lf, F_CANWILL, OT_S_POSSESSION, NA, NA, NULL)) {
|
|
char pwbuf[BUFLEN];
|
|
int power;
|
|
power = lf->level / 3;
|
|
if (power < 1) power = 1;
|
|
if (power > 10) power = 10;
|
|
sprintf(pwbuf, "pw:%d;",power);
|
|
f = addflag(lf->flags, F_CANWILL, OT_S_POSSESSION, NA, NA, pwbuf);
|
|
f->lifetime = FROMRACE;
|
|
}
|
|
} else {
|
|
// can't see corpse
|
|
f = lfhasflagval(lf, F_CANWILL, OT_S_POSSESSION, NA, NA, NULL);
|
|
if (f) killflag(f);
|
|
// drain life
|
|
if (isplayer(lf)) msg("Without your corpse, you feel yourself fading into nothingness.");
|
|
losehp(lf, 2, DT_DIRECT, NULL, "fading into nothingness");
|
|
}
|
|
}
|
|
}
|
|
|
|
//effects from other lifeforms
|
|
for (l = lf->cell->map->lf ; l ; l = l->next) {
|
|
if (!isdead(l) && (l != lf)) {
|
|
if (l->race->baseid != lf->race->baseid) { // can't smell your own race.
|
|
// gains/loses stench?
|
|
f = lfhasflag(l, F_STENCH);
|
|
if (f) {
|
|
int range,power;
|
|
range = f->val[0];
|
|
power = f->val[1];
|
|
if (getcelldist(l->cell, lf->cell) <= range) {
|
|
// you get nauseated
|
|
makenauseated(lf, power, 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
asp = hasactivespell(l, OT_S_CALMINGSCENT);
|
|
if (asp && (getcelldist(l->cell,lf->cell) == 1)) {
|
|
if ((getraceclass(lf) == RC_ANIMAL) && lfhasflag(lf, F_HOSTILE)) {
|
|
int maxhitdice;
|
|
// calming strong enough?
|
|
maxhitdice = asp->val[2] + 1;
|
|
if (gethitdice(lf) <= maxhitdice) {
|
|
makepeaceful(lf);
|
|
}
|
|
}
|
|
}
|
|
|
|
// they are hiding, and you haven't spotted them yet
|
|
f = lfhasflag(l, F_HIDING);
|
|
if (f && !lfhasflagval(lf, F_SPOTTED, l->id, NA, NA, NULL) && !isinbattle(lf)) {
|
|
// can you see their cell?
|
|
if (haslos(lf, l->cell)) {
|
|
int bonus = 0;
|
|
int dist;
|
|
if (!lfhasflag(l, F_SILENTMOVE) && !lfhasflag(lf, F_DEAF)) {
|
|
bonus += getskill(lf, SK_LISTEN);
|
|
}
|
|
|
|
|
|
dist = getcelldist(lf->cell, l->cell);
|
|
if (dist > 1) {
|
|
bonus -= (dist*2);
|
|
}
|
|
|
|
// did you spot them?
|
|
if (skillcheckvs(lf, SC_SEARCH, bonus, l, SC_STEALTH, f->val[0])) {
|
|
addflag(lf->flags, F_SPOTTED, l->id, NA, NA, NULL);
|
|
// announce
|
|
if (isplayer(lf)) {
|
|
char lname[BUFLEN];
|
|
getlfname(l, lname);
|
|
msg("You spot %s!", lname);
|
|
} else if (isplayer(l) && cansee(l, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("You think %s has spotted you!", lfname);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// secret doors, traps, etc?
|
|
if (isplayer(lf) && !isinbattle(lf) && !isblind(lf)) {
|
|
for (i = 0; i < lf->nlos; i++) {
|
|
if (!lf->los[i]->lf) {
|
|
object_t *o;
|
|
o = hasobwithflag(lf->los[i]->obpile, F_SECRET);
|
|
if (o) {
|
|
flag_t *f;
|
|
int mod = 0;
|
|
|
|
f = hasflag(o->flags, F_SECRET);
|
|
if (f && (f->val[0] != NA)) {
|
|
if (hasflag(o->flags, F_TRAP)) {
|
|
mod += getskill(lf, SK_TRAPS);
|
|
}
|
|
|
|
if (skillcheck(lf, SC_SEARCH, f->val[0], mod)) {
|
|
char obname[BUFLEN];
|
|
// reveal it
|
|
getobname(o, obname, o->amt);
|
|
msg("You notice %s!",obname);
|
|
killflag(f);
|
|
needredraw = B_TRUE;
|
|
drawscreen();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// summoned creatures
|
|
f = hasflag(lf->flags, F_SUMMONEDBY);
|
|
if (f) {
|
|
lifeform_t *creator;
|
|
creator = findlf(NULL, f->val[0]);
|
|
if (!creator) {
|
|
willvanish = B_TRUE;
|
|
} else {
|
|
if (f->val[1] > 0) {
|
|
f->val[1]--;
|
|
if (f->val[1] <= 0) {
|
|
willvanish = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (willvanish) {
|
|
if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s%s vanishes.",
|
|
(creator == player) ? "Your " : "",
|
|
(creator == player) ? noprefix(lfname) : lfname
|
|
);
|
|
}
|
|
|
|
// all objects vanish
|
|
while (lf->pack->first) {
|
|
killob(lf->pack->first);
|
|
}
|
|
|
|
// lf dies.
|
|
lf->hp = 0;
|
|
addflag(lf->flags, F_DEAD, B_TRUE, NA, NA, NULL);
|
|
addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL);
|
|
addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL);
|
|
|
|
// puff
|
|
addob(lf->cell->obpile, "puff of smoke");
|
|
}
|
|
}
|
|
if (isdead(lf)) return;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// IMPORTANT: any potentially damaging effects have to go after here...
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
f = hasflag(lf->flags, F_POISONED);
|
|
if (f) {
|
|
// chance of fighting it off - gets easier over time.
|
|
//
|
|
if (skillcheck(lf, SC_POISON, (f->lifetime * 9), 0 )) {
|
|
killflag(f);
|
|
} else {
|
|
// chance of losing hp
|
|
if (rnd(1,100) <= getpoisondamchance(f->val[0])) {
|
|
char buf[BUFLEN];
|
|
if (!hasflag(lf->flags, F_ASLEEP)) {
|
|
if (isplayer(lf)) {
|
|
msg("You %s violently.", getpoisondamverb(f->val[0]));
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s %ss violently.", lfname, getpoisondamverb(f->val[0]));
|
|
}
|
|
taketime(lf, getactspeed(lf));
|
|
}
|
|
|
|
sprintf(buf, "poisoning^from %s",f->text);
|
|
losehp(lf, f->val[1], DT_DIRECT, NULL, buf);
|
|
|
|
if (!hasflag(lf->flags, F_ASLEEP)) {
|
|
if (poisoncausesvomit(f->val[0])) {
|
|
addob(lf->cell->obpile, "pool of vomit");
|
|
}
|
|
}
|
|
|
|
loseconcentration(lf);
|
|
}
|
|
|
|
// extra effects
|
|
if (f->val[0] == P_COLD) {
|
|
if (rnd(1,100) <= 10) {
|
|
object_t *wep;
|
|
if (isplayer(lf)) {
|
|
msg("You shiver uncontrollably.");
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s shivers.", lfname);
|
|
}
|
|
wep = getweapon(lf);
|
|
if (wep) {
|
|
char wname[BUFLEN];
|
|
getobname(wep, wname, 1);
|
|
drop(wep, wep->amt);
|
|
}
|
|
|
|
loseconcentration(lf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
f = hasflag(lf->flags, F_NAUSEATED);
|
|
if (f) {
|
|
// chance of being delayed
|
|
if (onein(4)) {
|
|
if (isplayer(lf)) {
|
|
msg("You %s!", rnd(0,1) ? "retch" : "gag");
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s %s.", lfname, rnd(0,1) ? "retches" : "gags");
|
|
}
|
|
taketime(lf,getactspeed(lf));
|
|
|
|
loseconcentration(lf);
|
|
}
|
|
}
|
|
|
|
if (lfhasflag(lf, F_FROZEN)) {
|
|
// melt...
|
|
if (rnd(1,2)) {
|
|
losehp(lf, 1, DT_MELT, NULL, "melting");
|
|
addob(lf->cell->obpile, "small puddle of water");
|
|
if (isplayer(lf)) {
|
|
msg("You are melting!");
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s melts a little.",lfname);
|
|
}
|
|
}
|
|
}
|
|
if (isdead(lf)) return;
|
|
|
|
// damage from cell objects?
|
|
for (o = lf->cell->obpile->first ; o ; o = o->next) {
|
|
f = hasflag(o->flags, F_WALKDAM);
|
|
if (f) {
|
|
applywalkdam(lf, roll(f->text), f->val[0], o);
|
|
}
|
|
|
|
f = hasflag(o->flags, F_CAUSESCOUGH);
|
|
if (f && !isimmuneto(lf->flags, DT_POISONGAS)) {
|
|
char obname[BUFLEN];
|
|
getobname(o, obname, o->amt);
|
|
if (!skillcheck(lf, SC_CON, f->val[0] * o->amt, 0)) {
|
|
if (isplayer(lf)) {
|
|
msg("You cough on %s.", obname);
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s coughs on %s.",lfname, obname);
|
|
}
|
|
taketime(lf, 5);
|
|
loseconcentration(lf);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// for flags which can occur multiple times
|
|
for (f = o->flags->first ; f ; f = f->next) {
|
|
if ((f->id == F_DEEPWATER) && !isairborne(lf)) {
|
|
checkfordrowning(lf, o);
|
|
if (isdead(lf)) return;
|
|
} else if (f->id == F_WALKDAMBP) {
|
|
if (!isairborne(lf)) {
|
|
object_t *armour;
|
|
int dam;
|
|
enum BODYPART bp;
|
|
enum DAMTYPE damtype;
|
|
|
|
bp = f->val[0];
|
|
damtype = f->val[1];
|
|
dam = roll(f->text);
|
|
|
|
getobname(o, buf, o->amt);
|
|
|
|
// some things get your armour too!
|
|
armour = getouterequippedob(lf, bp);
|
|
if (armour) {
|
|
takedamage(armour, dam, damtype);
|
|
} else {
|
|
if (f->val[2] == FALLTHRU) {
|
|
// certain combinations might give announcements...
|
|
switch (damtype) {
|
|
case DT_WATER:
|
|
if ((bp == BP_FEET) && isplayer(lf) && hasbp(lf, bp)) {
|
|
msg("Your %s get wet.", getbodypartname(bp));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// apply damage to lf instead.
|
|
applywalkdam(lf, roll(f->text), f->val[1], o);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // end foreach object flag
|
|
}
|
|
if (isdead(lf)) return;
|
|
|
|
|
|
for (f = lf->flags->first ; f ; f = nextf) {
|
|
nextf = f->next;
|
|
// remove impossible flags
|
|
if ((f->id == F_BOOSTSPELL) && (f->val[0] == OT_S_PASSWALL)) {
|
|
if (!lfhasflag(lf, F_NONCORPOREAL)) {
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (f->id == F_ATTACHEDTO) {
|
|
lifeform_t *lf2;
|
|
lf2 = findlf(NULL, f->val[0]);
|
|
if (!lf2) {
|
|
killflag(f);
|
|
continue;
|
|
} else if (getcelldist(lf2->cell, lf->cell) != 1) {
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
}
|
|
if (f->id == F_GRABBEDBY) {
|
|
lifeform_t *lf2;
|
|
lf2 = findlf(NULL, f->val[0]);
|
|
if (!lf2) {
|
|
killflag(f);
|
|
continue;
|
|
} else if (getcelldist(lf2->cell, lf->cell) != 1) {
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
}
|
|
if (f->id == F_GRABBING) {
|
|
lifeform_t *lf2;
|
|
lf2 = findlf(NULL, f->val[0]);
|
|
if (!lf2) {
|
|
killflag(f);
|
|
continue;
|
|
} else if (getcelldist(lf2->cell, lf->cell) != 1) {
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
}
|
|
if (f->id == F_STABBEDBY) {
|
|
lifeform_t *lf2;
|
|
lf2 = findlf(NULL, f->val[0]);
|
|
// stabber can't see you anymore
|
|
if (!lf2 || !cansee(lf2, lf)) {
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
}
|
|
if (f->id == F_SPOTTED) {
|
|
lifeform_t *lf2;
|
|
lf2 = findlf(NULL, f->val[0]);
|
|
|
|
if (!lf || !cansee(lf, lf2) || !lfhasflag(lf2, F_HIDING)) {
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ((f->id == F_CHARMEDBY) ||
|
|
(f->id == F_PETOF) ||
|
|
(f->id == F_FLEEFROM) ||
|
|
(f->id == F_NOFLEEFROM)) {
|
|
lifeform_t *lf2;
|
|
lf2 = findlf(NULL, f->val[0]);
|
|
if (!lf2) {
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// recharge abilities
|
|
if (f->id == F_CANWILL) {
|
|
if (f->val[2] != NA) {
|
|
if (f->val[1] < f->val[2]) {
|
|
f->val[1]++;
|
|
}
|
|
}
|
|
}
|
|
// remove invalid targets
|
|
if ((f->id == F_TARGETLF) || (f->id == F_TARGETCELL)) {
|
|
lifeform_t *targ = NULL;
|
|
if (f->id == F_TARGETLF) {
|
|
targ = findlf(lf->cell->map, f->val[0]);
|
|
} else if (f->id == F_TARGETCELL) {
|
|
cell_t *c;
|
|
c = getcellat(lf->cell->map, f->val[0], f->val[1]);
|
|
if (c && c->lf) {
|
|
targ = c->lf;
|
|
}
|
|
}
|
|
if (targ && areallies(lf, targ)) {
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
char lfname[BUFLEN];
|
|
char targname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
getlfname(targ, targname);
|
|
msg("db: %s no longer targetting %s.",lfname,targname);
|
|
}
|
|
killflag(f);
|
|
continue;
|
|
}
|
|
} // end if f_target or f_targetcell
|
|
} // end loop through lf flags
|
|
|
|
}
|
|
|
|
// returns B_TRUE if the action which involved touching this should fail
|
|
int touch(lifeform_t *lf, object_t *o) {
|
|
flag_t *f;
|
|
char buf[BUFLEN];
|
|
char obname[BUFLEN];
|
|
char lfname[BUFLEN];
|
|
|
|
if ((gamemode != GM_GAMESTARTED)) return B_FALSE;
|
|
|
|
getlfname(lf, lfname);
|
|
getobname(o, obname, o->amt);
|
|
|
|
// freezing touch?
|
|
f = hasflag(lf->flags, F_FREEZINGTOUCH);
|
|
if (f) {
|
|
// not wearing gloves?
|
|
if (!getequippedob(lf->pack, BP_HANDS)) {
|
|
// default power of 4
|
|
dospelleffects(lf, OT_S_FREEZEOB, 4, NULL, o, NULL, B_UNCURSED, NULL);
|
|
|
|
// we use val[0] here rather than timeleft, because we don't
|
|
// want to decrement it each turn.
|
|
f->val[0]--;
|
|
if (f->val[0] <= 0) {
|
|
if (isplayer(lf)) {
|
|
msg("Your hands stop glowing blue.");
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s's hands stop glowing blue.");
|
|
}
|
|
killflag(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
// undead and blesed objects?
|
|
if (isundead(lf) && isblessed(o)) {
|
|
object_t *gloves;
|
|
// not wearing gloves?
|
|
gloves = getequippedob(lf->pack, BP_HANDS);
|
|
if (!gloves) {
|
|
if (isplayer(lf)) {
|
|
msg("The %s burn%s you as you touch %s!",noprefix(obname),
|
|
(o->amt == 1) ? "s" : "",
|
|
(o->amt == 1) ? "it" : "them" );
|
|
o->blessknown = B_TRUE;
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s touches %s then recoils in pain!",lfname, obname);
|
|
o->blessknown = B_TRUE;
|
|
}
|
|
// use real name here...
|
|
real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_FALSE, B_TRUE, B_FALSE);
|
|
sprintf(buf, "touching %s",obname);
|
|
losehp(lf, 2, DT_HOLY, NULL, buf);
|
|
// drop the object if we're holding it
|
|
if (o->pile->owner == lf) {
|
|
drop(o, ALL);
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
f = hasflag(o->flags, F_SHARP);
|
|
if (f) {
|
|
object_t *gloves;
|
|
gloves = getequippedob(lf->pack, BP_HANDS);
|
|
if (!gloves) {
|
|
if (isplayer(lf)) {
|
|
msg("Ow! You cut your finger on %s.", obname);
|
|
}
|
|
|
|
sprintf(buf, "touching %s", obname);
|
|
losehp(lf, rnd(1,2), DT_SLASH, NULL, buf);
|
|
}
|
|
}
|
|
|
|
// flaming objects?
|
|
if (hasflag(o->flags, F_ONFIRE)) {
|
|
// flaming weapons are ok
|
|
if (!isweapon(o)) {
|
|
object_t *gloves;
|
|
// wearing gloves? they get damaged.
|
|
gloves = getequippedob(lf->pack, BP_HANDS);
|
|
if (gloves) {
|
|
takedamage(gloves, 2, DT_FIRE);
|
|
} else {
|
|
// otherwise YOU get damaged.
|
|
if (isplayer(lf)) {
|
|
msg("Ow! You burn your hands on %s.",obname);
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s burns itself on %s.",lfname, obname);
|
|
}
|
|
sprintf(buf, "touching %s",obname);
|
|
losehp(lf, 2, DT_FIRE, NULL, buf);
|
|
return B_TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int unweild(lifeform_t *lf, object_t *o) {
|
|
flag_t *f;
|
|
char obname[BUFLEN];
|
|
char buf[BUFLEN];
|
|
|
|
getobname(o, obname, 1);
|
|
|
|
if (!cantakeoff(lf, o)) {
|
|
switch (reason) {
|
|
case E_CURSED:
|
|
if (isplayer(lf)) {
|
|
msg("Your %s appears to be stuck to your hand!", noprefix(obname));
|
|
if (!o->blessknown) {
|
|
o->blessknown = B_TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case E_NOTEQUIPPED:
|
|
if (isplayer(lf)) {
|
|
msg("You are not weilding that!");
|
|
}
|
|
break;
|
|
default:
|
|
if (isplayer(lf)) {
|
|
msg("For some reason, you cannot stop weilding your %s!", noprefix(obname));
|
|
}
|
|
break;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// remove the equipped flag
|
|
f = hasflag(o->flags, F_EQUIPPED);
|
|
killflagsofid(o->flags, F_EQUIPPED);
|
|
|
|
// unweilding doesn't take any time
|
|
if (gamemode == GM_GAMESTARTED) {
|
|
if (isplayer(lf)) {
|
|
msg("You are no longer weilding %s.", obname);
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
capitalise(buf);
|
|
msg("%s stops weilding %s.", buf, obname);
|
|
}
|
|
}
|
|
|
|
// lose flags
|
|
loseobflags(lf, o, F_EQUIPCONFER);
|
|
|
|
if (obproduceslight(o)) {
|
|
calclight((getoblocation(o))->map);
|
|
precalclos(lf);
|
|
drawscreen();
|
|
}
|
|
|
|
if (o->type->id == OT_ENERGYBLADE) {
|
|
stopspell(lf, OT_S_SUMMONWEAPON);
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where) {
|
|
int rv;
|
|
flag_t *cwflag;
|
|
if (!cancast(lf, aid, NULL)) {
|
|
if (isplayer(lf)) {
|
|
// announce
|
|
switch (reason) {
|
|
case E_NEEDGRAB:
|
|
msg("You need to hold someone before using this ability.");
|
|
break;
|
|
case E_NOTREADY:
|
|
msg("This ability is not recharged yet.");
|
|
break;
|
|
default:
|
|
msg("For some reason, you can't use this ability.");
|
|
break;
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// taketime() will happen during abiltiyeffects()
|
|
// use the ability
|
|
|
|
cwflag = lfhasflagval(lf, F_CANWILL, aid, NA, NA, NULL);
|
|
rv = abilityeffects(lf, aid, where, who, cwflag);
|
|
return rv;
|
|
}
|
|
|
|
|
|
int usestairs(lifeform_t *lf, object_t *o) {
|
|
flag_t *f;
|
|
map_t *curmap;
|
|
map_t *newmap;
|
|
cell_t *newcell;
|
|
int dir;
|
|
int newdepth;
|
|
char lfname[BUFLEN];
|
|
char obname[BUFLEN];
|
|
int isportal = B_FALSE;
|
|
lifeform_t *adjally[8];
|
|
int nadjallies = 0;
|
|
|
|
// need up update 'dlev:'
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
getlfname(lf, lfname);
|
|
getobname(o, obname, 1);
|
|
|
|
if (initiatemove(lf, NULL, NULL)) {
|
|
// failed?
|
|
return B_FALSE;
|
|
}
|
|
|
|
curmap = lf->cell->map;
|
|
|
|
f = hasflag(o->flags, F_CLIMBABLE);
|
|
assert(f);
|
|
dir = f->val[0];
|
|
|
|
// depth of new level?
|
|
if (dir == D_UP) {
|
|
newdepth = curmap->depth - 1;
|
|
isportal = B_FALSE;
|
|
} else if (dir == D_DOWN) {
|
|
newdepth = curmap->depth + 1;
|
|
isportal = B_FALSE;
|
|
} else {
|
|
// portal!
|
|
isportal = B_TRUE;
|
|
}
|
|
|
|
// check...
|
|
if (dir == D_DOWN) {
|
|
if (lfhasflag(lf, F_LEVITATING)) {
|
|
if (isplayer(lf)) {
|
|
msg("You can't reach the ground from up here!");
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
// announce
|
|
curs_set(1);
|
|
if (isportal) {
|
|
if (isplayer(lf)) {
|
|
msg("You enter %s...", obname);
|
|
// move cursor to msgwindow while we create the new level...
|
|
wrefresh(msgwin);
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s enters %s...", lfname, obname);
|
|
}
|
|
} else {
|
|
if (isplayer(lf)) {
|
|
msg("You %s %s the staircase...", getmoveverb(lf), getdirname(dir));
|
|
// move cursor to msgwindow while we create the new level...
|
|
wrefresh(msgwin);
|
|
} else if (cansee(player, lf)) {
|
|
msg("%s %s %s the staircase...", lfname, getmoveverbother(lf), getdirname(dir));
|
|
}
|
|
}
|
|
|
|
// find adjacent allies or enemies which will follow you
|
|
if (isplayer(lf)) {
|
|
getadjallies(lf, adjally, &nadjallies);
|
|
}
|
|
|
|
// do stairs go somewhere?
|
|
newcell = getstairdestination(o);
|
|
if (!newcell) {
|
|
if (isportal) {
|
|
// unconnected portal
|
|
if (isplayer(lf)) msg("This portal doesn't seem to go anywhere.");
|
|
} else {
|
|
// is there already a level of the correct depth?
|
|
newmap = findregionmap(lf->cell->map->region, newdepth);
|
|
if (newmap) {
|
|
dblog("ERROR - unlinked stairs!\n");
|
|
msg("ERROR - unlinked stairs!\n");
|
|
} else {
|
|
enum HABITAT newhabitat;
|
|
int newregion;
|
|
// generate a new map! this will fill in the destination of our stairs
|
|
newmap = addmap();
|
|
if (newdepth == 0) {
|
|
newregion = RG_WORLDMAP;
|
|
newhabitat = AUTO;
|
|
} else {
|
|
newregion = lf->cell->map->region;
|
|
newhabitat = AUTO;
|
|
}
|
|
createmap(newmap, newdepth, newregion, newhabitat, curmap, dir);
|
|
// link our stairs to the new map.
|
|
//linkstairs(o);
|
|
|
|
// NOW our stairs should have a destination
|
|
newcell = getstairdestination(o);
|
|
}
|
|
}
|
|
}
|
|
|
|
curs_set(0);
|
|
if (newcell) {
|
|
int n;
|
|
// check noone is in the way
|
|
if (newcell->lf) {
|
|
cell_t *c;
|
|
// if they are, move them
|
|
c = getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND);
|
|
if (c) {
|
|
// move them there
|
|
movelf(newcell->lf, c);
|
|
} else {
|
|
// TODO: handle this differently - ie always allow the player
|
|
// go there?
|
|
if (isplayer(lf)) msg("The stairs seem to be blocked.");
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
// announce
|
|
if (isplayer(lf)) {
|
|
announcearrival(lf, newcell->map);
|
|
f = hasflag(o->flags, F_MAPLINK);
|
|
if (f) f->known = B_KNOWN;
|
|
}
|
|
// move player to new map
|
|
moveto(lf, newcell, B_TRUE, B_TRUE);
|
|
if ((dir == D_UP) && !isairborne(lf)) {
|
|
taketime(lf, getmovespeed(lf)*2); // takes longer to climb
|
|
} else {
|
|
taketime(lf, getmovespeed(lf));
|
|
}
|
|
|
|
// move adjacent allies/monsters too
|
|
for (n = 0; n < nadjallies; n++) {
|
|
cell_t *c;
|
|
c = getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND);
|
|
if (c) {
|
|
if (!initiatemove(adjally[n], NULL, NULL)) {
|
|
movelf(adjally[n], c);
|
|
if ((dir == D_UP) && !isairborne(adjally[n])) {
|
|
taketime(adjally[n], getmovespeed(adjally[n])*2); // takes longer to climb
|
|
} else {
|
|
taketime(adjally[n], getmovespeed(adjally[n]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
dblog("ERROR - can't find opposite end of stairs/portal!");
|
|
msg("ERROR - can't find opposite end of stairs/portal!");
|
|
return B_TRUE;
|
|
}
|
|
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
needredraw = B_TRUE;
|
|
calclight(player->cell->map);
|
|
precalclos(lf);
|
|
drawscreen();
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
// use a ring of miracles if we have one, and drain 'charges'
|
|
// charges from it. if expired, it will vanish.
|
|
// returns B_TRUE if we found one.
|
|
int useringofmiracles(lifeform_t *lf, int charges) {
|
|
object_t *o;
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
if ( (o->type->id == OT_RING_MIRACLES) &&
|
|
isequipped(o) &&
|
|
getcharges(o) ) {
|
|
char obname[BUFLEN];
|
|
getobname(o, obname, 1);
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
msg("%s%s %s flashes!", lfname, getpossessive(lfname), noprefix(obname));
|
|
}
|
|
|
|
// use a charge
|
|
if (usecharge(o) <= 0) {
|
|
if (isplayer(lf) || cansee(player, lf)) {
|
|
msg("%s%s %s crumbles to dust.", lfname, getpossessive(lfname), noprefix(obname));
|
|
}
|
|
removeob(o, ALL);
|
|
}
|
|
makeknown(OT_RING_MIRACLES);
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int validateraces(void) {
|
|
int goterror = B_FALSE;
|
|
race_t *r;
|
|
flag_t *f;
|
|
skill_t *sk;
|
|
job_t *j;
|
|
int i;
|
|
cell_t fakecell;
|
|
map_t fakemap;
|
|
|
|
// add flags based on raceclass
|
|
for (r = firstrace ; r ; r = r->next) {
|
|
if (r->raceclass->id == RC_AQUATIC) {
|
|
addflag(r->flags, F_HASSKILL, SK_SWIMMING, PR_MASTER, NA, NULL);
|
|
addflag(r->flags, F_AQUATIC, B_TRUE, NA, NA, NULL);
|
|
addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL);
|
|
addflag(r->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL);
|
|
} else if (r->raceclass->id == RC_UNDEAD) {
|
|
addflag(r->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL);
|
|
addflag(r->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL);
|
|
addflag(r->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL);
|
|
addflag(r->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL);
|
|
addflag(r->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL);
|
|
addflag(r->flags, F_DTVULN, DT_HOLY, NA, NA, NULL);
|
|
addflag(r->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL);
|
|
} else if (r->raceclass->id == RC_PLANT) {
|
|
addflag(r->flags, F_DTRESIST, DT_BASH, NA, NA, NULL);
|
|
addflag(r->flags, F_DTVULN, DT_FIRE, NA, NA, NULL);
|
|
addflag(r->flags, F_DTVULN, DT_COLD, NA, NA, NULL);
|
|
addflag(r->flags, F_DTVULN, DT_DECAY, NA, NA, NULL);
|
|
addflag(r->flags, F_FLAMMABLE, PERMENANT, NA, NA, NULL);
|
|
}
|
|
}
|
|
|
|
// generate xp list
|
|
genxplist();
|
|
|
|
|
|
// make a fake cell
|
|
fakemap.lf = NULL;
|
|
fakemap.lastlf = NULL;
|
|
setcelltype(&fakecell, CT_CORRIDOR);
|
|
fakecell.lf = NULL;
|
|
fakecell.map = &fakemap;
|
|
|
|
for (r = firstrace ; r ; r = r->next) {
|
|
lifeform_t *lf;
|
|
|
|
// add a fake lf
|
|
lf = addlf(&fakecell, r->id, 1);
|
|
|
|
if (!hasflag(r->flags, F_SIZE)) {
|
|
printf("ERROR in race '%s' - missing F_SIZE.\n", r->name);
|
|
goterror = B_TRUE;
|
|
|
|
}
|
|
for (f = r->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_HASATTACK) {
|
|
if (!findot(f->val[0])) {
|
|
printf("ERROR in race '%s' - F_HASATTACK with bad object.\n", r->name);
|
|
goterror = B_TRUE;
|
|
}
|
|
if (strlen(f->text)) {
|
|
if (!strchr(f->text, 'd')) {
|
|
printf("ERROR in race '%s' - F_HASATTACK text does not seem to be in 'xdy' format.\n", r->name);
|
|
goterror = B_TRUE;
|
|
}
|
|
} else {
|
|
printf("ERROR in race '%s' - F_HASATTACK with no damage value.\n", r->name);
|
|
goterror = B_TRUE;
|
|
}
|
|
} else if (f->id == F_STARTOB) {
|
|
if (!f->text || (strlen(f->text) == 0)) {
|
|
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) ||
|
|
(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);
|
|
goterror = B_TRUE;
|
|
}
|
|
} else if (f->id == F_NOISETEXT) {
|
|
if (f->val[0] == N_FLY) {
|
|
if (!hasflag(r->flags, F_FLYING) && !hasflag(r->flags, F_LEVITATING)) {
|
|
printf("ERROR in race '%s' - has NOISETEXT N_FLY but isn't flying.", r->name);
|
|
goterror = B_TRUE;
|
|
|
|
}
|
|
}
|
|
if (f->val[1] == NA) {
|
|
printf("ERROR in race '%s' - has NOISETEXT but no volume.", r->name);
|
|
goterror = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// xp check...
|
|
calcxp(lf);
|
|
|
|
// remove a fake lf
|
|
killlf(lf);
|
|
|
|
}
|
|
|
|
|
|
i = 0;
|
|
for (sk = firstskill ; sk ; sk = sk->next) {
|
|
i++;
|
|
}
|
|
if (i >= MAXSKILLS) {
|
|
printf("ERROR - MAXSKILLS is %d but found %d skills.\n",MAXSKILLS,i);
|
|
goterror = B_TRUE;
|
|
}
|
|
for (j = firstjob ; j ; j = j->next) {
|
|
f = hasflag(j->flags, F_HASPET);
|
|
if (f) {
|
|
race_t *r;
|
|
r = findracebyname(f->text);
|
|
if (!r) {
|
|
printf("ERROR - job %s has unknown pet '%s'\n",j->name,f->text);
|
|
goterror = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
for (i = 0; i < MAXSKILLS; i++) {
|
|
if (i != SK_NONE) {
|
|
if (!findskill(i)) {
|
|
printf("ERROR - undefined skill %d\n",i);
|
|
goterror = B_TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return goterror;
|
|
}
|
|
|
|
int rest(lifeform_t *lf, int onpurpose) {
|
|
flag_t *f;
|
|
flag_t *ff;
|
|
int healtime = 3;
|
|
int wantclearmsg = B_TRUE;
|
|
int mpheal = 1;
|
|
int hpheal = 1;
|
|
flag_t *rf;
|
|
int training = B_FALSE;
|
|
int resting = B_FALSE;
|
|
object_t *restob = NULL;
|
|
|
|
|
|
rf = lfhasflag(lf, F_TRAINING);
|
|
if (rf) {
|
|
training = B_TRUE;
|
|
} else {
|
|
rf = isresting(lf);
|
|
if (rf) {
|
|
resting = B_TRUE;
|
|
// ie. resting via 'R'
|
|
restob = getrestob(lf);
|
|
}
|
|
}
|
|
|
|
taketime(lf, getactspeed(lf));
|
|
|
|
if (!lfhasflag(lf, F_POISONED)) {
|
|
// slowly heal hp/mp
|
|
if (!training) {
|
|
ff = lfhasflag(lf, F_RESTHEALAMT);
|
|
if (ff) {
|
|
hpheal = ff->val[0];
|
|
} else {
|
|
hpheal = 1;
|
|
}
|
|
|
|
ff = lfhasflag(lf, F_RESTHEALMPAMT);
|
|
if (ff) {
|
|
mpheal = ff->val[0];
|
|
} else {
|
|
mpheal = 1;
|
|
}
|
|
|
|
if (onpurpose) {
|
|
f = lfhasflag(lf, F_RESTCOUNT);
|
|
if (!f) {
|
|
f = addflag(lf->flags, F_RESTCOUNT, 0, NA, NA, NULL);
|
|
}
|
|
f->val[0]++;
|
|
f->lifetime = 2;
|
|
|
|
ff = lfhasflag(lf, F_RESTHEALTIME);
|
|
if (ff) {
|
|
healtime = ff->val[0];
|
|
} else {
|
|
// 3 turns = heal 1 hp
|
|
healtime = DEFAULTRESTHEALTIME;
|
|
}
|
|
|
|
// modify via restob if resting using 'R'
|
|
if (restob) {
|
|
if (rf->val[1] != NA) {
|
|
healtime -= rf->val[1];
|
|
limit(&healtime, 1, NA);
|
|
}
|
|
}
|
|
|
|
if (f->val[0] >= healtime) {
|
|
int difficulty;
|
|
if (isplayer(lf)) {
|
|
// ie. for hp, at con <= 4 and no first aid skill, you NEVER Heal!
|
|
difficulty = 25;
|
|
} else {
|
|
// ai passes more easily
|
|
difficulty = 10;
|
|
}
|
|
|
|
// modify difficulty if you're resting properly via 'R'
|
|
if (resting && restob) {
|
|
flag_t *f;
|
|
f = hasflag(restob->flags, F_HELPSREST);
|
|
if (f) {
|
|
difficulty -= f->val[0];
|
|
limit(&difficulty, 0, NA);
|
|
}
|
|
}
|
|
|
|
//if (isplayer(lf)) msg("hp given.");
|
|
if (lf->hp < lf->maxhp) {
|
|
// pass a skill check to regain hp
|
|
|
|
if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) {
|
|
gainhp(lf, hpheal);
|
|
}
|
|
}
|
|
|
|
if (lf->mp < getmaxmp(lf)) {
|
|
// pass a skill check to regain mp
|
|
if (skillcheck(lf, SC_IQ, difficulty, getskill(lf, SK_SPELLCASTING))) {
|
|
gainmp(lf, mpheal);
|
|
}
|
|
}
|
|
|
|
killflag(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (training) {
|
|
wantclearmsg = B_FALSE;
|
|
rf->val[2]--;
|
|
if (rf->val[2] == 0) {
|
|
// ask about gaining skills
|
|
if (isplayer(lf)) {
|
|
msg("You finish training.");
|
|
more();
|
|
}
|
|
killflag(rf); // kill resting/training flag.
|
|
|
|
enhanceskills(lf);
|
|
}
|
|
} else if (resting) {
|
|
// just asleep/resting
|
|
wantclearmsg = B_FALSE;
|
|
flag_t *hf;
|
|
int fullpartyrest = B_FALSE;
|
|
|
|
// resting
|
|
if (lf->hp >= lf->maxhp) {
|
|
hf = lfhasflag(lf, F_RESTUNTILHP);
|
|
if (hf) killflag(hf);
|
|
}
|
|
if (lf->mp >= getmaxmp(lf)) {
|
|
hf = lfhasflag(lf, F_RESTUNTILMP);
|
|
if (hf) killflag(hf);
|
|
}
|
|
|
|
hf = lfhasflag(lf, F_RESTUNTILALLIES);
|
|
if (hf) {
|
|
int moretogo = B_FALSE;
|
|
lifeform_t *l;
|
|
|
|
fullpartyrest = B_TRUE;
|
|
|
|
for (l = lf->cell->map->lf ; l ; l = l->next) {
|
|
if ((l != lf) && areallies(l, lf)) {
|
|
if (l->hp < l->maxhp) {
|
|
moretogo = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!moretogo) {
|
|
killflag(hf);
|
|
}
|
|
}
|
|
|
|
if (!lfhasflag(lf, F_RESTUNTILHP) &&
|
|
!lfhasflag(lf, F_RESTUNTILMP) &&
|
|
!lfhasflag(lf, F_RESTUNTILALLIES)) {
|
|
if (isplayer(lf)) {
|
|
if (fullpartyrest) {
|
|
msg("Your party has finished resting.");
|
|
} else {
|
|
msg("You finish resting.");
|
|
}
|
|
} else if (cansee(player, lf)) {
|
|
char lfname[BUFLEN];
|
|
getlfname(lf, lfname);
|
|
msg("%s finishes resting.",lfname);
|
|
}
|
|
if (isplayer(lf)) statdirty = B_TRUE;
|
|
killflag(rf);
|
|
wantclearmsg = B_FALSE;
|
|
}
|
|
}
|
|
} // end if !poisoned
|
|
|
|
if (statdirty || needredraw) {
|
|
drawscreen();
|
|
}
|
|
|
|
if (onpurpose && wantclearmsg) {
|
|
if (isplayer(lf)) {
|
|
// clear msg bar
|
|
clearmsg();
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int wear(lifeform_t *lf, object_t *o) {
|
|
int rv = B_FALSE;
|
|
char buf[BUFLEN],obname[BUFLEN];
|
|
flag_t *f;
|
|
enum BODYPART possbp[MAXBODYPARTS];
|
|
int nparts = 0;
|
|
enum BODYPART bp;
|
|
|
|
// this might impact your AR
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
|
|
getobname(o, obname, 1);
|
|
|
|
// check for already equipped first!
|
|
f = hasflag(o->flags, F_EQUIPPED);
|
|
if (f) {
|
|
if (isplayer(lf)) {
|
|
if (f->val[0] == BP_WEAPON) {
|
|
msg("You're weilding that!");
|
|
} else {
|
|
msg("You're already wearing that!");
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// metal objects and magshield?
|
|
if (lfhasflag(lf, F_MAGSHIELD)) {
|
|
if (isplayer(lf)) {
|
|
msg("Your %s evades your grasp!", noprefix(buf));
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
nparts = 0;
|
|
for (f = o->flags->first ; f ; f = f->next) {
|
|
if (f->id == F_GOESON) {
|
|
possbp[nparts] = f->val[0];
|
|
nparts++;
|
|
}
|
|
}
|
|
|
|
if (nparts == 0) {
|
|
if (isplayer(lf)) {
|
|
msg("You can't wear that!");
|
|
}
|
|
return B_TRUE;
|
|
} else if (nparts == 1) {
|
|
bp = possbp[0];
|
|
} else { // multiple possible locations
|
|
int i;
|
|
// go in first possible place
|
|
bp = BP_NONE;
|
|
for (i = 0; i < nparts; i++) {
|
|
if (!hasobwithflagval(lf->pack, F_EQUIPPED, possbp[i], NA, NA, NULL)) {
|
|
bp = possbp[i];
|
|
break;
|
|
}
|
|
}
|
|
if (bp == BP_NONE) {
|
|
if (isplayer(lf)) {
|
|
msg("You have no room to wear that.");
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
//}
|
|
}
|
|
|
|
while (!canwear(lf, o, bp)) {
|
|
int errresolved = B_FALSE;
|
|
if ((gamemode == GM_GAMESTARTED) && lf->created) {
|
|
switch (reason) {
|
|
case E_ALREADYUSING:
|
|
if (isplayer(lf)) {
|
|
msg("You're already wearing that!");
|
|
}
|
|
break;
|
|
case E_WEARINGSOMETHINGELSE:
|
|
f = hasflag(o->flags, F_GOESON);
|
|
if (f) {
|
|
object_t *inway;
|
|
// find what else is there
|
|
inway = getequippedob(lf->pack, f->val[0]);
|
|
getobname(inway,buf, 1);
|
|
if (isplayer(lf)) {
|
|
int ch;
|
|
char buf2[BUFLEN];
|
|
// take offending item off first - this takes extra time.
|
|
sprintf(buf2, "Remove your %s",noprefix(buf));
|
|
ch = askchar(buf2, "yn","y", B_TRUE);
|
|
if (ch == 'y') {
|
|
if (isarmour(inway)) {
|
|
if (!takeoff(player, inway)) {
|
|
// took it off!
|
|
errresolved = B_TRUE;
|
|
}
|
|
} else { // weapon
|
|
if (!unweild(player, inway)) {
|
|
// took it off!
|
|
errresolved = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// should never happen
|
|
if (isplayer(lf)) msg("You can't wear that!");
|
|
}
|
|
break;
|
|
case E_NOTKNOWN:
|
|
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));
|
|
break;
|
|
default:
|
|
if (isplayer(lf)) {
|
|
msg("You can't wear that!");
|
|
}
|
|
break;
|
|
}
|
|
} // end if gamestarted
|
|
if (!errresolved) {
|
|
return B_TRUE;
|
|
}
|
|
// if we DID resolve the error, loop around and check if we can wear again...
|
|
} // end while !canwear
|
|
|
|
// some checks first...
|
|
if (touch(lf, o)) {
|
|
taketime(lf, getactspeed(lf));
|
|
return B_TRUE;
|
|
}
|
|
|
|
// probably don't need this now...
|
|
if (hasflag(o->flags, F_DEAD)) {
|
|
taketime(lf, getactspeed(lf));
|
|
return B_TRUE;
|
|
}
|
|
|
|
// wear it
|
|
//f = hasflag(o->flags, F_GOESON);
|
|
//bp = f->val[0];
|
|
|
|
addflag(o->flags, F_EQUIPPED, bp, -1, -1, NULL);
|
|
taketime(lf, getactspeed(lf));
|
|
|
|
maketried(o->type->id);
|
|
|
|
/*
|
|
if (isplayer(lf)) {
|
|
// equipping unknown objects makes them known
|
|
if (!isknown(o)) {
|
|
// announce
|
|
announceob(o->type->id);
|
|
|
|
// make the obejct type known
|
|
makeknown(o->type->id);
|
|
getobname(o, obname, 1);
|
|
}
|
|
}
|
|
*/
|
|
|
|
// when you wear armour, you find out
|
|
// its bonuses.
|
|
if (isplayer(lf) && (o->type->obclass->id == OC_ARMOUR)) {
|
|
f = hasflag(o->flags, F_BONUS);
|
|
if (f && !f->known) {
|
|
f->known = B_TRUE;
|
|
getobname(o, obname, 1);
|
|
}
|
|
}
|
|
|
|
if ((gamemode == GM_GAMESTARTED) && lf->created) {
|
|
if (isplayer(lf)) {
|
|
msg("You are now wearing %s.", obname);
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
capitalise(buf);
|
|
msg("%s puts on %s.", buf, obname);
|
|
|
|
}
|
|
|
|
if (o->blessed == B_CURSED) {
|
|
if (isplayer(lf)) {
|
|
msg("Oh no! The %s releases a pulse of evil!", noprefix(obname));
|
|
o->blessknown = B_TRUE;
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s%s %s releases a pulse of evil!", buf, getpossessive(buf), obname);
|
|
o->blessknown = B_TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// warn if it will be cumbersome
|
|
if (isplayer(lf)) {
|
|
f = hasflag(o->flags, F_SHIELD);
|
|
if (f && (getskill(lf, SK_SHIELDS) <= PR_INEPT) ) {
|
|
msg("You find this shield very cumbersome to use.");
|
|
}
|
|
}
|
|
|
|
// give flags
|
|
giveobflags(lf, o, F_EQUIPCONFER);
|
|
|
|
return rv;
|
|
}
|
|
|
|
int weild(lifeform_t *lf, object_t *o) {
|
|
char buf[BUFLEN];
|
|
flag_t *f;
|
|
object_t *oo;
|
|
int twohanded = B_FALSE;
|
|
enum BODYPART weildloc,otherloc;
|
|
|
|
// this might impact your AR
|
|
if (isplayer(lf)) {
|
|
statdirty = B_TRUE;
|
|
}
|
|
|
|
if (o) {
|
|
getobname(o, buf, o->amt);
|
|
} else {
|
|
sprintf(buf, "nothing");
|
|
}
|
|
|
|
if (!canweild(lf, o)) {
|
|
if ((gamemode == GM_GAMESTARTED) && lf->created) {
|
|
if (isplayer(lf)) {
|
|
switch (reason) {
|
|
case E_ALREADYUSING:
|
|
msg("You are already weilding that!");
|
|
break;
|
|
case E_NOUNARMEDATTACK:
|
|
msg("You cannot fight without a weapon!");
|
|
break;
|
|
case E_IMPOSSIBLE:
|
|
msg("You cannot weild weapons!");
|
|
break;
|
|
case E_NOHANDS:
|
|
msg("You do not have enough free hands to weild this weapon.");
|
|
break;
|
|
case E_LOWCON:
|
|
msg("You are not healthy enough to use this weapon.");
|
|
break;
|
|
case E_LOWDEX:
|
|
msg("You are not dextrous enough to use this weapon.");
|
|
break;
|
|
case E_LOWIQ:
|
|
msg("You are not smart enough to use this weapon.");
|
|
break;
|
|
case E_LOWSTR:
|
|
msg("You are not strong enough to use this weapon.");
|
|
break;
|
|
default:
|
|
msg("For some reason, you weild this!");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// anything else weilded?
|
|
weildloc = getweildloc(o, &otherloc, &twohanded);
|
|
|
|
// firearm in regular hand?
|
|
// note: this is the same logic as in canweild()
|
|
if (o && !hasbp(lf, weildloc) && isfirearm(o) && !getequippedob(lf->pack, otherloc)) {
|
|
int temp;
|
|
// firearm can go in other hand.
|
|
// swap locations.
|
|
temp = weildloc;
|
|
weildloc = otherloc;
|
|
otherloc = temp;
|
|
}
|
|
|
|
|
|
// metal objects and magshield?
|
|
if (lfhasflag(lf, F_MAGSHIELD)) {
|
|
if (isplayer(lf)) {
|
|
msg("Your %s evades your grasp!", noprefix(buf));
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
|
|
// if we are skilled at twoweaponing, and somehting is in the way,
|
|
// ask if we want to use our other hand.
|
|
if (!twohanded && hasbp(lf, otherloc)) {
|
|
oo = getequippedob(lf->pack, weildloc);
|
|
if (getskill(lf, SK_TWOWEAPON) && oo && !hasflag(oo->flags, F_TWOHANDED)) {
|
|
char buf2[BUFLEN];
|
|
char ch;
|
|
sprintf(buf2, "Weild %s in your left hand?",buf);
|
|
ch = askchar(buf2, "yn","y", B_TRUE);
|
|
if (ch == 'y') {
|
|
enum BODYPART temp;
|
|
// swap locations.
|
|
temp = weildloc;
|
|
weildloc = otherloc;
|
|
otherloc = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
// any other objects in the way?
|
|
for (oo = lf->pack->first ; oo ; oo = oo->next) {
|
|
f = hasflagval(oo->flags, F_EQUIPPED, weildloc, -1, -1, NULL);
|
|
if (f) {
|
|
if (isarmour(oo)) {
|
|
char inwayname[BUFLEN];
|
|
char buf2[BUFLEN];
|
|
char ch;
|
|
if (isplayer(lf)) {
|
|
getobname(oo, inwayname, oo->amt);
|
|
// prompt before taking it off.
|
|
sprintf(buf2, "Remove your %s",noprefix(inwayname));
|
|
ch = askchar(buf2, "yn","y", B_TRUE);
|
|
} else {
|
|
ch = 'y';
|
|
}
|
|
if (ch == 'y') {
|
|
if (isarmour(oo)) {
|
|
if (takeoff(lf, oo)) {
|
|
// if we can't remove it, stop.
|
|
return B_TRUE;
|
|
}
|
|
} else { // weapon
|
|
if (unweild(lf, oo)) {
|
|
// if we can't remove it, stop.
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
} else {
|
|
return B_TRUE;
|
|
}
|
|
} else {
|
|
// just unweild it
|
|
if (unweild(lf, oo)) {
|
|
// if we can't unweild old weapon, stop
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
// this weapon is two handed and uses the other hand
|
|
if (hasflag(oo->flags, F_TWOHANDED)) {
|
|
f = hasflagval(oo->flags, F_EQUIPPED, otherloc, -1, -1, NULL);
|
|
if (f) {
|
|
// unweild it
|
|
if (unweild(lf, oo)) {
|
|
// if we can't unweild old weapon, stop
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// new weapon is two handed? check other hand too.
|
|
if (twohanded) {
|
|
f = hasflagval(oo->flags, F_EQUIPPED, otherloc, -1, -1, NULL);
|
|
if (f) {
|
|
if (isweapon(oo)) {
|
|
// just unweild it
|
|
if (unweild(lf, oo)) {
|
|
// if we can't unweild old weapon, stop
|
|
return B_TRUE;
|
|
}
|
|
} else { // armour
|
|
char buf2[BUFLEN];
|
|
char inwayname[BUFLEN];
|
|
char ch;
|
|
if (isplayer(lf)) {
|
|
// prompt before taking it off.
|
|
getobname(oo, inwayname, oo->amt);
|
|
sprintf(buf2, "Remove your %s",noprefix(inwayname));
|
|
ch = askchar(buf2, "yn","y", B_TRUE);
|
|
} else {
|
|
ch = 'y';
|
|
}
|
|
if (ch == 'y') {
|
|
if (isarmour(oo)) {
|
|
if (takeoff(lf, oo)) {
|
|
// if we can't remove it, stop.
|
|
return B_TRUE;
|
|
}
|
|
} else {
|
|
if (unweild(lf, oo)) {
|
|
// if we can't remove it, stop.
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
} else {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// if we asked to just unweild our weapon, exit now
|
|
// with no error.
|
|
if (!o) {
|
|
if ((gamemode == GM_GAMESTARTED) && lf->created && (lf->race->id != R_DANCINGWEAPON)) {
|
|
if (isplayer(lf)) {
|
|
msg("You are now fighting unarmed.");
|
|
} else if (cansee(player, lf)) {
|
|
getlfname(lf, buf);
|
|
msg("%s is now fighting unarmed.",buf);
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
// now weild this
|
|
addflag(o->flags, F_EQUIPPED, weildloc, -1, -1, NULL);
|
|
if (hasflag(o->flags, F_TWOHANDED)) {
|
|
addflag(o->flags, F_EQUIPPED, otherloc, -1, -1, NULL);
|
|
}
|
|
|
|
taketime(lf, getactspeed(lf));
|
|
|
|
maketried(o->type->id);
|
|
|
|
if ((gamemode == GM_GAMESTARTED) && lf->created && (lf->race->id != R_DANCINGWEAPON)) {
|
|
if (isplayer(lf)) {
|
|
char buf2[BUFLEN];
|
|
|
|
sprintf(buf2, "You are now weilding %c - %s", o->letter, buf);
|
|
if (twohanded) {
|
|
strcat(buf2, " (both hands)");
|
|
} else if (weildloc == BP_SECWEAPON) {
|
|
strcat(buf2, " (in left hand)");
|
|
}
|
|
strcat(buf2, ".");
|
|
msg(buf2);
|
|
// warn if it won't do any damage
|
|
if (!ismeleeweapon(o) && !isfirearm(o)) {
|
|
msg("You have a feeling that this weapon will not be very effective...");
|
|
} else {
|
|
// warn if unskilled in this weapon
|
|
skill_t *sk;
|
|
sk = getobskill(o);
|
|
if (sk && !getskill(lf, sk->id)) {
|
|
msg("You feel rather inept with this weapon.");
|
|
}
|
|
}
|
|
} else if (cansee(player, lf)) {
|
|
if (lf->race->id != R_DANCINGWEAPON) {
|
|
char buf2[BUFLEN];
|
|
getlfname(lf, buf2);
|
|
msg("%s weilds %s.", buf2, buf);
|
|
}
|
|
}
|
|
|
|
|
|
touch(lf, o);
|
|
|
|
if (o->blessed == B_CURSED) {
|
|
if (isplayer(lf)) {
|
|
msg("Oh no! The %s releases a pulse of evil!", strchr(buf, ' ')+1);
|
|
o->blessknown = B_TRUE;
|
|
} else if (cansee(player, lf)) {
|
|
char buf2[BUFLEN];
|
|
getlfname(lf, buf2);
|
|
msg("%s%s %s releases a pulse of evil!", buf2, getpossessive(buf2), buf);
|
|
o->blessknown = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (isfirearm(o)) {
|
|
// select ammo
|
|
setammo(lf, getrandomammo(lf));
|
|
|
|
if (getammo(lf)) {
|
|
autotarget(lf);
|
|
}
|
|
}
|
|
}
|
|
|
|
// give flags
|
|
giveobflags(lf, o, F_EQUIPCONFER);
|
|
|
|
// make certain flags known
|
|
if (isplayer(lf)) {
|
|
f = hasflag(o->flags, F_ARMOURPIERCE);
|
|
if (f) {
|
|
msg("Your %s seems unnaturally sharp!",noprefix(buf));
|
|
f->known = B_TRUE;
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
// will the lf flee after taking damage?
|
|
int willflee(lifeform_t *lf) {
|
|
enum IQBRACKET iqb;
|
|
flag_t *f;
|
|
|
|
|
|
if (hasflag(lf->flags, F_NOFLEE)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (hasflag(lf->flags, F_FLEEONDAM)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
iqb = getiqname(getattr(lf, A_IQ), NULL);
|
|
if ((iqb >= IQ_SMART) && isbleeding(lf)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
f = hasflag(lf->flags, F_FLEEONHPPCT);
|
|
if (f) {
|
|
if (gethppct(lf) <= f->val[0]) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
|