Monster AI improvements:

- [+] replace f_target with f_targetlf
- [+] wantrange.  for melee fighters (default), it's 0. for
      spells/archers, it's higiher.
    - [+] if we are further away than bestrange, move towards.
    - [+] if we are closer than bestrange, move away
    - [+] AND: move to wantrange before doing spells etc
    - [+] if we have a ranged attack and wantrange is default, increase
          it.
- [+] in movetowards/away, cells in the wrong dir should NEVER be
      acceptable!
* [+] mflag_push for monsters
          http://roguelikedeveloper.blogspot.com/2007/10/unangband-monst
          er-ai-part-three.html
- [+] randomly use ranged attacks when adjacent

* [+] show trail in askcoords
- [+] when throwing, pass range to askcoords
- [+] max monsters per room is depth + 1
* [+] why do humans take ages to appear?
- [+] fireball spell is slow
- [+] why can i throw objects through magic barriers?
- [+] add a bonus for mastery of cartography - magic mapping every 50
      turns.
- [+] crash with monsters moving off edge of world map
- [+] make magic barriers be ON stairs, not around them.
- [+] handle DIAGONAL entry to maps
    - [+] OR make this impossible.
- [+] druid should get auto nature knoeldge as they levle up (levs 5 10
      15).
- [+] CRASH flagpile corrupt
    - [+] happening during AI movement.
- [+] make lightning storm only hit enemies
- [+] store last known movement dir in TARGETLF and PETOF.
- [+] limit monsters per room not working?!?!
- [+] make askcoords let you show object piles with .
- [+] make askcoords say "A magical barrier (+xx other objects)"
- [+] combine getlastknownmovedir into getlastknowncell
* [+] BUG: secret doors are showing up as . again!
* [+] implement trails (footprints & scent)
* [+] aimovetowardslf(lf, wantattack)
* [+] make pets use wantdist code?
- [+] what does expert/master tracking give you?
    - [+] ex: your tracks don't last as long
    - [+] ms: you don't leave tracks.
- [+] change f_reducemovement from multiplier to addition
- [+] comma still showing up scents and footprints incorrectly!!!!!!!!
Initial shallow/deep water:
- [+] restrict movement
- [+] check for drowning in turneffectslf AND movelf
- [+] warn before walking onto dangerous objects.
- [+] change how walkdam works for deepwater.
    - [+] don't use walkdam flags.
- [+] don't make splashes of water on top of deepwater.
* [+] deep water will drown you if
- [+] don't leave footprints in either
- [+] create steam on fire damage, but don't CONVERT to it.
- [+] f_waterbreathing
    - [+] can't drown in water
- [+] extra damage from cold/elec if in deep/shallow water
Initial swimming implementation
* [+] sacred/cursed ground
- [+] vending machine
- [+] don't transfer f_rarity flag when making objects / lifeforms.
Initial work on adding a goal to the game!
This commit is contained in:
Rob Pearce 2011-05-25 02:12:00 +00:00
parent a763c3c4b1
commit 69982623ed
21 changed files with 2466 additions and 1236 deletions

710
ai.c
View File

@ -34,7 +34,7 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
} }
// already targetting this lf? // already targetting this lf?
f = lfhasflagval(lf, F_TARGET, victim->id, NA, NA, NULL); f = lfhasflagval(lf, F_TARGETLF, victim->id, NA, NA, NULL);
if (f) { if (f) {
if ((f->lifetime > 0) && (f->lifetime < timelimit)) { if ((f->lifetime > 0) && (f->lifetime < timelimit)) {
f->lifetime = timelimit; f->lifetime = timelimit;
@ -46,17 +46,17 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
char lfname[BUFLEN],vicname[BUFLEN]; char lfname[BUFLEN],vicname[BUFLEN];
getlfname(lf, lfname); getlfname(lf, lfname);
getlfname(victim, vicname); getlfname(victim, vicname);
dblog(".oO { %s settings new target: %s }", lfname, vicname); dblog(".oO { %s setting new target: %s }", lfname, vicname);
} }
killflagsofid(lf->flags, F_TARGET); killflagsofid(lf->flags, F_TARGETLF);
killflagsofid(lf->flags, F_TARGETCELL); killflagsofid(lf->flags, F_TARGETCELL);
if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) { if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) {
addflag(lf->flags, F_TARGET, victim->id, victim->cell->x, victim->cell->y, NULL); addflag(lf->flags, F_TARGETLF, victim->id, victim->cell->x, victim->cell->y, NULL);
} else { } else {
addtempflag(lf->flags, F_TARGET, victim->id , victim->cell->x , victim->cell->y, NULL,timelimit); addtempflag(lf->flags, F_TARGETLF, victim->id , victim->cell->x , victim->cell->y, NULL,timelimit);
} }
// tell the player // tell the player
if (cansee(player, lf)) { if (cansee(player, lf)) {
@ -155,6 +155,109 @@ enum OBTYPE aigetfleespell(lifeform_t *lf) {
return OT_NONE; return OT_NONE;
} }
// this function assumes that you can't just SEE the target!
cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *lasty, int *lastdir) {
flag_t *f, *tflag, *bestflag;
cell_t *c = NULL;
int besttime = -1;
int i;
// check scent/footprints first
for (i = 0; i < lf->nlos; i++) {
if (hastrailof(lf->los[i]->obpile, target, NA, &tflag, lf)) {
if (tflag->lifetime > besttime) {
besttime = tflag->lifetime;
bestflag = tflag;
c = lf->los[i];
}
}
}
if (c) {
if (lastx) *lastx = c->x;
if (lasty) *lasty = c->y;
if (lastdir) {
// can only obtain direction from footprints if your
// tracking skill is high enough.
if (bestflag->val[2] == S_SIGHT) {
if (getskill(lf, SK_TRACKING) >= PR_SKILLED) {
*lastdir = bestflag->val[1];
} else {
*lastdir = D_NONE;
}
} else {
*lastdir = bestflag->val[1];
}
}
return c;
}
f = ispetortarget(lf, target);
if (f) {
c = getcellat(lf->cell->map, f->val[1], f->val[2]);
if (c) {
if (lastx) *lastx = c->x;
if (lasty) *lasty = c->y;
if (lastdir && strlen(f->text)) {
*lastdir = atoi(f->text);
}
}
return c;
}
if (lastx) *lastx = NA;
if (lasty) *lasty = NA;
if (lastdir) *lastdir = D_NONE;
return NULL;
}
object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) {
int db = B_FALSE;
object_t *o;
if (lfhasflag(lf, F_DEBUG)) db = B_TRUE;
o = getfirearm(lf);
if (o && getammo(lf)) {
if (db) {
char gunname[BUFLEN];
getobname(o, gunname, o->amt);
if (db) dblog(".oO { will fire my gun (%s) at target. }",gunname);
}
*ra = RA_GUN;
return o;
}
// do we have a wand we can zap?
if (lfhasflag(lf, F_HUMANOID) || hasbp(lf, BP_HANDS)) {
if (lfhasflag(lf, F_FLEEFROM)) {
o = aigetwand(lf, F_AICASTTOFLEE);
} else {
o = aigetwand(lf, F_AICASTTOATTACK);
}
if (o) {
if (db) dblog(".oO { will zap %s instead of moving }", o->type->name);
*ra = RA_WAND;
return o;
}
}
// can we attack by throwing something?
if (hasbp(lf, BP_HANDS)) {
o = getbestthrowmissile(lf);
if (o) {
if (db) dblog(".oO { will throw %s at my target }", o->type->name);
*ra = RA_THROW;
return o;
}
}
if (db) dblog(".oO { found no ranged attack. }");
*ra = RA_NONE;
return NULL;
}
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose) { void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose) {
int specialcase = B_FALSE; int specialcase = B_FALSE;
flag_t *f; flag_t *f;
@ -293,7 +396,7 @@ flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int t
dblog(".oO { %s going to targecell: %d, %d }", lfname, c->x, c->y); dblog(".oO { %s going to targecell: %d, %d }", lfname, c->x, c->y);
} }
killflagsofid(lf->flags, F_TARGET); killflagsofid(lf->flags, F_TARGETLF);
killflagsofid(lf->flags, F_TARGETCELL); killflagsofid(lf->flags, F_TARGETCELL);
if (why == MR_LF) { if (why == MR_LF) {
@ -312,6 +415,296 @@ flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int t
return f; return f;
} }
// returns B_FALSE if we did something.
// returns B_TRUE if we failed (ie. did nothing)
int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) {
int db = B_FALSE;
int ismaster = B_FALSE;
flag_t *targetflag = NULL;
if (lfhasflag(lf, F_DEBUG)) db = B_TRUE;
targetflag = lfhasflagval(lf, F_PETOF, target->id, NA, NA, NULL);
if (targetflag) {
ismaster = B_TRUE;
} else {
targetflag = lfhasflagval(lf, F_TARGETLF, target->id, NA, NA, NULL);
}
if (cansee(lf, target)) {
int dist,wantdistmin,wantdistmax;
int attackok;
enum OBTYPE spell;
object_t *rangedob = NULL;
enum RANGEATTACK rangedattack = RA_NONE;
int movefailed = B_FALSE;
// pet movement
if (ismaster) {
if (isresting(target)) {
// rest as well.
rest(lf, B_TRUE);
return B_FALSE;
} else if (isadjacent(lf->cell, target->cell)) {
if (db) dblog(".oO { i can see my master adjacent - moving randomly }");
// move randomly. TODO: just return ??
dorandommove(lf, B_NOBADMOVES, B_TRUE);
return B_FALSE;
}
// otherwise fall through to below movement code.
}
// how far away is my target ?
dist = getcelldist(lf->cell, target->cell);
// how far away do i _want_ to be?
getwantdistance(lf,&wantdistmin,&wantdistmax, wantattack);
// reset F_TARGET lifetime to full.
if (targetflag) {
if (targetflag->id == F_TARGETLF) {
targetflag->lifetime = AI_FOLLOWTIME;
}
if (db) dblog(".oO { i can see my target (at %d,%d). might move towards it. }",target->cell->x,target->cell->y);
// remember their location
targetflag->val[1] = target->cell->x;
targetflag->val[2] = target->cell->y;
}
// is an attack possible?
attackok = B_FALSE;
if (wantattack) {
if (dist == 1) {
attackok = B_TRUE;
} else if (!lfhasflag(lf, F_HIDING)) {
attackok = B_TRUE;
}
}
if (attackok) {
objecttype_t *st;
// drink boost potions
if (!useitemwithflag(lf, F_AIBOOSTITEM)) {
return B_FALSE;
}
// try spells first.
// can we attack with spells (ie. ones which target the victim)?
// if target is adjacent, we will normally just attack rather than try a spell.
spell = aigetattackspell(lf, target);
st = findot(spell);
if ( (spell != OT_NONE) && // found a valid spell/ability to use
((dist != 1) || // there is distance between us and target
(st->obclass->id == OC_ABILITY) || // OR this works from adjacent
(rnd(1,3) == 1)) // OR random chance of using anyway...
) {
int spellfailed = B_FALSE;
lifeform_t *spelllf = NULL;
cell_t *spellcell = NULL;
object_t *spellob = NULL;
if (db) {
dblog(".oO { will cast attack spell: %s }", st->name);
}
// special cases: eg. spells like telekenesis
if (spell == OT_S_TELEKINESIS) {
float maxweight;
object_t *poss[MAXPILEOBS];
int nposs;
int i;
// find nearest object which can be picked up
// this is copied out of the telekenesis spell code!
maxweight = getlfweight(lf, B_NOOBS) +
(getlfweight(lf, B_NOOBS) * (getstatmod(lf, A_IQ) / 100));
nposs = 0;
for (i = 0; i < lf->nlos; i++) {
object_t *o;
for (o = lf->los[i]->obpile->first ; o ; o = o->next) {
if (!hasflag(o->flags, F_NOPICKUP) &&
getobweight(o) <= maxweight) {
poss[nposs] = o;
nposs++;
if (nposs >= MAXPILEOBS) break;
}
}
if (nposs >= MAXPILEOBS) break;
}
if (nposs > 0) {
spellob = poss[rnd(0,nposs-1)];
} else {
spellfailed = B_TRUE;
}
// cast spell at the player
spelllf = target;
spellcell = target->cell;
} else {
// pick targets based on spell flags
aigetspelltarget(lf, st, target, &spelllf, &spellcell, &spellob, F_AICASTTOATTACK);
}
if (spellfailed) {
if (db) dblog(".oO { cast spell/ability failed (1)! }");
} else {
if (getschool(spell) == SS_ABILITY) {
spellfailed = useability(lf, spell, spelllf, spellcell);
} else {
spellfailed = castspell(lf, spell, spelllf, spellob, spellcell);
}
}
if (spellfailed) {
if (db) dblog(".oO { cast spell/ability tried but failed (2)! reason = %d }", reason);
} else {
// spell succesful
}
return B_FALSE;
}
// see if we have a ranged attack. if so, adjust wantdist
// to maintain distance.
rangedob = aigetrangedattack(lf, &rangedattack);
if (rangedattack != RA_NONE) {
if (wantdistmin < 2) wantdistmin = 2;
if (wantdistmax < wantdistmin) wantdistmax = wantdistmin;
}
} // end if attackok
// move towards the target lf.
// try to get to our ideal range from them.
if (db) dblog(".oO { i am at distance %d, want to be at %d-%d }", dist, wantdistmin, wantdistmax);
if (dist > wantdistmax) {
if (db) dblog(".oO { moving towards target. }");
if (!movetowards(lf, target->cell, DT_ORTH)) {
// success
return B_FALSE;
} else {
if (db) dblog(".oO { move towards failed! - reason = %d }",reason);
movefailed = B_TRUE;
}
} else if (dist < wantdistmin) {
if (db) dblog(".oO { moving away from target. }");
if (!moveawayfrom(lf, target->cell, DT_ORTH)) {
// success
return B_FALSE;
} else {
if (db) dblog(".oO { move towards failed! - reason = %d }",reason);
movefailed = B_TRUE;
}
}
// if we got here, we're either at the correct distance or couldn't
// move.
if (attackok) {
enum IQBRACKET iqb;
iqb = getiqname(getattr(lf, A_IQ), NULL);
// if not adjacent, check for guns, wands, throwing
if ( (rangedattack != RA_NONE) &&
haslof(lf->cell, target->cell, LOF_NEED, NULL) && // and we have line of fire to them
(onein(2) || (getcelldist(lf->cell, target->cell) > 1) ) && // and we're not adjacent to target OR random
(iqb > IQ_ANIMAL) ) { // and we are smarter than an animal
if (rangedattack == RA_GUN) {
setguntarget(lf, target);
if (!shoot(lf)) {
// succesful
return B_FALSE;
} else {
if (db) dblog(".oO { shoot gun failed! reason = %d }", reason);
}
} else if (rangedattack == RA_THROW) {
// try to throw it!
if (!throwat(lf, rangedob, target->cell)) {
// succesful
return B_FALSE;
} else {
if (db) dblog(".oO { throw failed! }");
}
} else if (rangedattack == RA_WAND) {
objecttype_t *st;
cell_t *zapcell = NULL;
st = getlinkspell(rangedob);
if (st) {
enum FLAG purpose;
if (lfhasflag(lf, F_FLEEFROM)) {
purpose = F_AICASTTOFLEE;
} else {
purpose = F_AICASTTOATTACK;
}
aigetspelltarget(lf, st, target, NULL, &zapcell, NULL, purpose);
} else {
// no linkspell - just zap it.
zapcell = NULL;
}
// zap it
if (!operate(lf, rangedob, zapcell)) {
// succesful
return B_FALSE;
} else {
if (db) dblog(".oO { zap failed! }");
}
}
} // end if rangedattackok
} // end if attackok
// if we could see our traget, but everything we tried failed (spells, moving and ranged attack),
// just rest.
if (movefailed) {
rest(lf, B_TRUE);
return B_FALSE;
}
} else {
// can't see target.
// move towards their last known location instead
cell_t *targcell;
int lastx,lasty;
int lastdir;
targcell = aigetlastknownpos(lf, target, &lastx, &lasty, &lastdir);
if (targcell) {
// are we already AT their last known location?
if (targcell == lf->cell) {
if (db) dblog(".oO { cannot see target. i am already at their last known loc %d/%d }",lastx, lasty);
// go in their last known direction.
if (lastdir == D_NONE) {
if (db) dblog(".oO { i don't know my target's last known movement dir. }");
} else {
// try going in last known dir
if (db) dblog(".oO { trying my master's last known move dir (%s) }",getdirname(lastdir));
if (!trymove(lf, lastdir, B_TRUE)) {
if (db) dblog(".oO { ...successfully }");
// we now don't know their last known dir.
if (targetflag) {
free(targetflag->text);
targetflag->text = strdup("");
}
return B_FALSE;
}
}
} else {
// not already at their last known cell. try to go there.
if (db) dblog(".oO { i cannot see my target. moving to last known loc %d/%d }",lastx,lasty);
if (!aigoto(lf, targcell, MR_LF, target, PERMENANT)) {
if (db) dblog(".oO { aigoto target's last known loc failed! }");
}
}
} else {
// we don't know their last known location....
if (db) dblog(".oO { go to target's last known loc failed! }");
}
}
if (db) dblog(".oO { aimovetolf failed. }");
// FAILED.
return B_TRUE;
}
void aimovetotargetcell(lifeform_t *lf, flag_t *f) { void aimovetotargetcell(lifeform_t *lf, flag_t *f) {
int x,y; int x,y;
cell_t *c; cell_t *c;
@ -402,7 +795,6 @@ void aiturn(lifeform_t *lf) {
int icanattack = B_FALSE; int icanattack = B_FALSE;
object_t *curgun,*bestgun; object_t *curgun,*bestgun;
flag_t *f; flag_t *f;
flag_t *mf;
//flag_t *nextf; //flag_t *nextf;
// lifeform_t *fleefrom = NULL; // lifeform_t *fleefrom = NULL;
lifeform_t *target,*newtarget; lifeform_t *target,*newtarget;
@ -450,9 +842,9 @@ void aiturn(lifeform_t *lf) {
// are we a pet? // are we a pet?
mf = lfhasflagval(lf, F_PETOF, NA, NA, NA, NULL); f = lfhasflagval(lf, F_PETOF, NA, NA, NA, NULL);
if (mf && (getallegiance(lf) == AL_FRIENDLY)) { if (f && (getallegiance(lf) == AL_FRIENDLY)) {
master = findlf(lf->cell->map, mf->val[0]); master = findlf(lf->cell->map, f->val[0]);
} }
/////////////////////////////////////////////// ///////////////////////////////////////////////
@ -597,7 +989,7 @@ void aiturn(lifeform_t *lf) {
/////////////////////////////////////////////// ///////////////////////////////////////////////
// do we already have a target we are attacking? // do we already have a target we are attacking?
f = hasflag(lf->flags, F_TARGET); f = hasflag(lf->flags, F_TARGETLF);
if (f) { if (f) {
int targid; int targid;
int lastx,lasty; int lastx,lasty;
@ -608,222 +1000,9 @@ void aiturn(lifeform_t *lf) {
target = findlf(lf->cell->map, targid); target = findlf(lf->cell->map, targid);
if (target) { if (target) {
if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name); if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name);
if (cansee(lf, target)) { if (!aimovetolf(lf, target, B_TRUE)) {
int goingtomove = B_TRUE; // success
enum OBTYPE spell;
object_t *gun;
// reset F_TARGET lifetime to full.
f->lifetime = AI_FOLLOWTIME;
if (db) dblog(".oO { i can see my target (at %d,%d). might move towards it. }",target->cell->x,target->cell->y);
// remember last known loc
f->val[1] = target->cell->x;
f->val[2] = target->cell->y;
goingtomove = B_TRUE;
// drink boost potions
if (!useitemwithflag(lf, F_AIBOOSTITEM)) {
return;
}
if (!lfhasflag(lf, F_HIDING)) {
objecttype_t *st;
// can we attack with spells (ie. ones which target the victim)?
// if target is adjacent, we will normally just attack rather than try a spell.
spell = aigetattackspell(lf, target);
st = findot(spell);
if ( (spell != OT_NONE) && // found a valid spell/ability to use
((getcelldist(lf->cell, target->cell) != 1) || // there is distance between us and target
(st->obclass->id == OC_ABILITY) || // OR this works from adjacent
(rnd(1,3) == 1)) // OR random chance of using anyway...
) {
int spellfailed = B_FALSE;
lifeform_t *spelllf = NULL;
cell_t *spellcell = NULL;
object_t *spellob = NULL;
if (db) {
dblog(".oO { will cast attack spell: %s }", st->name);
}
// special cases: eg. spells like telekenesis
if (spell == OT_S_TELEKINESIS) {
float maxweight;
object_t *poss[MAXPILEOBS];
int nposs;
int i;
// find nearest object which can be picked up
// this is copied out of the telekenesis spell code!
maxweight = getlfweight(lf, B_NOOBS) +
(getlfweight(lf, B_NOOBS) * (getstatmod(lf, A_IQ) / 100));
nposs = 0;
for (i = 0; i < lf->nlos; i++) {
object_t *o;
for (o = lf->los[i]->obpile->first ; o ; o = o->next) {
if (!hasflag(o->flags, F_NOPICKUP) &&
getobweight(o) <= maxweight) {
poss[nposs] = o;
nposs++;
if (nposs >= MAXPILEOBS) break;
}
}
if (nposs >= MAXPILEOBS) break;
}
if (nposs > 0) {
spellob = poss[rnd(0,nposs-1)];
} else {
spellfailed = B_TRUE;
}
// cast spell at the player
spelllf = target;
spellcell = target->cell;
} else {
// pick targets based on spell flags
aigetspelltarget(lf, st, target, &spelllf, &spellcell, &spellob, F_AICASTTOATTACK);
}
if (spellfailed) {
if (db) dblog(".oO { cast spell/ability failed (1)! }");
} else {
if (getschool(spell) == SS_ABILITY) {
spellfailed = useability(lf, spell, spelllf, spellcell);
} else {
spellfailed = castspell(lf, spell, spelllf, spellob, spellcell);
}
}
if (spellfailed) {
if (db) dblog(".oO { cast spell/ability tried but failed (2)! reason = %d }", reason);
} else {
// spell succesful
return;
}
}
// if not adjacent, check for guns, wands, throwing
if (goingtomove && // if we are still planning on moving
(getcelldist(lf->cell, target->cell) > 1) && // and we're not adjacent to target
haslof(lf->cell, target->cell, LOF_NEED, NULL) && // and we have line of fire to them
(iqb > IQ_ANIMAL) ) { // and we are smarter than an animal
// can we attack by firing a weapon?
gun = getfirearm(lf);
if (goingtomove && gun && getammo(lf)) {
if (db) {
char gunname[BUFLEN];
getobname(gun, gunname, gun->amt);
dblog(".oO { will fire my gun (%s) at target. }",gunname);
}
setguntarget(lf, target);
if (!shoot(lf)) {
// succesful
return;
} else {
if (db) dblog(".oO { shoot gun failed! reason = %d }", reason);
}
} else {
if (db) dblog(".oO { not firing out gun }");
}
// can we attack by throwing something?
if (goingtomove && hasbp(lf, BP_HANDS)) {
o = getbestthrowmissile(lf);
if (o) {
if (db) dblog(".oO { will throw %s at my target instead of moving }", o->type->name);
// try to throw it!
if (!throwat(lf, o, target->cell)) {
// succesful
return;
} else {
if (db) dblog(".oO { throw failed! }");
}
}
}
// do we have a wand we can zap?
if (lfhasflag(lf, F_HUMANOID) || hasbp(lf, BP_HANDS)) {
if (lfhasflag(lf, F_FLEEFROM)) {
o = aigetwand(lf, F_AICASTTOFLEE);
} else {
o = aigetwand(lf, F_AICASTTOATTACK);
}
if (o) {
objecttype_t *st;
cell_t *zapcell = NULL;
st = getlinkspell(o);
if (st) {
enum FLAG purpose;
if (lfhasflag(lf, F_FLEEFROM)) {
purpose = F_AICASTTOFLEE;
} else {
purpose = F_AICASTTOATTACK;
}
aigetspelltarget(lf, st, target, NULL, &zapcell, NULL, purpose);
} else {
// no linkspell - just zap it.
zapcell = NULL;
}
// zap it
if (db) dblog(".oO { will zap %s instead of moving }", o->type->name);
if (!operate(lf, o, zapcell)) {
// succesful
return;
} else {
if (db) dblog(".oO { zap failed! }");
}
}
}
}
} // end if !hiding
// do we have a valid melee attack?
if (!icanattack) {
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
goingtomove = B_FALSE;
}
// if we are hiding, only attack when adjacent to maximise damage
if (lfhasflag(lf, F_HIDING) &&
(getcelldist(lf->cell, target->cell) != 1)) {
goingtomove = B_FALSE;
}
if (goingtomove) {
if (!movetowards(lf, target->cell, DT_ORTH)) {
// success
return;
} else {
if (db) dblog(".oO { move towards failed! - reason = %d }",reason);
}
}
} else {
cell_t *targcell;
if (db) dblog(".oO { i cannot see my target. moving to last known loc %d/%d }",lastx,lasty);
// can't see target.
// move towards their last known location instead
targcell = getcellat(lf->cell->map, lastx, lasty);
if (targcell) {
if (!aigoto(lf, targcell, MR_LF, target, PERMENANT)) {
if (db) dblog(".oO { aigoto target's last known loc failed! }");
}
} else {
if (db) dblog(".oO { go to target's last known loc failed! }");
}
/*
// just try to move in a random direction
if (db) dblog(".oO { will move randomly }");
// dorandommove will call taketime() if it fails,
// so it's safe to just return
dorandommove(lf, B_NOBADMOVES);
return; return;
*/
} }
} }
} }
@ -1025,68 +1204,10 @@ void aiturn(lifeform_t *lf) {
// master is resting. the normal rest code underneath this section // master is resting. the normal rest code underneath this section
// will never be called. // will never be called.
if (master) { if (master) {
lifeform_t *master; //lifeform_t *master;
master = findlf(lf->cell->map, mf->val[0]); //master = findlf(lf->cell->map, mf->val[0]);
if (master && cansee(lf, master)) { if (!aimovetolf(lf, master, B_FALSE)) {
// can see my master // success
if (isresting(master)) {
// rest as well.
rest(lf, B_TRUE);
return;
}
// - either move towards them or randomly
if (isadjacent(lf->cell, master->cell)) {
if (db) dblog(".oO { i can see my master - moving randomly }");
dorandommove(lf, B_NOBADMOVES, B_TRUE);
} else {
// move towards master if not adjacent
if (db) dblog(".oO { i can see my master - moving towards them }");
if (movetowards(lf, master->cell, DT_ORTH)) {
// failed
if (db) dblog(".oO { failed. moving randomly }");
dorandommove(lf, B_NOBADMOVES, B_TRUE);
} else {
// success
if (db) dblog(".oO { success. }");
}
}
return;
} else {
// try to move towards master's last known loc
if (mf->val[1] != NA) {
flag_t *movetoflag = NULL;
cell_t *newcell;
newcell = getcellat(lf->cell->map, mf->val[1], mf->val[2]);
if (newcell == lf->cell) {
int lastdir;
lastdir = getownerlastdir(lf);
if (lastdir != D_NONE) {
// try going in last known dir
if (db) dblog(".oO { cannot see my master and am at last known loc. trying last known dir (%s) }",getdirname(lastdir));
if (!trymove(lf, lastdir, B_TRUE)) {
if (db) dblog(".oO { ...successfully }");
killflagsofid(lf->flags, F_OWNERLASTDIR);
return;
}
}
} else {
if (db) dblog(".oO { cannot see my master - adding F_TARGETCELL for last known loc }");
movetoflag = aigoto(lf, newcell, MR_LF, master, PERMENANT);
}
if (movetoflag) {
aimovetotargetcell(lf, movetoflag);
} else {
if (db) dblog(".oO { cannot see my master and aigoto last known loc/dir failed. randommove. }");
dorandommove(lf, B_NOBADMOVES, B_TRUE);
}
} else {
if (db) dblog(".oO { cannot see my master and dont have a last known location. randommove. }");
dorandommove(lf, B_NOBADMOVES, B_TRUE);
}
return; return;
} }
} }
@ -1273,13 +1394,13 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
ok = B_TRUE; ok = B_TRUE;
} }
} else { } else {
dblog(".oO { cant cast %s - specialcase conditions not yet coded }", ot ? ot->name : "?unkownspell?"); if (db) dblog(".oO { cant cast %s - specialcase conditions not yet coded }", ot ? ot->name : "?unkownspell?");
return B_FALSE; return B_FALSE;
} }
} }
if (!ok) { if (!ok) {
dblog(".oO { cant cast %s - targetting conditions cannot be met }", ot ? ot->name : "?unkownspell?"); if (db) dblog(".oO { cant cast %s - targetting conditions cannot be met }", ot ? ot->name : "?unkownspell?");
return B_FALSE; return B_FALSE;
} }
@ -1409,15 +1530,6 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
} }
int getownerlastdir(lifeform_t *lf) {
flag_t *odflag;
odflag = lfhasflag(lf, F_OWNERLASTDIR);
if (odflag) {
return odflag->val[0];
}
return D_NONE;
}
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) { object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) {
object_t *o; object_t *o;

4
ai.h
View File

@ -4,16 +4,18 @@ void addignorecell(lifeform_t *lf, cell_t *c);
void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit); void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit);
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim); enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim);
enum OBTYPE aigetfleespell(lifeform_t *lf); enum OBTYPE aigetfleespell(lifeform_t *lf);
cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *lasty, int *lastdir);
object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra);
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose); void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose);
object_t *aigetwand(lifeform_t *lf, enum FLAG purpose); object_t *aigetwand(lifeform_t *lf, enum FLAG purpose);
flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int timelimit); flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int timelimit);
int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack);
void aimovetotargetcell(lifeform_t *lf, flag_t *f); void aimovetotargetcell(lifeform_t *lf, flag_t *f);
int aipickup(lifeform_t *lf, object_t *o); int aipickup(lifeform_t *lf, object_t *o);
int aipickupok(lifeform_t *lf, object_t *o); int aipickupok(lifeform_t *lf, object_t *o);
int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target); int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target);
int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose); int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose);
void aiturn(lifeform_t *lf); void aiturn(lifeform_t *lf);
int getownerlastdir(lifeform_t *lf);
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op); object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op);
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op); object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op);
int lookforobs(lifeform_t *lf, int covetsonly); int lookforobs(lifeform_t *lf, int covetsonly);

