- [+] idea: only see forwards? (ie. in last dir moved)

- [+] add player->facing
    - [+] this gets set to the last move direction
    - [+] you can only see in an arc in front of you
    - [+] going backwards just changes facing (and takes less time)
    - [+] shift+samedir = run
    - [+] shift + otherdir = walk without turning / strafe
    - [+] when ai is moving towards a seen target,  always strafe
    - [+] when fleeing, you can turn your back.
    - [+] make strafing backwards/sideays take longer
    - [+] enhanced-smell means you can see all LIFEFORMS or _smell
          obects_ in all directions 
        - [+] ie. look in all dirs, but in precalclos(), can only see
              RD_BACKWARDS/SIDEWAYS cells if they have lfs
        - [+] define "smelly" objects - non-undead lifeforms, food,
              ot_scent.  f_smellable
    - [+] make eyedestroyed half your FOV (lose the right side)
    - [+] change pirate to start with permenant IJ_EYEDESTROYED
- [+] mosnters should always turn to face sounds
- [+] shields should give no AR, but have a chance of blocking all
      damage based on shield skill
- [+] healing potions should fix nonpermenant injuries (check for this
      after checking for missing bodyparts)
- [+] shouldn't remember map cells anything when bezerk
- [+] show skillxp until next skill in @@
- [+] only allow 'c' to close doors which you can see.
- [+] bug in precalclos when going off map.
- [+] even with 0 cartography, remember cells. but then forget once
      they're >4 cells away.
- [+] Exp Level: 3 (-2147483087 XP, 2147483704 for next)
    - [+] add asserts
    - [+] calcxp is sometimes returning -xxxxxxx.  turned on debugging.
    - [+] wait for it to happen again
- [+] bug: player can see own cell when maxvisrange = 0(resting)
- [+] mods for perception skill:
    - [+] adept pereption:  FOV widened
    - [+] expert perception:  leave no footprints (rather than
          partically obscure)
    - [+] master perception:  see in nearly all dirs
This commit is contained in:
Rob Pearce 2011-09-11 23:52:14 +00:00
parent 8d9e444f84
commit ec5942d31f
18 changed files with 746 additions and 290 deletions

25
ai.c
View File