View File

@ -475,7 +475,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag)
getskill(lf, SK_BACKSTAB) && // able to backstab getskill(lf, SK_BACKSTAB) && // able to backstab
!cansee(victim, lf) && // victim can't see us !cansee(victim, lf) && // victim can't see us
!lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) && // haven't stabbed them before !lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) && // haven't stabbed them before
!lfhasflagval(victim, F_TARGET, lf->id, NA, NA, NULL) // victim isnt attacking us !lfhasflagval(victim, F_TARGETLF, lf->id, NA, NA, NULL) // victim isnt attacking us
) { ) {
addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL); addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL);
dam[0] *= (getskill(lf, SK_BACKSTAB)*2); dam[0] *= (getskill(lf, SK_BACKSTAB)*2);
@ -1163,6 +1163,9 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam
} }
} else if (damtype == DT_TOUCH) { } else if (damtype == DT_TOUCH) {
return "touch"; return "touch";
} else if (damtype == DT_WATER) {
// for when water-vulnerable things go into water
return "hurt";
} else if (damtype == DT_UNARMED) { } else if (damtype == DT_UNARMED) {
if (onein(2)) { if (onein(2)) {
return "punch"; return "punch";

76
defs.h
View File

@ -50,7 +50,9 @@ enum SKILL {
SK_SPELLCASTING, SK_SPELLCASTING,
SK_SPOTHIDDEN, SK_SPOTHIDDEN,
SK_STEALTH, SK_STEALTH,
SK_SWIMMING,
SK_TECHUSAGE, SK_TECHUSAGE,
SK_TRACKING,
SK_TRAPS, SK_TRAPS,
SK_TWOWEAPON, SK_TWOWEAPON,
// knowledge // knowledge
@ -83,7 +85,7 @@ enum SKILL {
SK_SS_TRANSLOCATION, SK_SS_TRANSLOCATION,
SK_SS_WILD, SK_SS_WILD,
}; };
#define MAXSKILLS 44 #define MAXSKILLS 46
// proficiency levels // proficiency levels
enum SKILLLEVEL { enum SKILLLEVEL {
@ -169,6 +171,14 @@ enum LFCONDITION {
C_HEALTHY = 5, C_HEALTHY = 5,
}; };
enum SENSE {
S_HEARING,
S_SIGHT,
S_SMELL,
S_TASTE,
S_TOUCH,
};
// AI defs // AI defs
// if target lf is out of view for this many turns, abandon chase // if target lf is out of view for this many turns, abandon chase
@ -210,7 +220,11 @@ enum LFCONDITION {
#define TICK_INTERVAL (20) #define TICK_INTERVAL (20)
#define SCENTTIME (15)
#define FOOTPRINTTIME (20)
// STRINGS // STRINGS
#define BUFLENTINY 10
#define BUFLENSMALL 64 #define BUFLENSMALL 64
#define BUFLEN 128 #define BUFLEN 128
#define HUGEBUFLEN 1024 #define HUGEBUFLEN 1024
@ -341,6 +355,8 @@ enum LOFTYPE {
#define SP_ULTRASLOW 35 #define SP_ULTRASLOW 35
#define SP_SLOWEST 40 #define SP_SLOWEST 40
#define SPEEDUNIT 5
// speed settings (lower is faster) // speed settings (lower is faster)
#define SPEED_ATTACK SP_NORMAL #define SPEED_ATTACK SP_NORMAL
#define SPEED_DEAD 50 #define SPEED_DEAD 50
@ -734,6 +750,8 @@ enum OBTYPE {
OT_WOODENTABLE, OT_WOODENTABLE,
OT_WOODENBARREL, OT_WOODENBARREL,
OT_WOODENSTOOL, OT_WOODENSTOOL,
OT_HOLYCIRCLE,
OT_PENTAGRAM,
OT_STAIRSDOWN, OT_STAIRSDOWN,
OT_STAIRSUP, OT_STAIRSUP,
OT_VENDINGMACHINE, OT_VENDINGMACHINE,
@ -1196,6 +1214,8 @@ enum OBTYPE {
OT_SPLASHWATER, OT_SPLASHWATER,
OT_PUDDLEWATER, OT_PUDDLEWATER,
OT_PUDDLEWATERL, OT_PUDDLEWATERL,
OT_WATERSHALLOW,
OT_WATERDEEP,
OT_ACIDSPLASH, OT_ACIDSPLASH,
OT_ACIDPUDDLE, OT_ACIDPUDDLE,
OT_ACIDPOOL, OT_ACIDPOOL,
@ -1208,6 +1228,9 @@ enum OBTYPE {
OT_MELTEDWAX, OT_MELTEDWAX,
OT_SOGGYPAPER, OT_SOGGYPAPER,
OT_FLESHCHUNK, OT_FLESHCHUNK,
// trail objects
OT_FOOTPRINT,
OT_SCENT,
// effects // effects
OT_FIRELARGE, OT_FIRELARGE,
OT_FIREMED, OT_FIREMED,
@ -1396,6 +1419,15 @@ enum BODYPART {
}; };
#define MAXBODYPARTS (12) #define MAXBODYPARTS (12)
// depth on a human
enum DEPTH {
DP_HEAD = 4,
DP_SHOULDERS = 3,
DP_WAIST = 2,
DP_FEET = 1,
DP_NONE = 0,
};
// empty types // empty types
#define WE_WALKABLE 1 #define WE_WALKABLE 1
#define WE_EMPTY 2 #define WE_EMPTY 2
@ -1437,6 +1469,13 @@ enum POISONTYPE {
P_WEAKNESS, P_WEAKNESS,
}; };
enum RANGEATTACK {
RA_NONE = 0,
RA_GUN,
RA_THROW,
RA_WAND,
};
enum FLAG { enum FLAG {
F_NONE, // dummy flag F_NONE, // dummy flag
// map flags // map flags
@ -1452,6 +1491,14 @@ enum FLAG {
// text is an object it contains. // text is an object it contains.
F_IDWHENUSED, // fully identify an object when worn/weilded/operated/etc F_IDWHENUSED, // fully identify an object when worn/weilded/operated/etc
F_STARTBLESSED, // v0 = b_blessed or b_cursed F_STARTBLESSED, // v0 = b_blessed or b_cursed
F_REPELBLESSED, // v0 = b_blessed or b_cursed. repels other obejcts
// of this blesstype.
F_TRAIL, // this object denotes the trail left by a lf.
// v0 = raceid of lf who left it
// v1 = direction the lf moved out of this cell
// v2 = enum sense used to see this (ie. s_smell, s_sight)
// (optional) text = lfid of lf who left this.
// should only be used for SCENT, not footprints.
// for items in shops // for items in shops
F_SHOPITEM, // causes shops to show this item as identified F_SHOPITEM, // causes shops to show this item as identified
F_VALUE, // how much an item is worth (over its base weight+material) F_VALUE, // how much an item is worth (over its base weight+material)
@ -1473,7 +1520,7 @@ enum FLAG {
// v0 = con skillcheck difficulty. // v0 = con skillcheck difficulty.
F_BLOCKSVIEW, // if v0 = true, cannot see past this F_BLOCKSVIEW, // if v0 = true, cannot see past this
// if v0 > 0, reduces your vision by v0. // if v0 > 0, reduces your vision by v0.
F_BLOCKSTHROW, // cannot throw past this F_BLOCKSLOF, // this object interrupts line of fire
F_THEREISHERE, // announce "there is xx here!", not "you see xx here" F_THEREISHERE, // announce "there is xx here!", not "you see xx here"
// text[0] is punctuation to use. // text[0] is punctuation to use.
F_OBDIETEXT, // text when the object dies F_OBDIETEXT, // text when the object dies
@ -1484,6 +1531,9 @@ enum FLAG {
F_NOQUALITY, // can't be masterwork / shoddy F_NOQUALITY, // can't be masterwork / shoddy
F_CORPSEOF, // this is a corpse of montype val0. F_CORPSEOF, // this is a corpse of montype val0.
F_DTCONVERT, // damtype val0 converts this to f->text F_DTCONVERT, // damtype val0 converts this to f->text
F_DTCREATEOB, // damtype val0 creates object f->text here
// v1 = radius to burst in
// v2 = dirtype
F_NODTCONVERT, // overrides DTCONVERT . F_NODTCONVERT, // overrides DTCONVERT .
F_NOMATCONVERT, // overrides MATCONVERT . F_NOMATCONVERT, // overrides MATCONVERT .
F_MATCONVERT, // touching material id val0 converts this to f->text F_MATCONVERT, // touching material id val0 converts this to f->text
@ -1537,6 +1587,7 @@ enum FLAG {
// v2 = nutrition left when partially eaten // v2 = nutrition left when partially eaten
F_DRINKABLE, // you can drink this. val1 = nutrition. 100 = a meal F_DRINKABLE, // you can drink this. val1 = nutrition. 100 = a meal
// -1 means "nutrition is weight x abs(val1)" // -1 means "nutrition is weight x abs(val1)"
// if v2=DONTKILL, this object does NOT die when drunk.
F_OPERABLE, // can operate? F_OPERABLE, // can operate?
F_POURABLE, // can pour? F_POURABLE, // can pour?
F_PUSHABLE, // can push this object F_PUSHABLE, // can push this object
@ -1556,6 +1607,7 @@ enum FLAG {
F_JAMMED, // is this door jammed? v0 is # turns it'll take to open it. F_JAMMED, // is this door jammed? v0 is # turns it'll take to open it.
F_SECRET, // this object is secret. v0 is sc_search difficulty F_SECRET, // this object is secret. v0 is sc_search difficulty
// to find it. // to find it.
// NA means 'can never find this'
// stairs / teleporters / portals // stairs / teleporters / portals
F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in
// also use this for portals // also use this for portals
@ -1664,6 +1716,7 @@ enum FLAG {
F_HASHIDDENNAME, // whether this object class has a hidden name F_HASHIDDENNAME, // whether this object class has a hidden name
F_IDENTIFIED, // whether this object is fully identified F_IDENTIFIED, // whether this object is fully identified
// bad flags // bad flags
F_DEEPWATER, // v0 = depth.oooooooooooo
F_WALKDAM, // val0 = damtype, text = dam per sec F_WALKDAM, // val0 = damtype, text = dam per sec
F_WALKDAMBP, // v0 = bodypart, v1 = damtype, text = dam per sec F_WALKDAMBP, // v0 = bodypart, v1 = damtype, text = dam per sec
// if v2 == FALLTHRU, damage falls through to lf if // if v2 == FALLTHRU, damage falls through to lf if
@ -1756,6 +1809,8 @@ enum FLAG {
// v1 = whether this spell needs line of fire // v1 = whether this spell needs line of fire
// MONSTER AI FLAGS // MONSTER AI FLAGS
F_DEMANDSBRIBE, // lf will demand gold from the player. F_DEMANDSBRIBE, // lf will demand gold from the player.
F_NOSWAP, // other mosnters won't swap with this one.
// cleared at start of turn.
F_VARLEVEL, // lf is generated with random level between F_VARLEVEL, // lf is generated with random level between
// 1 and its map dificulty/depth. // 1 and its map dificulty/depth.
// if v0 is set, this is the max level. // if v0 is set, this is the max level.
@ -1767,10 +1822,11 @@ enum FLAG {
F_XPMULTIPLY, // multiply xp val for killing this lf by v0 F_XPMULTIPLY, // multiply xp val for killing this lf by v0
F_NOJOBTEXT, // this lf's name is 'a xxx', not 'a xxx wizard' etc F_NOJOBTEXT, // this lf's name is 'a xxx', not 'a xxx wizard' etc
F_LASTDIR, // this is the last direction we moved. F_LASTDIR, // this is the last direction we moved.
F_OWNERLASTDIR, // for pets, this it the last dir our owner moved //F_OWNERLASTDIR, // for pets, this it the last dir our owner moved
// when we could see them. // when we could see them.
F_PETOF, // this lf is a pet of lfid v0 F_PETOF, // this lf is a pet of lfid v0
// v1/2 = last known location of my owner. // v1/2 = last known location of my owner.
// optional text is last known movement dir.
F_SUMMONEDBY, // this lf was summoned by lfid v0. if they die, we F_SUMMONEDBY, // this lf was summoned by lfid v0. if they die, we
// vanish. // vanish.
// v1 is lifetime left. this decrements each turn. // v1 is lifetime left. this decrements each turn.
@ -1789,7 +1845,10 @@ enum FLAG {
F_FLEEONDAM, // lf will run away instead of counterattacking F_FLEEONDAM, // lf will run away instead of counterattacking
F_FLEEONHPPCT, // lf will run away if its hp drop to v0% or lower F_FLEEONHPPCT, // lf will run away if its hp drop to v0% or lower
F_NOFLEE, // lf will not run away F_NOFLEE, // lf will not run away
F_TARGET, // lf will attack lfid v0. lastknown x/y is v1/v2 F_ATTACKRANGE, // v0/v1 = min/max celldist to stay away
// from f_targetlf (ie. lf we are attacking)
F_TARGETLF, // lf will attack lfid v0. lastknown x/y is v1/v2
// optional text is last known movement dir.
F_IGNORECELL, // won't accept targetcells of v0=x v1=y F_IGNORECELL, // won't accept targetcells of v0=x v1=y
// this is cleared at start of turn. // this is cleared at start of turn.
F_TARGETCELL, // lf will go towards this place. val0=x,val1=y F_TARGETCELL, // lf will go towards this place. val0=x,val1=y
@ -1837,6 +1896,8 @@ enum FLAG {
// text=spell text // text=spell text
// for monsters // for monsters
F_DOESNTMOVE, // this race doesn't move (but can still attack) F_DOESNTMOVE, // this race doesn't move (but can still attack)
F_AQUATIC, // this race can attack normally in water and suffers no
// movement penalties
F_HUMANOID, // this race can wear armour / use weapons F_HUMANOID, // this race can wear armour / use weapons
F_INSECT, // this race is classed as an insect F_INSECT, // this race is classed as an insect
F_UNDEAD, // this race is classed as undead F_UNDEAD, // this race is classed as undead
@ -1870,6 +1931,7 @@ enum FLAG {
// this flag does not get announced. // this flag does not get announced.
F_BLEEDABIL, // will automatically use the ability v0 when F_BLEEDABIL, // will automatically use the ability v0 when
// this lf starts bleeding. // this lf starts bleeding.
F_BREATHWATER, // can breath normally underwater
F_CANWILL, // can cast the spell/ability val0 without using MP F_CANWILL, // can cast the spell/ability val0 without using MP
// v1 is counter untiluse // v1 is counter untiluse
// v2 is what you need to use it // v2 is what you need to use it
@ -1890,6 +1952,7 @@ enum FLAG {
F_DETECTOBS, // autodetect nearby obs in orthog dist v0 F_DETECTOBS, // autodetect nearby obs in orthog dist v0
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_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.
@ -1912,6 +1975,7 @@ enum FLAG {
F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks. F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks.
F_INVISIBLE, // lifeform is invisible F_INVISIBLE, // lifeform is invisible
F_INVULNERABLE,// immune to most damage F_INVULNERABLE,// immune to most damage
// this can apply to objects too!
F_QUICKBITE, // deals v0 d d1 + d2 damage when you hit a bleeding victim F_QUICKBITE, // deals v0 d d1 + d2 damage when you hit a bleeding victim
// (bypasses armour) // (bypasses armour)
F_GRAVBOOSTED,// cannot walk or throw stuff F_GRAVBOOSTED,// cannot walk or throw stuff
@ -2037,6 +2101,8 @@ enum HUNGER {
#define B_FALSE (0) #define B_FALSE (0)
#define B_TRUE (-1) #define B_TRUE (-1)
#define B_DONTKILL (-1)
#define FALLTHRU (-8765) #define FALLTHRU (-8765)
//#define B_TEMP (-1) //#define B_TEMP (-1)
@ -2164,6 +2230,8 @@ enum ERROR {
E_NOOB = 52, E_NOOB = 52,
E_LEVITATING = 53, E_LEVITATING = 53,
E_PRONE = 54, E_PRONE = 54,
E_PENTAGRAM = 55,
E_SWIMMING = 56,
}; };

View File

@ -1,6 +1,8 @@
@ = human @ = human
: = timid animal : = timid animal
} = gas cloud { = water
} = gas
^ = trap / dangerous thing
) = dancing weapon ) = dancing weapon
A = avian / bird A = avian / bird
a = ant a = ant

12
flag.c
View File

@ -117,7 +117,6 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3,
f->pile = fp; f->pile = fp;
// notify // notify
if ((gamemode == GM_GAMESTARTED)) { if ((gamemode == GM_GAMESTARTED)) {
if (f->pile->owner) { if (f->pile->owner) {
@ -253,6 +252,7 @@ int flagcausesredraw(lifeform_t *lf, enum FLAG fid) {
case F_BLIND: case F_BLIND:
case F_DETECTLIFE: case F_DETECTLIFE:
case F_DETECTOBS: case F_DETECTOBS:
case F_ENHANCESMELL:
case F_FASTMOVE: case F_FASTMOVE:
case F_HIDING: case F_HIDING:
case F_INVISIBLE: case F_INVISIBLE:
@ -289,6 +289,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
switch (fid) { switch (fid) {
case F_ASLEEP: case F_ASLEEP:
case F_ATTRMOD:
case F_BLIND: case F_BLIND:
case F_EATING: case F_EATING:
case F_FASTMOVE: case F_FASTMOVE:
@ -415,6 +416,10 @@ void killflag(flag_t *f) {
int redostat = B_FALSE; int redostat = B_FALSE;
int redoscreen = B_FALSE; int redoscreen = B_FALSE;
if (f->id == F_SIZE) {
dblog("xxx");
}
lf = f->pile->owner; lf = f->pile->owner;
if (gamemode == GM_GAMESTARTED) { if (gamemode == GM_GAMESTARTED) {
@ -534,6 +539,11 @@ void killflagpile(flagpile_t *fp) {
} }
void timeeffectsflag(flag_t *f, int howlong) { void timeeffectsflag(flag_t *f, int howlong) {
// special case:
if (f->id == F_TRAIL) {
return;
}
if ((f->lifetime != PERMENANT) && (f->lifetime > 0)) { if ((f->lifetime != PERMENANT) && (f->lifetime > 0)) {
// special case - fast metabolism speeds up poison too. // special case - fast metabolism speeds up poison too.
if (f->id == F_POISONED) { if (f->id == F_POISONED) {

326
io.c
View File

@ -29,6 +29,8 @@ int statdirty = B_TRUE;
int hascolour = B_TRUE; int hascolour = B_TRUE;
int noredraw = B_FALSE;
extern int needredraw; extern int needredraw;
extern int numdraws; extern int numdraws;
@ -291,15 +293,16 @@ void animradial(cell_t *src, int radius, char ch, int colour) {
gl.ch = ch; gl.ch = ch;
gl.colour = colour; gl.colour = colour;
// update screen
updateviewfor(src);
drawlevelfor(player);
// hide cursor // hide cursor
curs_set(0); curs_set(0);
for (i = 0; i <= radius; i++) { for (i = 0; i <= radius; i++) {
int drawn = B_FALSE; int drawn = B_FALSE;
// update screen
updateviewfor(src);
drawlevelfor(player);
for (y = src->y - radius ; y <= src->y + radius ; y++) { for (y = src->y - radius ; y <= src->y + radius ; y++) {
for (x = src->x - radius ; x <= src->x + radius ; x++) { for (x = src->x - radius ; x <= src->x + radius ; x++) {
c = getcellat(src->map, x, y); c = getcellat(src->map, x, y);
@ -331,14 +334,16 @@ void animradialorth(cell_t *src, int radius, char ch,int colour) {
gl.ch = ch; gl.ch = ch;
gl.colour = colour; gl.colour = colour;
// update screen
updateviewfor(src);
drawlevelfor(player);
// hide cursor // hide cursor
curs_set(0); curs_set(0);
for (i = 0; i <= radius; i++) { for (i = 0; i <= radius; i++) {
int drawn = B_FALSE; int drawn = B_FALSE;
// update screen
updateviewfor(src);
drawlevelfor(player);
for (y = src->y - radius ; y <= src->y + radius ; y++) { for (y = src->y - radius ; y <= src->y + radius ; y++) {
for (x = src->x - radius ; x <= src->x + radius ; x++) { for (x = src->x - radius ; x <= src->x + radius ; x++) {
@ -448,7 +453,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars) {
return ch; return ch;
} }
cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange) { cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail) {
static int startlf = -1; static int startlf = -1;
int finished = B_FALSE; int finished = B_FALSE;
int moved = B_FALSE; int moved = B_FALSE;
@ -531,6 +536,8 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange)
drawlevelfor(player); drawlevelfor(player);
if (moved) { if (moved) {
int inlof = B_TRUE, inrange = B_TRUE;
cell_t *trailtarg = NULL;
// show what we are over in msg bar // show what we are over in msg bar
strcpy(buf, ""); strcpy(buf, "");
if (haslos(player, c)) { if (haslos(player, c)) {
@ -739,21 +746,13 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange)
// if scanned, show it. // if scanned, show it.
} else { } else {
// otherwise, show objects // otherwise, show objects
object_t *o;
// find top object name // find top object name
o = gettopobject(c); gettopobname(c, buf);
if (o) {
getobname(o, buf, o->amt);
}
} }
} }
} else { } else {
object_t *o;
// find top object name // find top object name
o = gettopobject(c); gettopobname(c, buf);
if (o) {
getobname(o, buf, o->amt);
}
} }
} else { } else {
// can't see objects or lf there // can't see objects or lf there
@ -772,12 +771,51 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange)
capitalise(buf); capitalise(buf);
if (srclf && (maxrange != UNLIMITED)) { if (srclf && (maxrange != UNLIMITED)) {
if (getcelldist(srclf->cell, c) > maxrange) { if (getcelldist(srclf->cell, c) > maxrange) {
strcat(buf, " [outofrange]"); inrange = B_FALSE;
strcat(buf, " [too-far]");
} }
} }
trailtarg = c;
if (loftype != LOF_DONTNEED) {
cell_t *newcell;
if (!haslof(srclf->cell, c, loftype, &newcell)) {
inlof = B_FALSE;
strcat(buf, " [no-lof]");
}
if (newcell) {
trailtarg = newcell;
}
}
wclear(msgwin); wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s",buf); mvwprintw(msgwin, 0, 0, "%s",buf);
wrefresh(msgwin); wrefresh(msgwin);
// show our line of fire
if (wanttrail && inrange) {
cell_t *retcell[MAXRETCELLS];
int nretcell,i;
glyph_t screenglyph;
// calc path
calcbresnham(srclf->cell->map, srclf->cell->x, srclf->cell->y, trailtarg->x, trailtarg->y, retcell, &nretcell);
for (i = 0; i < nretcell; i++) {
int thisx,thisy;
thisx = retcell[i]->x - viewx;
thisy = retcell[i]->y - viewy;
// get screen cell;
screenglyph.ch = mvwinch(gamewin, thisy, thisx) & A_CHARTEXT;
screenglyph.colour = PAIR_NUMBER(mvwinch(gamewin, thisy, thisx) & A_COLOR);
// draw it inverse.
setcol(gamewin, screenglyph.colour);
wattron(gamewin, A_REVERSE);
mvwprintw(gamewin, thisy, thisx, "%lc", screenglyph.ch);
wattroff(gamewin, A_REVERSE);
unsetcol(gamewin, screenglyph.colour);
}
}
} }
@ -791,10 +829,23 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange)
clearmsg(); clearmsg();
// remember this target // remember this target
if (c->lf) { if (c->lf && cansee(player, c->lf)) {
startlf = c->lf->id; startlf = c->lf->id;
} }
return c; return c;
} else if (ch == 'v') { // view
// TODO: show obpile or view lf
if (c->lf && cansee(player, c->lf)) {
showlfstats(c->lf, B_FALSE);
} else if (haslos(player, c)) {
object_t *o;
// show objects
o = doaskobject(c->obpile, "Describe which object", NULL, B_FALSE, B_FALSE, AO_NONE, F_NONE);
while (o) {
describeob(o);
o = doaskobject(c->obpile, "Describe which object", NULL, B_FALSE, B_FALSE, AO_NONE, F_NONE);
}
}
} else if (ch == 27) { // ESC - cancel } else if (ch == 27) { // ESC - cancel
finished = B_TRUE; finished = B_TRUE;
} else if ((ch == '\'') && (ntargets > 0)) { // cycle targets } else if ((ch == '\'') && (ntargets > 0)) { // cycle targets
@ -984,6 +1035,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
} }
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("%s can now breath underwater.",lfname);
donesomething = B_TRUE;
}
break;
case F_CANCAST: case F_CANCAST:
if (isplayer(lf)) { // don't know if monsters get it if (isplayer(lf)) { // don't know if monsters get it
objecttype_t *ot; objecttype_t *ot;
@ -1139,6 +1196,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
} }
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_ENHANCESMELL:
if (isplayer(lf)) {
msg("Your sense of smell is enhanced!");
}
donesomething = B_TRUE;
break;
case F_DRUNK: case F_DRUNK:
msg("%s %s tipsy.", lfname, isplayer(lf) ? "feel" : "looks"); msg("%s %s tipsy.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE; donesomething = B_TRUE;
@ -1454,6 +1517,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
msg("%s can see again.",lfname); msg("%s can see again.",lfname);
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("%s can no longer breath underwater.",lfname);
donesomething = B_TRUE;
}
break;
case F_CANCAST: case F_CANCAST:
if (isplayer(lf)) { // don't know if monsters lose it if (isplayer(lf)) { // don't know if monsters lose it
objecttype_t *ot; objecttype_t *ot;
@ -1516,6 +1585,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
} }
donesomething = B_TRUE; donesomething = B_TRUE;
break; break;
case F_ENHANCESMELL:
if (isplayer(lf)) {
msg("Your sense of smell is no longer enhanced.");
}
donesomething = B_TRUE;
break;
case F_DRUNK: case F_DRUNK:
msg("%s %s more steady now.", lfname, isplayer(lf) ? "feel" : "looks"); msg("%s %s more steady now.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE; donesomething = B_TRUE;
@ -2078,10 +2153,14 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int
ammo = getammo(op->owner); ammo = getammo(op->owner);
} }
if (countobs(op) <= 0) { if (countobs(op, B_TRUE) <= 0) {
// no objects in pack // no objects here
cls(); cls();
mvwprintw(mainwin, 2, 0, "You have no possessions."); if (op->owner) {
mvwprintw(mainwin, 2, 0, "You have no possessions.");
} else {
mvwprintw(mainwin, 2, 0, "There is nothing here.");
}
// wait for key // wait for key
centre(mainwin, getmaxy(mainwin)-1, "[Press any key]"); centre(mainwin, getmaxy(mainwin)-1, "[Press any key]");
getch(); getch();
@ -2115,11 +2194,15 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int
// can we include this object? // can we include this object?
ok = B_TRUE; ok = B_TRUE;
// check for wanted flags if (!canseeob(player, o)) ok = B_FALSE;
for (n = 0; n < nwantflags; n++) {
if (!hasflag(o->flags, wantflag[n])) { if (ok) {
ok = B_FALSE; // check for wanted flags
break; for (n = 0; n < nwantflags; n++) {
if (!hasflag(o->flags, wantflag[n])) {
ok = B_FALSE;
break;
}
} }
} }
@ -2270,7 +2353,7 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) {
clearretobs(); clearretobs();
if (countobs(op) <= 0) { if (countobs(op, B_FALSE) <= 0) {
// no objects in pack // no objects in pack
cls(); cls();
mvwprintw(mainwin, 2, 0, "You have no possessions."); mvwprintw(mainwin, 2, 0, "You have no possessions.");
@ -2304,8 +2387,13 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) {
for (o = op->first ; o ; o = o->next) { for (o = op->first ; o ; o = o->next) {
if (o->type->obclass->id == sortorder[c]) { if (o->type->obclass->id == sortorder[c]) {
int ok; int ok;
// can we include this object? // can we include this object?
ok = obmatchescondition(o, opts); if (!canseeob(player, o)) {
ok = B_FALSE;
} else {
ok = obmatchescondition(o, opts);
}
if (ok) { if (ok) {
mylist[i] = o; mylist[i] = o;
@ -2550,7 +2638,12 @@ void updatestatus(void) {
wrefresh(statwin); wrefresh(statwin);
} }
void updateviewfor(cell_t *cell) {
// returns true if view changed
int updateviewfor(cell_t *cell) {
int oldvx,oldvy;
oldvx = viewx;
oldvy = viewy;
// calculate viewport if required // calculate viewport if required
if ((viewx == -9999) || (viewy == -9999)) { if ((viewx == -9999) || (viewy == -9999)) {
// try to centre player // try to centre player
@ -2570,6 +2663,11 @@ void updateviewfor(cell_t *cell) {
while ((cell->y - viewy) <= (SCREENH/3)) { while ((cell->y - viewy) <= (SCREENH/3)) {
viewy--; viewy--;
} }
if ((viewx != oldvx) || (viewy != oldvy)) {
return B_TRUE;
}
return B_FALSE;
} }
@ -2968,6 +3066,9 @@ void describeob(object_t *o) {
case F_BLIND: case F_BLIND:
mvwprintw(mainwin, y, 0, "%s prevents you from seeing.", buf); y++; mvwprintw(mainwin, y, 0, "%s prevents you from seeing.", buf); y++;
break; break;
case F_BREATHWATER:
mvwprintw(mainwin, y, 0, "%s allows you to breath normally while underwater.", buf); y++;
break;
case F_CONTROL: case F_CONTROL:
mvwprintw(mainwin, y, 0, "%s lets you control teleportation and polymorphic effects.", buf); y++; mvwprintw(mainwin, y, 0, "%s lets you control teleportation and polymorphic effects.", buf); y++;
break; break;
@ -2986,6 +3087,9 @@ void describeob(object_t *o) {
case F_ENHANCESEARCH: case F_ENHANCESEARCH:
mvwprintw(mainwin, y, 0, "%s enhances your searching ability.", buf); y++; mvwprintw(mainwin, y, 0, "%s enhances your searching ability.", buf); y++;
break; break;
case F_ENHANCESMELL:
mvwprintw(mainwin, y, 0, "%s enhances your sense of smell.", buf); y++;
break;
case F_DRUNK: case F_DRUNK:
mvwprintw(mainwin, y, 0, "%s makes you tipsy.", buf); y++; mvwprintw(mainwin, y, 0, "%s makes you tipsy.", buf); y++;
break; break;
@ -3375,7 +3479,7 @@ void docomms(void) {
char ch; char ch;
flag_t *f; flag_t *f;
where = askcoords("Talk to who?", TT_MONSTER, player, UNLIMITED); where = askcoords("Talk to who?", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(player, where->lf)) { if (where && where->lf && cansee(player, where->lf)) {
lf = where->lf; lf = where->lf;
} }
@ -3416,7 +3520,7 @@ void docomms(void) {
char lfname2[BUFLEN]; char lfname2[BUFLEN];
case 'a': case 'a':
sprintf(buf, "Tell %s to attack who?",lfname); sprintf(buf, "Tell %s to attack who?",lfname);
c = askcoords(buf, TT_MONSTER, player, UNLIMITED); c = askcoords(buf, TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && c->lf && cansee(player, c->lf)) { if (c && c->lf && cansee(player, c->lf)) {
lf2 = c->lf; lf2 = c->lf;
@ -3890,7 +3994,8 @@ void dolook(cell_t *where, int onpurpose) {
// (also count objects without this flag) // (also count objects without this flag)
numobs = 0; numobs = 0;
for (o = where->obpile->first ; o ; o = o->next) { for (o = where->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_SECRET)) continue; if (!canseeob(player, o)) continue;
//if (hasflag(o->flags, F_SECRET)) continue;
if (hasflag(o->flags, F_COSMETIC)) continue; if (hasflag(o->flags, F_COSMETIC)) continue;
f = hasflag(o->flags, F_THEREISHERE); f = hasflag(o->flags, F_THEREISHERE);
@ -3922,11 +4027,11 @@ void dolook(cell_t *where, int onpurpose) {
msg("You %s %s here.", seeverb, buf); msg("You %s %s here.", seeverb, buf);
} }
} else if ((numobs > 1) && (numobs <= 3)) { } else if ((numobs > 1) && (numobs <= 3)) {
msg("You %s a few objects here.", seeverb); msg("You %s a few things here.", seeverb);
} else if ((numobs > 3) && (numobs <= 6)) { } else if ((numobs > 3) && (numobs <= 6)) {
msg("You %s some objects here.", seeverb); msg("You %s some things here.", seeverb);
} else if (numobs > 6) { } else if (numobs > 6) {
msg("You %s many objects here.", seeverb); msg("You %s many things here.", seeverb);
} }
seensomething = B_TRUE; seensomething = B_TRUE;
} }
@ -4253,29 +4358,49 @@ int dopickup(obpile_t *op) {
lifeform_t *fromlf = NULL; lifeform_t *fromlf = NULL;
char lfname[BUFLEN]; char lfname[BUFLEN];
char buf[BUFLEN]; char buf[BUFLEN];
int needtoask = B_TRUE;
int failed = B_FALSE;
if (op->owner) { if (op->owner) {
fromlf = op->owner; fromlf = op->owner;
getlfname(fromlf, lfname); getlfname(fromlf, lfname);
} }
obcount = countobs(op, B_TRUE);
obcount = countobs(op);
// anything here? // anything here?
if (obcount == 0) { if (obcount == 0) {
failed = B_TRUE;
} else if (!fromlf && (obcount == 1)) {
object_t *o;
// find first visible object
o = op->first;
while (o && !canseeob(player, o)) {
o = o->next;
}
if (o) {
if (o->amt == 1) {
// just get it
howmany = ALL;
retobs[0] = op->first;
retobscount[0] = op->first->amt;
nretobs = 1;
needtoask = B_FALSE;
}
} else {
failed = B_TRUE;
}
}
if (failed) {
if (fromlf) { if (fromlf) {
msg("%s is not carrying anything!", lfname); msg("%s is not carrying anything!", lfname);
} else { } else {
msg("There is nothing here to pick up!"); msg("There is nothing here to pick up!");
} }
return B_TRUE; return B_TRUE;
} else if (!fromlf && (obcount == 1) && (op->first->amt == 1)) { }
// just get it
howmany = ALL; if (needtoask) {
retobs[0] = op->first;
retobscount[0] = op->first->amt;
nretobs = 1;
} else {
if (fromlf) { if (fromlf) {
sprintf(buf, "Take what from %s",lfname); sprintf(buf, "Take what from %s",lfname);
} else { } else {
@ -4329,33 +4454,9 @@ void doenter(lifeform_t *lf) {
} }
void doexplain(char *question) { void doexplain(char *question) {
char buf[BUFLEN]; askcoords(question, TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
cell_t *where;
int done = B_FALSE;
while (!done) {
//sprintf(buf, "Select glyph to explain (ESC to cancel):");
where = askcoords(question, TT_NONE, player, UNLIMITED);
if (!where) {
clearmsg();
break;
}
// explain it
if (where->lf && cansee(player, where->lf)) {
showlfstats(where->lf, B_FALSE);
} else {
object_t *o;
// object description
o = gettopobject(where);
if (o) {
getobdesc(o, buf);
}
msg("%s", buf);
}
}
msg("Done.");
restoregamewindows(); restoregamewindows();
msg("Done.");
} }
void dofinaloblist(obpile_t *op) { void dofinaloblist(obpile_t *op) {
@ -4715,7 +4816,7 @@ void doselguntarget(void) {
getobname(gun, gunname, 1); getobname(gun, gunname, 1);
sprintf(buf, "Aim %s where?",gunname); sprintf(buf, "Aim %s where?",gunname);
where = askcoords(buf, TT_MONSTER, player, UNLIMITED); where = askcoords(buf, TT_MONSTER, player, UNLIMITED, LOF_NEED, B_TRUE);
if (where) { if (where) {
if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) { if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) {
setguntarget(player, where->lf); setguntarget(player, where->lf);
@ -4787,7 +4888,7 @@ void dothrow(obpile_t *op) {
// ask where to throw it // ask where to throw it
sprintf(buf2, "Throw %s where?",buf); sprintf(buf2, "Throw %s where?",buf);
where = askcoords(buf2, TT_MONSTER, player, UNLIMITED); where = askcoords(buf2, TT_MONSTER, player, maxdist, LOF_NEED, B_TRUE);
if (where) { if (where) {
cell_t *newwhere = NULL; cell_t *newwhere = NULL;
@ -4942,6 +5043,10 @@ void drawlevelfor(lifeform_t *lf) {
int db = B_FALSE; int db = B_FALSE;
int w,h; int w,h;
if (noredraw) {
return;
}
map = lf->cell->map; map = lf->cell->map;
needredraw = B_FALSE; needredraw = B_FALSE;
@ -4960,8 +5065,7 @@ void drawlevelfor(lifeform_t *lf) {
} }
for (y = 0; y < h; y++) { for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) { for (x = 0; x < w; x++) {
glyph_t glyph,screenglyph; glyph_t glyph;
int needdraw = B_FALSE;
cell = getcellat(map, x + viewx, y + viewy); cell = getcellat(map, x + viewx, y + viewy);
if (cell) { if (cell) {
@ -4972,23 +5076,16 @@ void drawlevelfor(lifeform_t *lf) {
} }
// only draw if screen char/colour is different // only draw if screen char/colour is different
screenglyph.ch = mvwinch(gamewin, y, x) & A_CHARTEXT; if (!screenglyphmatches(x, y, &glyph)) {
if (screenglyph.ch != glyph.ch) {
needdraw = B_TRUE;
} else {
screenglyph.colour = PAIR_NUMBER(mvwinch(gamewin, y, x) & A_COLOR);
if (screenglyph.colour != glyph.colour) {
needdraw = B_TRUE;
}
}
if (needdraw) {
drawglyph(&glyph, x, y); drawglyph(&glyph, x, y);
/*
if (db) { if (db) {
dblog(" drawing char '%lc'/%d at %d,%d (screenglyph was '%lc'/%d)\n\n", dblog(" drawing char '%lc'/%d at %d,%d (screenglyph was '%lc'/%d)\n\n",
glyph.ch, glyph.ch, glyph.ch, glyph.ch,
x,y, x,y,
screenglyph.ch, screenglyph.ch); screenglyph.ch, screenglyph.ch);
} }
*/
ndrawn++; ndrawn++;
} }
} }
@ -5574,7 +5671,7 @@ void handleinput(void) {
// something here? // something here?
if (hasgettableobs) { if (hasgettableobs) {
stoprunning(player); stoprunning(player);
} else if (!canmove(player, dir, NULL)) { // can't move anymore? } else if (!moveclear(player, dir, NULL)) { // can't move anymore?
stoprunning(player); stoprunning(player);
} else { } else {
if (trymove(player, dir, B_TRUE)) { if (trymove(player, dir, B_TRUE)) {
@ -6104,6 +6201,12 @@ void drawstatus(void) {
unsetcol(statwin, C_RED); unsetcol(statwin, C_RED);
} }
if (isswimming(player)) {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Swimming");
unsetcol(statwin, C_BOLDBLUE);
}
// paralysed somehow? // paralysed somehow?
if (isresting(player)) { if (isresting(player)) {
setcol(statwin, C_CYAN); setcol(statwin, C_CYAN);
@ -6448,6 +6551,17 @@ void redraw(void) {
wrefresh(gamewin); wrefresh(gamewin);
} }
void redrawpause(void) {
noredraw = B_TRUE;
}
void redrawresume(void) {
noredraw = B_FALSE;
if (needredraw) {
drawlevelfor(player);
}
}
void restoregamewindows(void) { void restoregamewindows(void) {
needredraw = B_TRUE; needredraw = B_TRUE;
statdirty = B_TRUE; statdirty = B_TRUE;
@ -6456,6 +6570,28 @@ void restoregamewindows(void) {
drawscreen(); drawscreen();
} }
int screenglyphmatches(int x, int y, glyph_t *g) {
int attribs;
glyph_t screenglyph;
screenglyph.ch = mvwinch(gamewin, y, x) & A_CHARTEXT;
if (screenglyph.ch != g->ch) {
return B_FALSE;
}
screenglyph.colour = PAIR_NUMBER(mvwinch(gamewin, y, x) & A_COLOR);
if (screenglyph.colour != g->colour) {
return B_FALSE;
}
// reverse video highlight from askcoords?
attribs = mvwinch(gamewin, y, x) & A_ATTRIBUTES;
if (attribs & A_REVERSE) {
return B_FALSE;
}
return B_TRUE;
}
void setcol(WINDOW *win, enum COLOUR col) { void setcol(WINDOW *win, enum COLOUR col) {
if (needsbold(col)) { if (needsbold(col)) {
wattron(win, A_BOLD); wattron(win, A_BOLD);
@ -7687,6 +7823,10 @@ void showlfstats(lifeform_t *lf, int showall) {
} }
// flags which aren't really intrinsics // flags which aren't really intrinsics
if (lfhasflag(lf, F_AQUATIC)) {
mvwprintw(mainwin, y, 0, "%s %s aquatic, and move normally through water.", you(lf), is(lf));
y++;
}
if (lfhasflag(lf, F_VEGETARIAN)) { if (lfhasflag(lf, F_VEGETARIAN)) {
mvwprintw(mainwin, y, 0, "%s %s a vegetarian.", you(lf), is(lf)); mvwprintw(mainwin, y, 0, "%s %s a vegetarian.", you(lf), is(lf));
y++; y++;
@ -7746,6 +7886,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, buf); mvwprintw(mainwin, y, 0, buf);
y++; y++;
} }
f = lfhasknownflag(lf, F_BREATHWATER);
if (f) {
mvwprintw(mainwin, y, 0, "%s can breath normally while underwater.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_CONTROL); f = lfhasknownflag(lf, F_CONTROL);
if (f) { if (f) {
mvwprintw(mainwin, y, 0, "%s can control teleportation and polymorphic effects.", you(lf)); mvwprintw(mainwin, y, 0, "%s can control teleportation and polymorphic effects.", you(lf));
@ -7782,6 +7927,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, "%s searching ability is enhanced.", you(lf), isplayer(lf) ? "Your" : "Its"); mvwprintw(mainwin, y, 0, "%s searching ability is enhanced.", you(lf), isplayer(lf) ? "Your" : "Its");
y++; y++;
} }
f = lfhasknownflag(lf, F_ENHANCESMELL);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s an enhanced sense of smell.", you(lf), isplayer(lf) ? "have" : "has");
y++;
}
f = lfhasknownflag(lf, F_DRUNK); f = lfhasknownflag(lf, F_DRUNK);
if (f) { if (f) {
@ -8058,7 +8208,7 @@ void showlfstats(lifeform_t *lf, int showall) {
y = 2; y = 2;
if (lfhasflag(lf, F_NOPACK)) { if (lfhasflag(lf, F_NOPACK)) {
mvwprintw(mainwin, y, 0, "It cannot carry anything."); mvwprintw(mainwin, y, 0, "It cannot carry anything.");
} else if (countobs(lf->pack)) { } else if (countobs(lf->pack, B_FALSE)) {
char invtitle[BUFLEN]; char invtitle[BUFLEN];
float packweight,maxweight,pct; float packweight,maxweight,pct;
packweight = getobpileweight(lf->pack); packweight = getobpileweight(lf->pack);

7
io.h
View File

@ -20,7 +20,7 @@ object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, en
object_t *doaskobject(obpile_t *op, char *title, int *count, int forpickup, int showpoints, long opts, ...); object_t *doaskobject(obpile_t *op, char *title, int *count, int forpickup, int showpoints, long opts, ...);
int askobjectmulti(obpile_t *op, char *prompt, long opts); int askobjectmulti(obpile_t *op, char *prompt, long opts);
char askchar(char *prompt, char *validchars, char *def, int showchars); char askchar(char *prompt, char *validchars, char *def, int showchars);
cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange); cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail);
char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def); char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def);
void centre(WINDOW *win, int y, char *format, ... ); void centre(WINDOW *win, int y, char *format, ... );
int chartodir(char ch); int chartodir(char ch);
@ -95,7 +95,10 @@ int needsbold(enum COLOUR col);
void nothinghappens(void); void nothinghappens(void);
void dblog(char *format, ... ); void dblog(char *format, ... );
void redraw(void); void redraw(void);
void redrawpause(void);
void redrawresume(void);
void restoregamewindows(void); void restoregamewindows(void);
int screenglyphmatches(int x, int y, glyph_t *g);
void setcol(WINDOW *win, enum COLOUR col); void setcol(WINDOW *win, enum COLOUR col);
void unsetcol(WINDOW *win, enum COLOUR col); void unsetcol(WINDOW *win, enum COLOUR col);
void setobcolour(WINDOW *win, object_t *o, int set); void setobcolour(WINDOW *win, object_t *o, int set);
@ -103,4 +106,4 @@ void showlfarmour(lifeform_t *lf);
void showlfstats(lifeform_t *lf, int showall); void showlfstats(lifeform_t *lf, int showall);
void tombstone(lifeform_t *lf); void tombstone(lifeform_t *lf);
void updatestatus(void); void updatestatus(void);
void updateviewfor(cell_t *cell); int updateviewfor(cell_t *cell);

640
lf.c

File diff suppressed because it is too large Load Diff

9
lf.h
View File

@ -6,6 +6,7 @@ job_t *addjob(enum JOB id, char *name);
race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass); race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass);
raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill); raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill);
skill_t *addskill(enum SKILL id, char *name, char *desc); skill_t *addskill(enum SKILL id, char *name, char *desc);
void addtrail(lifeform_t *lf, int dir);
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype); void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype);
void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o); void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o);
int areallies(lifeform_t *lf1, lifeform_t *lf2); int areallies(lifeform_t *lf1, lifeform_t *lf2);
@ -35,7 +36,8 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where);
int canweild(lifeform_t *lf, object_t *o); int canweild(lifeform_t *lf, object_t *o);
int cantakeoff(lifeform_t *lf, object_t *o); int cantakeoff(lifeform_t *lf, object_t *o);
int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell); int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell);
void checkxp(enum RACE rid); int checkfordrowning(lifeform_t *lf, object_t *o);
//void checkxp(enum RACE rid);
float comparelfs(lifeform_t *lf1, lifeform_t *lf2); float comparelfs(lifeform_t *lf1, lifeform_t *lf2);
int countinnateattacks(lifeform_t *lf); int countinnateattacks(lifeform_t *lf);
int countmoney(lifeform_t *lf); int countmoney(lifeform_t *lf);
@ -91,6 +93,7 @@ char *getbodypartname(enum BODYPART bp);
char *getbodypartequipname(enum BODYPART bp); char *getbodypartequipname(enum BODYPART bp);
object_t *getequippedob(obpile_t *op, enum BODYPART bp); object_t *getequippedob(obpile_t *op, enum BODYPART bp);
object_t *getfirearm(lifeform_t *lf); object_t *getfirearm(lifeform_t *lf);
int getfootprinttime(lifeform_t *lf);
lifeform_t *getguntarget(lifeform_t *lf); lifeform_t *getguntarget(lifeform_t *lf);
int getguntargetid(lifeform_t *lf); int getguntargetid(lifeform_t *lf);
//int gethealtime(lifeform_t *lf); //int gethealtime(lifeform_t *lf);
@ -160,6 +163,7 @@ char *getskilldesc(enum SKILL id );
char *getskillname(enum SKILL id ); char *getskillname(enum SKILL id );
char *getskilllevelname(enum SKILLLEVEL sl); char *getskilllevelname(enum SKILLLEVEL sl);
int getthrowspeed(int str); int getthrowspeed(int str);
void getwantdistance(lifeform_t *lf, int *min, int *max, int attacking);
object_t *getweapon(lifeform_t *lf); object_t *getweapon(lifeform_t *lf);
long getxpforlev(int level); long getxpforlev(int level);
void givejob(lifeform_t *lf, enum JOB jobid); void givejob(lifeform_t *lf, enum JOB jobid);
@ -206,6 +210,7 @@ int isloreskill(enum SKILL skid);
int ismaxedskill(lifeform_t *lf, enum SKILL skid); int ismaxedskill(lifeform_t *lf, enum SKILL skid);
int ispeaceful(lifeform_t *lf); int ispeaceful(lifeform_t *lf);
int ispetof(lifeform_t *lf, lifeform_t *owner); int ispetof(lifeform_t *lf, lifeform_t *owner);
flag_t *ispetortarget(lifeform_t *lf, lifeform_t *ownertarget);
int isplayer(lifeform_t *lf); int isplayer(lifeform_t *lf);
flag_t *ispoisoned(lifeform_t *lf); flag_t *ispoisoned(lifeform_t *lf);
flag_t *ispoisonedwith(lifeform_t *lf, enum POISONTYPE pt); flag_t *ispoisonedwith(lifeform_t *lf, enum POISONTYPE pt);
@ -214,6 +219,8 @@ int isprone(lifeform_t *lf);
flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt); flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt);
flag_t *isresting(lifeform_t *lf); flag_t *isresting(lifeform_t *lf);
object_t *isstuck(lifeform_t *lf); object_t *isstuck(lifeform_t *lf);
int isswimming(lifeform_t *lf);
int isundead(lifeform_t *lf);
flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt);
void killjob(job_t *job); void killjob(job_t *job);
void killlf(lifeform_t *lf); void killlf(lifeform_t *lf);

539
log.txt
View File

@ -2,364 +2,183 @@
====== NEW LOGFILE ==== ====== NEW LOGFILE ====
givejob() starting. rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +32%
xxx rollhitdice() ---- die 1/1 == 3
xxx TOTAL: 3
xxx -> modified to: 3
xxx rollhitdice() for giant rat - rolling 0d4 + 1
lfid 175 (kobold) spending 20 time rollhitdice() - mod is +0%
TOTAL: 1
lfid 180 (kobold) spending 20 time -> modified to: 1
rollhitdice() for xat - rolling 1d4 + 0
xxx rollhitdice() - mod is +54%
xxx rollhitdice() ---- die 1/1 == 2
lfid 181 (kobold) spending 20 time TOTAL: 2
-> modified to: 3
xxx rollhitdice() for giant rat - rolling 0d4 + 1
xxx rollhitdice() - mod is +0%
xxx TOTAL: 1
xxx -> modified to: 1
xxx rollhitdice() for kobold - rolling 1d4 + 0
lfid 198 (human) spending 20 time rollhitdice() - mod is +44%
rollhitdice() ---- die 1/1 == 3
xxx TOTAL: 3
xxx -> modified to: 4
xxx rollhitdice() for giant newt - rolling 1d4 + 0
xxx rollhitdice() - mod is +-16%
xxx rollhitdice() ---- die 1/1 == 4
xxx TOTAL: 4
xxx -> modified to: 4
xxx rollhitdice() for xat - rolling 1d4 + 0
lfid 175 (kobold) spending 20 time rollhitdice() - mod is +76%
rollhitdice() ---- die 1/1 == 1
xxx TOTAL: 1
lfid 180 (kobold) spending 20 time -> modified to: 1
rollhitdice() for giant newt - rolling 1d4 + 0
fireat(): dam = throwdam(3) * speed(2)/2 = 3 rollhitdice() - mod is +10%
lfid 181 (kobold) spending 20 time rollhitdice() ---- die 1/1 == 4
TOTAL: 4
fireat(): dam = throwdam(2) * speed(3)/2 = 2 -> modified to: 4
xxx rollhitdice() for giant newt - rolling 1d4 + 0
xxx rollhitdice() - mod is +76%
xxx rollhitdice() ---- die 1/1 == 4
lfid 195 (kobold) spending 20 time TOTAL: 4
-> modified to: 7
xxx rollhitdice() for xat - rolling 1d4 + 0
lfid 198 (human) spending 20 time rollhitdice() - mod is +-27%
rollhitdice() ---- die 1/1 == 4
xxx TOTAL: 4
xxx -> modified to: 3
xxx rollhitdice() for giant rat - rolling 0d4 + 1
xxx rollhitdice() - mod is +22%
xxx TOTAL: 1
lfid 175 (kobold) spending 20 time -> modified to: 1
rollhitdice() for giant rat - rolling 0d4 + 1
xxx rollhitdice() - mod is +10%
lfid 178 (kobold) spending 20 time TOTAL: 1
-> modified to: 1
xxx rollhitdice() for giant rat - rolling 0d4 + 1
lfid 180 (kobold) spending 20 time rollhitdice() - mod is +0%
TOTAL: 1
fireat(): dam = throwdam(3) * speed(2)/2 = 3 -> modified to: 1
xxx rollhitdice() for kobold - rolling 1d4 + 0
lfid 181 (kobold) spending 20 time rollhitdice() - mod is +-5%
rollhitdice() ---- die 1/1 == 4
xxx TOTAL: 4
xxx -> modified to: 4
xxx rollhitdice() for kobold - rolling 1d4 + 0
lfid 195 (kobold) spending 20 time rollhitdice() - mod is +88%
rollhitdice() ---- die 1/1 == 4
xxx TOTAL: 4
xxx -> modified to: 7
lfid 198 (human) spending 20 time rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +-5%
xxx rollhitdice() ---- die 1/1 == 4
xxx TOTAL: 4
xxx -> modified to: 4
xxx rollhitdice() for troglodyte - rolling 1d4 + 0
xxx rollhitdice() - mod is +0%
xxx rollhitdice() ---- die 1/1 == 4
lfid 175 (kobold) spending 20 time TOTAL: 4
-> modified to: 4
xxx rollhitdice() for giant newt - rolling 1d4 + 0
lfid 178 (kobold) spending 20 time rollhitdice() - mod is +10%
rollhitdice() ---- die 1/1 == 1
xxx TOTAL: 1
xxx -> modified to: 1
xxx rollhitdice() for giant newt - rolling 1d4 + 0
lfid 195 (kobold) spending 15 time rollhitdice() - mod is +0%
rollhitdice() ---- die 1/1 == 1
xxx TOTAL: 1
xxx -> modified to: 1
lfid 198 (human) spending 20 time rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +-11%
lfid 170 (giant rat) spending 15 time TOTAL: 1
-> modified to: 1
xxx rollhitdice() for giant newt - rolling 1d4 + 0
xxx rollhitdice() - mod is +76%
xxx rollhitdice() ---- die 1/1 == 3
xxx TOTAL: 3
xxx -> modified to: 5
xxx rollhitdice() for giant rat - rolling 0d4 + 1
xxx rollhitdice() - mod is +32%
xxx TOTAL: 1
lfid 178 (kobold) spending 15 time -> modified to: 1
rollhitdice() for giant newt - rolling 1d4 + 0
xxx rollhitdice() - mod is +-11%
xxx rollhitdice() ---- die 1/1 == 2
xxx TOTAL: 2
xxx -> modified to: 2
lfid 198 (human) spending 20 time rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +66%
xxx rollhitdice() ---- die 1/1 == 4
xxx TOTAL: 4
xxx -> modified to: 6
xxx rollhitdice() for giant newt - rolling 1d4 + 0
xxx rollhitdice() - mod is +76%
xxx rollhitdice() ---- die 1/1 == 1
xxx TOTAL: 1
xxx -> modified to: 1
xxx rollhitdice() for xat - rolling 1d4 + 0
xxx rollhitdice() - mod is +32%
xxx rollhitdice() ---- die 1/1 == 2
xxx TOTAL: 2
lfid 198 (human) spending 20 time -> modified to: 2
rollhitdice() for giant rat - rolling 0d4 + 1
xxx rollhitdice() - mod is +54%
xxx TOTAL: 1
xxx -> modified to: 1
xxx rollhitdice() for kobold - rolling 1d4 + 0
xxx rollhitdice() - mod is +54%
xxx rollhitdice() ---- die 1/1 == 1
lfid 167 (xat) spending 20 time TOTAL: 1
-> modified to: 1
xxx rollhitdice() for kobold - rolling 1d4 + 0
xxx rollhitdice() - mod is +10%
xxx rollhitdice() ---- die 1/1 == 3
xxx TOTAL: 3
xxx -> modified to: 3
xxx rollhitdice() for kobold - rolling 1d4 + 0
xxx rollhitdice() - mod is +0%
xxx rollhitdice() ---- die 1/1 == 3
xxx TOTAL: 3
xxx -> modified to: 3
lfid 198 (human) spending 20 time rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +32%
xxx rollhitdice() ---- die 1/1 == 3
xxx TOTAL: 3
xxx -> modified to: 3
xxx rollhitdice() for giant rat - rolling 0d4 + 1
xxx rollhitdice() - mod is +-16%
xxx TOTAL: 1
xxx -> modified to: 1
xxx rollhitdice() for xat - rolling 1d4 + 0
xxx rollhitdice() - mod is +22%
xxx rollhitdice() ---- die 1/1 == 2
xxx TOTAL: 2
xxx -> modified to: 2
xxx rollhitdice() for giant newt - rolling 1d4 + 0
xxx rollhitdice() - mod is +66%
lfid 198 (human) spending 20 time rollhitdice() ---- die 1/1 == 4
TOTAL: 4
xxx -> modified to: 6
xxx rollhitdice() for human - rolling 2d4 + 2
xxx rollhitdice() - mod is +0%
xxx rollhitdice() ---- die 1/2 == 6
xxx rollhitdice() ---- die 2/2 == 4
xxx TOTAL: 10
xxx -> modified to: 10
xxx rollhitdice() for young wolf - rolling 2d4 + 2
xxx rollhitdice() - mod is +100%
xxx rollhitdice() ---- die 1/2 == 4
xxx rollhitdice() ---- die 2/2 == 4
xxx TOTAL: 8
xxx -> modified to: 16
xxx xxx
lfid 198 (human) spending 20 time rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +44%
xxx rollhitdice() ---- die 1/1 == 3
xxx TOTAL: 3
xxx -> modified to: 4
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 40 time
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
lfid 175 (kobold) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx xxx

128
map.c
View File

@ -112,11 +112,13 @@ map_t *addmap(void) {
// when monsters are made during level generation, autogen will be true. otherwise false; // when monsters are made during level generation, autogen will be true. otherwise false;
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen) { lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen, int *nadded) {
lifeform_t *lf = NULL; lifeform_t *lf = NULL;
race_t *r; race_t *r;
int db = B_FALSE; int db = B_FALSE;
if (nadded) *nadded = 0;
// ie. don't create mosnters on closed doors! // ie. don't create mosnters on closed doors!
if (!cellwalkable(NULL, c, NULL)) { if (!cellwalkable(NULL, c, NULL)) {
return NULL; return NULL;
@ -133,13 +135,25 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
assert(r); assert(r);
if (db) dblog("adding rand lf %s to cell %d,%d",r->name,c->x,c->y);
if (db) {
char buf[BUFLEN];
sprintf(buf, "start addmonster for %s",r->name);
dbtimestart(buf);
}
//if (db) dblog("adding rand lf %s to cell %d,%d",r->name,c->x,c->y);
if (r) { if (r) {
if (db) dbtime("doing lf addition");
lf = addlf(c, r->id, getrandommonlevel(r, c->map)); lf = addlf(c, r->id, getrandommonlevel(r, c->map));
if (db) dbtime("finished lf addition");
if (lf) { if (lf) {
flag_t *f; flag_t *f;
if (nadded) (*nadded)++;
if (db) dbtime("checking for job");
lf->born = B_FALSE; lf->born = B_FALSE;
if (jobok) { if (jobok) {
for (f = lf->flags->first ; f ; f = f->next) { for (f = lf->flags->first ; f ; f = f->next) {
@ -173,6 +187,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
} }
// appears in groups? // appears in groups?
if (db) dbtime("handling groups");
if (autogen) { if (autogen) {
f = hasflag(lf->flags, F_NUMAPPEAR); f = hasflag(lf->flags, F_NUMAPPEAR);
if (f) { if (f) {
@ -188,7 +203,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
lifeform_t *newlf; lifeform_t *newlf;
// find an adjacent cell to one of the newly added monsters, // find an adjacent cell to one of the newly added monsters,
// starting with the first one // starting with the first one
adjcell = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL);
// did we find one? // did we find one?
if (!adjcell) break; if (!adjcell) break;
@ -196,6 +211,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
if (!newlf) { if (!newlf) {
break; break;
} }
if (nadded) (*nadded)++;
newlf->born = B_FALSE; newlf->born = B_FALSE;
// initial monster shoudl remember its minions // initial monster shoudl remember its minions
@ -215,6 +231,8 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
} }
// minons? // minons?
// appears in groups?
if (db) dbtime("handling minions");
if (autogen) { if (autogen) {
f = hasflag(lf->flags, F_MINIONS); f = hasflag(lf->flags, F_MINIONS);
if (f) { if (f) {
@ -229,7 +247,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
lifeform_t *newlf; lifeform_t *newlf;
race_t *newr; race_t *newr;
adjcell = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL);
if (!adjcell) break; if (!adjcell) break;
newr = findracebyname(f->text); newr = findracebyname(f->text);
@ -238,6 +256,8 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
newlf = addlf(adjcell, newr->id, getrandommonlevel(newr, adjcell->map)); newlf = addlf(adjcell, newr->id, getrandommonlevel(newr, adjcell->map));
if (!newlf) break; if (!newlf) break;
if (nadded) (*nadded)++;
newlf->born = B_FALSE; newlf->born = B_FALSE;
if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
newlf->born = B_TRUE; newlf->born = B_TRUE;
@ -247,6 +267,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
} }
if (db) dbtime("handling random objects");
// sometimes give the lf random objects (extra monsters through // sometimes give the lf random objects (extra monsters through
// 'numappears' don't get them. // 'numappears' don't get them.
if (lfhasflag(lf, F_HUMANOID) && !lfhasflag(lf, F_NOPACK)) { if (lfhasflag(lf, F_HUMANOID) && !lfhasflag(lf, F_NOPACK)) {
@ -266,6 +287,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
} }
} }
if (db) dbtime("giving torches");
// humanoids on dark levels which can't see will probably have some // humanoids on dark levels which can't see will probably have some
// kind of light producing device // kind of light producing device
if (!islit(c) && !hasflag(lf->flags, F_SEEINDARK) && !hasflag(lf->flags, F_TREMORSENSE)) { if (!islit(c) && !hasflag(lf->flags, F_SEEINDARK) && !hasflag(lf->flags, F_TREMORSENSE)) {
@ -294,6 +316,8 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
} // end if lf } // end if lf
} }
if (db) dbtimeend("finished addmonster");
return lf; return lf;
} }
@ -313,18 +337,21 @@ object_t *addrandomob(cell_t *c) {
return o; return o;
} }
int addrandomthing(cell_t *c, int obchance) { int addrandomthing(cell_t *c, int obchance, int *nadded) {
int rv = TT_NONE; int rv = TT_NONE;
// if there's already someone there, // if there's already someone there,
// then add an object. // then add an object.
if (c->lf || (rnd(1,100) <= obchance)) { if (c->lf || (rnd(1,100) <= obchance)) {
object_t *o;
// object // object
if (addrandomob(c)) { o = addrandomob(c);
if (o) {
if (nadded) *nadded = o->amt;
rv = TT_OBJECT; rv = TT_OBJECT;
} }
} else { } else {
// monster // monster
if (addmonster(c, R_RANDOM, B_TRUE, 1, B_TRUE)) { if (addmonster(c, R_RANDOM, B_TRUE, 1, B_TRUE, nadded)) {
rv = TT_MONSTER; rv = TT_MONSTER;
} }
} }
@ -486,7 +513,6 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
if (haslos(viewer, c)) { if (haslos(viewer, c)) {
// show cell contents // show cell contents
//drawcellwithcontents(cell, x-viewx, y-viewy);
if (c->lf && cansee(viewer, c->lf)) { // lifeform here which we can see if (c->lf && cansee(viewer, c->lf)) { // lifeform here which we can see
// draw the lf's race glyph // draw the lf's race glyph
*g = *(getlfglyph(c->lf)); *g = *(getlfglyph(c->lf));
@ -506,7 +532,7 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
} }
// objects here? // objects here?
if ((countobs(c->obpile) > 0)) { if ((countobs(c->obpile, B_FALSE) > 0)) {
object_t *o; object_t *o;
// draw highest object in sort order // draw highest object in sort order
@ -516,8 +542,6 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
*g = *(getglyph(o)); *g = *(getglyph(o));
} else { } else {
// objects here, but we can't see them. draw the cell. // objects here, but we can't see them. draw the cell.
// otherwise just draw the cell
//*g = c->obpile->first->type->obclass->glyph;
*g = c->type->glyph; *g = c->type->glyph;
if (!islit(c)) { if (!islit(c)) {
g->colour = C_BLUE; g->colour = C_BLUE;
@ -618,6 +642,7 @@ object_t *gettopobject(cell_t *where) {
flag_t *f; flag_t *f;
// ignore hidden traps, but not secret doors // ignore hidden traps, but not secret doors
if (hasflag(o->flags, F_SECRET) && !isdoor(o, NULL)) { if (hasflag(o->flags, F_SECRET) && !isdoor(o, NULL)) {
} else if (hasflag(o->flags, F_TRAIL) && !canseeob(player, o)) {
} else { } else {
f = hasflag(o->flags, F_IMPASSABLE); f = hasflag(o->flags, F_IMPASSABLE);
if (f && (f->val[0] > largest)) { if (f && (f->val[0] > largest)) {
@ -638,7 +663,9 @@ object_t *gettopobject(cell_t *where) {
// appear first. // appear first.
for (o = where->obpile->last ; o ; o = o->prev) { for (o = where->obpile->last ; o ; o = o->prev) {
if (o->type->obclass->id == sortorder[c]) { if (o->type->obclass->id == sortorder[c]) {
if (!hasflag(o->flags, F_SECRET)){ if (hasflag(o->flags, F_SECRET)) {
} else if (hasflag(o->flags, F_TRAIL) && !canseeob(player, o)) {
} else {
return o; return o;
} }
} }
@ -1083,26 +1110,46 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
} }
// add staircases - dungeons alway shave an up and down stairs // add staircases - dungeons always have an up and down stairs
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
// add up stairs // add up stairs
c = NULL; c = NULL;
while (!c || !isempty(c) || countobs(c->obpile)) { while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM); c = getrandomroomcell(map, ANYROOM);
} }
o = addob(c->obpile, "staircase going up"); o = addob(c->obpile, "staircase going up");
linkstairs(o); linkstairs(o);
// first dungeon level has barriers over the exit stairs
if ((map->region == RG_FIRSTDUNGEON) && (map->depth == 1)) {
if (c->lf) killlf(c->lf);
addob(c->obpile, "magical barrier");
/*
int d;
// surround stairs with barriers
for (d = DC_N; d <= DC_NW; d++) {
cell_t *newc;
newc = getcellindir(c, d);
if (newc && !newc->type->solid) {
// kill lfs there
if (newc->lf) killlf(newc->lf);
// add a barrier
addob(newc->obpile, "magical barrier");
}
}
*/
}
c = NULL; c = NULL;
while (!c || !isempty(c) || countobs(c->obpile)) { while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM); c = getrandomroomcell(map, ANYROOM);
} }
o = addob(c->obpile, "staircase going down"); o = addob(c->obpile, "staircase going down");
linkstairs(o); linkstairs(o);
} }
// add pillars & objects & monsters to rooms
if (wantrooms && (numrooms > 0)) { if (wantrooms && (numrooms > 0)) {
// add pillars & objects & monsters to rooms
for (i = 0; i < numrooms; i++) { for (i = 0; i < numrooms; i++) {
int numobsmin,numobsmax,numobs,n; int numobsmin,numobsmax,numobs,n;
int maxpillars; int maxpillars;
@ -1120,7 +1167,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
cell_t *c; cell_t *c;
c = getrandomroomcell(map, i); c = getrandomroomcell(map, i);
if (c && isempty(c) && !countobs(c->obpile)) { if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) {
setcelltype(cell, CT_WALL); setcelltype(cell, CT_WALL);
} }
} }
@ -1154,8 +1201,9 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
while (!done) { while (!done) {
c = getrandomroomcell(map, i); c = getrandomroomcell(map, i);
// if nothing there // if nothing there
if (c && isempty(c) && !countobs(c->obpile)) { if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) {
int obchance; int obchance;
int nadded = 0;
// limit # monster per room to depth+1 // limit # monster per room to depth+1
if (nmonsters >= (depth+1)) { if (nmonsters >= (depth+1)) {
@ -1165,8 +1213,8 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
obchance = getobchance(map->habitat) + 10; obchance = getobchance(map->habitat) + 10;
} }
if (addrandomthing(c,obchance) == TT_MONSTER) { if (addrandomthing(c,obchance, &nadded) == TT_MONSTER) {
nmonsters++; nmonsters += nadded;
} }
done = B_TRUE; done = B_TRUE;
} else { } else {
@ -1314,6 +1362,7 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap,
for (i = depth-1; i <= depth+1; i += 2) { for (i = depth-1; i <= depth+1; i += 2) {
map_t *othermap; map_t *othermap;
othermap = findregionmap(map->region, i); othermap = findregionmap(map->region, i);
// TODO: set upmap/downmap for use later on.
if (othermap) { if (othermap) {
if (i == (depth-1)) { if (i == (depth-1)) {
map->nextmap[D_UP] = othermap->id; map->nextmap[D_UP] = othermap->id;
@ -1438,7 +1487,7 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap,
} }
} }
// join up any unlinked staircases // join up any unlinked staircases in this map.
for (y = 0; y < map->h; y++) { for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) { for (x = 0; x < map->w; x++) {
cell_t *c; cell_t *c;
@ -1451,6 +1500,9 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap,
} }
} }
// TODO: search for unlinked pits/holes in roof in adjacent maps
// if we find any, add a matching end as close as we can in this map.
// add random objects and monsters // add random objects and monsters
for (y = 0; y < map->h; y++) { for (y = 0; y < map->h; y++) {
for (x = 0; x < map->w; x++) { for (x = 0; x < map->w; x++) {
@ -1458,7 +1510,7 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap,
c = getcellat(map, x, y); c = getcellat(map, x, y);
if (c && isempty(c)) { if (c && isempty(c)) {
if (rnd(1,100) <= getthingchance(map->habitat)) { if (rnd(1,100) <= getthingchance(map->habitat)) {
addrandomthing(c, getobchance(map->habitat)); addrandomthing(c, getobchance(map->habitat), NULL);
} }
} }
} }
@ -1833,6 +1885,7 @@ cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) {
cell_t *selection = NULL; cell_t *selection = NULL;
cell_t *bestcell = NULL; cell_t *bestcell = NULL;
int closest = 999; int closest = 999;
// oooooo TODO handle side being diagonal
switch (side) { switch (side) {
case D_N: case D_N:
x = 0; x = 0;
@ -2120,10 +2173,10 @@ int getthingchance(int habitat) {
} }
cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand) { cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand) {
return real_getrandomadjcell(c, wantempty, allowexpand, NULL); return real_getrandomadjcell(c, wantempty, allowexpand, LOF_NEED, NULL);
} }
cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum OBTYPE *dontwantob) { cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob) {
int radius = 1; int radius = 1;
int x,y; int x,y;
cell_t *poss[MAXCANDIDATES]; cell_t *poss[MAXCANDIDATES];
@ -2139,7 +2192,7 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum OB
if (new && if (new &&
(new != c) && (new != c) &&
(getcelldist(c,new) == radius) && (getcelldist(c,new) == radius) &&
haslof(c, new, LOF_WALLSTOP, NULL)) { haslof(c, new, needlof, NULL)) {
enum OBTYPE *badoid; enum OBTYPE *badoid;
int ok = B_FALSE; int ok = B_FALSE;
numwithlof++; numwithlof++;
@ -2159,7 +2212,8 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum OB
} }
} }
} else if (wantempty == WE_NOTWALL) { } else if (wantempty == WE_NOTWALL) {
if (!new->type->solid){ if ((!new->type->solid) && !hasobwithflag(new->obpile, F_IMPASSABLE)) {
//if (!new->type->solid) {
ok = B_TRUE; ok = B_TRUE;
} }
} else { } else {
@ -2372,13 +2426,33 @@ int hasobject(cell_t *c) {
int hasknownobject(cell_t *c) { int hasknownobject(cell_t *c) {
object_t *o; object_t *o;
for (o = c->obpile->first ; o ; o = o->next) { for (o = c->obpile->first ; o ; o = o->next) {
if (o && !hasflag(o->flags, F_SECRET)) { if (o && canseeob(player, o)) {
return B_TRUE; return B_TRUE;
} }
} }
return B_FALSE; return B_FALSE;
} }
object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tflag, lifeform_t *viewer) {
object_t *o;
flag_t *f;
for (o = op->first ; o ; o = o->next) {
if (viewer && !canseeob(viewer, o)) continue;
if ((oid == NA) || (o->type->id == oid)) {
f = hasflag(o->flags, F_TRAIL);
// raceid and lfid must match
if (f && (f->val[0] == lf->race->id) && (atoi(f->text) == lf->id)) {
if (tflag) {
*tflag = f;
}
return o;
}
}
}
return NULL;
}
int isadjacent(cell_t *src, cell_t *dst) { int isadjacent(cell_t *src, cell_t *dst) {
if (getcelldist(src, dst) == 1) { if (getcelldist(src, dst) == 1) {
return B_TRUE; return B_TRUE;

7
map.h
View File

@ -3,9 +3,9 @@
cell_t *addcell(map_t *map, int x, int y); cell_t *addcell(map_t *map, int x, int y);
void addhomeobs(lifeform_t *lf); void addhomeobs(lifeform_t *lf);
map_t *addmap(void); map_t *addmap(void);
lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen); lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen, int *nadded);
object_t *addrandomob(cell_t *c); object_t *addrandomob(cell_t *c);
int addrandomthing(cell_t *c, int obchance); int addrandomthing(cell_t *c, int obchance, int *nadded);
int cellhaslos(cell_t *c1, cell_t *dest); int cellhaslos(cell_t *c1, cell_t *dest);
cell_t *getcellat(map_t *map, int x, int y); cell_t *getcellat(map_t *map, int x, int y);
int getcelldist(cell_t *src, cell_t *dst); int getcelldist(cell_t *src, cell_t *dst);
@ -43,7 +43,7 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved);
int getobchance(int habitat); int getobchance(int habitat);
int getthingchance(int habitat); int getthingchance(int habitat);
cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand); cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand);
cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum OBTYPE *dontwantob); cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob);
cell_t *getrandomcell(map_t *map); cell_t *getrandomcell(map_t *map);
cell_t *getrandomcelloftype(map_t *map, int id); cell_t *getrandomcelloftype(map_t *map, int id);
int getrandomdir(int dirtype); int getrandomdir(int dirtype);
@ -55,6 +55,7 @@ object_t *hasenterableobject(cell_t *c);
lifeform_t *haslf(cell_t *c); lifeform_t *haslf(cell_t *c);
int hasknownobject(cell_t *c); int hasknownobject(cell_t *c);
int hasobject(cell_t *c); int hasobject(cell_t *c);
object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tflag, lifeform_t *viewer);
int isadjacent(cell_t *src, cell_t *dst); int isadjacent(cell_t *src, cell_t *dst);
int isdark(cell_t *c); int isdark(cell_t *c);
int isdiggable(cell_t *c); int isdiggable(cell_t *c);

390
move.c
View File

@ -29,66 +29,65 @@ extern WINDOW *gamewin, *msgwin;
int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) { int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) {
if (isplayer(lf)) { if (isplayer(lf)) {
if (canmove(lf, dir, error)) { if (ispossiblemove(lf, dir)) {
return B_TRUE; return B_TRUE;
} }
} else { } else {
if (canmove(lf, dir, error) && willmove(lf, dir, error)) { if (ispossiblemove(lf, dir) && willmove(lf, dir, error)) {
return B_TRUE; return B_TRUE;
} }
} }
return B_FALSE; return B_FALSE;
} }
int canmove(lifeform_t *lf, int dir, enum ERROR *error) { int isorthogonal(int dir) {
cell_t *cell; switch (dir) {
flag_t *f; case D_N:
case D_E:
// default case D_S:
if (error) { case D_W:
*error = E_OK; case DC_N:
rdata = NULL; case DC_E:
case DC_S:
case DC_W:
return B_TRUE;
} }
return B_FALSE;
if (isburdened(lf) >= BR_OVERLOADED) {
if (error) *error = E_TOOHEAVY;
return B_FALSE;
}
// check if we are paralyzed, frozen, etc
if (isimmobile(lf)) {
if (error) *error = E_CANTMOVE;
return B_FALSE;
}
cell = getcellindir(lf->cell, dir);
if (!cell) {
if (error) *error = E_OFFMAP;
return B_FALSE;
}
f = lfhasflag(lf, F_GRABBEDBY);
if (f) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
if (lf2 && (lf2 != cell->lf)) {
if (error) {
rdata = lf2;
*error = E_GRABBEDBY;
}
return B_FALSE;
}
}
// not attacking
if (lfhasflag(lf, F_DOESNTMOVE) && !cell->lf) {
*error = E_CANTMOVE;
return B_FALSE;
}
return cellwalkable(lf, cell, error);
} }
// ie. moving into a wall isn't possible
// moving into a lf/door IS possible since you will attack/open it
// moving while grabbed IS possible since you'll try to break free
int ispossiblemove(lifeform_t *lf, int dir) {
enum ERROR error;
if (moveclear(lf, dir, &error)) {
return B_TRUE;
} else {
object_t *inway = NULL;
switch (error) {
case E_OFFMAP:
if (lf->cell->map->region == RG_WORLDMAP) {
return B_TRUE;
}
break;
case E_DOORINWAY:
case E_CANTMOVE:
case E_GRABBEDBY:
case E_TOOHEAVY:
case E_LFINWAY:
return B_TRUE;
case E_OBINWAY:
inway = (object_t *)rdata;
if (inway && ispushable(inway)) {
return B_TRUE;
}
break;
default:
break;
}
}
return B_FALSE;
}
// lf is the one moving, lf2 is the one who is being forced to swap // lf is the one moving, lf2 is the one who is being forced to swap
int canswapwith(lifeform_t *lf, lifeform_t *lf2) { int canswapwith(lifeform_t *lf, lifeform_t *lf2) {
@ -96,6 +95,12 @@ int canswapwith(lifeform_t *lf, lifeform_t *lf2) {
if (isplayer(lf2)) { if (isplayer(lf2)) {
return B_FALSE; return B_FALSE;
} }
// mosnters don't swap with people who have F_NOSWAP.
if (!isplayer(lf) && lfhasflag(lf2, F_NOSWAP)) {
return B_FALSE;
}
// cannot swap if lf's cell is dangerous to lf2 // cannot swap if lf's cell is dangerous to lf2
if (celldangerous(lf2, lf->cell, B_FALSE, NULL)) { if (celldangerous(lf2, lf->cell, B_FALSE, NULL)) {
return B_FALSE; return B_FALSE;
@ -133,6 +138,16 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err
// obvious things that you can see // obvious things that you can see
if (!onlyifknown || (haslos(lf, cell) && !lfhasflag(lf, F_UNDEAD))) { if (!onlyifknown || (haslos(lf, cell) && !lfhasflag(lf, F_UNDEAD))) {
for (o = cell->obpile->first ; o ; o = o->next) { for (o = cell->obpile->first ; o ; o = o->next) {
f = hasflag(o->flags, F_DEEPWATER);
if (f) {
if (!isairborne(lf) && (getobdepth(o, lf) >= DP_HEAD) && !getskill(lf, SK_SWIMMING)) {
if (error) {
*error = E_AVOIDOB;
rdata = o;
}
return B_TRUE;
}
}
f = hasflag(o->flags, F_WALKDAM); f = hasflag(o->flags, F_WALKDAM);
if (f) { if (f) {
if ((f->val[0] != DT_WATER) || isvulnto(lf->flags, DT_WATER)) { if ((f->val[0] != DT_WATER) || isvulnto(lf->flags, DT_WATER)) {
@ -205,6 +220,14 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) {
// must check for lf before checking for impassable objects, // must check for lf before checking for impassable objects,
// so that we are able to attack monsters embedded in walls. // so that we are able to attack monsters embedded in walls.
if (cell->lf && (cell->lf != lf)) { if (cell->lf && (cell->lf != lf)) {
// usually can't attack while swimming
if (isswimming(lf) && (getskill(lf, SK_SWIMMING) <= PR_EXPERT)) {
if (!lfhasflag(lf, F_AQUATIC)) {
if (error) *error = E_SWIMMING;
return B_FALSE;
}
}
if (error) *error = E_LFINWAY; if (error) *error = E_LFINWAY;
return B_FALSE; return B_FALSE;
} }
@ -345,6 +368,12 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d
int nposs; int nposs;
enum ERROR error; enum ERROR error;
if (dirtype == DT_ORTH) {
maxdist = getcelldistorth(src, dst);
} else {
maxdist = getcelldist(src, dst);
}
for (d = DC_N; d <= DC_NW; d++) { for (d = DC_N; d <= DC_NW; d++) {
dist[d - DC_N] = -1; dist[d - DC_N] = -1;
} }
@ -429,12 +458,19 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, in
int nposs; int nposs;
enum ERROR error; enum ERROR error;
if (dirtype == DT_ORTH) {
mindist = getcelldistorth(src, dst);
} else {
mindist = getcelldist(src, dst);
}
for (d = DC_N; d <= DC_NW; d++) { for (d = DC_N; d <= DC_NW; d++) {
dist[d - DC_N] = -1; dist[d - DC_N] = -1;
} }
for (d = DC_N; d <= DC_NW; d++) { for (d = DC_N; d <= DC_NW; d++) {
int ok = B_FALSE; int ok = B_FALSE;
int thisdist;
c = getcellindir(src, d); c = getcellindir(src, d);
if (!c) continue; if (!c) continue;
@ -465,16 +501,20 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, in
ok = B_TRUE; ok = B_TRUE;
} }
} }
// get distance
if (ok) { if (ok) {
int thisdist;
if (dirtype == DT_ORTH) { if (dirtype == DT_ORTH) {
thisdist = getcelldistorth(c, dst); thisdist = getcelldistorth(c, dst);
} else { } else {
thisdist = getcelldist(c, dst); thisdist = getcelldist(c, dst);
} }
dist[d - DC_N] = thisdist;
if (thisdist < mindist) { if (thisdist < mindist) {
dist[d - DC_N] = thisdist;
mindist = thisdist; mindist = thisdist;
} else {
dist[d - DC_N] = -1;
} }
} else { } else {
dist[d - DC_N] = -1; // ie. invalid dist[d - DC_N] = -1; // ie. invalid
@ -536,7 +576,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
} }
for (i = 0; i < howfar; i++) { for (i = 0; i < howfar; i++) {
if (canmove(lf, dir, &reason)) { if (moveclear(lf, dir, &reason)) {
if ((i == 0) && seen) { if ((i == 0) && seen) {
msg("%s %s knocked backwards!",lfname,is(lf)); msg("%s %s knocked backwards!",lfname,is(lf));
} }
@ -561,6 +601,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc
// don't fall // don't fall
mightfall = B_FALSE; mightfall = B_FALSE;
break; break;
case E_SWIMMING:
case E_LFINWAY: case E_LFINWAY:
newcell = getcellindir(lf->cell, dir); newcell = getcellindir(lf->cell, dir);
newlf = newcell->lf; newlf = newcell->lf;
@ -619,6 +660,62 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype ) {
return rv; return rv;
} }
// ie. is the destination cell free?
int moveclear(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
flag_t *f;
// default
if (error) {
*error = E_OK;
rdata = NULL;
}
if (isburdened(lf) >= BR_OVERLOADED) {
if (error) *error = E_TOOHEAVY;
return B_FALSE;
}
// check if we are paralyzed, frozen, etc
if (isimmobile(lf)) {
if (error) *error = E_CANTMOVE;
return B_FALSE;
}
cell = getcellindir(lf->cell, dir);
if (!cell) {
if (error) *error = E_OFFMAP;
return B_FALSE;
}
f = lfhasflag(lf, F_GRABBEDBY);
if (f) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
if (lf2 && (lf2 != cell->lf)) {
if (error) {
rdata = lf2;
*error = E_GRABBEDBY;
}
return B_FALSE;
}
}
if ((lf->race->id == RC_DEMON) && hasob(cell->obpile, OT_PENTAGRAM)) {
*error = E_PENTAGRAM;
return B_FALSE;
}
// not attacking
if (lfhasflag(lf, F_DOESNTMOVE) && !cell->lf) {
*error = E_CANTMOVE;
return B_FALSE;
}
return cellwalkable(lf, cell, error);
}
// IMPORTANT: don't modify lf's flagpile during this code! // IMPORTANT: don't modify lf's flagpile during this code!
// particularly don't remove flags... // particularly don't remove flags...
@ -673,6 +770,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
int changedlev = B_FALSE; int changedlev = B_FALSE;
int preroom = -1, postroom = -1; int preroom = -1, postroom = -1;
int prespeed = B_FALSE, postspeed = B_FALSE; int prespeed = B_FALSE, postspeed = B_FALSE;
int prewater = B_FALSE;
assert(newcell); assert(newcell);
@ -689,8 +787,14 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
// update current cell + room id // update current cell + room id
prespeed = getmovespeed(lf); prespeed = getmovespeed(lf);
preroom = lf->cell->roomid; preroom = lf->cell->roomid;
lf->cell->lf = NULL;
// getting out of water?
if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) {
prewater = B_TRUE;
}
// move out...
lf->cell->lf = NULL;
// if required, relink lifeform to new map // if required, relink lifeform to new map
if (newcell->map != lf->cell->map) { if (newcell->map != lf->cell->map) {
@ -756,10 +860,39 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
} }
if (isplayer(lf)) {
if (prewater && !hasobwithflag(newcell->obpile, F_DEEPWATER)) {
// getitng out of water?
statdirty = B_TRUE;
}
}
// check ground objects // check ground objects
if (!isairborne(lf)) { if (!isairborne(lf)) {
for (o = newcell->obpile->first ; o ; o = nexto ) { for (o = newcell->obpile->first ; o ; o = nexto ) {
nexto = o->next; nexto = o->next;
f = hasflag(o->flags, F_DEEPWATER);
if (f) {
if (checkfordrowning(lf, o)) {
didmsg = B_TRUE;
if (isdead(lf)) return B_TRUE;
}
// did you just enter the water?
if (!prewater) {
if (getskill(lf, SK_SWIMMING)) {
if (isplayer(lf)) {
msg("You start swimming.");
didmsg = B_TRUE;
statdirty = B_TRUE;
} else if (cansee(player, lf)) {
msg("%s starts swimming.", lfname);
didmsg = B_TRUE;
}
}
}
}
f = hasflag(o->flags, F_SHARP); f = hasflag(o->flags, F_SHARP);
if (f && hasbp(lf, BP_FEET)) { if (f && hasbp(lf, BP_FEET)) {
object_t *boots; object_t *boots;
@ -994,7 +1127,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
// see objects on ground // see objects on ground
if (isplayer(lf)) { if (isplayer(lf)) {
int numobs; int numobs;
numobs = countnoncosmeticobs(newcell->obpile); numobs = countnoncosmeticobs(newcell->obpile, B_TRUE);
if ((numobs == 0) && !newcell->writing) { if ((numobs == 0) && !newcell->writing) {
// just clear the message buffer // just clear the message buffer
if (!didmsg) clearmsg(); if (!didmsg) clearmsg();
@ -1363,11 +1496,26 @@ int pullnextto(lifeform_t *lf, cell_t *c) {
// do pre-move checks like slipping on stuff in your current cell, // do pre-move checks like slipping on stuff in your current cell,
// webs, etc. // webs, etc.
// cell can be null if you're using stairs. // cell can be null if you're using stairs.
// return true if something happened
int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) { int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) {
object_t *o, *nexto; object_t *o, *nexto;
char buf[BUFLEN]; char buf[BUFLEN];
flag_t *f; flag_t *f;
// demon in pentagram
if ((getraceclass(lf) == RC_DEMON) && hasob(lf->cell->obpile, OT_PENTAGRAM)) {
if (isplayer(lf)) {
msg("You cannot escape the pentagram!");
} else if (cansee(player, lf)) {
char lfname[BUFLEN];
getlfname(lf, lfname);
msg("%s struggles within a pentagram!", lfname);
}
reason = E_OK;
taketime(lf, getmovespeed(lf));
return B_TRUE;
}
// gravboosted // gravboosted
if (lfhasflag(lf, F_GRAVBOOSTED)) { if (lfhasflag(lf, F_GRAVBOOSTED)) {
@ -1544,6 +1692,11 @@ void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int onpurpose) {
// move them... // move them...
lf2->cell = cell1; lf2->cell = cell1;
cell1->lf = lf2; cell1->lf = lf2;
// remember that we just swapped
if (!isplayer(lf1)) {
addflag(lf1->flags, F_NOSWAP, B_TRUE, NA, NA, NULL);
}
} }
// teleport somewhere, along with puffs of smoke etc // teleport somewhere, along with puffs of smoke etc
@ -1585,7 +1738,7 @@ int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke) {
// show any objects here, just like if we moved. // show any objects here, just like if we moved.
// BUT don't let dolook() clear the msg bar if there are // BUT don't let dolook() clear the msg bar if there are
// no objects here. // no objects here.
if (isplayer(lf) && countnoncosmeticobs(lf->cell->obpile)) { if (isplayer(lf) && countnoncosmeticobs(lf->cell->obpile, B_TRUE)) {
dolook(lf->cell, B_FALSE); dolook(lf->cell, B_FALSE);
} }
return B_FALSE; return B_FALSE;
@ -1598,6 +1751,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
char buf[BUFLEN]; char buf[BUFLEN];
int dontclearmsg = B_FALSE; int dontclearmsg = B_FALSE;
int moveok; int moveok;
int drunk = B_FALSE;
flag_t *f; flag_t *f;
f = isdrunk(lf); f = isdrunk(lf);
@ -1606,19 +1760,36 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
if (rnd(1,6) <= ((f->lifetime/DRUNKTIME)+1)) { if (rnd(1,6) <= ((f->lifetime/DRUNKTIME)+1)) {
// randomize move // randomize move
dir = rnd(DC_N, DC_NW); dir = rnd(DC_N, DC_NW);
drunk = B_TRUE; // ie. you can walk into walls now.
} }
} }
} }
cell = getcellindir(lf->cell, dir); cell = getcellindir(lf->cell, dir);
moveok = B_FALSE; if (celldangerous(lf, cell, B_TRUE, &errcode)) {
if (onpurpose) { if ((errcode == E_AVOIDOB) && rdata) {
if (canandwillmove(lf, dir, &errcode)) { char obname[BUFLEN];
moveok = B_TRUE; char ques[BUFLEN];
char ch;
object_t *avoidob;
avoidob = (object_t *)rdata;
getobname(avoidob, obname, avoidob->amt);
sprintf(ques, "Really %s into %s?", getmoveverb(lf), obname);
ch = askchar(ques, "yn","n", B_TRUE);
if (ch != 'y') {
return B_TRUE;
}
} }
} else { }
if (canmove(lf, dir, &errcode)) {
moveok = B_FALSE;
if (moveclear(lf, dir, &errcode)) {
if (onpurpose) {
if (canandwillmove(lf, dir, &errcode)) {
moveok = B_TRUE;
}
} else {
moveok = B_TRUE; moveok = B_TRUE;
} }
} }
@ -1627,27 +1798,36 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
lifeform_t *alf; lifeform_t *alf;
if (initiatemove(lf, cell, &dontclearmsg)) { if (initiatemove(lf, cell, &dontclearmsg)) {
// failed? // failed?
return B_FALSE; return B_TRUE;
} }
// move to new cell
reason = E_OK; reason = E_OK;
// remember last dir we walked // remember last dir we walked
killflagsofid(lf->flags, F_LASTDIR); killflagsofid(lf->flags, F_LASTDIR);
addflag(lf->flags, F_LASTDIR, dir, NA, NA, NULL); addflag(lf->flags, F_LASTDIR, dir, NA, NA, NULL);
// add footprints in our current cell.
addtrail(lf, dir);
// do your pets see you move? // do your pets see you move?
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) { if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {
lifeform_t *l; lifeform_t *l;
for (l = lf->cell->map->lf ; l ; l = l->next) { for (l = lf->cell->map->lf ; l ; l = l->next) {
if (ispetof(l,lf) && cansee(l, lf)) { if (cansee(l, lf)) {
killflagsofid(l->flags, F_OWNERLASTDIR); flag_t *tf;
addflag(l->flags, F_OWNERLASTDIR, dir, NA, NA, NULL); tf = ispetortarget(l, lf);
if (tf) {
// update text field
free(tf->text);
asprintf(&(tf->text), "%d", dir);
}
} }
} }
} }
moveto(lf, cell, onpurpose, dontclearmsg); // now move to new cell
moveto(lf, cell, drunk ? B_FALSE : onpurpose, dontclearmsg);
if (onpurpose) { if (onpurpose) {
taketime(lf, getmovespeed(lf)); taketime(lf, getmovespeed(lf));
} }
@ -1662,7 +1842,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
newdir = getdirtowards(alf->cell, lf->cell, alf, B_FALSE, DT_ORTH); newdir = getdirtowards(alf->cell, lf->cell, alf, B_FALSE, DT_ORTH);
// do a manual canmove check here first, to avoid 'the stirge flies into a wall' // do a manual canmove check here first, to avoid 'the stirge flies into a wall'
// if the move fails. // if the move fails.
if ((newdir != D_NONE) && canmove(alf, newdir, NULL)) { if ((newdir != D_NONE) && moveclear(alf, newdir, NULL)) {
trymove(alf, newdir, B_FALSE); trymove(alf, newdir, B_FALSE);
} }
@ -1675,11 +1855,11 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
reason = errcode; reason = errcode;
switch (errcode) { switch (errcode) {
case E_OFFMAP: case E_OFFMAP:
if (lf->cell->map->region == RG_WORLDMAP) { if ((lf->cell->map->region == RG_WORLDMAP) && (isorthogonal(dir))) {
// we are allowed to walk off the edge // we are allowed to walk off the edge
walkoffmap(lf, dir, B_TRUE); return walkoffmap(lf, dir, B_TRUE);
} }
break; // otherwise fall through...
case E_WALLINWAY: case E_WALLINWAY:
if (isplayer(lf)) { if (isplayer(lf)) {
msg("Ouch! You %s into a wall.", getmoveverb(lf)); msg("Ouch! You %s into a wall.", getmoveverb(lf));
@ -1718,7 +1898,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
opendoor(lf, inway); opendoor(lf, inway);
} else { } else {
msg("Ouch! You %s into a door.", getmoveverb(lf)); msg("Ouch! You %s into a door.", getmoveverb(lf));
setcellknown(cell, B_FALSE); setcellknown(cell, B_FALSE);
sprintf(buf, "%sing into a door", getmoveverb(lf)); sprintf(buf, "%sing into a door", getmoveverb(lf));
losehp(lf, 1, DT_BASH, NULL, buf); losehp(lf, 1, DT_BASH, NULL, buf);
if (onpurpose) taketime(lf, getmovespeed(lf)); if (onpurpose) taketime(lf, getmovespeed(lf));
@ -1777,6 +1957,11 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
} }
} }
break; break;
case E_SWIMMING:
if (isplayer(lf)) {
msg("You can't attack while swimming!");
}
break;
case E_LFINWAY: case E_LFINWAY:
if (canswapwith(lf, cell->lf)) { if (canswapwith(lf, cell->lf)) {
lifeform_t *lfinway; lifeform_t *lfinway;
@ -1828,6 +2013,12 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
} }
if (onpurpose) taketime(lf, getmovespeed(lf)); if (onpurpose) taketime(lf, getmovespeed(lf));
break; break;
case E_PENTAGRAM:
if (isplayer(lf)) {
msg("You cannot seem to enter the pentagram.");
}
if (onpurpose) taketime(lf, getmovespeed(lf));
break;
case E_TOOHEAVY: case E_TOOHEAVY:
if (isplayer(lf)) { if (isplayer(lf)) {
msg("Your load is too heavy to move with!"); msg("Your load is too heavy to move with!");
@ -1956,13 +2147,14 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
} }
cell = getcellindir(lf->cell, dir); cell = getcellindir(lf->cell, dir);
if (celldangerous(lf, cell, B_TRUE, error)) {
if (cell && celldangerous(lf, cell, B_TRUE, error)) {
if (error) *error = E_WONT; if (error) *error = E_WONT;
return B_FALSE; return B_FALSE;
} }
// don't attack other monsters // don't attack other monsters
if (cell->lf) { // if someone is in the way if (cell && cell->lf) { // if someone is in the way
if (lf->race->raceclass->id == RC_INSECT) { if (lf->race->raceclass->id == RC_INSECT) {
if (hasactivespell(cell->lf, OT_S_REPELINSECTS)) { if (hasactivespell(cell->lf, OT_S_REPELINSECTS)) {
if (error) *error = E_WONT; if (error) *error = E_WONT;
@ -1993,33 +2185,35 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) {
} }
// look for avoided objects (because they are cursed). // look for avoided objects (because they are cursed).
for (o = cell->obpile->first ; o ; o = o->next) { if (cell) {
flag_t *f; for (o = cell->obpile->first ; o ; o = o->next) {
sprintf(buf, "%ld",o->id); flag_t *f;
f = lfhasflagval(lf, F_AVOIDCURSEDOB, NA, NA, NA, buf); sprintf(buf, "%ld",o->id);
if (f) { f = lfhasflagval(lf, F_AVOIDCURSEDOB, NA, NA, NA, buf);
// still cursed? if (f) {
if (iscursed(o)) { // still cursed?
if (error) *error = E_WONT; if (iscursed(o)) {
return B_FALSE;
} else {
// remove the flag.
killflag(f);
}
}
if (hasflag(o->flags, F_TRAP)) {
if (hasflag(o->flags, F_SECRET)) {
// hidden traps?
if (iq >= IQ_SMART) {
if (error) *error = E_WONT; if (error) *error = E_WONT;
return B_FALSE; return B_FALSE;
} else {
// remove the flag.
killflag(f);
} }
} else { }
// non-hidden traps?
if (iq >= IQ_AVERAGE) { if (hasflag(o->flags, F_TRAP)) {
if (error) *error = E_WONT; if (hasflag(o->flags, F_SECRET)) {
return B_FALSE; // hidden traps?
if (iq >= IQ_SMART) {
if (error) *error = E_WONT;
return B_FALSE;
}
} else {
// non-hidden traps?
if (iq >= IQ_AVERAGE) {
if (error) *error = E_WONT;
return B_FALSE;
}
} }
} }
} }

4
move.h
View File

@ -1,7 +1,6 @@
#include "defs.h" #include "defs.h"
int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error); int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error);
int canmove(lifeform_t *lf, int dir, enum ERROR *error);
int canswapwith(lifeform_t *lf, lifeform_t *lf2); int canswapwith(lifeform_t *lf, lifeform_t *lf2);
int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *error); int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *error);
int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error); int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error);
@ -13,6 +12,7 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d
int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype); int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int dirtype);
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 moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype); int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype);
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);
@ -21,6 +21,8 @@ int opendoorat(lifeform_t *lf, cell_t *c);
int opendoor(lifeform_t *lf, object_t *o); int opendoor(lifeform_t *lf, object_t *o);
int pullnextto(lifeform_t *lf, cell_t *c); int pullnextto(lifeform_t *lf, cell_t *c);
int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg); int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg);
int isorthogonal(int dir);
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);
int trymove(lifeform_t *lf, int dir, int onpurpose); int trymove(lifeform_t *lf, int dir, int onpurpose);

43
nexus.c
View File

@ -3,6 +3,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/time.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "ai.h" #include "ai.h"
@ -34,6 +35,9 @@ hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL;
glyph_t playerglyph,tempglyph; glyph_t playerglyph,tempglyph;
double startticks,lastticks;
struct timeval starttv, tv,newtv;
// maintains unique lifeform ID numbers // maintains unique lifeform ID numbers
long nextlfid = 0; long nextlfid = 0;
@ -58,6 +62,8 @@ void *rdata; // globel for returning data
lifeform_t *player = NULL; lifeform_t *player = NULL;
int gameover; int gameover;
int obdb = B_FALSE;
enum GAMEMODE gamemode = GM_FIRST; enum GAMEMODE gamemode = GM_FIRST;
long curtime = 0; long curtime = 0;
@ -171,7 +177,9 @@ int main(int argc, char **argv) {
if (where->lf) { if (where->lf) {
killlf(where->lf); killlf(where->lf);
} }
// add player
// add player nearby
where = real_getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL);
real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player' real_addlf(where, R_HUMAN, 1, C_PLAYER); // this will assign 'player'
user = getenv("USER"); user = getenv("USER");
@ -464,6 +472,27 @@ void cleanup(void) {
// free races // free races
} }
void dbtimestart(char *text) {
gettimeofday(&tv, NULL);
starttv = tv;
dblog("START\t%s", text);
}
void dbtime(char *text) {
double ticks;
gettimeofday(&newtv, NULL);
ticks = ((newtv.tv_sec - tv.tv_sec) * 1000000) + (newtv.tv_usec - tv.tv_usec);
dblog("+%f\t%s", ticks, text);
tv = newtv;
}
void dbtimeend(char *text) {
double ticks;
gettimeofday(&newtv, NULL);
ticks = ((newtv.tv_sec - starttv.tv_sec) * 1000000) + (newtv.tv_usec - starttv.tv_usec);
dblog("FINISHED %s (total time %f)", text, ticks);
}
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) {
if (d < 0) { if (d < 0) {
*xinc = xinc1; *xinc = xinc1;
@ -953,7 +982,7 @@ int rollhitdice(lifeform_t *lf) {
int roll = 0; int roll = 0;
int i; int i;
float mod; float mod;
int db = B_FALSE; int db = B_TRUE;
f = hasflag(lf->flags, F_HITDICE); f = hasflag(lf->flags, F_HITDICE);
if (f) { if (f) {
@ -964,11 +993,11 @@ int rollhitdice(lifeform_t *lf) {
ndice = 1; ndice = 1;
plus = 0; plus = 0;
} }
if (db && isplayer(lf)) dblog("rollhitdice() - rolling %dd4 + %d",ndice,plus); if (db) dblog("rollhitdice() for %s - rolling %dd4 + %d",lf->race->name,ndice,plus);
mod = getstatmod(lf, A_CON); mod = getstatmod(lf, A_CON);
if (mod > 0) mod *= 2; if (mod > 0) mod *= 2;
if (db && isplayer(lf)) dblog("rollhitdice() - mod is +%0.0f%%",mod); if (db) dblog("rollhitdice() - mod is +%0.0f%%",mod);
if (ndice == 0) { if (ndice == 0) {
int thisroll; int thisroll;
@ -983,14 +1012,14 @@ int rollhitdice(lifeform_t *lf) {
int thisroll; int thisroll;
thisroll = rolldie(1, 4) + plus; thisroll = rolldie(1, 4) + plus;
if (thisroll < 1) thisroll = 1; if (thisroll < 1) thisroll = 1;
if (db && isplayer(lf)) dblog("rollhitdice() ---- die %d/%d == %d",i+1,ndice,thisroll); if (db) dblog("rollhitdice() ---- die %d/%d == %d",i+1,ndice,thisroll);
roll += thisroll; roll += thisroll;
} }
} }
if (db && isplayer(lf)) dblog("TOTAL: %d",roll); if (db) dblog("TOTAL: %d",roll);
roll = roll + (int)((float)roll * (mod/100)); roll = roll + (int)((float)roll * (mod/100));
if (db && isplayer(lf)) dblog(" -> modified to: %d",roll); if (db) dblog(" -> modified to: %d",roll);
return roll; return roll;
} }

View File

@ -5,6 +5,9 @@ command_t *addcommand(enum COMMAND id, char c, char *desc);
void checkdeath(void); void checkdeath(void);
void checkendgame(void); void checkendgame(void);
void cleanup(void); void cleanup(void);
void dbtime(char *text);
void dbtimeend(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); char *getdirname(int dir);

528
objects.c
View File

@ -44,6 +44,8 @@ extern int reason;
extern int needredraw; extern int needredraw;
extern int statdirty; extern int statdirty;
extern int obdb;
char letorder[MAXPILEOBS] = { char letorder[MAXPILEOBS] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
@ -658,6 +660,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
// inherit flags from objecttype // inherit flags from objecttype
copyflags(o->flags, ot->flags, NA); copyflags(o->flags, ot->flags, NA);
// don't want certain objecttype only flags...
killflagsofid(o->flags, F_RARITY);
// random flags... // random flags...
f = hasflag(o->flags, F_RNDCHARGES); f = hasflag(o->flags, F_RNDCHARGES);
@ -1146,6 +1150,8 @@ int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fr
if (!where) return 0; if (!where) return 0;
redrawpause();
if (dirtype == DT_ORTH) { if (dirtype == DT_ORTH) {
distfunc = getcelldistorth; distfunc = getcelldistorth;
} else { } else {
@ -1168,6 +1174,7 @@ int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fr
} }
} }
redrawresume();
return nadded; return nadded;
} }
@ -1413,6 +1420,11 @@ void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) {
} }
} }
if (hasflag(o->flags, F_INVULNERABLE)) {
*dam = 0;
return;
}
// immune? // immune?
if (isimmuneto(o->flags, damtype)) { if (isimmuneto(o->flags, damtype)) {
*dam = 0; *dam = 0;
@ -1750,6 +1762,54 @@ int canbepoisoned(enum OBTYPE oid) {
return B_FALSE; return B_FALSE;
} }
int canseeob(lifeform_t *lf, object_t *o) {
flag_t *f;
if (gamemode != GM_GAMESTARTED) {
return B_TRUE;
}
if (hasflag(o->flags, F_SECRET) && isplayer(lf)) {
// can't see
return B_FALSE;
}
f = hasflag(o->flags, F_TRAIL);
if (f) {
if (f->val[2] == S_SIGHT) {
enum SKILLLEVEL slev;
int cutoffpct;
int cutoff;
slev = getskill(lf, SK_TRACKING);
switch (slev) {
case PR_NOVICE: cutoffpct = 80; break;
case PR_BEGINNER: cutoffpct = 65; break;
case PR_ADEPT: cutoffpct = 50; break;
case PR_SKILLED: cutoffpct = 35; break;
case PR_EXPERT: cutoffpct = 20; break;
case PR_MASTER: cutoffpct = 0; break;
default:
case PR_INEPT: cutoffpct = 200; break;
}
cutoff = pctof(cutoffpct, FOOTPRINTTIME);
if (f->lifetime >= cutoff) {
return B_TRUE;
} else {
return B_FALSE;
}
} else {
// ie. SCENT
// can't smell your own race...
if ((f->val[0] != lf->race->id) && lfhasflag(lf, F_ENHANCESMELL)) {
return B_TRUE;
} else {
return B_FALSE;
}
}
}
return B_TRUE;
}
// does the pile "op" have an object we can // does the pile "op" have an object we can
// stack "match" with // stack "match" with
object_t *canstackob(obpile_t *op, object_t *match) { object_t *canstackob(obpile_t *op, object_t *match) {
@ -1929,23 +1989,35 @@ int countnames(char **list) {
return count; return count;
} }
int countobs(obpile_t *op) { int countobs(obpile_t *op, int onlyifknown) {
object_t *o; object_t *o;
int count = 0; int count = 0;
for (o = op->first ; o ; o = o->next) { for (o = op->first ; o ; o = o->next) {
count++; if (onlyifknown) {
if (canseeob(player, o)) {
count++;
}
} else {
count++;
}
} }
return count; return count;
} }
int countnoncosmeticobs(obpile_t *op) { int countnoncosmeticobs(obpile_t *op, int onlyifknown) {
object_t *o; object_t *o;
int count = 0; int count = 0;
for (o = op->first ; o ; o = o->next) { for (o = op->first ; o ; o = o->next) {
if (!hasflag(o->flags, F_COSMETIC) && !hasflag(o->flags, F_SECRET)) { if (!hasflag(o->flags, F_COSMETIC) && !hasflag(o->flags, F_SECRET)) {
count++; if (onlyifknown) {
if (canseeob(player, o)) {
count++;
}
} else {
count++;
}
} }
} }
return count; return count;
@ -1993,11 +2065,17 @@ int curseob(object_t *o) {
return rv; return rv;
} }
void damageallobs(object_t *exception, obpile_t *op, int howmuch, int damtype) { void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype) {
object_t *o, *nexto; object_t *o, *nexto;
for (o = op->first ; o ; o = nexto) { for (o = op->first ; o ; o = nexto) {
nexto = o->next; nexto = o->next;
if ((o != exception) && !hasflag(o->flags, F_DEAD)) {
// special case to stop steam from hurting water
if (srcob && (srcob->material->id == MT_GAS)) {
continue;
}
if ((o != srcob) && !hasflag(o->flags, F_DEAD)) {
takedamage(o, howmuch, damtype); takedamage(o, howmuch, damtype);
} }
} }
@ -3023,6 +3101,22 @@ int getnutrition(object_t *o) {
return (int)nutrition; return (int)nutrition;
} }
enum DEPTH getobdepth(object_t *o, lifeform_t *lf) {
int depth = DP_NONE;
flag_t *f;
f = hasflag(o->flags, F_DEEPWATER);
if (f) {
depth = f->val[0];
if (lf) {
int mod;
mod = SZ_HUMAN - getlfsize(lf);
depth += mod;
limit(&depth, DP_NONE, DP_HEAD);
}
}
return depth;
}
char *getobdesc(object_t *o, char *buf) { char *getobdesc(object_t *o, char *buf) {
if (isknown(o)) { if (isknown(o)) {
if (o->type->id == OT_CORPSE) { if (o->type->id == OT_CORPSE) {
@ -3197,10 +3291,88 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
showall = B_TRUE; showall = B_TRUE;
} }
if (showall) { f = hasflag(o->flags, F_TRAIL);
strcpy(basename,o->type->name); if (f) {
race_t *r = NULL;
enum SKILLLEVEL slev;
slev = getskill(player, SK_TRACKING);
r = findrace(f->val[0]);
assert(r);
if (f->val[2] == S_SMELL) {
char buf[BUFLEN];
float pct;
char dname[BUFLEN];
char adjective[BUFLEN];
lifeform_t *who = NULL;
pct = ((float)f->lifetime / (float)SCENTTIME)*100;
if (pct >= 66) {
strcpy(adjective, "strong ");
} else if (pct >= 33) {
strcpy(adjective, "");
} else {
strcpy(adjective, "weak ");
}
strcpy(basename, "");
if (strlen(f->text)) {
who = findlf(where->map, atoi(f->text));
}
if (who) {
char lfname[BUFLEN];
real_getlfname(who, lfname, B_FALSE);
sprintf(buf, "%s%s %sscent",lfname,getpossessive(lfname), adjective);
} else {
sprintf(buf, "%s %sscent",r->name, adjective);
}
strcat(basename, buf);
strcat(basename, " leading ");
sprintf(dname, "%s", getdirname(f->val[1]));
dname[0] = tolower(dname[0]);
strcat(basename, dname);
} else {
char buf[BUFLEN];
// adept and upwards gets depth
if (slev >= PR_BEGINNER) {
float pct;
pct = ((float)f->lifetime / (float)FOOTPRINTTIME)*100;
if (pct >= 66) {
strcpy(basename, "fresh ");
} else if (pct >= 33) {
strcpy(basename, "");
} else {
strcpy(basename, "faint ");
}
} else {
strcpy(basename, "");
}
// adept and upwards get "monstername footprints"
if (slev >= PR_ADEPT) {
sprintf(buf, "%s %s",r->name, o->type->name);
strcat(basename, buf);
} else {
sprintf(basename, "%s", o->type->name);
}
// skilled and upwards get the direction
if (slev >= PR_SKILLED) {
char dname[BUFLEN];
strcat(basename, " leading ");
sprintf(dname, "%s", getdirname(f->val[1]));
dname[0] = tolower(dname[0]);
strcat(basename, dname);
}
} // end if sight/smell
} else { } else {
strcpy(basename,gethiddenname(o)); if (showall) {
strcpy(basename,o->type->name);
} else {
strcpy(basename,gethiddenname(o));
}
} }
if (o->type->obclass->id == OC_BOOK) { if (o->type->obclass->id == OC_BOOK) {
@ -3306,7 +3478,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
strcpy(localbuf, ""); strcpy(localbuf, "");
// figure out pluralname // figure out pluralname
if ((count == 1) && !hasflag(o->flags, F_NO_A)) { if (count == 1) {
pluralname = strdup(basename); pluralname = strdup(basename);
} else { } else {
// multiple objects? // multiple objects?
@ -3399,7 +3571,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
int bonus; int bonus;
bonus = f->val[0]; bonus = f->val[0];
if (bonus != 0) { if (bonus != 0) {
sprintf(buf2, "%s%d ", (bonus < 0) ? "" : "+", bonus); sprintf(buf2, "%s%d ", (bonus < 0) ? "-" : "+", abs(bonus));
strcat(localbuf, buf2); strcat(localbuf, buf2);
} }
} }
@ -3513,23 +3685,32 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
} }
// apply prefix now! // apply prefix now!
if ((count == 1) && !hasflag(o->flags, F_NO_A)) { if (count == 1) {
if (hasflag(o->flags, F_UNIQUE)) { // TODO: && o->identified if (hasflag(o->flags, F_NO_A)) {
strcpy(prefix, "The"); if (o->type->id == OT_GOLD) {
} else { sprintf(prefix, "%d ",count);
if (needan(localbuf)) {
strcpy(prefix, "an");
} else { } else {
strcpy(prefix, "a"); // nothing.
strcpy(prefix, "");
}
} else {
if (hasflag(o->flags, F_UNIQUE)) { // TODO: && o->identified
strcpy(prefix, "The ");
} else {
if (needan(localbuf)) {
strcpy(prefix, "an ");
} else {
strcpy(prefix, "a ");
}
} }
} }
} else { } else {
// multiple objects? // multiple objects?
sprintf(prefix, "%d",count); sprintf(prefix, "%d ",count);
} }
// prepend prefix on to buf // prepend prefix on to buf
sprintf(buf, "%s %s", prefix, localbuf); sprintf(buf, "%s%s", prefix, localbuf);
return buf; return buf;
} }
@ -3688,8 +3869,10 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
flag_t *omposs[MAXCANDIDATES]; flag_t *omposs[MAXCANDIDATES];
int noms = 0; int noms = 0;
db = obdb;
if (forcedepth != NA) { //if (forcedepth != NA) {
if (forcedepth >= 0) {
depth = forcedepth; depth = forcedepth;
} else { } else {
depth = getmapdifficulty(map); depth = getmapdifficulty(map);
@ -3751,7 +3934,7 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
} }
if (rarok && condok) { if (rarok && condok) {
//if (db) dblog("-> possibility: %s, rarity=%d",ot->name, rarflag->val[1]); if (db) dblog("-> possibility: %s, rarity=%d",ot->name, rarflag->val[1]);
poss[nposs] = ot; poss[nposs] = ot;
nposs++; nposs++;
if (nposs >= MAXRANDOMOBCANDIDATES) break; if (nposs >= MAXRANDOMOBCANDIDATES) break;
@ -3901,6 +4084,7 @@ char *getrandomobwithdt(map_t *map, enum DAMTYPE damtype, char *buf) {
char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf, int depthmod) { char *getrandomobwithclass(map_t *map, enum OBCLASS cid, char *buf, int depthmod) {
//return real_getrandomob(map, buf, RO_OBCLASS, cid, map->depth + depthmod); //return real_getrandomob(map, buf, RO_OBCLASS, cid, map->depth + depthmod);
if (depthmod == NA) depthmod = 0;
return real_getrandomob(map, buf, RO_OBCLASS, cid, getmapdifficulty(map) + depthmod); return real_getrandomob(map, buf, RO_OBCLASS, cid, getmapdifficulty(map) + depthmod);
} }
@ -4060,6 +4244,25 @@ int getthrowdam(object_t *o) {
return (int)dam; return (int)dam;
} }
char *gettopobname(cell_t *c, char *retbuf) {
char buf[BUFLEN];
object_t *o;
o = gettopobject(c);
if (o) {
int nother;
getobname(o, buf, o->amt);
strcat(retbuf, buf);
// other obs here too?
nother = countnoncosmeticobs(c->obpile, B_TRUE) - 1;
if (nother >= 1) {
sprintf(buf, " (+%d other thing%s)", nother, (nother == 1) ? "" : "s");
strcat(retbuf, buf);
}
return retbuf;
}
return NULL;
}
enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded) { enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded) {
enum BODYPART weildloc; enum BODYPART weildloc;
if (o) { if (o) {
@ -4570,7 +4773,7 @@ void initobjects(void) {
addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSTHROW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
@ -4583,7 +4786,7 @@ void initobjects(void) {
addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSTHROW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL);
@ -4599,7 +4802,7 @@ void initobjects(void) {
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSTHROW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
// addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); // addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
@ -4611,7 +4814,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "'"); addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSTHROW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL); addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
@ -4621,7 +4824,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "'"); addflag(lastot->flags, F_GLYPH, NA, NA, NA, "'");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PUSHABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSTHROW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL); addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
@ -4643,16 +4846,56 @@ void initobjects(void) {
addot(OT_VENDINGMACHINE, "vending machine", "A gold-operated vending machine.", MT_METAL, 500, OC_DFEATURE); addot(OT_VENDINGMACHINE, "vending machine", "A gold-operated vending machine.", MT_METAL, 500, OC_DFEATURE);
addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, ""); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, "");
addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "_"); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "_");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_HOLYCIRCLE, "holy circle", "A consecrated area imbued with holy power.", MT_NOTHING, 0, OC_DFEATURE);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, "");
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "_");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_REPELBLESSED, B_CURSED, NA, NA, NULL);
addot(OT_PENTAGRAM, "pentagram", "A area imbued with evil.", MT_NOTHING, 0, OC_DFEATURE);
addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, "");
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "_");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, ".");
addflag(lastot->flags, F_REPELBLESSED, B_BLESSED, NA, NA, NULL);
addot(OT_PORTAL, "magic portal", "A magical portal to a different place...", MT_MAGIC, 0, OC_DFEATURE); addot(OT_PORTAL, "magic portal", "A magical portal to a different place...", MT_MAGIC, 0, OC_DFEATURE);
addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, NA, NA, "&"); addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, NA, NA, "&");
addflag(lastot->flags, F_CLIMBABLE, D_IN, NA, NA, NULL); addflag(lastot->flags, F_CLIMBABLE, D_IN, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addot(OT_WATERSHALLOW, "shallow water", "Waist-deep water.", MT_WATER, 150, OC_DFEATURE);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DEEPWATER, DP_WAIST, NA, NA, NULL);
addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice");
addflag(lastot->flags, F_DTCREATEOB, DT_FIRE, 1, DT_COMPASS, "cloud of steam");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, B_DONTKILL, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 3, NA, NA, NULL);
addot(OT_WATERDEEP, "deep water", "Very deep water.", MT_WATER, 300, OC_DFEATURE);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BOLDBLUE, NA, NA, "{");
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice");
addflag(lastot->flags, F_DTCREATEOB, DT_FIRE, 1, DT_COMPASS, "cloud of steam");
addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, B_DONTKILL, NULL);
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addflag(lastot->flags, F_DEEPWATER, DP_HEAD, NA, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 4, NA, NA, NULL);
// traps // traps
addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_NOTHING, 0, OC_MISC); addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_NOTHING, 0, OC_MISC);
addflag(lastot->flags, F_TRAP, 10, B_FALSE, 20, NULL); addflag(lastot->flags, F_TRAP, 10, B_FALSE, 20, NULL);
@ -4805,7 +5048,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "#"); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSTHROW, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL); addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL);
@ -5143,15 +5386,18 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4 // l4
addot(OT_S_WEAKEN, "weaken", "Temporarily lowers the target's muscle strength.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_WEAKEN, "weaken", "Temporarily lowers the target's muscle strength.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_PARALYZE, "paralyze", "Disables the target's muscles, leaving them unable to move.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_PARALYZE, "paralyze", "Disables the target's muscles, leaving them unable to move.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_ANIMATEDEAD, "animate dead", "Imbues nearby corpses with life, creating an undead zombie.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_ANIMATEDEAD, "animate dead", "Imbues nearby corpses with life, creating an undead zombie.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
@ -5162,6 +5408,7 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l7 // l7
addot(OT_S_POSSESSION, "possession", "Completely possess an enemy, moving your consciousness into their body.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_POSSESSION, "possession", "Completely possess an enemy, moving your consciousness into their body.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL);
@ -5457,6 +5704,7 @@ void initobjects(void) {
addot(OT_S_DIG, "dig", "Blasts away earth to create passages.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_DIG, "dig", "Blasts away earth to create passages.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
addot(OT_S_ENTANGLE, "entangle", "Causes magical vines to hold enemies.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_ENTANGLE, "entangle", "Causes magical vines to hold enemies.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
@ -5708,11 +5956,13 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL);
// l5 // l5
addot(OT_S_DISPERSAL, "dispersal", "Scatters everything in the target cell around the area.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_DISPERSAL, "dispersal", "Scatters everything in the target cell around the area.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l6 // l6
addot(OT_S_GATE, "gate", "Creates a portal to a different dungeon level.", MT_NOTHING, 0, OC_SPELL); addot(OT_S_GATE, "gate", "Creates a portal to a different dungeon level.", MT_NOTHING, 0, OC_SPELL);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
@ -6487,7 +6737,7 @@ void initobjects(void) {
addot(OT_ICESHEET, "sheet of ice", "A large sheet of slippery ice.", MT_ICE, 0.5, OC_MISC); addot(OT_ICESHEET, "sheet of ice", "A large sheet of slippery ice.", MT_ICE, 0.5, OC_MISC);
addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, NA, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "_"); addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "_");
addflag(lastot->flags, F_DTCONVERT, DT_FIRE, NA, NA, "large puddle of water"); addflag(lastot->flags, F_DTCONVERT, DT_FIRE, NA, NA, "large puddle of water");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "large puddle of water"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "large puddle of water");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "melts"); addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "melts");
@ -6584,7 +6834,7 @@ void initobjects(void) {
addot(OT_PUDDLEOIL, "puddle of oil", "A slippery puddle of oil.", MT_OIL, 0, OC_MISC); addot(OT_PUDDLEOIL, "puddle of oil", "A slippery puddle of oil.", MT_OIL, 0, OC_MISC);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, ","); // should really be dark grey
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_FLAMMABLE, 5, NA, NA, "medium fire"); addflag(lastot->flags, F_FLAMMABLE, 5, NA, NA, "medium fire");
@ -6612,9 +6862,9 @@ void initobjects(void) {
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL); addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addot(OT_MUDPOOL, "pool of mud", "A large puddle of wet mud.", MT_WATER, 0, OC_MISC); addot(OT_MUDPOOL, "pool of mud", "A large puddle of wet mud.", MT_WATER, 0, OC_MISC);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ","); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
@ -6627,7 +6877,7 @@ void initobjects(void) {
addot(OT_PUDDLEWATER, "small puddle of water", "A small puddle of water.", MT_WATER, 0, OC_MISC); addot(OT_PUDDLEWATER, "small puddle of water", "A small puddle of water.", MT_WATER, 0, OC_MISC);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
@ -6641,7 +6891,7 @@ void initobjects(void) {
addot(OT_PUDDLEWATERL, "large puddle of water", "A large pool of water.", MT_WATER, 0, OC_MISC); addot(OT_PUDDLEWATERL, "large puddle of water", "A large pool of water.", MT_WATER, 0, OC_MISC);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, ",");
addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 85, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 85, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
@ -6651,6 +6901,7 @@ void initobjects(void) {
addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL); addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL);
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+2"); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+2");
addot(OT_BLOODSTAIN, "blood stain", "A dried stain of blood.", MT_BLOOD, 0, OC_MISC); addot(OT_BLOODSTAIN, "blood stain", "A dried stain of blood.", MT_BLOOD, 0, OC_MISC);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
@ -6746,9 +6997,27 @@ void initobjects(void) {
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
// trail objects
addot(OT_FOOTPRINT, "footprints", "Footprints which show the passage of some kind of creature.", MT_NOTHING, 0, OC_MISC);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NO_PLURAL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "."); // ie not really visible
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
// NOTE: must add F_TRAIL when creating this object.
addot(OT_SCENT, "scent", "The scent of a creature, only perceivable to those with an enhanced sense of smell.", MT_NOTHING, 0, OC_MISC);
addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NO_PLURAL, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "."); // ie not really visible
addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL);
// NOTE: must add F_TRAIL when creating this object.
// effects // effects
addot(OT_FIRELARGE, "large fire", "A large, roaring inferno.", MT_FIRE, 0, OC_EFFECT); addot(OT_FIRELARGE, "large fire", "A large, roaring inferno.", MT_FIRE, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "}"); addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "^");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dies down a little"); addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dies down a little");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "medium fire"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "medium fire");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
@ -6759,7 +7028,7 @@ void initobjects(void) {
addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 3, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_FIREMED, "medium fire", "A medium-sized roaring fire.", MT_FIRE, 0, OC_EFFECT); addot(OT_FIREMED, "medium fire", "A medium-sized roaring fire.", MT_FIRE, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "}"); addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "^");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small fire"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small fire");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dies down a little"); addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dies down a little");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
@ -6770,7 +7039,7 @@ void initobjects(void) {
addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_FIRESMALL, "small fire", "A small blaze.", MT_FIRE, 0, OC_EFFECT); addot(OT_FIRESMALL, "small fire", "A small blaze.", MT_FIRE, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "}"); addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, "^");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "goes out"); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "goes out");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
@ -6781,7 +7050,7 @@ void initobjects(void) {
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_STEAMCLOUD, "cloud of steam", "A thick cloud of scalding steam.", MT_GAS, 0, OC_EFFECT); addot(OT_STEAMCLOUD, "cloud of steam", "A thick cloud of scalding steam.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL); addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of steam"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of steam");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
@ -6793,7 +7062,7 @@ void initobjects(void) {
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_STEAMPUFF, "puff of steam", "A small puff of scalding steam.", MT_GAS, 0, OC_EFFECT); addot(OT_STEAMPUFF, "puff of steam", "A small puff of scalding steam.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses"); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
@ -6805,7 +7074,7 @@ void initobjects(void) {
addot(OT_SLEETSTORM, "storm of sleet", "An intense storm of sleet. Hampers movement", MT_GAS, 0, OC_EFFECT); addot(OT_SLEETSTORM, "storm of sleet", "An intense storm of sleet. Hampers movement", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_CYAN, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL); addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
@ -6813,7 +7082,7 @@ void initobjects(void) {
addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSVIEW, 3, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, 3, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_REDUCEMOVEMENT, 2, NA, NA, NULL); addflag(lastot->flags, F_REDUCEMOVEMENT, 3, NA, NA, NULL);
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addflag(lastot->flags, F_WALKDAMBP, BP_HEAD, DT_WATER, NA, "1d2"); addflag(lastot->flags, F_WALKDAMBP, BP_HEAD, DT_WATER, NA, "1d2");
addflag(lastot->flags, F_WALKDAMBP, BP_SHOULDERS, DT_WATER, NA, "1d2"); addflag(lastot->flags, F_WALKDAMBP, BP_SHOULDERS, DT_WATER, NA, "1d2");
@ -6823,7 +7092,7 @@ void initobjects(void) {
addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, NA, "1d2"); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, NA, "1d2");
addot(OT_MIST, "thick mist", "A thick cloud of obscuring mist.", MT_GAS, 0, OC_EFFECT); addot(OT_MIST, "thick mist", "A thick cloud of obscuring mist.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "clears"); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "clears");
addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL); addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
@ -6833,7 +7102,7 @@ void initobjects(void) {
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_SMOKECLOUD, "cloud of smoke", "A thick cloud of black smoke.", MT_GAS, 0, OC_EFFECT); addot(OT_SMOKECLOUD, "cloud of smoke", "A thick cloud of black smoke.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL); addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of smoke"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of smoke");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
@ -6846,7 +7115,7 @@ void initobjects(void) {
addot(OT_SMOKEPUFF, "puff of smoke", "A small puff of black smoke.", MT_GAS, 0, OC_EFFECT); addot(OT_SMOKEPUFF, "puff of smoke", "A small puff of black smoke.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, NA, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses"); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
@ -6857,7 +7126,7 @@ void initobjects(void) {
addflag(lastot->flags, F_CAUSESCOUGH, 18, NA, NA, NULL); addflag(lastot->flags, F_CAUSESCOUGH, 18, NA, NA, NULL);
addot(OT_POISONCLOUD, "cloud of poison gas", "A thick cloud of poisonous gas.", MT_GAS, 0, OC_EFFECT); addot(OT_POISONCLOUD, "cloud of poison gas", "A thick cloud of poisonous gas.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "}");
addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "thins out a little"); addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "thins out a little");
addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of gas"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puff of gas");
addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL);
@ -6869,7 +7138,7 @@ void initobjects(void) {
addflag(lastot->flags, F_BLOCKSVIEW, 2, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSVIEW, 2, NA, NA, NULL);
addot(OT_POISONPUFF, "puff of poison gas", "A small puff of poisonous gas.", MT_GAS, 0, OC_EFFECT); addot(OT_POISONPUFF, "puff of poison gas", "A small puff of poisonous gas.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "}");
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses"); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "disperses");
addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
@ -6879,7 +7148,7 @@ void initobjects(void) {
addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!");
addot(OT_HAILSTORM, "hail storm", "An intense storm of damaging hail.", MT_GAS, 0, OC_EFFECT); addot(OT_HAILSTORM, "hail storm", "An intense storm of damaging hail.", MT_GAS, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "{"); addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "}");
addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL); addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL);
addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
@ -6906,8 +7175,7 @@ void initobjects(void) {
addot(OT_MAGICBARRIER, "magical barrier", "A glowing, impassable barrier of magical energy.", MT_MAGIC, 0, OC_EFFECT); addot(OT_MAGICBARRIER, "magical barrier", "A glowing, impassable barrier of magical energy.", MT_MAGIC, 0, OC_EFFECT);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "#"); addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "vanishes"); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "vanishes");
addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL); addflag(lastot->flags, F_PRODUCESLIGHT, 1, NA, NA, NULL);
@ -7292,6 +7560,7 @@ void initobjects(void) {
addot(OT_TEETH, "teeth", "teeth object", MT_BONE, 0, OC_WEAPON); addot(OT_TEETH, "teeth", "teeth object", MT_BONE, 0, OC_WEAPON);
addflag(lastot->flags, F_DAM, DT_BITE, NA, NA, "1d2"); addflag(lastot->flags, F_DAM, DT_BITE, NA, NA, "1d2");
addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL);
addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL);
addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL);
@ -8178,6 +8447,11 @@ int isimpassableob(object_t *o, lifeform_t *lf) {
return B_TRUE; return B_TRUE;
} }
} }
if (lf && (lf->race->raceclass->id == RC_UNDEAD)) {
if (hasflagval(o->flags, F_REPELBLESSED, B_CURSED, NA, NA, NULL)) {
return B_TRUE;
}
}
return B_FALSE; return B_FALSE;
} }
@ -9088,7 +9362,7 @@ void obdie(object_t *o) {
} }
int obfits(object_t *o, obpile_t *op) { int obfits(object_t *o, obpile_t *op) {
if (countobs(op) >= MAXPILEOBS) { if (countobs(op, B_FALSE) >= MAXPILEOBS) {
return B_FALSE; return B_FALSE;
} }
return B_TRUE; return B_TRUE;
@ -9279,10 +9553,10 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
if (isplayer(lf)) { if (isplayer(lf)) {
if (strlen(f->text) > 0) { if (strlen(f->text) > 0) {
where = askcoords(f->text, ttype, lf, UNLIMITED); where = askcoords(f->text, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
} else { } else {
sprintf(buf, "Where will you aim %s?",obname); sprintf(buf, "Where will you aim %s?",obname);
where = askcoords(buf, ttype, lf, UNLIMITED); where = askcoords(buf, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
if (!haslos(lf, where)) { if (!haslos(lf, where)) {
// exception - wand of digging doesn't need los // exception - wand of digging doesn't need los
if (isknown(o) && (o->type->id == OT_WAND_DIGGING)) { if (isknown(o) && (o->type->id == OT_WAND_DIGGING)) {
@ -9440,7 +9714,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
case 0: // butterflies around user case 0: // butterflies around user
willid = B_TRUE; willid = B_TRUE;
where = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); where = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND);
addmonster(where, R_BUTTERFLY, B_FALSE, rnd(10,20), B_FALSE); addmonster(where, R_BUTTERFLY, B_FALSE, rnd(10,20), B_FALSE, NULL);
if (haslos(player, where)) { if (haslos(player, where)) {
msg("A swarm of butterflies appears!"); msg("A swarm of butterflies appears!");
} }
@ -10147,6 +10421,8 @@ void quaff(lifeform_t *lf, object_t *o) {
int playercansee; int playercansee;
int forcedrop = B_FALSE; int forcedrop = B_FALSE;
int seen; int seen;
int killobwhendone = B_TRUE;
flag_t *drinkflag;
getobname(o, obname, 1); getobname(o, obname, 1);
@ -10210,14 +10486,21 @@ void quaff(lifeform_t *lf, object_t *o) {
if (o->type->obclass->id == OC_POTION) { if (o->type->obclass->id == OC_POTION) {
potioneffects(lf, o->type->id, o->blessed, &seen); potioneffects(lf, o->type->id, o->blessed, &seen);
} else if (hasflag(o->flags, F_DRINKABLE)) { } else {
// drinkable thing which isn't a potion? drinkflag= hasflag(o->flags, F_DRINKABLE);
flag_t *f; if (drinkflag) {
f = hasflag(o->flags, F_LINKOB); // drinkable thing which isn't a potion?
if (f) { flag_t *f;
potioneffects(lf, f->val[0], o->blessed, NULL); f = hasflag(o->flags, F_LINKOB);
} else { if (f) {
eat(lf, o); potioneffects(lf, f->val[0], o->blessed, NULL);
} else {
eat(lf, o);
}
//
if (drinkflag->val[2] == B_DONTKILL) {
killobwhendone = B_FALSE;
}
} }
} }
@ -10233,8 +10516,11 @@ void quaff(lifeform_t *lf, object_t *o) {
// try to add an empty container to our pack // try to add an empty container to our pack
addemptyob(lf->pack, o); addemptyob(lf->pack, o);
} }
// lose the potion
removeob(o, 1); if (killobwhendone) {
// lose the potion
removeob(o, 1);
}
} }
@ -10544,11 +10830,15 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i
if (c && isempty(c)) { if (c && isempty(c)) {
object_t *newob; object_t *newob;
newob = addob(c->obpile, "magical barrier"); newob = addob(c->obpile, "magical barrier");
addflag(newob->flags, F_OBHP, i, i, NA, NULL);
if (first && haslos(player, c)) { if (first && haslos(player, c)) {
msg("A magical barrier appears!"); msg("A magical barrier appears!");
first = B_FALSE; first = B_FALSE;
} }
// it will disappear eventually
addflag(newob->flags, F_OBHP, i, i, NA, NULL);
addflag(newob->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(newob->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
} }
} }
break; break;
@ -11056,7 +11346,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
capitalise(obcaps); capitalise(obcaps);
obcaps = strrep(obcaps, "An ", "The ", NULL); obcaps = strrep(obcaps, "An ", "The ", NULL);
obcaps = strrep(obcaps, "A ", "The ", NULL); obcaps = strrep(obcaps, "A ", "The ", NULL);
msg("%s shatters!",obcaps); msg("%s shatter%s!",obcaps, (o->amt == 1) ? "s" : "");
free(obcaps); free(obcaps);
seen = B_TRUE; seen = B_TRUE;
@ -11332,6 +11622,29 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno
} }
} }
// damage type creates other objects?
f = hasflagval(o->flags, F_DTCREATEOB, damtype, NA, NA, NULL);
if (f) {
cell_t *loc;
int radius;
int dirtype;
objecttype_t *ot;
loc = getoblocation(o);
ot = findotn(f->text);
if (ot && !hasob(loc->obpile, ot->id)) {
if (f->val[1] == NA) {
radius = 0;
dirtype = NA;
} else {
radius = f->val[1];
dirtype = f->val[2];
}
addobburst(loc, radius, dirtype, f->text, NULL, LOF_WALLSTOP);
}
}
// damage type converts this into something else? // damage type converts this into something else?
f = hasflagval(o->flags, F_DTCONVERT, damtype, NA, NA, NULL); f = hasflagval(o->flags, F_DTCONVERT, damtype, NA, NA, NULL);
if (f && !hasflag(o->flags, F_NODTCONVERT)) { if (f && !hasflag(o->flags, F_NODTCONVERT)) {
@ -11348,6 +11661,7 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno
adjustdamob(o, &howmuch, damtype); adjustdamob(o, &howmuch, damtype);
// effects which have to happen before damage is applied... // effects which have to happen before damage is applied...
// explodes? // explodes?
f = hasflag(o->flags, F_EXPLODEONDAM); f = hasflag(o->flags, F_EXPLODEONDAM);
@ -11445,6 +11759,11 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno
// object dies! // object dies!
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
// if we didn't want this announced, don't say that it died either
if (!wantannounce) {
addflag(o->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL);
}
} else if (hpflag) { } else if (hpflag) {
// object was just damaged // object was just damaged
getobconditionname(o, postdamname); getobconditionname(o, postdamname);
@ -11967,7 +12286,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed,
shatter(newob, youhit, dambuf, thrower); shatter(newob, youhit, dambuf, thrower);
} else { } else {
// don't announce damage to the thrown object // don't announce damage to the thrown object
real_takedamage(newob, speed, DT_BASH, B_FALSE); real_takedamage(newob, speed-1, DT_BASH, B_FALSE);
} }
return B_FALSE; return B_FALSE;
@ -11977,24 +12296,42 @@ void timeeffectsob(object_t *o) {
flag_t *f, *nextf; flag_t *f, *nextf;
cell_t *location; cell_t *location;
lifeform_t *owner; lifeform_t *owner;
char obname[BUFLEN]; object_t *sg;
char obname[BUFLEN],ownername[BUFLEN];
if (hasflag(o->flags, F_DEAD)) return; if (hasflag(o->flags, F_DEAD)) return;
getobname(o, obname, o->amt); getobname(o, obname, o->amt);
location = getoblocation(o);
/*
if (o->pile->where) { if (o->pile->where) {
location = o->pile->where; location = o->pile->where;
} else { } else {
location = NULL; location = NULL;
} }
*/
if (o->pile->owner) { if (o->pile->owner) {
owner = o->pile->owner; owner = o->pile->owner;
getlfname(owner, ownername);
} else { } else {
owner = NULL; owner = NULL;
} }
// special case for trail flags
f = hasflag(o->flags, F_TRAIL);
if (f) {
if (f->lifetime > 0) {
f->lifetime--;
if (f->lifetime <= 0) {
// object dies.
killob(o);
return;
}
}
}
// expire flags // expire flags
timeeffectsflags(o->flags); timeeffectsflags(o->flags);
@ -12073,6 +12410,55 @@ void timeeffectsob(object_t *o) {
} }
} }
// sacred ground?
sg = hasobwithflagval(location->obpile, F_REPELBLESSED, o->blessed, NA, NA, NULL);
if (sg) {
char sgname[BUFLEN];
cell_t *newc;
int canseeloc = B_FALSE;
if (haslos(player, location)) {
getobname(sg, sgname, sg->amt);
canseeloc = B_FALSE;
msg("The %s pulses %s!", noprefix(sgname),
(o->blessed == B_CURSED) ? "white" : "black");
}
// object gets thrown away
newc = getrandomadjcell(location, WE_NOTWALL, B_ALLOWEXPAND);
if (newc) {
//flag_t *inv;
// make sure the object doesn't take damage
//inv = addflag(o->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL);
fireat(NULL, o, o->amt, newc, 1, NULL);
if (canseeloc) {
// player now knows that this is blessed
o->blessknown = B_TRUE;
}
//if (needredraw) drawlevelfor(player);
// update location
//if (inv) killflag(inv);
location = newc;
} else {
// object can't go anywhere - it disintegrates.
if (owner && cansee(player, owner)) {
msg("%s%s vanish%s in a surge of %s power!", ownername, getpossessive(ownername),
obname, (o->amt == 1) ? "es" : "",
(o->blessed = B_CURSED) ? "holy" : "evil");
} else if (haslos(player, location)) {
msg("%s vanish%s in a surge of %s power!", obname, (o->amt == 1) ? "es" : "",
(o->blessed = B_CURSED) ? "holy" : "evil");
}
removeob(o, o->amt);
return;
}
}
if (location) { if (location) {
// does object's material change cell type? // does object's material change cell type?
if (o->material->id == MT_FIRE) { if (o->material->id == MT_FIRE) {
@ -12331,7 +12717,9 @@ void timeeffectsob(object_t *o) {
object_t *splash; object_t *splash;
ourcell = getoblocation(o); ourcell = getoblocation(o);
// drip // drip
splash = addob(ourcell->obpile, "splash of water"); if (!hasobwithflag(ourcell->obpile, F_DEEPWATER)) {
splash = addob(ourcell->obpile, "splash of water");
}
} }
} }

View File

@ -25,6 +25,7 @@ void applyobmod(object_t *o, obmod_t *om);
int blessob(object_t *o); int blessob(object_t *o);
void brightflash(cell_t *centre, int range, lifeform_t *immunelf); void brightflash(cell_t *centre, int range, lifeform_t *immunelf);
int canbepoisoned(enum OBTYPE oid); int canbepoisoned(enum OBTYPE oid);
int canseeob(lifeform_t *lf, object_t *o);
object_t *canstackob(obpile_t *op, object_t *match); object_t *canstackob(obpile_t *op, object_t *match);
object_t *canstacknewot(obpile_t *op, objecttype_t *match); object_t *canstacknewot(obpile_t *op, objecttype_t *match);
int changemat(object_t *o, enum MATERIAL mat); int changemat(object_t *o, enum MATERIAL mat);
@ -32,10 +33,10 @@ objecttype_t *checkobnames(char *haystack, char *needle);
void colourmatchob(object_t *o, lifeform_t *lf); void colourmatchob(object_t *o, lifeform_t *lf);
void copyobprops(object_t *dst, object_t *src); void copyobprops(object_t *dst, object_t *src);
int countnames(char **list); int countnames(char **list);
int countobs(obpile_t *op); int countobs(obpile_t *op, int onlyifknown);
int countnoncosmeticobs(obpile_t *op); int countnoncosmeticobs(obpile_t *op, int onlyifknown);
int curseob(object_t *o); int curseob(object_t *o);
void damageallobs(object_t *exception, obpile_t *op, int howmuch, int damtype); void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype);
void dumprandomobs(int amt); void dumprandomobs(int amt);
void explodeob(object_t *o, flag_t *f, int bigness); void explodeob(object_t *o, flag_t *f, int bigness);
void extinguish(object_t *o); void extinguish(object_t *o);
@ -80,6 +81,7 @@ char getnextletter(obpile_t *op, char *wantletter);
int getnumshards(object_t *o); int getnumshards(object_t *o);
int getnutritionbase(object_t *o); int getnutritionbase(object_t *o);
int getnutrition(object_t *o); int getnutrition(object_t *o);
enum DEPTH getobdepth(object_t *o, lifeform_t *lf);
char *getobdesc(object_t *o, char *buf); char *getobdesc(object_t *o, char *buf);
char *getobequipinfo(object_t *o, char *buf); char *getobequipinfo(object_t *o, char *buf);
char *getobextrainfo(object_t *o, char *buf); char *getobextrainfo(object_t *o, char *buf);
@ -104,6 +106,7 @@ char *getschoolnameshort(enum SPELLSCHOOL sch);
int getshatterdam(object_t *o); int getshatterdam(object_t *o);
enum SKILLLEVEL gettechlevel(object_t *o); enum SKILLLEVEL gettechlevel(object_t *o);
int getthrowdam(object_t *o); int getthrowdam(object_t *o);
char *gettopobname(cell_t *c, char *retbuf);
enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded); enum BODYPART getweildloc(object_t *o, enum BODYPART *otherloc, int *twohanded);
int hasedibleob(obpile_t *op); int hasedibleob(obpile_t *op);
object_t *hasknownob(obpile_t *op, enum OBTYPE oid); object_t *hasknownob(obpile_t *op, enum OBTYPE oid);

256
spell.c
View File

@ -107,7 +107,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (isplayer(user)) { if (isplayer(user)) {
sprintf(buf, "Charge who (max range %d)?",range); sprintf(buf, "Charge who (max range %d)?",range);
// TODO: ask for direction // TODO: ask for direction
targcell = askcoords(buf, TT_MONSTER, user, range); targcell = askcoords(buf, TT_MONSTER, user, range, LOF_NEED, B_TRUE);
if (!targcell) { if (!targcell) {
msg("Cancelled."); msg("Cancelled.");
return TRUE; return TRUE;
@ -254,7 +254,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else { } else {
sprintf(buf, "Darkwalk to where?"); sprintf(buf, "Darkwalk to where?");
} }
targcell = askcoords(buf, TT_NONE, user, range); targcell = askcoords(buf, TT_NONE, user, range, LOF_DONTNEED, B_FALSE);
} else { } else {
return B_TRUE; return B_TRUE;
} }
@ -538,7 +538,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
sprintf(buf, "Jump where (max distance 2)?"); sprintf(buf, "Jump where (max distance 2)?");
while (!targcell) { while (!targcell) {
// ask where // ask where
targcell = askcoords(buf, TT_NONE, user, 2); targcell = askcoords(buf, TT_NONE, user, 2, LOF_DONTNEED, B_TRUE);
if (!targcell) { if (!targcell) {
return B_TRUE; return B_TRUE;
} else if (getcelldist(user->cell, targcell) > 2) { } else if (getcelldist(user->cell, targcell) > 2) {
@ -801,7 +801,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
if (isplayer(user)) { if (isplayer(user)) {
sprintf(buf, "Swoop who (max range %d)?",srange); sprintf(buf, "Swoop who (max range %d)?",srange);
// TODO: ask for direction // TODO: ask for direction
targcell = askcoords(buf, TT_MONSTER, user, srange); targcell = askcoords(buf, TT_MONSTER, user, srange, LOF_NEED, B_TRUE);
if (!targcell) { if (!targcell) {
msg("Cancelled."); msg("Cancelled.");
return TRUE; return TRUE;
@ -935,13 +935,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_FALSE; return B_FALSE;
} else if (abilid == OT_A_DEBUG) { } else if (abilid == OT_A_DEBUG) {
cell_t *where; cell_t *where;
where = askcoords("Debug who?", TT_MONSTER, user, UNLIMITED); where = askcoords("Debug who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf) { if (where && where->lf) {
debug(where->lf); debug(where->lf);
} }
} else if (abilid == OT_A_EMPLOY) { } else if (abilid == OT_A_EMPLOY) {
cell_t *where; cell_t *where;
where = askcoords("Assign job to who?", TT_MONSTER, user, UNLIMITED); where = askcoords("Assign job to who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf) { if (where && where->lf) {
char question[BUFLEN]; char question[BUFLEN];
char lfname[BUFLEN]; char lfname[BUFLEN];
@ -965,7 +965,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} }
} else if (abilid == OT_A_ENHANCE) { } else if (abilid == OT_A_ENHANCE) {
cell_t *where; cell_t *where;
where = askcoords("Enhance stats of who?", TT_MONSTER, user, UNLIMITED); where = askcoords("Enhance stats of who?", TT_MONSTER, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf) { if (where && where->lf) {
char ch; char ch;
enum ATTRIB att; enum ATTRIB att;
@ -1483,7 +1483,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_BLINDNESS) { } else if (spellid == OT_S_BLINDNESS) {
int failed = B_FALSE; int failed = B_FALSE;
// ask for target // ask for target
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if (isblind(target)) { if (isblind(target)) {
fizzle(caster); fizzle(caster);
@ -1547,6 +1548,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
// create a line of fire towards the target cell // create a line of fire towards the target cell
calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcell); calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcell);
redrawpause();
// don't set caster's cell on fire! // don't set caster's cell on fire!
for (i = 1; i < nretcell; i++) { for (i = 1; i < nretcell; i++) {
cell_t *c; cell_t *c;
@ -1558,24 +1560,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (o) { if (o) {
setobcreatedby(o, caster); setobcreatedby(o, caster);
if (c->lf) {
char buf[BUFLEN];
char damstring[BUFLEN];
char realcname[BUFLEN];
getlfname(c->lf,buf);
if (!isimmuneto(c->lf->flags, DT_FIRE)) {
msg("%s burn%s!",buf,isplayer(c->lf) ? "" : "s");
}
real_getlfname(caster, realcname, B_FALSE);
sprintf(damstring, "%s%s wave of fire", realcname, getpossessive(realcname));
losehp(c->lf, rolldie(2,10), DT_FIRE, caster, damstring);
}
} }
} }
redrawresume();
// now burn things
for (i = 1; i < nretcell; i++) {
cell_t *c;
c = retcell[i];
if (c->lf) {
char buf[BUFLEN];
char damstring[BUFLEN];
char realcname[BUFLEN];
getlfname(c->lf,buf);
if (!isimmuneto(c->lf->flags, DT_FIRE)) {
msg("%s burn%s!",buf,isplayer(c->lf) ? "" : "s");
}
real_getlfname(caster, realcname, B_FALSE);
sprintf(damstring, "%s%s wave of fire", realcname, getpossessive(realcname));
losehp(c->lf, rolldie(2,10), DT_FIRE, caster, damstring);
}
}
if (cansee(player, caster)) { if (cansee(player, caster)) {
needredraw = B_TRUE; needredraw = B_TRUE;
} }
} else if (spellid == OT_S_CALLLIGHTNING) { } else if (spellid == OT_S_CALLLIGHTNING) {
int failed = B_FALSE; int failed = B_FALSE;
// ask for a target cell // ask for a target cell
@ -1617,13 +1626,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (targcell->obpile->first) { if (targcell->obpile->first) {
// select object from cell... // select object from cell...
if (countobs(targcell->obpile) == 1) { targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
targob = targcell->obpile->first; if (!targob) {
} else { failed = B_TRUE;
targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
if (!targob) {
failed = B_TRUE;
}
} }
} else { } else {
failed = B_TRUE; failed = B_TRUE;
@ -2045,7 +2050,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
// add the monster // add the monster
newlf = addmonster(targcell, r->id, randomjobsok, 1, B_FALSE); newlf = addmonster(targcell, r->id, randomjobsok, 1, B_FALSE, NULL);
if (newlf) { if (newlf) {
// assign job if required // assign job if required
if (forcejob) { if (forcejob) {
@ -2152,9 +2157,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_DIG) { } else if (spellid == OT_S_DIG) {
int numseen = 0; int numseen = 0;
int maxrange;
cell_t *retcell[MAXRETCELLS]; cell_t *retcell[MAXRETCELLS];
int nretcell,i; int nretcell,i;
int ndigs;
// don't need line of fire OR sight! // don't need line of fire OR sight!
if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power)) return B_TRUE;
@ -2163,25 +2168,47 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y,
targcell->x, targcell->y, retcell, &nretcell); targcell->x, targcell->y, retcell, &nretcell);
maxrange = power; ndigs = 0;
// get rid of rock in the cells... // get rid of rock in the cells...
for (i = 0; i < nretcell && (i <= maxrange); i++) { for (i = 0; i < nretcell && (ndigs <= power) ; i++) {
int seenthiscell = B_FALSE;
if (haslos(player, retcell[i])) seenthiscell = B_TRUE;
if (retcell[i]->type->solid) { if (retcell[i]->type->solid) {
setcelltype(retcell[i], getemptycelltype(retcell[i]->map->habitat)); setcelltype(retcell[i], getemptycelltype(retcell[i]->map->habitat));
if (haslos(player, retcell[i])) numseen++; if (seenthiscell) {
ndigs++;
numseen++;
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
} else {
object_t *o;
for (o = retcell[i]->obpile->first ; o ; o = o->next) {
if (hasflag(o->flags, F_IMPASSABLE)) {
char obname[BUFLEN];
// destroy this object then stop.
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
if (seenthiscell) {
if (!hasflag(o->flags, F_OBDIETEXT)) {
getobname(o, obname, o->amt);
msg("%s crumble%s to dust!", obname, (o->amt == 1) ? "s" : "");
}
if (seenbyplayer) *seenbyplayer = B_TRUE;
}
ndigs++;
}
}
} }
} }
// announce destruction of any walls seen
// announce if any seen
if (numseen) { if (numseen) {
msg("The wall%s crumble%s to dust!", msg("The wall%s crumble%s to dust!",
(numseen == 1) ? "" : "s", (numseen == 1) ? "" : "s",
(numseen == 1) ? "s" : "" (numseen == 1) ? "s" : ""
); );
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
} else { } else if (ndigs == 0) {
if (isplayer(caster)) nothinghappens(); if (isplayer(caster)) nothinghappens();
} }
} else if (spellid == OT_S_DETECTLIFE) { } else if (spellid == OT_S_DETECTLIFE) {
@ -2313,15 +2340,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
object_t *o, *nexto; object_t *o, *nexto;
int donesomething = B_FALSE; int donesomething = B_FALSE;
if (!validatespellcell(caster, &targcell,TT_MONSTER|TT_OBJECT, spellid, power)) return B_TRUE;
if (!targcell) { if (!targcell) {
if (isplayer(caster)) { if (isplayer(caster)) {
sprintf(buf, "Where will you target your dispersal?");
targcell = askcoords(buf, TT_MONSTER|TT_OBJECT, caster, UNLIMITED);
if (!targcell) { // no cell
fizzle(caster);
return B_TRUE;
}
} else {
fizzle(caster); fizzle(caster);
return B_TRUE; return B_TRUE;
} }
@ -2494,7 +2515,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_FEEBLEMIND) { } else if (spellid == OT_S_FEEBLEMIND) {
// ask for target // ask for target
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if ((getattr(target, A_IQ) <= 3) || skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { if ((getattr(target, A_IQ) <= 3) || skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (cansee(player, target)) { if (cansee(player, target)) {
@ -2588,6 +2610,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
anim(caster->cell, targcell, '^', C_RED); anim(caster->cell, targcell, '^', C_RED);
redrawpause();
// add fires as follows (3 = medium, 2 = medium, 1 = smell) // add fires as follows (3 = medium, 2 = medium, 1 = smell)
// //
// 1 // 1
@ -2642,6 +2665,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} }
} }
redrawresume();
} else { } else {
failed = B_TRUE; failed = B_TRUE;
@ -3529,21 +3554,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster); fizzle(caster);
} }
} else if (spellid == OT_S_MINDSCAN) { } else if (spellid == OT_S_MINDSCAN) {
cell_t *where;
int failed = B_FALSE; int failed = B_FALSE;
if (isplayer(caster)) { if (isplayer(caster)) {
// ask for a target cell if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE;
sprintf(buf, "Whose mind will you scan?");
where = askcoords(buf, TT_MONSTER, caster, UNLIMITED); if (targcell && haslos(caster, targcell) && haslf(targcell)) {
if (where && haslos(caster, where) && haslf(where)) {
char targname[BUFLEN]; char targname[BUFLEN];
lifeform_t *oldplayer; lifeform_t *oldplayer;
// temporarily change player pointer... // temporarily change player pointer...
oldplayer = player; oldplayer = player;
player = where->lf; player = targcell->lf;
// //
getlfname(where->lf, targname); getlfname(targcell->lf, targname);
sprintf(buf, "Mindscanning %s, ESC to quit.", targname); sprintf(buf, "Mindscanning %s, ESC to quit.", targname);
doexplain(buf); doexplain(buf);
@ -3585,7 +3608,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_PARALYZE) { } else if (spellid == OT_S_PARALYZE) {
int howlong; int howlong;
int saved = B_FALSE; int saved = B_FALSE;
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if (lfhasflag(target, F_PARALYZED)) { if (lfhasflag(target, F_PARALYZED)) {
fizzle(caster); fizzle(caster);
@ -3619,7 +3643,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_PAIN) { } else if (spellid == OT_S_PAIN) {
int failed = B_FALSE; int failed = B_FALSE;
// ask for target // ask for target
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if (lfhasflag(target, F_PAIN)) { if (lfhasflag(target, F_PAIN)) {
fizzle(caster); fizzle(caster);
@ -3654,7 +3679,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster); fizzle(caster);
} }
} else if (spellid == OT_S_PETRIFY) { } else if (spellid == OT_S_PETRIFY) {
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
// some thigns can't be stoned // some thigns can't be stoned
if (!lfcanbestoned(target)) { if (!lfcanbestoned(target)) {
@ -3933,11 +3959,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (targcell->obpile->first) { // no lifeform there } else if (targcell->obpile->first) { // no lifeform there
targob = NULL; targob = NULL;
// select object from cell... // select object from cell...
if (countobs(targcell->obpile) == 1) { targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
targob = targcell->obpile->first;
} else {
targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
}
if (targob) { if (targob) {
if (ismetal(targob->material->id)) { if (ismetal(targob->material->id)) {
@ -4122,23 +4144,37 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS);
knockback(target, dir, 2, caster, 0); knockback(target, dir, 2, caster, 0);
} else { } else {
o = hasobwithflag(targcell->obpile, F_DOOR); int donesomething = B_FALSE;
if (o) { object_t *nexto;
int dooropen; for (o = targcell->obpile->first ; o ; o = nexto) {
isdoor(o, &dooropen); // just check whether it's open, we know it's a door nexto = o->next;
if (dooropen) { if (hasflag(o->flags, F_IMPASSABLE)) {
fizzle(caster); int gotit = B_FALSE;
} else { int dooropen;
if (haslos(player, targcell)) { if (isdoor(o, &dooropen)) {
getobname(o, buf, o->amt); if (!dooropen) {
msg("%s %s!",isplayer(caster) ? "You blast" : "Something blasts", buf); gotit = B_TRUE;
}
} else {
gotit = B_TRUE;
}
if (gotit) {
if (haslos(player, targcell)) {
getobname(o, buf, o->amt);
msg("%s %s!",isplayer(caster) ? "You blast" : "Something blasts", buf);
}
addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL);
if (seenbyplayer) *seenbyplayer = B_TRUE;
donesomething = B_TRUE;
} }
takedamage(o, 999, DT_DIRECT);
if (seenbyplayer) *seenbyplayer = B_TRUE;
} }
} else { }
if (!donesomething) {
fizzle(caster); fizzle(caster);
} }
} }
} else if (spellid == OT_S_LEVITATION) { } else if (spellid == OT_S_LEVITATION) {
flag_t *f; flag_t *f;
@ -4190,7 +4226,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} }
// undead will flee from light // undead will flee from light
if (lfhasflag(l, F_UNDEAD)) { if (isundead(l)) {
// runs away from caster // runs away from caster
addtempflag(l->flags, F_FLEEFROM, caster->id, NA, NA, NULL, 20); addtempflag(l->flags, F_FLEEFROM, caster->id, NA, NA, NULL, 20);
} }
@ -4254,7 +4290,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
for (i = 0; i < caster->nlos; i++) { for (i = 0; i < caster->nlos; i++) {
target = caster->los[i]->lf; target = caster->los[i]->lf;
if (target) { if (target && areenemies(caster, target)) {
poss[nposs++] = target; poss[nposs++] = target;
} }
} }
@ -4422,18 +4458,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_GRAVBOOST) { } else if (spellid == OT_S_GRAVBOOST) {
// ask for target // ask for target
if (!target) { if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE;
if (isplayer(caster)) {
cell_t *where;
sprintf(buf, "Where will you target your spell?");
where = askcoords(buf, TT_MONSTER, caster, UNLIMITED);
if (where && haslos(caster, where) && haslf(where)) {
target = haslf(where);
} else {
fizzle(caster);
}
}
}
if (target) { if (target) {
int howlong = 15; int howlong = 15;
@ -4615,7 +4640,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int donesomething = B_FALSE; int donesomething = B_FALSE;
// stop targetting anybody // stop targetting anybody
if (killflagsofid(target->flags, F_TARGET)) { if (killflagsofid(target->flags, F_TARGETLF)) {
donesomething = B_TRUE; donesomething = B_TRUE;
} }
if (killflagsofid(target->flags, F_TARGETCELL)) { if (killflagsofid(target->flags, F_TARGETCELL)) {
@ -4649,16 +4674,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_POLYMORPH) { } else if (spellid == OT_S_POLYMORPH) {
race_t *r = NULL; race_t *r = NULL;
// ask for target if required if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE;
if (!target && isplayer(caster)) { target = targcell->lf;
cell_t *where;
where = askcoords("Who will you polymorph?", TT_MONSTER, caster, UNLIMITED);
if (haslos(caster, where)) {
target = where->lf;
} else {
target = NULL;
}
}
if (!target) { if (!target) {
fizzle(caster); fizzle(caster);
@ -4968,7 +4985,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f->obfrom = spellid; f->obfrom = spellid;
} else if (spellid == OT_S_SLEEP) { } else if (spellid == OT_S_SLEEP) {
int howlong; int howlong;
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if (lfhasflag(target, F_ASLEEP) || !cansleep(target)) { if (lfhasflag(target, F_ASLEEP) || !cansleep(target)) {
fizzle(caster); fizzle(caster);
@ -5023,7 +5041,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_SLOW) { } else if (spellid == OT_S_SLOW) {
int howlong = 15; int howlong = 15;
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (isplayer(target)) { if (isplayer(target)) {
@ -5064,7 +5083,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
badoid[0] = OT_MUDPOOL; badoid[0] = OT_MUDPOOL;
badoid[1] = OT_NONE; badoid[1] = OT_NONE;
for (i = 0; i < powerleft; i++) { for (i = 0; i < powerleft; i++) {
c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, badoid); c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_DONTNEED, badoid);
if (c) { if (c) {
o = addob(c->obpile, "pool of mud"); o = addob(c->obpile, "pool of mud");
if (o) { if (o) {
@ -5296,7 +5315,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
sprintf(buf, "Where will you teleport to?"); sprintf(buf, "Where will you teleport to?");
while (!c) { while (!c) {
int ch; int ch;
c = askcoords(buf, TT_NONE, caster, UNLIMITED); c = askcoords(buf, TT_NONE, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (!c->known) { if (!c->known) {
// confirm // confirm
ch = askchar("Are you sure to want to teleport into the unknown?", "yn", "n", B_TRUE); ch = askchar("Are you sure to want to teleport into the unknown?", "yn", "n", B_TRUE);
@ -5452,17 +5471,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (!targob) { if (!targob) {
// ask for a target cell (to take objects from) // ask for a target cell (to take objects from)
sprintf(buf, "Where will you focus your telekinetic power?"); sprintf(buf, "Where will you focus your telekinetic power?");
where = askcoords(buf, TT_OBJECT | TT_DOOR, caster, UNLIMITED); where = askcoords(buf, TT_OBJECT | TT_DOOR, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && haslos(caster, where)) { if (where && haslos(caster, where)) {
if (where->obpile->first) { if (where->obpile->first) {
// select object from cell... // select object from cell...
if (countobs(where->obpile) == 1) { targob = askobject(where->obpile, "Target which object", NULL, AO_NONE);
targob = where->obpile->first; if (!targob) {
} else { failed = B_TRUE;
targob = askobject(where->obpile, "Target which object", NULL, AO_NONE);
if (!targob) {
failed = B_TRUE;
}
} }
// TODO: check object weight! // TODO: check object weight!
} else { } else {
@ -5489,7 +5504,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char obname[BUFLEN]; char obname[BUFLEN];
getobname(targob, obname, 1); getobname(targob, obname, 1);
sprintf(buf, "Where will you move %s to?", obname); sprintf(buf, "Where will you move %s to?", obname);
targcell = askcoords(buf, TT_MONSTER | TT_PLAYER, caster, UNLIMITED); // TODO: start trail from the object
targcell = askcoords(buf, TT_MONSTER | TT_PLAYER, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
} }
// not liftable? // not liftable?
@ -5554,7 +5570,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
for (i = 0; i < caster->nlos; i++) { for (i = 0; i < caster->nlos; i++) {
targcell = caster->los[i]; targcell = caster->los[i];
target = targcell->lf; target = targcell->lf;
if (target && hasflag(target->flags, F_UNDEAD)) { if (target && isundead(target)) {
int howlong = 10; int howlong = 10;
int worked = B_TRUE; int worked = B_TRUE;
// TODO: does it work? depends on caster level & intelligence & power // TODO: does it work? depends on caster level & intelligence & power
@ -5879,7 +5895,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} }
} else if (spellid == OT_S_WEAKEN) { } else if (spellid == OT_S_WEAKEN) {
// ask for target // ask for target
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) {
if (cansee(player, target)) { if (cansee(player, target)) {
@ -5969,7 +5986,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE;
// ask for target // ask for target
if (spellid == OT_S_GIFT) { if (spellid == OT_S_GIFT) {
if (!validatespelllf(caster, &target)) return B_TRUE; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
} else { } else {
target = caster; target = caster;
} }
@ -6406,6 +6424,9 @@ int getspellrange(enum OBTYPE spellid, int power) {
case OT_S_CALLWIND: case OT_S_CALLWIND:
range = (power*2); range = (power*2);
break; break;
case OT_S_DIG:
range = power;
break;
case OT_S_LIGHTNINGBOLT: case OT_S_LIGHTNINGBOLT:
range = (power*3); range = (power*3);
break; break;
@ -6612,7 +6633,7 @@ int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, i
r = findrace(poss[rnd(0,nposs-1)]); r = findrace(poss[rnd(0,nposs-1)]);
if (r) { if (r) {
// add it! // add it!
newlf = addmonster(c, r->id, B_FALSE, 1, B_FALSE); newlf = addmonster(c, r->id, B_FALSE, 1, B_FALSE, NULL);
// not worth any xp // not worth any xp
killflagsofid(newlf->flags, F_XPVAL); killflagsofid(newlf->flags, F_XPVAL);
addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL);
@ -6644,13 +6665,12 @@ lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **targe
maxrange = UNLIMITED; maxrange = UNLIMITED;
} }
// ask for a target lifeform // ask for a target lifeform
if (isplayer(user)) { if (isplayer(user)) {
cell_t *where; cell_t *where;
char buf[BUFLEN]; char buf[BUFLEN];
sprintf(buf, "Where will you target your %s?",ot->name); sprintf(buf, "Where will you target your %s?",ot->name);
where = askcoords(buf, TT_MONSTER, user, maxrange); where = askcoords(buf, TT_MONSTER, user, maxrange, LOF_DONTNEED, B_FALSE);
if (where) { if (where) {
if (!haslf(where)) { if (!haslf(where)) {
msg("There is nobody there!"); msg("There is nobody there!");
@ -6781,7 +6801,7 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e
} else { } else {
sprintf(buf, "Where will you target your spell [max range %d]?",maxrange); sprintf(buf, "Where will you target your spell [max range %d]?",maxrange);
} }
where = askcoords(buf, targtype, caster, maxrange); where = askcoords(buf, targtype, caster, maxrange, needlof, needlof ? B_TRUE : B_FALSE);
if (!where) { if (!where) {
int ch; int ch;
ch = askchar("Abandon your spell?","yn","n", B_TRUE); ch = askchar("Abandon your spell?","yn","n", B_TRUE);
@ -6862,6 +6882,7 @@ int getmpcost(lifeform_t *lf, enum OBTYPE oid) {
} }
/*
lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **target) { lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **target) {
if (!caster) { if (!caster) {
return *target; return *target;
@ -6888,3 +6909,4 @@ lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **target) {
} }
return *target; return *target;
} }
*/

View File

@ -28,7 +28,7 @@ void stopallspells(lifeform_t *lf);
int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime); int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, int howmany, int lifetime);
lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target); lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **target);
cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power); cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, enum OBTYPE spellid, int power);
lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf); //lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);
#endif #endif