@ -669,7 +669,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
if (db) { if (db) {
dblog(".oO { moving towards target. }"); dblog(".oO { moving towards target. }");
} }
if (!movetowards(lf, target->cell, DT_ORTH)) { if (!movetowards(lf, target->cell, DT_ORTH, B_FALSE)) {
turntoface(lf, target->cell);
// success // success
return B_FALSE; return B_FALSE;
} else { } else {
@ -678,7 +679,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
} }
} else if (dist < wantdistmin) { } else if (dist < wantdistmin) {
if (db) dblog(".oO { moving away from target to maintain mindist %d. }", wantdistmin); if (db) dblog(".oO { moving away from target to maintain mindist %d. }", wantdistmin);
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_KEEPLOF)) { // maintain LOF if (!moveawayfrom(lf, target->cell, DT_ORTH, B_KEEPLOF, B_TRUE)) { // maintain LOF, and keep facing the target
// success // success
return B_FALSE; return B_FALSE;
} else { } else {
@ -772,7 +773,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
} else { } else {
// try going in last known dir // try going in last known dir
if (db) dblog(".oO { trying my master's last known move dir (%s) }",getdirname(lastdir)); if (db) dblog(".oO { trying my master's last known move dir (%s) }",getdirname(lastdir));
if (!trymove(lf, lastdir, B_TRUE)) { if (!trymove(lf, lastdir, B_TRUE, B_FALSE)) {
if (db) dblog(".oO { ...successfully }"); if (db) dblog(".oO { ...successfully }");
// we now don't know their last known dir. // we now don't know their last known dir.
if (targetflag) { if (targetflag) {
@ -819,8 +820,8 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y); if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y);
c = getcellat(lf->cell->map, x, y); c = getcellat(lf->cell->map, x, y);
if (c) { if (c) {
// try to move towards the cll // try to move towards the cell
if (movetowards(lf, c, DT_ORTH)) { if (movetowards(lf, c, DT_ORTH, B_FALSE )) {
// couldn't move towards it for some reason. // couldn't move towards it for some reason.
// so stop trying. // so stop trying.
if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }"); if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }");
@ -849,6 +850,8 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
} }
killflag(f); killflag(f);
} else {
turntoface(lf, c);
} }
} }
} else { } else {
@ -957,7 +960,7 @@ void aiturn(lifeform_t *lf) {
if (db) { if (db) {
char lfname[BUFLEN]; char lfname[BUFLEN];
real_getlfname(lf, lfname, B_FALSE); real_getlfname(lf, lfname, B_FALSE);
dblog("AIMOVE: %s", lfname); dblog("AIMOVE: %s, facing %s", lfname, getdirnameshort(lf->facing));
} }
// if lifeform isn't alive, skip turn // if lifeform isn't alive, skip turn
@ -1225,7 +1228,7 @@ void aiturn(lifeform_t *lf) {
if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) && if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) &&
!hasobwithflag(target->cell->obpile, F_DEEPWATER)) { !hasobwithflag(target->cell->obpile, F_DEEPWATER)) {
// move away! // move away!
if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE)) { if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE, B_TRUE)) {
return; return;
} }
} }
@ -1400,10 +1403,14 @@ void aiturn(lifeform_t *lf) {
// death? // death?
} else { } else {
// then move towards them... // then move towards them...
if (db) dblog(".oO { moving towards my new target }"); if (db) dblog(".oO { moving towards my new target (%d,%d) -> (%d,%d) }", lf->cell->x, lf->cell->y,
newtarget->cell->x, newtarget->cell->y);
if (icanattack) { if (icanattack) {
if (!movetowards(lf, newtarget->cell, DT_ORTH)) return; if (!movetowards(lf, newtarget->cell, DT_ORTH, B_FALSE)) {
turntoface(lf, newtarget->cell);
return;
}
} else { } else {
if (db) dblog(".oO { won't move towards target - i have no weapon. }"); if (db) dblog(".oO { won't move towards target - i have no weapon. }");
} }

View File

@ -496,6 +496,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
int deflected = B_FALSE; int deflected = B_FALSE;
int weppassthrough = B_FALSE; int weppassthrough = B_FALSE;
int firstisbackstab = B_FALSE; int firstisbackstab = B_FALSE;
int blocked = B_FALSE;
int hit = B_FALSE; int hit = B_FALSE;
int critical = 0; int critical = 0;
char wepname[BUFLEN]; char wepname[BUFLEN];
@ -752,6 +753,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
if (ndam > 0) { if (ndam > 0) {
object_t *shield = NULL;
flag_t *f; flag_t *f;
for (i = 0; i < ndam; i++) { for (i = 0; i < ndam; i++) {
int reduceamt = 0; int reduceamt = 0;
@ -790,6 +792,29 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
if (lfhasflag(lf, F_HOLYAURA) && isvulnto(victim->flags, DT_HOLY)) { if (lfhasflag(lf, F_HOLYAURA) && isvulnto(victim->flags, DT_HOLY)) {
damtype[i] = DT_HOLY; damtype[i] = DT_HOLY;
} }
// blocked by defender's shield?
shield = getshield(victim);
if (shield && cansee(victim, lf)) {
int difficulty;
difficulty = 25 + ((gethitdice(lf) - gethitdice(victim)*3) );
if (skillcheck(victim, SC_SHIELDBLOCK, difficulty, 0)) {
char shname[BUFLEN];
// announce
real_getobname(shield, shname, 1, B_TRUE, B_FALSE, B_TRUE, B_FALSE, B_FALSE);
if (isplayer(lf)) { // player is atatcking
msg("%s blocks your attack with %s.", victimname, shname);
} else if (cansee(player, lf) || cansee(player, victim)) { // monster is attacking
msg("%s block%s %s%s attack with %s.", victimname, isplayer(victim) ? "" : "s",
attackername, getpossessive(attackername),
shname);
}
// apply all damage to shield
takedamage(shield, dam[i], damtype[i]);
practice(victim, SK_SHIELDS, 1);
blocked = B_TRUE;
break; // stop processing damage now.
}
}
} }
// modify based on resistances // modify based on resistances
@ -986,13 +1011,13 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
} // end foreach damtype } // end foreach damtype
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW)) {
wepeffects(wep->flags, victim->cell, damflag, dam[0]);
}
// other effects // other effects
if (!isdead(victim)) { if (!isdead(victim) && !blocked) {
// special weapon effects, as long as you're not doing a heavy blow
if (!lfhasflag(lf, F_HEAVYBLOW)) {
wepeffects(wep->flags, victim->cell, damflag, dam[0]);
}
if (isunarmed) { if (isunarmed) {
f = lfhasflag(lf, F_FREEZINGTOUCH); f = lfhasflag(lf, F_FREEZINGTOUCH);
if (f) { if (f) {
@ -1086,27 +1111,28 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
fightback(victim, lf); fightback(victim, lf);
} } // end if !isdead(victim)
// retaliation happens even if victim died // retaliation happens even if victim died
getflags(victim->flags, retflag, &nretflags, F_RETALIATE, F_NONE); if (!blocked) {
for (i = 0; i < nretflags; i++) { getflags(victim->flags, retflag, &nretflags, F_RETALIATE, F_NONE);
f = retflag[i]; for (i = 0; i < nretflags; i++) {
if (f->id == F_RETALIATE) { f = retflag[i];
int rdam; if (f->id == F_RETALIATE) {
char damstring[BUFLEN]; int rdam;
rdam = rolldie(f->val[0], f->val[1]); char damstring[BUFLEN];
if (cansee(player, victim)) { rdam = rolldie(f->val[0], f->val[1]);
msg("^%c%s%s %s %s %s!", isplayer(victim) ? 'b' : 'n', victimname, getpossessive(victimname), if (cansee(player, victim)) {
noprefix(f->text), msg("^%c%s%s %s %s %s!", isplayer(victim) ? 'b' : 'n', victimname, getpossessive(victimname),
getattackverb(victim, NULL, f->val[2], rdam, lf->maxhp), noprefix(f->text),
attackername); getattackverb(victim, NULL, f->val[2], rdam, lf->maxhp),
attackername);
}
snprintf(damstring, BUFLEN, "%s%s %s", victimname, getpossessive(victimname), noprefix(f->text));
losehp_real(lf, rdam, f->val[2], victim, damstring, B_TRUE, NULL, B_TRUE);
} }
snprintf(damstring, BUFLEN, "%s%s %s", victimname, getpossessive(victimname), noprefix(f->text));
losehp_real(lf, rdam, f->val[2], victim, damstring, B_TRUE, NULL, B_TRUE);
} }
} }
} else { // miss! } else { // miss!
if (aidb) dblog(".oO { i missed! }"); if (aidb) dblog(".oO { i missed! }");
// announce it // announce it
@ -1176,7 +1202,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
} }
// twoweapon? // twoweapon?
if (hit) { if (hit && !blocked) {
enum SKILLLEVEL slev; enum SKILLLEVEL slev;
slev = getskill(lf, SK_TWOWEAPON); slev = getskill(lf, SK_TWOWEAPON);
if (slev >= PR_SKILLED) { if (slev >= PR_SKILLED) {

Binary file not shown.

29
defs.h
View File

@ -2,7 +2,6 @@
#define __DEFS_H #define __DEFS_H
// MACROS // MACROS
#define MAXOF(a,b) (a > b ? a : b) #define MAXOF(a,b) (a > b ? a : b)
@ -52,6 +51,8 @@
#define B_APPENDYOU (-1) #define B_APPENDYOU (-1)
#define B_SPLATTER (-1) #define B_SPLATTER (-1)
#define B_FROMINJURY (-1) #define B_FROMINJURY (-1)
#define B_KEEPDIR (-2)
//#define B_TEMP (-1) //#define B_TEMP (-1)
//#define B_PERM (-2) //#define B_PERM (-2)
@ -201,6 +202,7 @@
// DIRECTIONS // DIRECTIONS
#define D_NONE -1 #define D_NONE -1
#define D_UNKNOWN -2 #define D_UNKNOWN -2
#define D_ALL -3
// Orthogonal directions // Orthogonal directions
#define D_N 0 #define D_N 0
@ -225,6 +227,13 @@
#define MAXDIR_MAP 15 #define MAXDIR_MAP 15
// relative directions
enum RELATIVEDIR {
RD_FORWARDS,
RD_BACKWARDS,
RD_SIDEWAYS,
};
/////////////////////////////////////// ///////////////////////////////////////
// STRINGS // STRINGS
/////////////////////////////////////// ///////////////////////////////////////
@ -347,6 +356,18 @@ enum NOISECLASS {
NC_OTHER = 2, NC_OTHER = 2,
}; };
enum QUADRANT {
Q_NONE = -1,
Q_NNE = 0,
Q_ENE = 1,
Q_ESE = 2,
Q_SSE = 3,
Q_SSW = 4,
Q_WSW = 5,
Q_WNW = 6,
Q_NNW = 7,
};
enum SAYPHRASE { enum SAYPHRASE {
SP_BEG, SP_BEG,
SP_BEGATTACK, SP_BEGATTACK,
@ -1795,6 +1816,7 @@ enum FLAG {
// check. // check.
// v2 = sc_dodge difficulty // v2 = sc_dodge difficulty
F_OBJECTTRAP, // this trap can go onto an object (door, chest, etc) F_OBJECTTRAP, // this trap can go onto an object (door, chest, etc)
F_SMELLY, // lfs with enhacned scent can smell this object
// doors // doors
F_DOOR, // this object is a door - ie. can open it F_DOOR, // this object is a door - ie. can open it
// v0 and v1 are like F_IMPASSABLE // v0 and v1 are like F_IMPASSABLE
@ -2251,7 +2273,7 @@ enum FLAG {
F_DISEASEIMMUNE, // lf can't be diseased F_DISEASEIMMUNE, // lf can't be diseased
F_DRUNK, // v1 is drunknness - 1-5. F_DRUNK, // v1 is drunknness - 1-5.
F_ENHANCESEARCH, // gives v0 bonus on search checks. F_ENHANCESEARCH, // gives v0 bonus on search checks.
F_ENHANCESMELL, // can 'see' scents. F_ENHANCESMELL, // can 'see' scents with v0 range.
F_EXTRADAM, // do 'text' extra damage of damtype v0 when you hit F_EXTRADAM, // do 'text' extra damage of damtype v0 when you hit
// if v1 is TRUE, also deal extra damage based on // if v1 is TRUE, also deal extra damage based on
// the flagpile's F_BONUS flag. // the flagpile's F_BONUS flag.
@ -2800,6 +2822,7 @@ typedef struct cell_s {
// known to player? // known to player?
int known; int known;
struct glyph_s knownglyph; struct glyph_s knownglyph;
int knowntime;
// FOR CONSTRUCTION // FOR CONSTRUCTION
int visited; int visited;
@ -2884,6 +2907,8 @@ typedef struct lifeform_s {
long oblist[MAXPILEOBS]; long oblist[MAXPILEOBS];
int x,y; int x,y;
int facing; // which way are we facing
int losdirty; int losdirty;
int nlos; int nlos;
cell_t **los; cell_t **los;

43
io.c
View File

@ -856,6 +856,12 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src
strcat(extrainfo, buf2); strcat(extrainfo, buf2);
} }
} }
if (c->lf->facing != D_ALL) {
char buf2[BUFLEN];
snprintf(buf2, BUFLEN, "facing %s",getdirnameshort(c->lf->facing));
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, buf2);
}
// show iextra info if lf isn't feigning death // show iextra info if lf isn't feigning death
if (strlen(extrainfo) && !lfhasflag(c->lf, F_FEIGNINGDEATH)) { if (strlen(extrainfo) && !lfhasflag(c->lf, F_FEIGNINGDEATH)) {
@ -3416,6 +3422,8 @@ void describeob(object_t *o) {
f = hasflag(o->flags, F_OBHP); f = hasflag(o->flags, F_OBHP);
if (isarmour(o) && getskill(player, SK_ARMOUR)) { if (isarmour(o) && getskill(player, SK_ARMOUR)) {
showfullhp = B_TRUE; showfullhp = B_TRUE;
} else if (isshield(o) && getskill(player, SK_SHIELDS)) {
showfullhp = B_TRUE;
} else if ((o->type->material->id == MT_METAL) && getskill(player, SK_METALWORK)) { } else if ((o->type->material->id == MT_METAL) && getskill(player, SK_METALWORK)) {
showfullhp = B_TRUE; showfullhp = B_TRUE;
} else if ( ((o->type->material->id == MT_LEATHER) || (o->type->material->id == MT_CLOTH)) && } else if ( ((o->type->material->id == MT_LEATHER) || (o->type->material->id == MT_CLOTH)) &&
@ -4131,13 +4139,12 @@ void doclose(void) {
int adjdoors; int adjdoors;
int forcedir = D_NONE; int forcedir = D_NONE;
// how many doors are nearby? // how many doors are nearby?
adjdoors = 0; adjdoors = 0;
for (dir = DC_N; dir <= DC_NW; dir++) { for (dir = DC_N; dir <= DC_NW; dir++) {
cell_t *c; cell_t *c;
c = getcellindir(player->cell, dir); c = getcellindir(player->cell, dir);
if (c) { if (c && haslos(player, c)) {
object_t *door; object_t *door;
door = hasobwithflag(c->obpile, F_DOOR); door = hasobwithflag(c->obpile, F_DOOR);
if (door) { if (door) {
@ -4152,7 +4159,7 @@ void doclose(void) {
} }
if (adjdoors == 0) { if (adjdoors == 0) {
msg("There are no open doors nearby!"); msg("You can't see any open doors nearby!");
return; return;
} else if (adjdoors == 1) { } else if (adjdoors == 1) {
dir = forcedir; dir = forcedir;
@ -4167,7 +4174,7 @@ void doclose(void) {
} else { } else {
cell_t *c; cell_t *c;
c = getcellindir(player->cell, dir); c = getcellindir(player->cell, dir);
if (c) { if (c && haslos(player, c)) {
failed = closedoorat(player, c); failed = closedoorat(player, c);
} }
} }
@ -6848,7 +6855,7 @@ void handleinput(void) {
if (stopnow) { if (stopnow) {
stoprunning(player); stoprunning(player);
} else { } else {
if (trymove(player, rundir, B_TRUE)) { if (trymove(player, rundir, B_TRUE, B_FALSE)) {
// failed. // failed.
stoprunning(player); stoprunning(player);
} else { } else {
@ -6868,6 +6875,7 @@ void handleinput(void) {
char temp[2]; char temp[2];
flag_t repeatflag; flag_t repeatflag;
int wantrepeat = B_FALSE; int wantrepeat = B_FALSE;
int dir;
repeatflag.val[0] = NA; repeatflag.val[1] = NA; repeatflag.val[2] = NA; repeatflag.val[0] = NA; repeatflag.val[1] = NA; repeatflag.val[2] = NA;
repeatflag.text = NULL; repeatflag.text = NULL;
@ -6978,9 +6986,9 @@ void handleinput(void) {
case 'u': case 'u':
case 'b': case 'b':
case 'n': case 'n':
trymove(player, chartodir(ch), B_TRUE); trymove(player, chartodir(ch), B_TRUE, B_FALSE);
break; break;
// running // run / strafe
case 'H': case 'H':
case 'J': case 'J':
case 'K': case 'K':
@ -6989,7 +6997,12 @@ void handleinput(void) {
case 'U': case 'U':
case 'B': case 'B':
case 'N': case 'N':
tryrun(player, chartodir(ch)); dir = chartodir(ch);
if (dir == player->facing) { // shift+samedir = run
tryrun(player, dir);
} else { // shift + diffdir = strafe
trymove(player, dir, B_TRUE, B_TRUE);
}
break; break;
case 's': // slowwalk case 's': // slowwalk
trysneak(player, D_NONE); trysneak(player, D_NONE);
@ -7326,6 +7339,10 @@ void msg_real(char *format, ... ) {
if (db) dblog("adding to msgbuf: [%s]",buf); if (db) dblog("adding to msgbuf: [%s]",buf);
if (strstr(buf, "(null)")) {
assert(2 == 3);
}
assert(!strchr(buf, '#')); assert(!strchr(buf, '#'));
// ie. can the message buffer fit: // ie. can the message buffer fit:
// what is already there + 2 spaces + the new text + '--more--' ? // what is already there + 2 spaces + the new text + '--more--' ?
@ -8106,20 +8123,22 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
if (isplayer(lf)) { if (isplayer(lf)) {
int attpoints; int attpoints;
int pct;
attpoints = getattpoints(lf); attpoints = getattpoints(lf);
doheadingsmall(mainwin, y, 0, ftext, "Training"); doheadingsmall(mainwin, y, 0, ftext, "Training");
if ((lf->skillpoints == 0) && (attpoints == 0)) { pct = ((float)lf->skillxp / (float)SKILLXPPERPOINT) * 100.0;
wprintw(mainwin, "n/a"); limit(&pct, 0, 100);
} else { if (lf->skillpoints || attpoints ) {
/* /*
wprintw(mainwin, "%d skill%s, %d attrib%s", lf->skillpoints, wprintw(mainwin, "%d skill%s, %d attrib%s", lf->skillpoints,
(lf->skillpoints == 1) ? "" : "s", (lf->skillpoints == 1) ? "" : "s",
attpoints, attpoints,
(attpoints == 1) ? "" : "s"); (attpoints == 1) ? "" : "s");
*/ */
wprintw(mainwin, "%d skill point%s", lf->skillpoints, wprintw(mainwin, "%d skill point%s, ", lf->skillpoints,
(lf->skillpoints == 1) ? "" : "s"); (lf->skillpoints == 1) ? "" : "s");
} }
wprintw(mainwin, "%d%%", pct);
y++; y++;
} }
} }

529
lf.c
View File

@ -145,10 +145,18 @@ int appearsrandomly(enum RACE rid) {
void awardxpfor(lifeform_t *killed, float pct) { void awardxpfor(lifeform_t *killed, float pct) {
int xpval,xpeach,i,nposs; int xpval,xpeach,i,nposs;
int initialxp;
lifeform_t *poss[MAXCANDIDATES], *l; lifeform_t *poss[MAXCANDIDATES], *l;
int n; int n;
xpval = (int) ((float)calcxp(killed) * (pct/100));
initialxp = calcxp(killed);
assert(initialxp < 10000);
assert(initialxp >= 0);
xpval = (int) ((float)initialxp * (pct/100));
assert(xpval < 10000);
assert(xpval >= 0);
// find all allies on the map // find all allies on the map
nposs = 0; nposs = 0;
@ -3332,7 +3340,7 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) {
interrupt(lf); interrupt(lf);
if (lfhasflag(lf, F_FEIGNINGDEATH)) { if (lfhasflag(lf, F_FEIGNINGDEATH)) {
// don't responsd. // don't respond.
return; return;
} }
@ -3349,7 +3357,6 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) {
killflagsofid(lf->flags, F_ASLEEP); killflagsofid(lf->flags, F_ASLEEP);
// monsters might flee, fight back, etc // monsters might flee, fight back, etc
if (!isplayer(lf)) { if (!isplayer(lf)) {
if (isplayer(attacker) && ishirable(lf)) { if (isplayer(attacker) && ishirable(lf)) {
// can never recruit this person now! // can never recruit this person now!
addflag(lf->flags, F_NOHIRE, B_TRUE, NA, NA, NULL); addflag(lf->flags, F_NOHIRE, B_TRUE, NA, NA, NULL);
@ -3366,6 +3373,10 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) {
if (!isplayer(attacker)) return; if (!isplayer(attacker)) return;
} }
// turn to face our attacker
if (isadjacent(lf->cell, attacker->cell)) {
turntoface(lf, attacker->cell);
}
aiattack(lf, attacker, DEF_AIFOLLOWTIME); aiattack(lf, attacker, DEF_AIFOLLOWTIME);
// any nearby monsters which will help out? // any nearby monsters which will help out?
@ -3651,7 +3662,7 @@ int flee(lifeform_t *lf) {
} }
} }
// move away from them // move away from them
if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE)) { if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE, B_FALSE)) {
if (db) dblog("%s - fleeing by moving away", lfname); if (db) dblog("%s - fleeing by moving away", lfname);
return B_TRUE; return B_TRUE;
} }
@ -3875,6 +3886,9 @@ void gainmp(lifeform_t *lf, int amt) {
void gainxp(lifeform_t *lf, long amt) { void gainxp(lifeform_t *lf, long amt) {
int newskillpoints = 0; int newskillpoints = 0;
int doxp = B_TRUE; int doxp = B_TRUE;
assert(amt >= 0);
if (lfhasflag(lf, F_HASNEWLEVEL) || (lf->level == 0)) { if (lfhasflag(lf, F_HASNEWLEVEL) || (lf->level == 0)) {
doxp = B_FALSE; doxp = B_FALSE;
} }
@ -3882,11 +3896,13 @@ void gainxp(lifeform_t *lf, long amt) {
if (doxp) { if (doxp) {
lf->xp += amt; lf->xp += amt;
if (isplayer(lf)) statdirty = B_TRUE; if (isplayer(lf)) statdirty = B_TRUE;
assert(lf->xp >= 0);
} }
// skill xp // skill xp
if (isplayer(lf)) { if (isplayer(lf)) {
lf->skillxp += amt; lf->skillxp += amt;
assert(lf->skillxp >= 0);
while (lf->skillxp >= SKILLXPPERPOINT) { while (lf->skillxp >= SKILLXPPERPOINT) {
newskillpoints++; newskillpoints++;
lf->skillxp -= SKILLXPPERPOINT; lf->skillxp -= SKILLXPPERPOINT;
@ -3906,6 +3922,221 @@ void gainxp(lifeform_t *lf, long amt) {
} }
} }
int fovlist_contains(int *endx, int *endy, int nendcells, int x, int y) {
int i;
for (i = 0;i < nendcells; i++) {
if ((endx[i] == x) && (endy[i] == y)) {
return B_TRUE;
}
}
return B_FALSE;
}
int get_fov_quad_endpoints(lifeform_t *lf, enum QUADRANT quad, int maxvisrange, int *endx, int *endy, int *nendcells) {
int ix,iy,start,end;
switch (quad) {
case Q_NNE: // n to ne
iy = lf->cell->y - maxvisrange;
start = lf->cell->x;
end = lf->cell->x + maxvisrange;
for (ix = start; ix <= end; ix++) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_ENE: // ne to e
ix = lf->cell->x + maxvisrange;
start = lf->cell->y - maxvisrange;
end = lf->cell->y;
for (iy = start; iy <= end; iy++) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_ESE: // e to se
ix = lf->cell->x + maxvisrange;
start = lf->cell->y;
end = lf->cell->y + maxvisrange;
for (iy = start; iy <= end; iy++) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_SSE: // se to s
iy = lf->cell->y + maxvisrange;
start = lf->cell->x + maxvisrange;
end = lf->cell->x;
for (ix = start; ix >= end; ix--) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_SSW: // s to sw
iy = lf->cell->y + maxvisrange;
start = lf->cell->x;
end = lf->cell->x - maxvisrange;
for (ix = start; ix >= end; ix--) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_WSW: // sw to w
ix = lf->cell->x - maxvisrange;
start = lf->cell->y + maxvisrange;
end = lf->cell->y;
for (iy = start; iy >= end; iy--) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_WNW: // w to nw
ix = lf->cell->x - maxvisrange;
start = lf->cell->y;
end = lf->cell->y - maxvisrange;
for (iy = start; iy >= end; iy--) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_NNW: // nw to n
iy = lf->cell->y - maxvisrange;
start = lf->cell->x - maxvisrange;
end = lf->cell->x;
for (ix = start; ix <= end; ix++) {
if (!fovlist_contains(endx,endy,*nendcells,ix,iy)) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
}
break;
case Q_NONE:
break;
}
return *nendcells;
}
int get_adjacent_quadrants(int dir, enum QUADRANT *start, enum QUADRANT *end) {
switch (dir) {
case DC_N: // nw to ne
if (start) *start = Q_NNW;
if (end) *end = Q_NNE;
break;
case DC_NE: // n to ne, ne to e
if (start) *start = Q_NNE;
if (end) *end = Q_ENE;
break;
case DC_E: // ne to se
if (start) *start = Q_ENE;
if (end) *end = Q_ESE;
break;
case DC_SE: // e to se, se to s
if (start) *start = Q_ESE;
if (end) *end = Q_SSE;
break;
case DC_S: // se to sw
if (start) *start = Q_SSE;
if (end) *end = Q_SSW;
break;
case DC_SW: // s to sw, sw to w
if (start) *start = Q_SSW;
if (end) *end = Q_WSW;
break;
case DC_W: //sw to nw
if (start) *start = Q_WSW;
if (end) *end = Q_WNW;
break;
case DC_NW: // w to nw, nw to n
if (start) *start = Q_WNW;
if (end) *end = Q_NNW;
break;
default:
if (start) *start = Q_NONE;
if (end) *end = Q_NONE;
return B_TRUE;
}
return B_FALSE;
}
int get_circular_fov_endpoints(lifeform_t *lf, int maxvisrange, int *endx, int *endy, int *nendcells) {
int ix,iy,start,end,db = B_FALSE;
*nendcells = 0;
// n
iy = lf->cell->y - maxvisrange;
start = lf->cell->x - maxvisrange;
end = lf->cell->x + maxvisrange;
if (db) dblog("North::%d,%d - %d,%d",start,iy,end,iy);
for (ix = start; ix < end; ix++) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
// e
ix = lf->cell->x + maxvisrange;
start = lf->cell->y - maxvisrange;
end = lf->cell->y + maxvisrange;
if (db) dblog("East::%d,%d - %d,%d",ix,start,ix,end);
for (iy = start; iy < end; iy++) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
// s
iy = lf->cell->y + maxvisrange;
start = lf->cell->x + maxvisrange;
end = lf->cell->x - maxvisrange;
if (db) dblog("South::%d,%d - %d,%d",start,iy,end,iy);
for (ix = start; ix > end; ix--) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
// w
ix = lf->cell->x - maxvisrange;
start = lf->cell->y + maxvisrange;
end = lf->cell->y - maxvisrange;
if (db) dblog("West::%d,%d - %d,%d",ix,start,ix,end);
for (iy = start; iy > end; iy--) {
endx[*nendcells] = ix;
endy[*nendcells] = iy;
(*nendcells)++;
assert(*nendcells < MAXVISLIMIT);
}
return *nendcells;
}
int getactspeed(lifeform_t *lf) { int getactspeed(lifeform_t *lf) {
int speed = 0; int speed = 0;
flag_t *f; flag_t *f;
@ -4741,12 +4972,6 @@ int getfootprinttime(lifeform_t *lf) {
case SZ_ENORMOUS: time += 30; break; case SZ_ENORMOUS: time += 30; break;
} }
if (time > 0) {
if (getskill(lf, SK_PERCEPTION) == PR_EXPERT) {
time /= 2;
limit(&time, 1, NA);
}
}
return time; return time;
} }
@ -5495,7 +5720,6 @@ int getvisrange(lifeform_t *lf, int useambient) {
for (i = 0; i < nretflags; i++) { for (i = 0; i < nretflags; i++) {
switch (retflag[i]->val[0]) { switch (retflag[i]->val[0]) {
case IJ_BLACKEYE: case IJ_BLACKEYE:
case IJ_EYEDESTROYED:
range /= 2; range /= 2;
break; break;
} }
@ -6252,6 +6476,10 @@ object_t *getrestob(lifeform_t *lf) {
// returns proficiency level in a given skill // returns proficiency level in a given skill
enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id) { enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id) {
flag_t *f; flag_t *f;
// special case:
if ((id == SK_CARTOGRAPHY) && lfhasflag(lf, F_RAGE)) {
return PR_INEPT;
}
f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL); f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL);
if (f) { if (f) {
return f->val[1]; return f->val[1];
@ -7008,6 +7236,12 @@ int giveskill(lifeform_t *lf, enum SKILL id) {
newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL);
newf->lifetime = FROMSKILL; newf->lifetime = FROMSKILL;
} }
} else if (id == SK_PERCEPTION) {
if ((f->val[1] == PR_ADEPT) || (f->val[1] == PR_MASTER)) {
// our FOV gets wider
lf->losdirty = B_TRUE;
if (isplayer(lf)) needredraw = B_TRUE;
}
} else if (id == SK_STEALTH) { } else if (id == SK_STEALTH) {
if (f->val[1] == PR_BEGINNER) { if (f->val[1] == PR_BEGINNER) {
newf = addflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); newf = addflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL);
@ -7398,6 +7632,20 @@ job_t *hasjob(lifeform_t *lf, enum JOB job) {
return j; return j;
} }
void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch) {
int i;
for (i = 0; i < abs(howmuch); i++) {
if (start) {
if (*start == Q_NNE) *start = Q_NNW;
else (*start)--;
}
if (end) {
if (*end == Q_NNW) *end = Q_NNE;
else (*end)++;
}
}
}
// where shoudl always be body, hands, legs or head // where shoudl always be body, hands, legs or head
// damtype should be bash or slash // damtype should be bash or slash
int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
@ -7526,7 +7774,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) {
case 1: case 1:
inj = IJ_EYELIDSCRAPED; desc = strdup("eyelid is scraped^accuracy penalty"); break; inj = IJ_EYELIDSCRAPED; desc = strdup("eyelid is scraped^accuracy penalty"); break;
case 2: case 2:
inj = IJ_EYEDESTROYED; desc = strdup("right eye is destroyed^permenant vision loss"); inj = IJ_EYEDESTROYED; desc = strdup("right eye is destroyed^field of view halved");
howlong = PERMENANT; howlong = PERMENANT;
break; break;
@ -8271,6 +8519,7 @@ void initjobs(void) {
} }
} }
addflag(lastjob->flags, F_NOSCORE, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_NOSCORE, B_TRUE, NA, NA, NULL);
addflag(lastjob->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addjob(J_ADVENTURER, "Adventurer"); addjob(J_ADVENTURER, "Adventurer");
// stats // stats
@ -8584,7 +8833,7 @@ void initjobs(void) {
addflag(lastjob->flags, F_EXTRALUCK, B_TRUE, 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_HASPET, NA, NA, NA, "young hawk");
addflag(lastjob->flags, F_MAXATTACKS, 2, 2, NA, NULL);// this is so that our hookhand works addflag(lastjob->flags, F_MAXATTACKS, 2, 2, NA, NULL);// this is so that our hookhand works
addflag(lastjob->flags, F_VISRANGEMOD, -4, NA, NA, NULL); addflag(lastjob->flags, F_INJURY, IJ_EYEDESTROYED, NA, NA, NULL);
// also: has a hook instead of fists. // also: has a hook instead of fists.
addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL);
@ -8647,7 +8896,6 @@ void initjobs(void) {
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "helmet"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "helmet");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "suit of ring mail"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "suit of ring mail");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of gauntlets"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of gauntlets");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "set of greaves");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of metal boots"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of metal boots");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler");
addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10-20 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10-20 gold coins");
@ -9174,7 +9422,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, 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_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+5"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+5");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, 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_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4+1"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4+1");
@ -9442,7 +9690,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SIZE, SZ_HUMAN, 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_DUNGEON, 72, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, 72, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 72, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "8d4"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "8d4");
addflag(lastrace->flags, F_ARMOURRATING, 9, 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_EVASION, 10, NA, NA, NULL);
@ -9470,7 +9718,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_FOREST, 68, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 68, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4");
addflag(lastrace->flags, F_ARMOURRATING, 9, 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_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_EVASION, 0, 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_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
@ -9500,7 +9748,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_FOREST, 65, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 65, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "10d4"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "10d4");
addflag(lastrace->flags, F_ARMOURRATING, 9, 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_ENHANCESMELL, 4, NA, NA, NULL);
addflag(lastrace->flags, F_EVASION, 0, 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_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, "");
@ -9787,12 +10035,11 @@ void initrace(void) {
addflag(lastrace->flags, F_HOSTILE, 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_SIZE, SZ_LARGE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 62, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 62, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_HATESRACE, R_GNOLL, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACE, R_GNOLL, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4+3"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4+3");
addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STAYINROOM, NA, NA, NA, NULL); // stay in our maze addflag(lastrace->flags, F_STAYINROOM, NA, NA, NA, NULL); // stay in our maze
addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "5-7"); addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "5-7");
@ -10018,7 +10265,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 4, NA, "screams in pain^screams of pain"); 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_RESISTMAG, 5, NA, NA, NULL);
addflag(lastrace->flags, F_MORALE, 25, 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_ENHANCESMELL, 3, NA, NA, NULL);
addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL);
addrace(R_POLTERGEIST, "poltergeist", 50, 'p', C_GREEN, MT_FLESH, RC_UNDEAD); // sPirit addrace(R_POLTERGEIST, "poltergeist", 50, 'p', C_GREEN, MT_FLESH, RC_UNDEAD); // sPirit
@ -10088,7 +10335,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_SMALL, 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_RARITY, H_DUNGEON, 65, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+3"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+3");
addflag(lastrace->flags, F_EVASION, 40, NA, 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_MOVESPEED, SP_NORMAL, NA, NA, NULL);
@ -10207,7 +10454,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+0"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+0");
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, 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_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 3, NA, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL);
addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL);
@ -10436,7 +10683,7 @@ void initrace(void) {
addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL);
addflag(lastrace->flags, F_MATVULN, MT_SILVER, 200, NA, NULL); addflag(lastrace->flags, F_MATVULN, MT_SILVER, 200, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL); 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_HOSTILE, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL);
@ -10446,7 +10693,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3");
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, 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_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, 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_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_HASATTACK, OT_TEETH, NA, NA, "1d6");
@ -10469,7 +10716,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4+5"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4+5");
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, 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_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, 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_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_HASATTACK, OT_TEETH, NA, NA, "1d8");
@ -10493,7 +10740,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3");
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, 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_ACTIONSPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, 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_HASATTACK, OT_CLAWS, NA, NA, "1d4"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
@ -10525,7 +10772,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL);
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_ANT; lastrace->baseid = R_ANT;
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -10549,7 +10796,7 @@ void initrace(void) {
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "giant worker ant"); addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "giant worker ant");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
addrace(R_ANTLION, "giant antlion", 30, 'a', C_YELLOW, MT_FLESH, RC_ANIMAL); addrace(R_ANTLION, "giant antlion", 30, 'a', C_YELLOW, MT_FLESH, RC_ANIMAL);
lastrace->baseid = R_ANT; lastrace->baseid = R_ANT;
addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
@ -10573,7 +10820,7 @@ void initrace(void) {
addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL);
addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
addrace(R_CHICKEN, "chicken", 0.5, 'c', C_BROWN, MT_FLESH, RC_ANIMAL); addrace(R_CHICKEN, "chicken", 0.5, 'c', C_BROWN, MT_FLESH, RC_ANIMAL);
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, 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_SIZE, SZ_SMALL, NA, NA, NULL);
@ -10599,7 +10846,7 @@ void initrace(void) {
addflag(lastrace->flags, F_RARITY, H_VILLAGE, 100, NA, NULL); addflag(lastrace->flags, F_RARITY, H_VILLAGE, 100, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_FOREST, 82, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 82, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
addflag(lastrace->flags, F_MAXATTACKS, 1, 2, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 1, 2, NA, NULL);
@ -10623,7 +10870,7 @@ void initrace(void) {
addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 77, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 77, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 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_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+3"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+3");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6");
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
@ -10661,7 +10908,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, 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_HANDS, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, B_TRUE, 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_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 5, 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_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining");
addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "howls^a howl"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "howls^a howl");
@ -10686,7 +10933,7 @@ void initrace(void) {
addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, 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_SHOULDERS, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_NOSPELLS, 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_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL);
addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL);
@ -10709,7 +10956,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d2"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d2");
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 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_EVASION, 10, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, 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_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
@ -10737,7 +10984,7 @@ void initrace(void) {
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, "1d3"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3");
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, 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_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
@ -10766,7 +11013,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3+3"); 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_HASATTACK, OT_TEETH, NA, NA, "1d4+3");
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, 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_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
@ -10791,7 +11038,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+5"); 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_EXTRADAM, DT_COLD, NA, NA, "1d6");
addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, 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_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
@ -10828,7 +11075,7 @@ void initrace(void) {
addflag(lastrace->flags, F_SILENTMOVE, 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_CHARGE, NA, NA, "range:4;");
addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:0d1+4;"); addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:0d1+4;");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addrace(R_NEWT, "giant newt", 4, ':', C_BROWN, MT_FLESH, RC_ANIMAL); 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_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL);
@ -10876,7 +11123,7 @@ void initrace(void) {
addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2");
addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3");
addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL);
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, 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_SECWEAPON, NA, NA, NULL);
addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL);
@ -11135,7 +11382,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL);
addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, 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_MOVESPEED, SP_NORMAL, NA, NA, "");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 97, NA, ""); addflag(lastrace->flags, F_RARITY, H_FOREST, 97, NA, "");
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+2"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+2");
@ -11159,7 +11406,7 @@ void initrace(void) {
addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, 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_SIZE, SZ_MEDIUM, NA, NA, NULL);
addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, "");
addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL);
addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, "");
addflag(lastrace->flags, F_RARITY, H_FOREST, 90, NA, ""); addflag(lastrace->flags, F_RARITY, H_FOREST, 90, NA, "");
addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3"); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3");
@ -12213,6 +12460,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) {
a->polyrevert = B_FALSE; a->polyrevert = B_FALSE;
// for precalcing line of sight // for precalcing line of sight
a->facing = rnd(DC_N, DC_NW);
a->losdirty = B_TRUE; a->losdirty = B_TRUE;
a->nlos = 0; a->nlos = 0;
//a->los = malloc(sizeof(cell_t *) * MAXVISRANGE); //a->los = malloc(sizeof(cell_t *) * MAXVISRANGE);
@ -12391,19 +12639,14 @@ void addtrail(lifeform_t *lf, int dir) {
// footprints first // footprints first
if (!isairborne(lf) && !lfhasflag(lf, F_NONCORPOREAL)) { if (!isairborne(lf) && !lfhasflag(lf, F_NONCORPOREAL)) {
int fpdir; int fpdir;
enum SKILLLEVEL slev;
slev = getskill(lf, SK_PERCEPTION); if (getskill(lf, SK_PERCEPTION) >= PR_EXPERT) {
if (slev == PR_MASTER) {
// no footprints! // no footprints!
return; return;
} else if (slev == PR_EXPERT) {
fpdir = D_NONE;
} else { } else {
fpdir = dir; fpdir = dir;
} }
footprint = hastrailof(lf->cell->obpile, lf, OT_FOOTPRINT, &fpflag, NULL); footprint = hastrailof(lf->cell->obpile, lf, OT_FOOTPRINT, &fpflag, NULL);
if (footprint) { if (footprint) {
assert(fpflag); assert(fpflag);
@ -13893,7 +14136,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
dist = getcelldist(l->cell, c); dist = getcelldist(l->cell, c);
// listen check difficulty is based on sound distance vs max hearing distance // listen check difficulty is based on sound distance vs max hearing distance
if (nt == NC_SPEECH) { if ((nt == NC_SPEECH) && isplayer(l)) {
// you always hear it, as long as you're in range // you always hear it, as long as you're in range
difficulty = 0; difficulty = 0;
} else { } else {
@ -14010,7 +14253,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
practice(l, SK_LISTEN, 1); practice(l, SK_LISTEN, 1);
} }
} }
} } // end if !isplayer and not asleep
// wake up a little // wake up a little
f = lfhasflag(l, F_ASLEEP); f = lfhasflag(l, F_ASLEEP);
@ -14028,7 +14271,6 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
} else { } else {
// ie resting on purpose via 'R' // ie resting on purpose via 'R'
// only wake up if the sound if very close // only wake up if the sound if very close
//if (getcelldist(c, l->cell) == 1) {
if (volume >= getcelldist(c, l->cell)) { if (volume >= getcelldist(c, l->cell)) {
// wake up! // wake up!
if (isplayer(l)) { if (isplayer(l)) {
@ -14056,8 +14298,27 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha
isplayer(l) ? "your" : "its"); isplayer(l) ? "your" : "its");
} }
} }
} else { // not alseep
// monsters will turn to face the sound, as long as they're
// not attacking something
if (!isplayer(l)) {
flag_t *f;
int willrespond = B_FALSE;
f = aihastarget(l);
if (f && (f->id == F_TARGETLF)) {
// might ignore the sound...
if (pctchance(volume*20)) {
willrespond = B_TRUE;
}
} else willrespond = B_TRUE;
if (willrespond) {
// turn to face the sound
turntoface(l, c);
}
}
} }
} } // end for each lf on map
return rv; return rv;
} }
@ -14349,14 +14610,14 @@ void precalclos_new(lifeform_t *lf) {
cell_t **los; cell_t **los;
int *blocker; int *blocker;
int nlos = 0,i,nn; int nlos = 0,i,nn;
int ix,iy;
flag_t *f; flag_t *f;
cell_t *endcell[MAXVISLIMIT]; int endx[MAXVISLIMIT],endy[MAXVISLIMIT];
int nendcells = 0; int nendcells = 0;
cell_t *retcell[MAXRETCELLS]; cell_t *retcell[MAXRETCELLS];
int numpixels; int numpixels;
int db = B_FALSE; //int db = B_FALSE;
int start,end; enum SKILLLEVEL plev;
flag_t *missingeye,*enhancesmell;
f = hasflag(lf->flags, F_XRAYVIS); f = hasflag(lf->flags, F_XRAYVIS);
if (f) { if (f) {
@ -14365,6 +14626,13 @@ void precalclos_new(lifeform_t *lf) {
startxray = 0; startxray = 0;
} }
// right eye missing?
missingeye = lfhasflagval(lf, F_INJURY, IJ_EYEDESTROYED, NA, NA, NULL);
// enhanced smell means we can "see" lifeforms and "smelly" objects in all
// directions.
enhancesmell = lfhasflag(lf, F_ENHANCESMELL);
los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH));
blocker = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); blocker = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH));
@ -14375,79 +14643,36 @@ void precalclos_new(lifeform_t *lf) {
maxvisrange = getvisrange(lf, B_FALSE); maxvisrange = getvisrange(lf, B_FALSE);
nightvisrange = getnightvisrange(lf); nightvisrange = getnightvisrange(lf);
plev = getskill(lf, SK_PERCEPTION);
// find all cells at max fov // find all cells at max fov
nendcells = 0; nendcells = 0;
// n if (MAXOF(maxvisrange, nightvisrange) == 0) {
iy = lf->cell->y - maxvisrange; } else if (lf->facing == D_ALL) {
limit(&iy,0,lf->cell->map->h-1); get_circular_fov_endpoints(lf, maxvisrange, endx, endy, &nendcells);
start = lf->cell->x - maxvisrange; } else {
end = lf->cell->x + maxvisrange; enum QUADRANT startq, endq,curq;
limit(&start,0,lf->cell->map->w-1);
limit(&end,0,lf->cell->map->w-1);
if (db) dblog("North::%d,%d - %d,%d",start,iy,end,iy);
for (ix = start; ix < end; ix++) {
c = getcellat(lf->cell->map, ix, iy);
if (c) {
if (db) dblog("N:endcell[%d] = %d,%d",nendcells,c->x, c->y);
endcell[nendcells++] = c;
}
assert(nendcells < MAXVISLIMIT);
}
// e
ix = lf->cell->x + maxvisrange;
limit(&ix,0,lf->cell->map->w-1);
start = lf->cell->y - maxvisrange;
end = lf->cell->y + maxvisrange;
limit(&start,0,lf->cell->map->h-1);
limit(&end,0,lf->cell->map->h-1);
if (db) dblog("East::%d,%d - %d,%d",ix,start,ix,end);
for (iy = start; iy < end; iy++) {
c = getcellat(lf->cell->map, ix, iy);
if (c) {
if (db) dblog("E:endcell[%d] = %d,%d",nendcells,c->x, c->y);
endcell[nendcells++] = c;
}
assert(nendcells < MAXVISLIMIT);
}
// s
iy = lf->cell->y + maxvisrange;
limit(&iy,0,lf->cell->map->h-1);
start = lf->cell->x + maxvisrange;
end = lf->cell->x - maxvisrange;
limit(&start,0,lf->cell->map->w-1);
limit(&end,0,lf->cell->map->w-1);
if (db) dblog("South::%d,%d - %d,%d",start,iy,end,iy);
for (ix = start; ix > end; ix--) {
c = getcellat(lf->cell->map, ix, iy);
if (c) {
if (db) dblog("S:endcell[%d] = %d,%d",nendcells,c->x, c->y);
endcell[nendcells++] = c;
}
assert(nendcells < MAXVISLIMIT);
}
// w
ix = lf->cell->x - maxvisrange;
limit(&ix,0,lf->cell->map->w-1);
start = lf->cell->y + maxvisrange;
end = lf->cell->y - maxvisrange;
limit(&start,0,lf->cell->map->h-1);
limit(&end,0,lf->cell->map->h-1);
if (db) dblog("West::%d,%d - %d,%d",ix,start,ix,end);
for (iy = start; iy > end; iy--) {
c = getcellat(lf->cell->map, ix, iy);
if (c) {
if (db) dblog("W:endcell[%d] = %d,%d",nendcells,c->x, c->y);
endcell[nendcells++] = c;
}
assert(nendcells < MAXVISLIMIT);
}
if (!get_adjacent_quadrants(lf->facing, &startq, &endq)) {
if (missingeye) endq = startq; // ie. lose the right hand one
if (plev >= PR_MASTER) inc_quad_range(&startq, missingeye ? NULL : &endq, 2);
else if (plev >= PR_ADEPT) inc_quad_range(&startq, missingeye ? NULL : &endq, 1);
curq = startq;
get_fov_quad_endpoints(lf, curq, maxvisrange, endx, endy, &nendcells);
while (curq != endq) {
if (curq == Q_NNW) curq = Q_NNE;
else curq++;
get_fov_quad_endpoints(lf, curq, maxvisrange, endx, endy, &nendcells);
}
}
} // end if facing == all
assert(nendcells < MAXVISLIMIT); assert(nendcells < MAXVISLIMIT);
// look in circle around lf // look in the lf's field of vision arc
//for (ang = 0; ang < 360; ang += 30) { //for (ang = 0; ang < 360; ang += 30) {
for (nn = 0; nn < nendcells; nn++) { for (nn = 0; nn < nendcells; nn++) {
int keepgoing = B_TRUE; int keepgoing = B_TRUE;
@ -14460,7 +14685,7 @@ void precalclos_new(lifeform_t *lf) {
xray = startxray; xray = startxray;
currange = 0; currange = 0;
// calc path to end cell // calc path to end cell
calcbresnham(lf->cell->map, lf->cell->x, lf->cell->y, endcell[nn]->x, endcell[nn]->y, retcell, &numpixels ); calcbresnham(lf->cell->map, lf->cell->x, lf->cell->y, endx[nn], endy[nn], retcell, &numpixels );
// keep going until we lose los // keep going until we lose los
for (n = 0; keepgoing && (n < numpixels); n++) { for (n = 0; keepgoing && (n < numpixels); n++) {
/* /*
@ -14507,16 +14732,39 @@ void precalclos_new(lifeform_t *lf) {
blocker[nlos] = keepgoing ? B_FALSE : B_TRUE; blocker[nlos] = keepgoing ? B_FALSE : B_TRUE;
nlos++; nlos++;
} }
// TODO: remember if we saw any _lit_ cells
} }
} else { // ie. if !c } else { // ie. if !c
keepgoing = B_FALSE; keepgoing = B_FALSE;
} }
} // end foreach cell and while keepgoing } // end foreach cell and while keepgoing
} }
assert(nlos < (MAX_MAPW * MAX_MAPH)); assert(nlos < (MAX_MAPW * MAX_MAPH));
// deal with enhanced smell - do a second sweep in all directions.
if (enhancesmell) {
int n;
get_circular_fov_endpoints(lf, enhancesmell->val[0], endx, endy, &nendcells);
for (i = 0;i < nendcells; i++) {
calcbresnham(lf->cell->map, lf->cell->x, lf->cell->y, endx[i], endy[i], retcell, &numpixels );
// keep going until we lose los
for (n = 0; n < numpixels; n++) {
if ((retcell[n]->lf && (retcell[n]->lf->race->raceclass->id != RC_UNDEAD)) ||
hasobwithflag(retcell[n]->obpile, F_SMELLY) ) { // && (endcell[i]->lf != lf)) {
int nn,found = B_FALSE;
for (nn = 0; nn < nlos; nn++) { // can we already see this cell?
if (los[nn] == retcell[n]) {
found = B_TRUE; break;
}
}
if (!found) {
los[nlos++] = retcell[n];
}
}
}
}
}
// now fill in lifeform structure // now fill in lifeform structure
lf->los = malloc(sizeof(cell_t *) * nlos); lf->los = malloc(sizeof(cell_t *) * nlos);
for (i = 0; i < nlos; i++) { for (i = 0; i < nlos; i++) {
@ -15110,6 +15358,16 @@ void setattr(lifeform_t *lf, enum ATTRIB attr, int val) {
} }
} }
int setfacing(lifeform_t *lf, int dir) {
if (lf->facing == dir) { // already facing that way
return B_TRUE;
}
lf->facing = dir;
lf->losdirty = B_TRUE;
if (isplayer(lf)) needredraw = B_TRUE;
return B_FALSE;
}
void setfollowdistance(lifeform_t *lf, int min, int max) { void setfollowdistance(lifeform_t *lf, int min, int max) {
flag_t *f; flag_t *f;
f = lfhasflag(lf, F_FOLLOWRANGE); f = lfhasflag(lf, F_FOLLOWRANGE);
@ -15406,12 +15664,13 @@ void initskills(void) {
addskilldesc(SK_BACKSTAB, PR_EXPERT, "^gYour unseen attacks inflict 6x damage.", B_FALSE); addskilldesc(SK_BACKSTAB, PR_EXPERT, "^gYour unseen attacks inflict 6x damage.", B_FALSE);
addskilldesc(SK_BACKSTAB, PR_MASTER, "^gYour unseen attacks inflict 7x damage.", B_FALSE); addskilldesc(SK_BACKSTAB, PR_MASTER, "^gYour unseen attacks inflict 7x damage.", B_FALSE);
addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps.", 0); // untrainable addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps.", 0); // untrainable
addskilldesc(SK_CARTOGRAPHY, PR_NOVICE, "^gYou now make basic maps of your surroundings.", B_TRUE); addskilldesc(SK_CARTOGRAPHY, PR_INEPT, "- Without this skill, you will quickly forget your surroundings.", B_FALSE);
addskilldesc(SK_CARTOGRAPHY, PR_BEGINNER, "^gYour map now shows the location of staircases.", B_TRUE); addskilldesc(SK_CARTOGRAPHY, PR_NOVICE, "^gYou can now remember the basics of your surroundings.", B_TRUE);
addskilldesc(SK_CARTOGRAPHY, PR_ADEPT, "^gYour map now shows the location of doors.", B_TRUE); addskilldesc(SK_CARTOGRAPHY, PR_BEGINNER, "^gYou can now remember the location of staircases.", B_TRUE);
addskilldesc(SK_CARTOGRAPHY, PR_ADEPT, "^gYour can now remember the location of doors.", B_TRUE);
addskilldesc(SK_CARTOGRAPHY, PR_SKILLED, "^gYou no longer forget your surroundings.", B_FALSE); addskilldesc(SK_CARTOGRAPHY, PR_SKILLED, "^gYou no longer forget your surroundings.", B_FALSE);
addskilldesc(SK_CARTOGRAPHY, PR_EXPERT, "^gYour map will now show the location of objects.", B_TRUE); addskilldesc(SK_CARTOGRAPHY, PR_EXPERT, "^gYour can now remember the location of objects.", B_TRUE);
addskilldesc(SK_CARTOGRAPHY, PR_MASTER, "^gEvery 50 turns, you can map a small area around you.", B_FALSE); addskilldesc(SK_CARTOGRAPHY, PR_MASTER, "^gEvery 50 turns, you can intuitively map a small area around you.", B_FALSE);
addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.", 0); // untrainable addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.", 0); // untrainable
addskilldesc(SK_CHANNELING, PR_NOVICE, "^gThe power level of wands and scrolls is increased by 1.", B_FALSE); addskilldesc(SK_CHANNELING, PR_NOVICE, "^gThe power level of wands and scrolls is increased by 1.", B_FALSE);
addskilldesc(SK_CHANNELING, PR_BEGINNER, "^gThe power level of wands and scrolls is increased by 2.", B_FALSE); addskilldesc(SK_CHANNELING, PR_BEGINNER, "^gThe power level of wands and scrolls is increased by 2.", B_FALSE);
@ -15465,7 +15724,7 @@ void initskills(void) {
addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can repair cloth items up to 70% condition", B_FALSE); addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can repair cloth items up to 70% condition", B_FALSE);
addskilldesc(SK_SEWING, PR_EXPERT, "^gYou can repair cloth items up to 85% condition", B_FALSE); addskilldesc(SK_SEWING, PR_EXPERT, "^gYou can repair cloth items up to 85% condition", B_FALSE);
addskilldesc(SK_SEWING, PR_MASTER, "^gYou can fully repair cloth items.", B_FALSE); addskilldesc(SK_SEWING, PR_MASTER, "^gYou can fully repair cloth items.", B_FALSE);
addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block projectiles.", 50); addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block attacks.", 50);
addskilldesc(SK_SHIELDS, PR_INEPT, "- Without this skill, shield accuracy penalties are tripled.", B_FALSE); addskilldesc(SK_SHIELDS, PR_INEPT, "- Without this skill, shield accuracy penalties are tripled.", B_FALSE);
addskilldesc(SK_SHIELDS, PR_NOVICE, "^gShield accuracy penalties are reduced by 5%.", B_FALSE); addskilldesc(SK_SHIELDS, PR_NOVICE, "^gShield accuracy penalties are reduced by 5%.", B_FALSE);
addskilldesc(SK_SHIELDS, PR_BEGINNER, "^gShield accuracy penalties are reduced by 10%.", B_FALSE); addskilldesc(SK_SHIELDS, PR_BEGINNER, "^gShield accuracy penalties are reduced by 10%.", B_FALSE);
@ -15487,9 +15746,10 @@ void initskills(void) {
addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now see footprints.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now see footprints.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_BEGINNER, "^gYou can now determine how recently footprints were made.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_BEGINNER, "^gYou can now determine how recently footprints were made.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYou can now identify creatures from their footprints.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYou can now identify creatures from their footprints.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYour field of vision is now wider.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_SKILLED, "^gYou can now recognise the direction of footprints.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_SKILLED, "^gYou can now recognise the direction of footprints.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_EXPERT, "^gYou can now partially obscure your own footprints.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_EXPERT, "^gYou can now move without leaving footprints.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou can now move without leaving footprints.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou now have perception of your blind spots.", B_TRUE);
addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable? addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable?
addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou gain the 'hide' ability.", B_FALSE); addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou gain the 'hide' ability.", B_FALSE);
addskilldesc(SK_STEALTH, PR_EXPERT, "^gYou can now hide even when monsters are nearby.", B_TRUE); addskilldesc(SK_STEALTH, PR_EXPERT, "^gYou can now hide even when monsters are nearby.", B_TRUE);
@ -17545,6 +17805,11 @@ int touch(lifeform_t *lf, object_t *o) {
return B_FALSE; return B_FALSE;
} }
void turntoface(lifeform_t *lf, cell_t *dstcell) {
setfacing(lf, getdirtowards(lf->cell, dstcell, lf, B_FALSE, DT_COMPASS) );
}
void unsummon(lifeform_t *lf, int vanishobs) { void unsummon(lifeform_t *lf, int vanishobs) {
lifeform_t *creator = NULL; lifeform_t *creator = NULL;
flag_t *f; flag_t *f;

6
lf.h
View File

@ -88,12 +88,15 @@ skill_t *findskillbyname(char *name);
enum SKILLLEVEL findskilllevbyname(char *name); enum SKILLLEVEL findskilllevbyname(char *name);
int flee(lifeform_t *lf); int flee(lifeform_t *lf);
void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose); void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose);
int fovlist_contains(int *endx, int *endy, int nendcells, int x, int y);
int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong); int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong);
void gainhp(lifeform_t *lf, int amt); void gainhp(lifeform_t *lf, int amt);
void gainlevel(lifeform_t *lf); void gainlevel(lifeform_t *lf);
void gainmp(lifeform_t *lf, int amt); void gainmp(lifeform_t *lf, int amt);
void gainxp(lifeform_t *lf, long amt); void gainxp(lifeform_t *lf, long amt);
void genxplist(void); void genxplist(void);
int get_adjacent_quadrants(int dir, enum QUADRANT *start, enum QUADRANT *end);
int get_circular_fov_endpoints(lifeform_t *lf, int maxvisrange, int *endx, int *endy, int *nendcells);
int getactspeed(lifeform_t *lf); int getactspeed(lifeform_t *lf);
int getadjenemies(lifeform_t *lf, lifeform_t **adjlf, int *nadjlfs); int getadjenemies(lifeform_t *lf, lifeform_t **adjlf, int *nadjlfs);
void getwhowillfollow(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *nadjallies); void getwhowillfollow(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *nadjallies);
@ -214,6 +217,7 @@ map_t *gotolev(lifeform_t *lf, int depth, object_t *fromstairs);
int gotosleep(lifeform_t *lf, int onpurpose); int gotosleep(lifeform_t *lf, int onpurpose);
int hasfreeaction(lifeform_t *lf); int hasfreeaction(lifeform_t *lf);
job_t *hasjob(lifeform_t *lf, enum JOB job); job_t *hasjob(lifeform_t *lf, enum JOB job);
void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch);
int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype); int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype);
int lfcanbestoned(lifeform_t *lf); int lfcanbestoned(lifeform_t *lf);
flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid); flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid);
@ -314,6 +318,7 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t
int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus); int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus);
//int setammo(lifeform_t *lf, object_t *o); //int setammo(lifeform_t *lf, object_t *o);
void setattr(lifeform_t *lf, enum ATTRIB attr, int val); void setattr(lifeform_t *lf, enum ATTRIB attr, int val);
int setfacing(lifeform_t *lf, int dir);
void setfollowdistance(lifeform_t *lf, int min, int max); void setfollowdistance(lifeform_t *lf, int min, int max);
void setguntarget(lifeform_t *lf, lifeform_t *targ); void setguntarget(lifeform_t *lf, lifeform_t *targ);
void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph); void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph);
@ -343,6 +348,7 @@ int throwat(lifeform_t *thrower, object_t *o, cell_t *where);
void timeeffectslf(lifeform_t *lf); void timeeffectslf(lifeform_t *lf);
int tryclimb(lifeform_t *lf, cell_t *where, char *towhat); int tryclimb(lifeform_t *lf, cell_t *where, char *towhat);
int touch(lifeform_t *lf, object_t *o); int touch(lifeform_t *lf, object_t *o);
void turntoface(lifeform_t *lf, cell_t *dstcell);
void unpoison(lifeform_t *lf); void unpoison(lifeform_t *lf);
void unsummon(lifeform_t *lf, int vanishobs); void unsummon(lifeform_t *lf, int vanishobs);
int unweild(lifeform_t *lf, object_t *o); int unweild(lifeform_t *lf, object_t *o);

58
map.c
View File

@ -60,6 +60,7 @@ cell_t *addcell(map_t *m, int x, int y) {
cell->origlittimer = 0; cell->origlittimer = 0;
cell->writing = NULL; cell->writing = NULL;
cell->known = B_FALSE; cell->known = B_FALSE;
cell->knowntime = 0;
cell->knownglyph.ch = ' '; cell->knownglyph.ch = ' ';
cell->knownglyph.colour = C_GREY; cell->knownglyph.colour = C_GREY;
cell->visited = B_FALSE; cell->visited = B_FALSE;
@ -397,7 +398,9 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int
ot = NULL; ot = NULL;
} }
if (ot) { if (ot) {
addobfast(lf->pack, ot->id); object_t *o;
o = addobfast(lf->pack, ot->id);
if (o) turnon(NULL, o);
} }
} }
} }
@ -3871,7 +3874,6 @@ void forgetcells(map_t *map, int amt) {
poss[nposs] = c; poss[nposs] = c;
nposs++; nposs++;
} }
} }
if (amtleft > nposs) amtleft = nposs; if (amtleft > nposs) amtleft = nposs;
@ -5098,39 +5100,37 @@ void setcellknown(cell_t *cell, int forcelev) {
slev = getskill(player, SK_CARTOGRAPHY); slev = getskill(player, SK_CARTOGRAPHY);
} }
// photographic memory counts as novice level cell->known = B_TRUE;
if ((slev == PR_INEPT) && lfhasflag(player, F_PHOTOMEM)) { // default to remembering the cell's glyph
slev = PR_NOVICE; cell->knownglyph = cell->type->glyph;
} // high cartography skill lets us remember certain objects...
if (slev >= PR_EXPERT) {
o = gettopobject(cell, B_TRUE);
if (slev >= PR_NOVICE) { if (o) {
cell->known = B_TRUE; cell->knownglyph = *(getglyph(o));
// default to remembering the cell's glyph
cell->knownglyph = cell->type->glyph;
// high cartography skill lets us remember certain objects...
if (slev >= PR_EXPERT) {
o = gettopobject(cell, B_TRUE);
if (o) {
cell->knownglyph = *(getglyph(o));
}
} }
if (slev >= PR_ADEPT) { }
for (o = cell->obpile->first ; o ; o = o->next) { if (slev >= PR_ADEPT) {
if ((o->type->obclass->id == OC_DFEATURE) || (o->type->obclass->id == OC_TERRAIN)) { for (o = cell->obpile->first ; o ; o = o->next) {
if (!issecretdoor(o)) { if ((o->type->obclass->id == OC_DFEATURE) || (o->type->obclass->id == OC_TERRAIN)) {
cell->knownglyph = *(getglyph(o)); if (!issecretdoor(o)) {
} cell->knownglyph = *(getglyph(o));
} }
} }
} }
if (slev >= PR_BEGINNER) { }
o = hasobwithflag(cell->obpile, F_CLIMBABLE); if (slev >= PR_BEGINNER) {
if (o) { o = hasobwithflag(cell->obpile, F_CLIMBABLE);
cell->knownglyph = *(getglyph(o)); if (o) {
} cell->knownglyph = *(getglyph(o));
} }
} }
if (slev == PR_INEPT) {
cell->knowntime = getattr(player, A_IQ)*3;
} else {
cell->knowntime = PERMENANT;
}
//getcellglyph(&(cell->knownglyph), cell, player); //getcellglyph(&(cell->knownglyph), cell, player);
} }

62
move.c
View File

@ -345,6 +345,17 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
return B_TRUE; return B_TRUE;
} }
int getrelativedir(lifeform_t *lf, int dir) {
int diff;
diff = abs(lf->facing - dir);
if (diff <= 1) {
return RD_FORWARDS;
} else if (diff == 2) {
return RD_SIDEWAYS;
}
return RD_BACKWARDS;
}
int diropposite(int dir) { int diropposite(int dir) {
switch (dir) { switch (dir) {
case D_N: case D_N:
@ -427,7 +438,7 @@ int dorandommove(lifeform_t *lf, int badmovesok, int restonfail) {
} }
} }
} }
return trymove(lf, dir, B_TRUE); return trymove(lf, dir, B_TRUE, B_FALSE);
} }
@ -702,7 +713,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
if ((i == 0) && seen) { if ((i == 0) && seen) {
msg("%s %s knocked backwards!",lfname,is(lf)); msg("%s %s knocked backwards!",lfname,is(lf));
} }
trymove(lf, dir, B_FALSE); trymove(lf, dir, B_FALSE, B_FALSE);
} }
if (reason != E_OK) { if (reason != E_OK) {
@ -796,7 +807,7 @@ int makeorthogonal(int dir) {
} }
// see 'movetowards' for description of dirtype // see 'movetowards' for description of dirtype
int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof ) { int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe ) {
int dir; int dir;
int rv = B_TRUE; int rv = B_TRUE;
@ -810,7 +821,7 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof ) {
if (dir == D_NONE) { if (dir == D_NONE) {
rv = B_TRUE; rv = B_TRUE;
} else { } else {
rv = trymove(lf, dir, B_TRUE); rv = trymove(lf, dir, B_TRUE, strafe);
} }
return rv; return rv;
} }
@ -1442,11 +1453,16 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
// use compass/dt_compass for involuntary movement (eg. being knocked back by // use compass/dt_compass for involuntary movement (eg. being knocked back by
// an explosion) // an explosion)
// //
int movetowards(lifeform_t *lf, cell_t *dst, int dirtype) { int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe) {
int dir; int dir;
int rv = B_TRUE; int rv = B_TRUE;
int db = B_FALSE;
if (lfhasflag(lf, F_DEBUG)) db = B_TRUE;
if (isblind(lf)) { if (isblind(lf)) {
if (db) dblog(".oO { i am blind - movetorwards calling dorandommove. }");
dorandommove(lf, B_TRUE, B_TRUE); dorandommove(lf, B_TRUE, B_TRUE);
return B_FALSE; return B_FALSE;
} }
@ -1454,7 +1470,8 @@ int movetowards(lifeform_t *lf, cell_t *dst, int dirtype) {
// move towards them // move towards them
dir = getdirtowards(lf->cell, dst, lf, B_TRUE, dirtype); dir = getdirtowards(lf->cell, dst, lf, B_TRUE, dirtype);
if (dir != D_NONE) { if (dir != D_NONE) {
rv = trymove(lf, dir, B_TRUE); if (db) dblog(".oO { dir from %d,%d -> %d,%d is %s }", lf->cell->x, lf->cell->y, dst->x, dst->y, getdirname(dir));
rv = trymove(lf, dir, B_TRUE, strafe);
} }
return rv; return rv;
} }
@ -1757,7 +1774,7 @@ int closedoor(lifeform_t *lf, object_t *o) {
} }
int tryrun(lifeform_t *lf, int dir) { int tryrun(lifeform_t *lf, int dir) {
if (!trymove(lf, dir, B_TRUE)) { if (!trymove(lf, dir, B_TRUE, B_TRUE)) {
// success! // success!
addflag(lf->flags, F_RUNNING, dir, B_FALSE, NA, NULL); addflag(lf->flags, F_RUNNING, dir, B_FALSE, NA, NULL);
} }
@ -1778,7 +1795,7 @@ int trysneak(lifeform_t *lf, int dir) {
} }
} }
addflag(lf->flags, F_SNEAK, NA, NA, NA, NULL); addflag(lf->flags, F_SNEAK, NA, NA, NA, NULL);
trymove(lf, dir, B_TRUE); trymove(lf, dir, B_TRUE, B_FALSE);
killflagsofid(lf->flags, F_SNEAK); killflagsofid(lf->flags, F_SNEAK);
return B_FALSE; return B_FALSE;
@ -2129,15 +2146,29 @@ void triggertrap(lifeform_t *lf, object_t *o, object_t *trapob, cell_t *where) {
if (lf) interrupt(lf); if (lf) interrupt(lf);
} }
int trymove(lifeform_t *lf, int dir, int onpurpose) { int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
cell_t *cell; cell_t *cell;
enum ERROR errcode; enum ERROR errcode;
char buf[BUFLEN]; char buf[BUFLEN];
int dontclearmsg = B_FALSE; int dontclearmsg = B_FALSE;
int moveok; int moveok;
int rndmove = B_FALSE; int rndmove = B_FALSE;
int howlong;
flag_t *f; flag_t *f;
howlong = getmovespeed(lf);
if (onpurpose && !strafe) {
// if the given dir is behind us, just turn.
if (getrelativedir(lf, dir) != RD_FORWARDS) {
howlong /= 2;
limit(&howlong, 1, NA);
setfacing(lf, dir);
taketime(lf, howlong);
return B_FALSE;
}
}
f = lfhasflag(lf, F_DRUNK); f = lfhasflag(lf, F_DRUNK);
if (f) { if (f) {
if (!hasjob(lf, J_PIRATE)) { if (!hasjob(lf, J_PIRATE)) {
@ -2224,7 +2255,18 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
// now move to new cell // now move to new cell
moveto(lf, cell, rndmove ? B_FALSE : onpurpose, dontclearmsg); moveto(lf, cell, rndmove ? B_FALSE : onpurpose, dontclearmsg);
if (onpurpose) { if (onpurpose) {
taketime(lf, getmovespeed(lf)); // strafing sideways/backwards takes longer
if (strafe) {
switch (getrelativedir(lf, dir)) {
case RD_SIDEWAYS: howlong = pctof(125, howlong); break;
case RD_BACKWARDS: howlong = pctof(150, howlong); break;
case RD_FORWARDS:
default:
break;
}
}
taketime(lf, howlong);
if (!rndmove && !strafe) setfacing(lf, dir); // face the way we moved
} }
// attached lfs or lfs you have grabbed will move the same direction if they can // attached lfs or lfs you have grabbed will move the same direction if they can

7
move.h
View File

@ -6,6 +6,7 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error); int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error);
int closedoorat(lifeform_t *lf, cell_t *c); int closedoorat(lifeform_t *lf, cell_t *c);
int closedoor(lifeform_t *lf, object_t *o); int closedoor(lifeform_t *lf, object_t *o);
int getrelativedir(lifeform_t *lf, int dir);
int diropposite(int dir); int diropposite(int dir);
int dorandommove(lifeform_t *lf, int badmovesok, int restonfail); int dorandommove(lifeform_t *lf, int badmovesok, int restonfail);
int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype, int keepinlof); int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype, int keepinlof);
@ -13,12 +14,12 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, in
int getwalkoffdir(lifeform_t *lf, int dir); int getwalkoffdir(lifeform_t *lf, int dir);
int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff); int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff);
int makeorthogonal(int dir); int makeorthogonal(int dir);
int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof); int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe);
int moveclear(lifeform_t *lf, int dir, enum ERROR *error); int moveclear(lifeform_t *lf, int dir, enum ERROR *error);
int moveeffects(lifeform_t *lf); int moveeffects(lifeform_t *lf);
int movelf(lifeform_t *lf, cell_t *newcell); int movelf(lifeform_t *lf, cell_t *newcell);
int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg); int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg);
int movetowards(lifeform_t *lf, cell_t *dst, int dirtype); int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe);
int move_will_hurt(lifeform_t *lf); int move_will_hurt(lifeform_t *lf);
int opendoorat(lifeform_t *lf, cell_t *c); int opendoorat(lifeform_t *lf, cell_t *c);
int opendoor(lifeform_t *lf, object_t *o); int opendoor(lifeform_t *lf, object_t *o);
@ -29,7 +30,7 @@ int ispossiblemove(lifeform_t *lf, int dir);
void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int onpurpose); void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int onpurpose);
int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke); int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke);
void triggertrap(lifeform_t *lf, object_t *o, object_t *trapob, cell_t *where); void triggertrap(lifeform_t *lf, object_t *o, object_t *trapob, cell_t *where);
int trymove(lifeform_t *lf, int dir, int onpurpose); int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe);
int tryrun(lifeform_t *lf, int dir); int tryrun(lifeform_t *lf, int dir);
int trysneak(lifeform_t *lf, int dir); int trysneak(lifeform_t *lf, int dir);
int walkoffmap(lifeform_t *lf, int dir, int onpurpose); int walkoffmap(lifeform_t *lf, int dir, int onpurpose);

67
nexus.c
View File

@ -110,6 +110,7 @@ int main(int argc, char **argv) {
int x,y; int x,y;
cell_t *c; cell_t *c;
vault_t *v; vault_t *v;
enum SKILLLEVEL slev;
atexit(cleanup); atexit(cleanup);
@ -233,6 +234,7 @@ int main(int argc, char **argv) {
real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player' real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player'
addflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL); addflag(player->flags, F_CANWILL, OT_A_PRAY, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_TRAIN, NA, NA, NULL); addflag(player->flags, F_CANWILL, OT_A_TRAIN, NA, NA, NULL);
addflag(player->flags, F_CANWILL, OT_A_DEBUG, NA, NA, NULL); /////////
o = hasob(where->obpile, OT_PLAYERSTART); o = hasob(where->obpile, OT_PLAYERSTART);
killob(o); killob(o);
@ -326,14 +328,17 @@ int main(int argc, char **argv) {
calclight(player->cell->map); calclight(player->cell->map);
// pre-calc line-of-sight for player // pre-calc line-of-sight for player
//precalclos(player); //precalclos(player);
player->facing = D_ALL;
setlosdirty(player); setlosdirty(player);
// don't want any mosnters starting within los/lof of player // don't want any mosnters starting within los/lof of player
slev = getskill(player, SK_CARTOGRAPHY);
for (y = 0; y < player->cell->map->h; y++) { for (y = 0; y < player->cell->map->h; y++) {
for (x = 0; x < player->cell->map->w; x++) { for (x = 0; x < player->cell->map->w; x++) {
c = getcellat(player->cell->map, x, y); c = getcellat(player->cell->map, x, y);
if (c && c->lf && (haslos(player, c) || haslof(player->cell, c, LOF_WALLSTOP, NULL))) { if (c && (haslos(player, c) || haslof(player->cell, c, LOF_WALLSTOP, NULL))) {
if (!isplayer(c->lf) && !ispetof(c->lf, player)) { setcellknown(c, slev);
if (c->lf && !isplayer(c->lf) && !ispetof(c->lf, player)) {
killlf(c->lf); killlf(c->lf);
} }
} }
@ -348,6 +353,7 @@ int main(int argc, char **argv) {
// redo light and player los // redo light and player los
calclight(player->cell->map); calclight(player->cell->map);
player->facing = rnd(DC_N, DC_NW);
precalclos(player); precalclos(player);
// show level // show level
@ -776,43 +782,6 @@ void donextturn(map_t *map) {
} }
} }
char *getdirname(int dir) {
switch (dir) {
case D_N:
return "North";
case D_E:
return "East";
case D_S:
return "South";
case D_W:
return "West";
case D_UP:
return "up";
case D_DOWN:
return "down";
case D_UNKNOWN:
return "D_UNKNOWN";
case D_NONE:
return "D_NONE";
case DC_N:
return "North";
case DC_NE:
return "Northeast";
case DC_E:
return "East";
case DC_SE:
return "Southeast";
case DC_S:
return "South";
case DC_SW:
return "Southwest";
case DC_W:
return "West";
case DC_NW:
return "Northwest";
}
return "?errordir?";
}
enum COLOUR getpctcol(float num, float max) { enum COLOUR getpctcol(float num, float max) {
float pct; float pct;
@ -923,6 +892,10 @@ void calcbresnham(map_t *m, int x1, int y1, int x2, int y2, cell_t **retcell, in
y = y1; y = y1;
for (i = 0; i < *numpixels; i++) { for (i = 0; i < *numpixels; i++) {
retcell[i] = getcellat(m, x, y); retcell[i] = getcellat(m, x, y);
if (!retcell[i]) { // we've gone off the map - stop here
*numpixels = i;
return;
}
dobresnham(d, xinc1, yinc1, dinc1, xinc2, yinc2, dinc2, &xinc, &yinc, &dinc); dobresnham(d, xinc1, yinc1, dinc1, xinc2, yinc2, dinc2, &xinc, &yinc, &dinc);
// move to next cell // move to next cell
d += dinc; d += dinc;
@ -1414,6 +1387,9 @@ void timeeffectsworld(map_t *map, int updategametime) {
object_t *o,*nexto; object_t *o,*nexto;
int x,y; int x,y;
long firstlftime; long firstlftime;
enum SKILLLEVEL cartskill;
cartskill = getskill(player, SK_CARTOGRAPHY);
// now go through the list and make the first element be 0 // now go through the list and make the first element be 0
l = map->lf; l = map->lf;
@ -1466,6 +1442,19 @@ void timeeffectsworld(map_t *map, int updategametime) {
c = getcellat(map, x, y); c = getcellat(map, x, y);
if (c) { if (c) {
object_t *pit; object_t *pit;
if (cartskill <= PR_INEPT) {
// if you are inept at cartography, you will forget
// cells outside your view which are far away.
if (c->knowntime > 0) {
c->knowntime--;
if (c->knowntime <= 0) {
c->known = B_FALSE;
c->knowntime = 0;
}
}
}
pit = hasobwithflagval(c->obpile, F_PIT, D_DOWN, NA, NA, NULL); pit = hasobwithflagval(c->obpile, F_PIT, D_DOWN, NA, NA, NULL);
if (pit) { if (pit) {
obsfallthrough(c, pit); obsfallthrough(c, pit);

View File

@ -10,7 +10,6 @@ void dbtimeend(char *text);
void dbtimestart(char *text); void dbtimestart(char *text);
void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, int dinc2, int *xinc, int *yinc, int *dinc); void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, int dinc2, int *xinc, int *yinc, int *dinc);
void donextturn(map_t *map); void donextturn(map_t *map);
char *getdirname(int dir);
enum COLOUR getpctcol(float num, float max); enum COLOUR getpctcol(float num, float max);
void getrarityrange(int depth, int *min, int *max, int range, int oodok); void getrarityrange(int depth, int *min, int *max, int range, int oodok);
int init(void); int init(void);

View File

@ -5854,6 +5854,7 @@ void initobjects(void) {
addocnoun(lastobjectclass, "food"); addocnoun(lastobjectclass, "food");
addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, "");
addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastobjectclass->flags, F_SMELLY, B_TRUE, NA, NA, NULL);
addoc(OC_GODSTONE, "Godstones", "Ancient artifacts, created by the elder gods.", '*', C_BOLDMAGENTA); addoc(OC_GODSTONE, "Godstones", "Ancient artifacts, created by the elder gods.", '*', C_BOLDMAGENTA);
addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL); addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL);
addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pulsating purple stone"); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pulsating purple stone");
@ -9134,7 +9135,6 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL);
addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL);
// similar to a buckler, but repairable, lighter, and less durable // similar to a buckler, but repairable, lighter, and less durable
@ -9142,28 +9142,24 @@ void initobjects(void) {
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL);
addflag(lastot->flags, F_OBHP, 18, 18, NA, NULL); addflag(lastot->flags, F_OBHP, 18, 18, NA, NULL);
addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR, SZ_MEDIUM); addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL);
addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL);
addot(OT_SHIELDLARGE, "large shield", "A large (if somewhat cumbersome) shield.", MT_METAL, 6.00, OC_ARMOUR, SZ_MEDIUM); addot(OT_SHIELDLARGE, "large shield", "A large (if somewhat cumbersome) shield.", MT_METAL, 6.00, OC_ARMOUR, SZ_MEDIUM);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 8, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 20, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 20, NA, NULL);
addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL);
addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR, SZ_HUMAN); addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR, SZ_HUMAN);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL);
addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL);
addflag(lastot->flags, F_ARMOURRATING, 12, NA, NA, NULL);
addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 30, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 30, NA, NULL);
addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL);
@ -10537,6 +10533,7 @@ void killob(object_t *o) {
if (o->type->id == OT_STAIRSUP) { if (o->type->id == OT_STAIRSUP) {
msg("warning: removing an up staircase!"); msg("warning: removing an up staircase!");
dblog("warning: removing an up staircase!"); dblog("warning: removing an up staircase!");
assert(1 == 0);
} }
// remove flags conferred by this object // remove flags conferred by this object
@ -11240,7 +11237,7 @@ void obdie(object_t *o) {
if (strlen(desc)) { if (strlen(desc)) {
if (o->pile->owner) { if (o->pile->owner) {
if (isplayer(o->pile->owner)) { if (isplayer(o->pile->owner)) {
msg("Your %s %s!",noprefix(obname), desc); msg("^wYour %s %s!",noprefix(obname), desc);
} else if (cansee(player, o->pile->owner)) { } else if (cansee(player, o->pile->owner)) {
char monname[BUFLEN]; char monname[BUFLEN];
getlfname(o->pile->owner, monname); getlfname(o->pile->owner, monname);
@ -14383,7 +14380,6 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno
} }
if (!hpflag || (hpflag->val[0] <= 0)) { if (!hpflag || (hpflag->val[0] <= 0)) {
// special cases.... // special cases....
if (damtype == DT_FIRE) { if (damtype == DT_FIRE) {
if ((o->material->id == MT_FLESH) && onein(3)) { // fire sometimes roasts flesh if ((o->material->id == MT_FLESH) && onein(3)) { // fire sometimes roasts flesh

8
save.c
View File

@ -363,8 +363,8 @@ map_t *loadmap(char *basefile) {
c = addcell(m, x, y); c = addcell(m, x, y);
// cell info // cell info
fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
&roomid, &celltypeid, &c->known, &c->knownglyph.ch, &c->knownglyph.colour, &c->visited, &c->lit, &c->origlit, &c->littimer,&temphab); &roomid, &celltypeid, &c->known, &c->knowntime, &c->knownglyph.ch, &c->knownglyph.colour, &c->visited, &c->lit, &c->origlit, &c->littimer,&temphab);
c->habitat = findhabitat(temphab); c->habitat = findhabitat(temphab);
c->room = findroom(m, roomid); c->room = findroom(m, roomid);
@ -910,8 +910,8 @@ int savemap(map_t *m) {
cell_t *c; cell_t *c;
c = getcellat(m, x, y); c = getcellat(m, x, y);
// cell info // cell info
fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
c->room ? c->room->id : -1, c->type->id, c->known, c->knownglyph.ch, c->knownglyph.colour, c->visited,c->lit,c->origlit,c->littimer,c->habitat->id ); c->room ? c->room->id : -1, c->type->id, c->known, c->knowntime, c->knownglyph.ch, c->knownglyph.colour, c->visited,c->lit,c->origlit,c->littimer,c->habitat->id );
// cell objects // cell objects
for (o = c->obpile->first ; o ; o = o->next) { for (o = c->obpile->first ; o ; o = o->next) {
fprintf(f, "ob:%ld\n",o->id); fprintf(f, "ob:%ld\n",o->id);

View File

@ -4556,9 +4556,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
donesomething = B_TRUE; donesomething = B_TRUE;
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
getflags(target->flags, retflag, &nretflags, F_NOBODYPART, F_NONE); // severed body parts
getflags(target->flags, retflag, &nretflags, F_INJURY, F_NOBODYPART, F_NONE);
for (i = 0; i < nretflags; i++) { for (i = 0; i < nretflags; i++) {
if (retflag[i]->val[1] == B_FROMINJURY) { if ((retflag[i]->id == F_NOBODYPART) && (retflag[i]->val[1] == B_FROMINJURY)) {
if (isplayer(target)) { if (isplayer(target)) {
msg("Your %s grows back!", getbodypartname(retflag[0]->val[0])); msg("Your %s grows back!", getbodypartname(retflag[0]->val[0]));
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
@ -4571,6 +4572,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
killflag(retflag[i]); killflag(retflag[i]);
donesomething = B_TRUE; donesomething = B_TRUE;
} else if ((retflag[i]->id == F_INJURY) && (retflag[i]->lifetime > 0)) {
killflag(retflag[i]);
donesomething = B_TRUE;
} }
} }

97
text.c
View File

@ -193,6 +193,82 @@ char *getattrname(enum ATTRIB att) {
return "?badattrib?"; return "?badattrib?";
} }
char *getdirname(int dir) {
switch (dir) {
case D_N:
return "North";
case D_E:
return "East";
case D_S:
return "South";
case D_W:
return "West";
case D_UP:
return "up";
case D_DOWN:
return "down";
case D_UNKNOWN:
return "D_UNKNOWN";
case D_NONE:
return "D_NONE";
case DC_N:
return "North";
case DC_NE:
return "Northeast";
case DC_E:
return "East";
case DC_SE:
return "Southeast";
case DC_S:
return "South";
case DC_SW:
return "Southwest";
case DC_W:
return "West";
case DC_NW:
return "Northwest";
}
return "?errordir?";
}
char *getdirnameshort(int dir) {
switch (dir) {
case D_N:
return "N";
case D_E:
return "E";
case D_S:
return "S";
case D_W:
return "W";
case D_UP:
return "U";
case D_DOWN:
return "D";
case D_UNKNOWN:
return "?";
case D_NONE:
return "-";
case DC_N:
return "N";
case DC_NE:
return "NE";
case DC_E:
return "E";
case DC_SE:
return "SE";
case DC_S:
return "S";
case DC_SW:
return "SW";
case DC_W:
return "W";
case DC_NW:
return "NW";
}
return "?";
}
int gethitconferlifetime(char *text, int *min, int *max) { int gethitconferlifetime(char *text, int *min, int *max) {
int howlong; int howlong;
int localmin = -1,localmax = -1; int localmin = -1,localmax = -1;
@ -950,9 +1026,8 @@ void texttospellopts(char *text, ... ) {
va_start(args, text); va_start(args, text);
wantname = va_arg(args, char *); wantname = va_arg(args, char *);
if (wantname) writeto = va_arg(args, void *); if (wantname) writeto = va_arg(args, void *);
while (wantname) { while (wantname) { // process this one
int foundidx = -1,i; int foundidx = -1,i;
// process this one
// validate 'wantname' - must match one of 'validname[]' // validate 'wantname' - must match one of 'validname[]'
for (i = 0; validname[i]; i++) { for (i = 0; validname[i]; i++) {
@ -963,21 +1038,21 @@ void texttospellopts(char *text, ... ) {
} }
assert(foundidx != -1); assert(foundidx != -1);
// blank our dest buffer
if (argtype[foundidx] == 'i') {
*((int *)writeto) = 0;
} else if (argtype[foundidx] == 'b') {
*((int *)writeto) = B_FALSE;
} else if (argtype[foundidx] == 's') {
strcpy((char *)writeto, "");
}
// look for 'wantname' within 'text' // look for 'wantname' within 'text'
for (p = text ; *p ; p++) { for (p = text ; *p ; p++) {
if (!strncmp(p, wantname, strlen(wantname)) ) { // found it! if (!strncmp(p, wantname, strlen(wantname)) ) { // found it!
char localval[BUFLEN]; char localval[BUFLEN];
char *valfull; char *valfull;
// blank our dest buffer
if (argtype[foundidx] == 'i') {
*((int *)writeto) = 0;
} else if (argtype[foundidx] == 'b') {
*((int *)writeto) = B_FALSE;
} else if (argtype[foundidx] == 's') {
strcpy((char *)writeto, "");
}
// extract value from text // extract value from text
// p will point to "pw:xxx;" // p will point to "pw:xxx;"
strcpy(localval, p + strlen(wantname)); // localval is "xxx;" strcpy(localval, p + strlen(wantname)); // localval is "xxx;"

2
text.h
View File

@ -8,6 +8,8 @@ char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dic
int flip(int ch); int flip(int ch);
char *getattrabbrev(enum ATTRIB att); char *getattrabbrev(enum ATTRIB att);
char *getattrname(enum ATTRIB att); char *getattrname(enum ATTRIB att);
char *getdirname(int dir);
char *getdirnameshort(int dir);
int gethitconferlifetime(char *text, int *min, int *max); int gethitconferlifetime(char *text, int *min, int *max);
char *getpossessive(char *text); char *getpossessive(char *text);
char *getdrunktext(flag_t *drunkflag); char *getdrunktext(flag_t *drunkflag);

View File

@ -1,12 +1,12 @@
@id:playerstart_4 @id:playerstart_4
@map @map
####### ###x###
#wwwww# #ww_ww#
#ww.ww# #ww.ww#
#w.p._x x_.p._x
#ww.ww# #ww.ww#
#wwwww# #ww_ww#
####### ###x###
@end @end
@legend @legend
#:cell:rock wall #:cell:rock wall