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?
f = lfhasflagval(lf, F_TARGET, victim->id, NA, NA, NULL);
f = lfhasflagval(lf, F_TARGETLF, victim->id, NA, NA, NULL);
if (f) {
if ((f->lifetime > 0) && (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];
getlfname(lf, lfname);
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);
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 {
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
if (cansee(player, lf)) {
@ -155,6 +155,109 @@ enum OBTYPE aigetfleespell(lifeform_t *lf) {
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) {
int specialcase = B_FALSE;
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);
}
killflagsofid(lf->flags, F_TARGET);
killflagsofid(lf->flags, F_TARGETLF);
killflagsofid(lf->flags, F_TARGETCELL);
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;
}
// 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) {
int x,y;
cell_t *c;
@ -402,7 +795,6 @@ void aiturn(lifeform_t *lf) {
int icanattack = B_FALSE;
object_t *curgun,*bestgun;
flag_t *f;
flag_t *mf;
//flag_t *nextf;
// lifeform_t *fleefrom = NULL;
lifeform_t *target,*newtarget;
@ -450,9 +842,9 @@ void aiturn(lifeform_t *lf) {
// are we a pet?
mf = lfhasflagval(lf, F_PETOF, NA, NA, NA, NULL);
if (mf && (getallegiance(lf) == AL_FRIENDLY)) {
master = findlf(lf->cell->map, mf->val[0]);
f = lfhasflagval(lf, F_PETOF, NA, NA, NA, NULL);
if (f && (getallegiance(lf) == AL_FRIENDLY)) {
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?
f = hasflag(lf->flags, F_TARGET);
f = hasflag(lf->flags, F_TARGETLF);
if (f) {
int targid;
int lastx,lasty;
@ -608,222 +1000,9 @@ void aiturn(lifeform_t *lf) {
target = findlf(lf->cell->map, targid);
if (target) {
if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name);
if (cansee(lf, target)) {
int goingtomove = B_TRUE;
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);
if (!aimovetolf(lf, target, B_TRUE)) {
// success
return;
*/
}
}
}
@ -1025,68 +1204,10 @@ void aiturn(lifeform_t *lf) {
// master is resting. the normal rest code underneath this section
// will never be called.
if (master) {
lifeform_t *master;
master = findlf(lf->cell->map, mf->val[0]);
if (master && cansee(lf, master)) {
// can see my master
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);
}
//lifeform_t *master;
//master = findlf(lf->cell->map, mf->val[0]);
if (!aimovetolf(lf, master, B_FALSE)) {
// success
return;
}
}
@ -1273,13 +1394,13 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG
ok = B_TRUE;
}
} 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;
}
}
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;
}
@ -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 *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);
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim);
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);
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);
int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack);
void aimovetotargetcell(lifeform_t *lf, flag_t *f);
int aipickup(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 aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose);
void aiturn(lifeform_t *lf);
int getownerlastdir(lifeform_t *lf);
object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op);
object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op);
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
!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_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);
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) {
return "touch";
} else if (damtype == DT_WATER) {
// for when water-vulnerable things go into water
return "hurt";
} else if (damtype == DT_UNARMED) {
if (onein(2)) {
return "punch";

76
defs.h
View File

@ -50,7 +50,9 @@ enum SKILL {
SK_SPELLCASTING,
SK_SPOTHIDDEN,
SK_STEALTH,
SK_SWIMMING,
SK_TECHUSAGE,
SK_TRACKING,
SK_TRAPS,
SK_TWOWEAPON,
// knowledge
@ -83,7 +85,7 @@ enum SKILL {
SK_SS_TRANSLOCATION,
SK_SS_WILD,
};
#define MAXSKILLS 44
#define MAXSKILLS 46
// proficiency levels
enum SKILLLEVEL {
@ -169,6 +171,14 @@ enum LFCONDITION {
C_HEALTHY = 5,
};
enum SENSE {
S_HEARING,
S_SIGHT,
S_SMELL,
S_TASTE,
S_TOUCH,
};
// AI defs
// if target lf is out of view for this many turns, abandon chase
@ -210,7 +220,11 @@ enum LFCONDITION {
#define TICK_INTERVAL (20)
#define SCENTTIME (15)
#define FOOTPRINTTIME (20)
// STRINGS
#define BUFLENTINY 10
#define BUFLENSMALL 64
#define BUFLEN 128
#define HUGEBUFLEN 1024
@ -341,6 +355,8 @@ enum LOFTYPE {
#define SP_ULTRASLOW 35
#define SP_SLOWEST 40
#define SPEEDUNIT 5
// speed settings (lower is faster)
#define SPEED_ATTACK SP_NORMAL
#define SPEED_DEAD 50
@ -734,6 +750,8 @@ enum OBTYPE {
OT_WOODENTABLE,
OT_WOODENBARREL,
OT_WOODENSTOOL,
OT_HOLYCIRCLE,
OT_PENTAGRAM,
OT_STAIRSDOWN,
OT_STAIRSUP,
OT_VENDINGMACHINE,
@ -1196,6 +1214,8 @@ enum OBTYPE {
OT_SPLASHWATER,
OT_PUDDLEWATER,
OT_PUDDLEWATERL,
OT_WATERSHALLOW,
OT_WATERDEEP,
OT_ACIDSPLASH,
OT_ACIDPUDDLE,
OT_ACIDPOOL,
@ -1208,6 +1228,9 @@ enum OBTYPE {
OT_MELTEDWAX,
OT_SOGGYPAPER,
OT_FLESHCHUNK,
// trail objects
OT_FOOTPRINT,
OT_SCENT,
// effects
OT_FIRELARGE,
OT_FIREMED,
@ -1396,6 +1419,15 @@ enum BODYPART {
};
#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
#define WE_WALKABLE 1
#define WE_EMPTY 2
@ -1437,6 +1469,13 @@ enum POISONTYPE {
P_WEAKNESS,
};
enum RANGEATTACK {
RA_NONE = 0,
RA_GUN,
RA_THROW,
RA_WAND,
};
enum FLAG {
F_NONE, // dummy flag
// map flags
@ -1452,6 +1491,14 @@ enum FLAG {
// text is an object it contains.
F_IDWHENUSED, // fully identify an object when worn/weilded/operated/etc
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
F_SHOPITEM, // causes shops to show this item as identified
F_VALUE, // how much an item is worth (over its base weight+material)
@ -1473,7 +1520,7 @@ enum FLAG {
// v0 = con skillcheck difficulty.
F_BLOCKSVIEW, // if v0 = true, cannot see past this
// 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"
// text[0] is punctuation to use.
F_OBDIETEXT, // text when the object dies
@ -1484,6 +1531,9 @@ enum FLAG {
F_NOQUALITY, // can't be masterwork / shoddy
F_CORPSEOF, // this is a corpse of montype val0.
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_NOMATCONVERT, // overrides MATCONVERT .
F_MATCONVERT, // touching material id val0 converts this to f->text
@ -1537,6 +1587,7 @@ enum FLAG {
// v2 = nutrition left when partially eaten
F_DRINKABLE, // you can drink this. val1 = nutrition. 100 = a meal
// -1 means "nutrition is weight x abs(val1)"
// if v2=DONTKILL, this object does NOT die when drunk.
F_OPERABLE, // can operate?
F_POURABLE, // can pour?
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_SECRET, // this object is secret. v0 is sc_search difficulty
// to find it.
// NA means 'can never find this'
// stairs / teleporters / portals
F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in
// also use this for portals
@ -1664,6 +1716,7 @@ enum FLAG {
F_HASHIDDENNAME, // whether this object class has a hidden name
F_IDENTIFIED, // whether this object is fully identified
// bad flags
F_DEEPWATER, // v0 = depth.oooooooooooo
F_WALKDAM, // val0 = damtype, text = dam per sec
F_WALKDAMBP, // v0 = bodypart, v1 = damtype, text = dam per sec
// if v2 == FALLTHRU, damage falls through to lf if
@ -1756,6 +1809,8 @@ enum FLAG {
// v1 = whether this spell needs line of fire
// MONSTER AI FLAGS
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
// 1 and its map dificulty/depth.
// 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_NOJOBTEXT, // this lf's name is 'a xxx', not 'a xxx wizard' etc
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.
F_PETOF, // this lf is a pet of lfid v0
// 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
// vanish.
// v1 is lifetime left. this decrements each turn.
@ -1789,7 +1845,10 @@ enum FLAG {
F_FLEEONDAM, // lf will run away instead of counterattacking
F_FLEEONHPPCT, // lf will run away if its hp drop to v0% or lower
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
// this is cleared at start of turn.
F_TARGETCELL, // lf will go towards this place. val0=x,val1=y
@ -1837,6 +1896,8 @@ enum FLAG {
// text=spell text
// for monsters
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_INSECT, // this race is classed as an insect
F_UNDEAD, // this race is classed as undead
@ -1870,6 +1931,7 @@ enum FLAG {
// this flag does not get announced.
F_BLEEDABIL, // will automatically use the ability v0 when
// this lf starts bleeding.
F_BREATHWATER, // can breath normally underwater
F_CANWILL, // can cast the spell/ability val0 without using MP
// v1 is counter untiluse
// v2 is what you need to use it
@ -1890,6 +1952,7 @@ enum FLAG {
F_DETECTOBS, // autodetect nearby obs in orthog dist v0
F_DRUNK, // v1 is drunknness - 1-5.
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
// if v1 is TRUE, also deal extra damage based on
// the flagpile's F_BONUS flag.
@ -1912,6 +1975,7 @@ enum FLAG {
F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks.
F_INVISIBLE, // lifeform is invisible
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
// (bypasses armour)
F_GRAVBOOSTED,// cannot walk or throw stuff
@ -2037,6 +2101,8 @@ enum HUNGER {
#define B_FALSE (0)
#define B_TRUE (-1)
#define B_DONTKILL (-1)
#define FALLTHRU (-8765)
//#define B_TEMP (-1)
@ -2164,6 +2230,8 @@ enum ERROR {
E_NOOB = 52,
E_LEVITATING = 53,
E_PRONE = 54,
E_PENTAGRAM = 55,
E_SWIMMING = 56,
};

View File

@ -1,6 +1,8 @@
@ = human
: = timid animal
} = gas cloud
{ = water
} = gas
^ = trap / dangerous thing
) = dancing weapon
A = avian / bird
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;
// notify
if ((gamemode == GM_GAMESTARTED)) {
if (f->pile->owner) {
@ -253,6 +252,7 @@ int flagcausesredraw(lifeform_t *lf, enum FLAG fid) {
case F_BLIND:
case F_DETECTLIFE:
case F_DETECTOBS:
case F_ENHANCESMELL:
case F_FASTMOVE:
case F_HIDING:
case F_INVISIBLE:
@ -289,6 +289,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) {
switch (fid) {
case F_ASLEEP:
case F_ATTRMOD:
case F_BLIND:
case F_EATING:
case F_FASTMOVE:
@ -415,6 +416,10 @@ void killflag(flag_t *f) {
int redostat = B_FALSE;
int redoscreen = B_FALSE;
if (f->id == F_SIZE) {
dblog("xxx");
}
lf = f->pile->owner;
if (gamemode == GM_GAMESTARTED) {
@ -534,6 +539,11 @@ void killflagpile(flagpile_t *fp) {
}
void timeeffectsflag(flag_t *f, int howlong) {
// special case:
if (f->id == F_TRAIL) {
return;
}
if ((f->lifetime != PERMENANT) && (f->lifetime > 0)) {
// special case - fast metabolism speeds up poison too.
if (f->id == F_POISONED) {

326
io.c
View File

@ -29,6 +29,8 @@ int statdirty = B_TRUE;
int hascolour = B_TRUE;
int noredraw = B_FALSE;
extern int needredraw;
extern int numdraws;
@ -291,15 +293,16 @@ void animradial(cell_t *src, int radius, char ch, int colour) {
gl.ch = ch;
gl.colour = colour;
// update screen
updateviewfor(src);
drawlevelfor(player);
// hide cursor
curs_set(0);
for (i = 0; i <= radius; i++) {
int drawn = B_FALSE;
// update screen
updateviewfor(src);
drawlevelfor(player);
for (y = src->y - radius ; y <= src->y + radius ; y++) {
for (x = src->x - radius ; x <= src->x + radius ; x++) {
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.colour = colour;
// update screen
updateviewfor(src);
drawlevelfor(player);
// hide cursor
curs_set(0);
for (i = 0; i <= radius; i++) {
int drawn = B_FALSE;
// update screen
updateviewfor(src);
drawlevelfor(player);
for (y = src->y - radius ; y <= src->y + radius ; y++) {
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;
}
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;
int finished = B_FALSE;
int moved = B_FALSE;
@ -531,6 +536,8 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange)
drawlevelfor(player);
if (moved) {
int inlof = B_TRUE, inrange = B_TRUE;
cell_t *trailtarg = NULL;
// show what we are over in msg bar
strcpy(buf, "");
if (haslos(player, c)) {
@ -739,21 +746,13 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange)
// if scanned, show it.
} else {
// otherwise, show objects
object_t *o;
// find top object name
o = gettopobject(c);
if (o) {
getobname(o, buf, o->amt);
}
gettopobname(c, buf);
}
}
} else {
object_t *o;
// find top object name
o = gettopobject(c);
if (o) {
getobname(o, buf, o->amt);
}
gettopobname(c, buf);
}
} else {
// 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);
if (srclf && (maxrange != UNLIMITED)) {
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);
mvwprintw(msgwin, 0, 0, "%s",buf);
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();
// remember this target
if (c->lf) {
if (c->lf && cansee(player, c->lf)) {
startlf = c->lf->id;
}
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
finished = B_TRUE;
} else if ((ch == '\'') && (ntargets > 0)) { // cycle targets
@ -984,6 +1035,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
}
donesomething = B_TRUE;
break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("%s can now breath underwater.",lfname);
donesomething = B_TRUE;
}
break;
case F_CANCAST:
if (isplayer(lf)) { // don't know if monsters get it
objecttype_t *ot;
@ -1139,6 +1196,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) {
}
donesomething = B_TRUE;
break;
case F_ENHANCESMELL:
if (isplayer(lf)) {
msg("Your sense of smell is enhanced!");
}
donesomething = B_TRUE;
break;
case F_DRUNK:
msg("%s %s tipsy.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
@ -1454,6 +1517,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
msg("%s can see again.",lfname);
donesomething = B_TRUE;
break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("%s can no longer breath underwater.",lfname);
donesomething = B_TRUE;
}
break;
case F_CANCAST:
if (isplayer(lf)) { // don't know if monsters lose it
objecttype_t *ot;
@ -1516,6 +1585,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) {
}
donesomething = B_TRUE;
break;
case F_ENHANCESMELL:
if (isplayer(lf)) {
msg("Your sense of smell is no longer enhanced.");
}
donesomething = B_TRUE;
break;
case F_DRUNK:
msg("%s %s more steady now.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
@ -2078,10 +2153,14 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int
ammo = getammo(op->owner);
}
if (countobs(op) <= 0) {
// no objects in pack
if (countobs(op, B_TRUE) <= 0) {
// no objects here
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
centre(mainwin, getmaxy(mainwin)-1, "[Press any key]");
getch();
@ -2115,11 +2194,15 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int
// can we include this object?
ok = B_TRUE;
// check for wanted flags
for (n = 0; n < nwantflags; n++) {
if (!hasflag(o->flags, wantflag[n])) {
ok = B_FALSE;
break;
if (!canseeob(player, o)) ok = B_FALSE;
if (ok) {
// check for wanted flags
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();
if (countobs(op) <= 0) {
if (countobs(op, B_FALSE) <= 0) {
// no objects in pack
cls();
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) {
if (o->type->obclass->id == sortorder[c]) {
int ok;
// can we include this object?
ok = obmatchescondition(o, opts);
if (!canseeob(player, o)) {
ok = B_FALSE;
} else {
ok = obmatchescondition(o, opts);
}
if (ok) {
mylist[i] = o;
@ -2550,7 +2638,12 @@ void updatestatus(void) {
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
if ((viewx == -9999) || (viewy == -9999)) {
// try to centre player
@ -2570,6 +2663,11 @@ void updateviewfor(cell_t *cell) {
while ((cell->y - viewy) <= (SCREENH/3)) {
viewy--;
}
if ((viewx != oldvx) || (viewy != oldvy)) {
return B_TRUE;
}
return B_FALSE;
}
@ -2968,6 +3066,9 @@ void describeob(object_t *o) {
case F_BLIND:
mvwprintw(mainwin, y, 0, "%s prevents you from seeing.", buf); y++;
break;
case F_BREATHWATER:
mvwprintw(mainwin, y, 0, "%s allows you to breath normally while underwater.", buf); y++;
break;
case F_CONTROL:
mvwprintw(mainwin, y, 0, "%s lets you control teleportation and polymorphic effects.", buf); y++;
break;
@ -2986,6 +3087,9 @@ void describeob(object_t *o) {
case F_ENHANCESEARCH:
mvwprintw(mainwin, y, 0, "%s enhances your searching ability.", buf); y++;
break;
case F_ENHANCESMELL:
mvwprintw(mainwin, y, 0, "%s enhances your sense of smell.", buf); y++;
break;
case F_DRUNK:
mvwprintw(mainwin, y, 0, "%s makes you tipsy.", buf); y++;
break;
@ -3375,7 +3479,7 @@ void docomms(void) {
char ch;
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)) {
lf = where->lf;
}
@ -3416,7 +3520,7 @@ void docomms(void) {
char lfname2[BUFLEN];
case 'a':
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)) {
lf2 = c->lf;
@ -3890,7 +3994,8 @@ void dolook(cell_t *where, int onpurpose) {
// (also count objects without this flag)
numobs = 0;
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;
f = hasflag(o->flags, F_THEREISHERE);
@ -3922,11 +4027,11 @@ void dolook(cell_t *where, int onpurpose) {
msg("You %s %s here.", seeverb, buf);
}
} 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)) {
msg("You %s some objects here.", seeverb);
msg("You %s some things here.", seeverb);
} else if (numobs > 6) {
msg("You %s many objects here.", seeverb);
msg("You %s many things here.", seeverb);
}
seensomething = B_TRUE;
}
@ -4253,29 +4358,49 @@ int dopickup(obpile_t *op) {
lifeform_t *fromlf = NULL;
char lfname[BUFLEN];
char buf[BUFLEN];
int needtoask = B_TRUE;
int failed = B_FALSE;
if (op->owner) {
fromlf = op->owner;
getlfname(fromlf, lfname);
}
obcount = countobs(op);
obcount = countobs(op, B_TRUE);
// anything here?
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) {
msg("%s is not carrying anything!", lfname);
} else {
msg("There is nothing here to pick up!");
}
return B_TRUE;
} else if (!fromlf && (obcount == 1) && (op->first->amt == 1)) {
// just get it
howmany = ALL;
retobs[0] = op->first;
retobscount[0] = op->first->amt;
nretobs = 1;
} else {
}
if (needtoask) {
if (fromlf) {
sprintf(buf, "Take what from %s",lfname);
} else {
@ -4329,33 +4454,9 @@ void doenter(lifeform_t *lf) {
}
void doexplain(char *question) {
char buf[BUFLEN];
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.");
askcoords(question, TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
restoregamewindows();
msg("Done.");
}
void dofinaloblist(obpile_t *op) {
@ -4715,7 +4816,7 @@ void doselguntarget(void) {
getobname(gun, gunname, 1);
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->lf && haslof(player->cell, where, LOF_NEED, NULL)) {
setguntarget(player, where->lf);
@ -4787,7 +4888,7 @@ void dothrow(obpile_t *op) {
// ask where to throw it
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) {
cell_t *newwhere = NULL;
@ -4942,6 +5043,10 @@ void drawlevelfor(lifeform_t *lf) {
int db = B_FALSE;
int w,h;
if (noredraw) {
return;
}
map = lf->cell->map;
needredraw = B_FALSE;
@ -4960,8 +5065,7 @@ void drawlevelfor(lifeform_t *lf) {
}
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
glyph_t glyph,screenglyph;
int needdraw = B_FALSE;
glyph_t glyph;
cell = getcellat(map, x + viewx, y + viewy);
if (cell) {
@ -4972,23 +5076,16 @@ void drawlevelfor(lifeform_t *lf) {
}
// only draw if screen char/colour is different
screenglyph.ch = mvwinch(gamewin, y, x) & A_CHARTEXT;
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) {
if (!screenglyphmatches(x, y, &glyph)) {
drawglyph(&glyph, x, y);
/*
if (db) {
dblog(" drawing char '%lc'/%d at %d,%d (screenglyph was '%lc'/%d)\n\n",
glyph.ch, glyph.ch,
x,y,
screenglyph.ch, screenglyph.ch);
}
*/
ndrawn++;
}
}
@ -5574,7 +5671,7 @@ void handleinput(void) {
// something here?
if (hasgettableobs) {
stoprunning(player);
} else if (!canmove(player, dir, NULL)) { // can't move anymore?
} else if (!moveclear(player, dir, NULL)) { // can't move anymore?
stoprunning(player);
} else {
if (trymove(player, dir, B_TRUE)) {
@ -6104,6 +6201,12 @@ void drawstatus(void) {
unsetcol(statwin, C_RED);
}
if (isswimming(player)) {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Swimming");
unsetcol(statwin, C_BOLDBLUE);
}
// paralysed somehow?
if (isresting(player)) {
setcol(statwin, C_CYAN);
@ -6448,6 +6551,17 @@ void redraw(void) {
wrefresh(gamewin);
}
void redrawpause(void) {
noredraw = B_TRUE;
}
void redrawresume(void) {
noredraw = B_FALSE;
if (needredraw) {
drawlevelfor(player);
}
}
void restoregamewindows(void) {
needredraw = B_TRUE;
statdirty = B_TRUE;
@ -6456,6 +6570,28 @@ void restoregamewindows(void) {
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) {
if (needsbold(col)) {
wattron(win, A_BOLD);
@ -7687,6 +7823,10 @@ void showlfstats(lifeform_t *lf, int showall) {
}
// 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)) {
mvwprintw(mainwin, y, 0, "%s %s a vegetarian.", you(lf), is(lf));
y++;
@ -7746,6 +7886,11 @@ void showlfstats(lifeform_t *lf, int showall) {
mvwprintw(mainwin, y, 0, buf);
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);
if (f) {
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");
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);
if (f) {
@ -8058,7 +8208,7 @@ void showlfstats(lifeform_t *lf, int showall) {
y = 2;
if (lfhasflag(lf, F_NOPACK)) {
mvwprintw(mainwin, y, 0, "It cannot carry anything.");
} else if (countobs(lf->pack)) {
} else if (countobs(lf->pack, B_FALSE)) {
char invtitle[BUFLEN];
float packweight,maxweight,pct;
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, ...);
int askobjectmulti(obpile_t *op, char *prompt, long opts);
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);
void centre(WINDOW *win, int y, char *format, ... );
int chartodir(char ch);
@ -95,7 +95,10 @@ int needsbold(enum COLOUR col);
void nothinghappens(void);
void dblog(char *format, ... );
void redraw(void);
void redrawpause(void);
void redrawresume(void);
void restoregamewindows(void);
int screenglyphmatches(int x, int y, glyph_t *g);
void setcol(WINDOW *win, enum COLOUR col);
void unsetcol(WINDOW *win, enum COLOUR col);
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 tombstone(lifeform_t *lf);
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);
raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill);
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 applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o);
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 cantakeoff(lifeform_t *lf, object_t *o);
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);
int countinnateattacks(lifeform_t *lf);
int countmoney(lifeform_t *lf);
@ -91,6 +93,7 @@ char *getbodypartname(enum BODYPART bp);
char *getbodypartequipname(enum BODYPART bp);
object_t *getequippedob(obpile_t *op, enum BODYPART bp);
object_t *getfirearm(lifeform_t *lf);
int getfootprinttime(lifeform_t *lf);
lifeform_t *getguntarget(lifeform_t *lf);
int getguntargetid(lifeform_t *lf);
//int gethealtime(lifeform_t *lf);
@ -160,6 +163,7 @@ char *getskilldesc(enum SKILL id );
char *getskillname(enum SKILL id );
char *getskilllevelname(enum SKILLLEVEL sl);
int getthrowspeed(int str);
void getwantdistance(lifeform_t *lf, int *min, int *max, int attacking);
object_t *getweapon(lifeform_t *lf);
long getxpforlev(int level);
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 ispeaceful(lifeform_t *lf);
int ispetof(lifeform_t *lf, lifeform_t *owner);
flag_t *ispetortarget(lifeform_t *lf, lifeform_t *ownertarget);
int isplayer(lifeform_t *lf);
flag_t *ispoisoned(lifeform_t *lf);
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 *isresting(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);
void killjob(job_t *job);
void killlf(lifeform_t *lf);

539
log.txt
View File

@ -2,364 +2,183 @@
====== NEW LOGFILE ====
givejob() starting.
xxx
xxx
xxx
xxx
lfid 175 (kobold) spending 20 time
lfid 180 (kobold) spending 20 time
xxx
xxx
lfid 181 (kobold) spending 20 time
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 175 (kobold) spending 20 time
xxx
lfid 180 (kobold) spending 20 time
fireat(): dam = throwdam(3) * speed(2)/2 = 3
lfid 181 (kobold) spending 20 time
fireat(): dam = throwdam(2) * speed(3)/2 = 2
xxx
xxx
xxx
lfid 195 (kobold) spending 20 time
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
lfid 175 (kobold) spending 20 time
xxx
lfid 178 (kobold) spending 20 time
xxx
lfid 180 (kobold) spending 20 time
fireat(): dam = throwdam(3) * speed(2)/2 = 3
xxx
lfid 181 (kobold) spending 20 time
xxx
xxx
xxx
lfid 195 (kobold) spending 20 time
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
lfid 175 (kobold) spending 20 time
xxx
lfid 178 (kobold) spending 20 time
xxx
xxx
xxx
lfid 195 (kobold) spending 15 time
xxx
xxx
lfid 198 (human) spending 20 time
lfid 170 (giant rat) spending 15 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 178 (kobold) spending 15 time
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
lfid 198 (human) spending 20 time
xxx
xxx
xxx
xxx
xxx
xxx
lfid 167 (xat) spending 20 time
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
lfid 198 (human) spending 20 time
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 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
rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +32%
rollhitdice() ---- die 1/1 == 3
TOTAL: 3
-> modified to: 3
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +0%
TOTAL: 1
-> modified to: 1
rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +54%
rollhitdice() ---- die 1/1 == 2
TOTAL: 2
-> modified to: 3
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +0%
TOTAL: 1
-> modified to: 1
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +44%
rollhitdice() ---- die 1/1 == 3
TOTAL: 3
-> modified to: 4
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +-16%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 4
rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +76%
rollhitdice() ---- die 1/1 == 1
TOTAL: 1
-> modified to: 1
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +10%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 4
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +76%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 7
rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +-27%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 3
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +22%
TOTAL: 1
-> modified to: 1
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +10%
TOTAL: 1
-> modified to: 1
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +0%
TOTAL: 1
-> modified to: 1
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +-5%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 4
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +88%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 7
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +-5%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 4
rollhitdice() for troglodyte - rolling 1d4 + 0
rollhitdice() - mod is +0%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 4
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +10%
rollhitdice() ---- die 1/1 == 1
TOTAL: 1
-> modified to: 1
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +0%
rollhitdice() ---- die 1/1 == 1
TOTAL: 1
-> modified to: 1
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +-11%
TOTAL: 1
-> modified to: 1
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +76%
rollhitdice() ---- die 1/1 == 3
TOTAL: 3
-> modified to: 5
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +32%
TOTAL: 1
-> modified to: 1
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +-11%
rollhitdice() ---- die 1/1 == 2
TOTAL: 2
-> modified to: 2
rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +66%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 6
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +76%
rollhitdice() ---- die 1/1 == 1
TOTAL: 1
-> modified to: 1
rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +32%
rollhitdice() ---- die 1/1 == 2
TOTAL: 2
-> modified to: 2
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +54%
TOTAL: 1
-> modified to: 1
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +54%
rollhitdice() ---- die 1/1 == 1
TOTAL: 1
-> modified to: 1
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +10%
rollhitdice() ---- die 1/1 == 3
TOTAL: 3
-> modified to: 3
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +0%
rollhitdice() ---- die 1/1 == 3
TOTAL: 3
-> modified to: 3
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +32%
rollhitdice() ---- die 1/1 == 3
TOTAL: 3
-> modified to: 3
rollhitdice() for giant rat - rolling 0d4 + 1
rollhitdice() - mod is +-16%
TOTAL: 1
-> modified to: 1
rollhitdice() for xat - rolling 1d4 + 0
rollhitdice() - mod is +22%
rollhitdice() ---- die 1/1 == 2
TOTAL: 2
-> modified to: 2
rollhitdice() for giant newt - rolling 1d4 + 0
rollhitdice() - mod is +66%
rollhitdice() ---- die 1/1 == 4
TOTAL: 4
-> modified to: 6
rollhitdice() for human - rolling 2d4 + 2
rollhitdice() - mod is +0%
rollhitdice() ---- die 1/2 == 6
rollhitdice() ---- die 2/2 == 4
TOTAL: 10
-> modified to: 10
rollhitdice() for young wolf - rolling 2d4 + 2
rollhitdice() - mod is +100%
rollhitdice() ---- die 1/2 == 4
rollhitdice() ---- die 2/2 == 4
TOTAL: 8
-> modified to: 16
xxx
rollhitdice() for kobold - rolling 1d4 + 0
rollhitdice() - mod is +44%
rollhitdice() ---- die 1/1 == 3
TOTAL: 3
-> modified to: 4
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;
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;
race_t *r;
int db = B_FALSE;
if (nadded) *nadded = 0;
// ie. don't create mosnters on closed doors!
if (!cellwalkable(NULL, c, NULL)) {
return NULL;
@ -133,13 +135,25 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
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 (db) dbtime("doing lf addition");
lf = addlf(c, r->id, getrandommonlevel(r, c->map));
if (db) dbtime("finished lf addition");
if (lf) {
flag_t *f;
if (nadded) (*nadded)++;
if (db) dbtime("checking for job");
lf->born = B_FALSE;
if (jobok) {
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?
if (db) dbtime("handling groups");
if (autogen) {
f = hasflag(lf->flags, F_NUMAPPEAR);
if (f) {
@ -188,7 +203,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
lifeform_t *newlf;
// find an adjacent cell to one of the newly added monsters,
// 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?
if (!adjcell) break;
@ -196,6 +211,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
if (!newlf) {
break;
}
if (nadded) (*nadded)++;
newlf->born = B_FALSE;
// 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?
// appears in groups?
if (db) dbtime("handling minions");
if (autogen) {
f = hasflag(lf->flags, F_MINIONS);
if (f) {
@ -229,7 +247,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto
lifeform_t *newlf;
race_t *newr;
adjcell = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND);
adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL);
if (!adjcell) break;
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));
if (!newlf) break;
if (nadded) (*nadded)++;
newlf->born = B_FALSE;
if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL);
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
// 'numappears' don't get them.
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
// kind of light producing device
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
}
if (db) dbtimeend("finished addmonster");
return lf;
}
@ -313,18 +337,21 @@ object_t *addrandomob(cell_t *c) {
return o;
}
int addrandomthing(cell_t *c, int obchance) {
int addrandomthing(cell_t *c, int obchance, int *nadded) {
int rv = TT_NONE;
// if there's already someone there,
// then add an object.
if (c->lf || (rnd(1,100) <= obchance)) {
object_t *o;
// object
if (addrandomob(c)) {
o = addrandomob(c);
if (o) {
if (nadded) *nadded = o->amt;
rv = TT_OBJECT;
}
} else {
// 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;
}
}
@ -486,7 +513,6 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
if (haslos(viewer, c)) {
// show cell contents
//drawcellwithcontents(cell, x-viewx, y-viewy);
if (c->lf && cansee(viewer, c->lf)) { // lifeform here which we can see
// draw the lf's race glyph
*g = *(getlfglyph(c->lf));
@ -506,7 +532,7 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
}
// objects here?
if ((countobs(c->obpile) > 0)) {
if ((countobs(c->obpile, B_FALSE) > 0)) {
object_t *o;
// draw highest object in sort order
@ -516,8 +542,6 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) {
*g = *(getglyph(o));
} else {
// 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;
if (!islit(c)) {
g->colour = C_BLUE;
@ -618,6 +642,7 @@ object_t *gettopobject(cell_t *where) {
flag_t *f;
// ignore hidden traps, but not secret doors
if (hasflag(o->flags, F_SECRET) && !isdoor(o, NULL)) {
} else if (hasflag(o->flags, F_TRAIL) && !canseeob(player, o)) {
} else {
f = hasflag(o->flags, F_IMPASSABLE);
if (f && (f->val[0] > largest)) {
@ -638,7 +663,9 @@ object_t *gettopobject(cell_t *where) {
// appear first.
for (o = where->obpile->last ; o ; o = o->prev) {
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;
}
}
@ -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++) {
// add up stairs
c = NULL;
while (!c || !isempty(c) || countobs(c->obpile)) {
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
}
o = addob(c->obpile, "staircase going up");
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;
while (!c || !isempty(c) || countobs(c->obpile)) {
while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) {
c = getrandomroomcell(map, ANYROOM);
}
o = addob(c->obpile, "staircase going down");
linkstairs(o);
}
// add pillars & objects & monsters to rooms
if (wantrooms && (numrooms > 0)) {
// add pillars & objects & monsters to rooms
for (i = 0; i < numrooms; i++) {
int numobsmin,numobsmax,numobs,n;
int maxpillars;
@ -1120,7 +1167,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
cell_t *c;
c = getrandomroomcell(map, i);
if (c && isempty(c) && !countobs(c->obpile)) {
if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) {
setcelltype(cell, CT_WALL);
}
}
@ -1154,8 +1201,9 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) {
while (!done) {
c = getrandomroomcell(map, i);
// if nothing there
if (c && isempty(c) && !countobs(c->obpile)) {
if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) {
int obchance;
int nadded = 0;
// limit # monster per room to 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;
}
if (addrandomthing(c,obchance) == TT_MONSTER) {
nmonsters++;
if (addrandomthing(c,obchance, &nadded) == TT_MONSTER) {
nmonsters += nadded;
}
done = B_TRUE;
} 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) {
map_t *othermap;
othermap = findregionmap(map->region, i);
// TODO: set upmap/downmap for use later on.
if (othermap) {
if (i == (depth-1)) {
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 (x = 0; x < map->w; x++) {
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
for (y = 0; y < map->h; y++) {
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);
if (c && isempty(c)) {
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 *bestcell = NULL;
int closest = 999;
// oooooo TODO handle side being diagonal
switch (side) {
case D_N:
x = 0;
@ -2120,10 +2173,10 @@ int getthingchance(int habitat) {
}
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 x,y;
cell_t *poss[MAXCANDIDATES];
@ -2139,7 +2192,7 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum OB
if (new &&
(new != c) &&
(getcelldist(c,new) == radius) &&
haslof(c, new, LOF_WALLSTOP, NULL)) {
haslof(c, new, needlof, NULL)) {
enum OBTYPE *badoid;
int ok = B_FALSE;
numwithlof++;
@ -2159,7 +2212,8 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum OB
}
}
} 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;
}
} else {
@ -2372,13 +2426,33 @@ int hasobject(cell_t *c) {
int hasknownobject(cell_t *c) {
object_t *o;
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_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) {
if (getcelldist(src, dst) == 1) {
return B_TRUE;

7
map.h
View File

@ -3,9 +3,9 @@
cell_t *addcell(map_t *map, int x, int y);
void addhomeobs(lifeform_t *lf);
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);
int addrandomthing(cell_t *c, int obchance);
int addrandomthing(cell_t *c, int obchance, int *nadded);
int cellhaslos(cell_t *c1, cell_t *dest);
cell_t *getcellat(map_t *map, int x, int y);
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 getthingchance(int habitat);
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 *getrandomcelloftype(map_t *map, int id);
int getrandomdir(int dirtype);
@ -55,6 +55,7 @@ object_t *hasenterableobject(cell_t *c);
lifeform_t *haslf(cell_t *c);
int hasknownobject(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 isdark(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) {
if (isplayer(lf)) {
if (canmove(lf, dir, error)) {
if (ispossiblemove(lf, dir)) {
return B_TRUE;
}
} else {
if (canmove(lf, dir, error) && willmove(lf, dir, error)) {
if (ispossiblemove(lf, dir) && willmove(lf, dir, error)) {
return B_TRUE;
}
}
return B_FALSE;
}
int canmove(lifeform_t *lf, int dir, enum ERROR *error) {
cell_t *cell;
flag_t *f;
// default
if (error) {
*error = E_OK;
rdata = NULL;
int isorthogonal(int dir) {
switch (dir) {
case D_N:
case D_E:
case D_S:
case D_W:
case DC_N:
case DC_E:
case DC_S:
case DC_W:
return B_TRUE;
}
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);
return B_FALSE;
}
// 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
int canswapwith(lifeform_t *lf, lifeform_t *lf2) {
@ -96,6 +95,12 @@ int canswapwith(lifeform_t *lf, lifeform_t *lf2) {
if (isplayer(lf2)) {
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
if (celldangerous(lf2, lf->cell, B_FALSE, NULL)) {
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
if (!onlyifknown || (haslos(lf, cell) && !lfhasflag(lf, F_UNDEAD))) {
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);
if (f) {
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,
// so that we are able to attack monsters embedded in walls.
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;
return B_FALSE;
}
@ -345,6 +368,12 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d
int nposs;
enum ERROR error;
if (dirtype == DT_ORTH) {
maxdist = getcelldistorth(src, dst);
} else {
maxdist = getcelldist(src, dst);
}
for (d = DC_N; d <= DC_NW; d++) {
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;
enum ERROR error;
if (dirtype == DT_ORTH) {
mindist = getcelldistorth(src, dst);
} else {
mindist = getcelldist(src, dst);
}
for (d = DC_N; d <= DC_NW; d++) {
dist[d - DC_N] = -1;
}
for (d = DC_N; d <= DC_NW; d++) {
int ok = B_FALSE;
int thisdist;
c = getcellindir(src, d);
if (!c) continue;
@ -465,16 +501,20 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, in
ok = B_TRUE;
}
}
// get distance
if (ok) {
int thisdist;
if (dirtype == DT_ORTH) {
thisdist = getcelldistorth(c, dst);
} else {
thisdist = getcelldist(c, dst);
}
dist[d - DC_N] = thisdist;
if (thisdist < mindist) {
dist[d - DC_N] = thisdist;
mindist = thisdist;
} else {
dist[d - DC_N] = -1;
}
} else {
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++) {
if (canmove(lf, dir, &reason)) {
if (moveclear(lf, dir, &reason)) {
if ((i == 0) && seen) {
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
mightfall = B_FALSE;
break;
case E_SWIMMING:
case E_LFINWAY:
newcell = getcellindir(lf->cell, dir);
newlf = newcell->lf;
@ -619,6 +660,62 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype ) {
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!
// particularly don't remove flags...
@ -673,6 +770,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
int changedlev = B_FALSE;
int preroom = -1, postroom = -1;
int prespeed = B_FALSE, postspeed = B_FALSE;
int prewater = B_FALSE;
assert(newcell);
@ -689,8 +787,14 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
// update current cell + room id
prespeed = getmovespeed(lf);
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 (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
if (!isairborne(lf)) {
for (o = newcell->obpile->first ; o ; o = nexto ) {
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);
if (f && hasbp(lf, BP_FEET)) {
object_t *boots;
@ -994,7 +1127,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
// see objects on ground
if (isplayer(lf)) {
int numobs;
numobs = countnoncosmeticobs(newcell->obpile);
numobs = countnoncosmeticobs(newcell->obpile, B_TRUE);
if ((numobs == 0) && !newcell->writing) {
// just clear the message buffer
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,
// webs, etc.
// cell can be null if you're using stairs.
// return true if something happened
int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) {
object_t *o, *nexto;
char buf[BUFLEN];
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
if (lfhasflag(lf, F_GRAVBOOSTED)) {
@ -1544,6 +1692,11 @@ void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int onpurpose) {
// move them...
lf2->cell = cell1;
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
@ -1585,7 +1738,7 @@ int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke) {
// show any objects here, just like if we moved.
// BUT don't let dolook() clear the msg bar if there are
// no objects here.
if (isplayer(lf) && countnoncosmeticobs(lf->cell->obpile)) {
if (isplayer(lf) && countnoncosmeticobs(lf->cell->obpile, B_TRUE)) {
dolook(lf->cell, B_FALSE);
}
return B_FALSE;
@ -1598,6 +1751,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
char buf[BUFLEN];
int dontclearmsg = B_FALSE;
int moveok;
int drunk = B_FALSE;
flag_t *f;
f = isdrunk(lf);
@ -1606,19 +1760,36 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
if (rnd(1,6) <= ((f->lifetime/DRUNKTIME)+1)) {
// randomize move
dir = rnd(DC_N, DC_NW);
drunk = B_TRUE; // ie. you can walk into walls now.
}
}
}
cell = getcellindir(lf->cell, dir);
moveok = B_FALSE;
if (onpurpose) {
if (canandwillmove(lf, dir, &errcode)) {
moveok = B_TRUE;
if (celldangerous(lf, cell, B_TRUE, &errcode)) {
if ((errcode == E_AVOIDOB) && rdata) {
char obname[BUFLEN];
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;
}
}
@ -1627,27 +1798,36 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
lifeform_t *alf;
if (initiatemove(lf, cell, &dontclearmsg)) {
// failed?
return B_FALSE;
return B_TRUE;
}
// move to new cell
reason = E_OK;
// remember last dir we walked
killflagsofid(lf->flags, F_LASTDIR);
addflag(lf->flags, F_LASTDIR, dir, NA, NA, NULL);
// add footprints in our current cell.
addtrail(lf, dir);
// do your pets see you move?
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {
lifeform_t *l;
for (l = lf->cell->map->lf ; l ; l = l->next) {
if (ispetof(l,lf) && cansee(l, lf)) {
killflagsofid(l->flags, F_OWNERLASTDIR);
addflag(l->flags, F_OWNERLASTDIR, dir, NA, NA, NULL);
if (cansee(l, lf)) {
flag_t *tf;
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) {
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);
// do a manual canmove check here first, to avoid 'the stirge flies into a wall'
// 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);
}
@ -1675,11 +1855,11 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
reason = errcode;
switch (errcode) {
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
walkoffmap(lf, dir, B_TRUE);
}
break;
return walkoffmap(lf, dir, B_TRUE);
}
// otherwise fall through...
case E_WALLINWAY:
if (isplayer(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);
} else {
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));
losehp(lf, 1, DT_BASH, NULL, buf);
if (onpurpose) taketime(lf, getmovespeed(lf));
@ -1777,6 +1957,11 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
}
}
break;
case E_SWIMMING:
if (isplayer(lf)) {
msg("You can't attack while swimming!");
}
break;
case E_LFINWAY:
if (canswapwith(lf, cell->lf)) {
lifeform_t *lfinway;
@ -1828,6 +2013,12 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) {
}
if (onpurpose) taketime(lf, getmovespeed(lf));
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:
if (isplayer(lf)) {
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);
if (celldangerous(lf, cell, B_TRUE, error)) {
if (cell && celldangerous(lf, cell, B_TRUE, error)) {
if (error) *error = E_WONT;
return B_FALSE;
}
// 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 (hasactivespell(cell->lf, OT_S_REPELINSECTS)) {
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).
for (o = cell->obpile->first ; o ; o = o->next) {
flag_t *f;
sprintf(buf, "%ld",o->id);
f = lfhasflagval(lf, F_AVOIDCURSEDOB, NA, NA, NA, buf);
if (f) {
// still cursed?
if (iscursed(o)) {
if (error) *error = E_WONT;
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 (cell) {
for (o = cell->obpile->first ; o ; o = o->next) {
flag_t *f;
sprintf(buf, "%ld",o->id);
f = lfhasflagval(lf, F_AVOIDCURSEDOB, NA, NA, NA, buf);
if (f) {
// still cursed?
if (iscursed(o)) {
if (error) *error = E_WONT;
return B_FALSE;
} else {
// remove the flag.
killflag(f);
}
} else {
// non-hidden traps?
if (iq >= IQ_AVERAGE) {
if (error) *error = E_WONT;
return B_FALSE;
}
if (hasflag(o->flags, F_TRAP)) {
if (hasflag(o->flags, F_SECRET)) {
// 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"
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 celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, 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 knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff);
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 movelf(lifeform_t *lf, cell_t *newcell);
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 pullnextto(lifeform_t *lf, cell_t *c);
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);
int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke);
int trymove(lifeform_t *lf, int dir, int onpurpose);

43
nexus.c
View File

@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include "ai.h"
@ -34,6 +35,9 @@ hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL;
glyph_t playerglyph,tempglyph;
double startticks,lastticks;
struct timeval starttv, tv,newtv;
// maintains unique lifeform ID numbers
long nextlfid = 0;
@ -58,6 +62,8 @@ void *rdata; // globel for returning data
lifeform_t *player = NULL;
int gameover;
int obdb = B_FALSE;
enum GAMEMODE gamemode = GM_FIRST;
long curtime = 0;
@ -171,7 +177,9 @@ int main(int argc, char **argv) {
if (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'
user = getenv("USER");
@ -464,6 +472,27 @@ void cleanup(void) {
// 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) {
if (d < 0) {
*xinc = xinc1;
@ -953,7 +982,7 @@ int rollhitdice(lifeform_t *lf) {
int roll = 0;
int i;
float mod;
int db = B_FALSE;
int db = B_TRUE;
f = hasflag(lf->flags, F_HITDICE);
if (f) {
@ -964,11 +993,11 @@ int rollhitdice(lifeform_t *lf) {
ndice = 1;
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);
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) {
int thisroll;
@ -983,14 +1012,14 @@ int rollhitdice(lifeform_t *lf) {
int thisroll;
thisroll = rolldie(1, 4) + plus;
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;
}
}
if (db && isplayer(lf)) dblog("TOTAL: %d",roll);
if (db) dblog("TOTAL: %d",roll);
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;
}

View File

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

528
objects.c
View File

@ -44,6 +44,8 @@ extern int reason;
extern int needredraw;
extern int statdirty;
extern int obdb;
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',
@ -658,6 +660,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack) {
// inherit flags from objecttype
copyflags(o->flags, ot->flags, NA);
// don't want certain objecttype only flags...
killflagsofid(o->flags, F_RARITY);
// random flags...
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;
redrawpause();
if (dirtype == DT_ORTH) {
distfunc = getcelldistorth;
} else {
@ -1168,6 +1174,7 @@ int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fr
}
}
redrawresume();
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?
if (isimmuneto(o->flags, damtype)) {
*dam = 0;
@ -1750,6 +1762,54 @@ int canbepoisoned(enum OBTYPE oid) {
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
// stack "match" with
object_t *canstackob(obpile_t *op, object_t *match) {
@ -1929,23 +1989,35 @@ int countnames(char **list) {
return count;
}
int countobs(obpile_t *op) {
int countobs(obpile_t *op, int onlyifknown) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
count++;
if (onlyifknown) {
if (canseeob(player, o)) {
count++;
}
} else {
count++;
}
}
return count;
}
int countnoncosmeticobs(obpile_t *op) {
int countnoncosmeticobs(obpile_t *op, int onlyifknown) {
object_t *o;
int count = 0;
for (o = op->first ; o ; o = o->next) {
if (!hasflag(o->flags, F_COSMETIC) && !hasflag(o->flags, F_SECRET)) {
count++;
if (onlyifknown) {
if (canseeob(player, o)) {
count++;
}
} else {
count++;
}
}
}
return count;
@ -1993,11 +2065,17 @@ int curseob(object_t *o) {
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;
for (o = op->first ; o ; o = nexto) {
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);
}
}
@ -3023,6 +3101,22 @@ int getnutrition(object_t *o) {
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) {
if (isknown(o)) {
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;
}
if (showall) {
strcpy(basename,o->type->name);
f = hasflag(o->flags, F_TRAIL);
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 {
strcpy(basename,gethiddenname(o));
if (showall) {
strcpy(basename,o->type->name);
} else {
strcpy(basename,gethiddenname(o));
}
}
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, "");
// figure out pluralname
if ((count == 1) && !hasflag(o->flags, F_NO_A)) {
if (count == 1) {
pluralname = strdup(basename);
} else {
// multiple objects?
@ -3399,7 +3571,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
int bonus;
bonus = f->val[0];
if (bonus != 0) {
sprintf(buf2, "%s%d ", (bonus < 0) ? "" : "+", bonus);
sprintf(buf2, "%s%d ", (bonus < 0) ? "-" : "+", abs(bonus));
strcat(localbuf, buf2);
}
}
@ -3513,23 +3685,32 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan
}
// apply prefix now!
if ((count == 1) && !hasflag(o->flags, F_NO_A)) {
if (hasflag(o->flags, F_UNIQUE)) { // TODO: && o->identified
strcpy(prefix, "The");
} else {
if (needan(localbuf)) {
strcpy(prefix, "an");
if (count == 1) {
if (hasflag(o->flags, F_NO_A)) {
if (o->type->id == OT_GOLD) {
sprintf(prefix, "%d ",count);
} 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 {
// multiple objects?
sprintf(prefix, "%d",count);
sprintf(prefix, "%d ",count);
}
// prepend prefix on to buf
sprintf(buf, "%s %s", prefix, localbuf);
sprintf(buf, "%s%s", prefix, localbuf);
return buf;
}
@ -3688,8 +3869,10 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth
flag_t *omposs[MAXCANDIDATES];
int noms = 0;
db = obdb;
if (forcedepth != NA) {
//if (forcedepth != NA) {
if (forcedepth >= 0) {
depth = forcedepth;
} else {
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 (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;
nposs++;
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) {
//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);
}
@ -4060,6 +4244,25 @@ int getthrowdam(object_t *o) {
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 weildloc;
if (o) {
@ -4570,7 +4773,7 @@ void initobjects(void) {
addflag(lastot->flags, F_DOOR, B_TRUE, 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_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_DAMAGABLE, 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_IMPASSABLE, SZ_MAX, 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_DAMAGABLE, 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_PUSHABLE, 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_NOBLESS, 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_IMPASSABLE, SZ_LARGE, 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_DAMAGABLE, B_TRUE, NA, 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_IMPASSABLE, SZ_LARGE, 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_DAMAGABLE, B_TRUE, NA, 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);
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_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);
addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, NA, NA, "&");
addflag(lastot->flags, F_CLIMBABLE, D_IN, NA, NA, NULL);
addflag(lastot->flags, F_NOPICKUP, 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
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);
@ -4805,7 +5048,7 @@ void initobjects(void) {
addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_LARGE, 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_DAMAGABLE, B_TRUE, NA, 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_SPELLLEVEL, 3, 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
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_SPELLLEVEL, 4, 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);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, 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_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);
addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, 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_SPELLLEVEL, 5, 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
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);
@ -5457,6 +5704,7 @@ void initobjects(void) {
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_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);
addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, 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_SPELLLEVEL, 4, 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
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_SPELLLEVEL, 5, 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
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);
@ -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);
addflag(lastot->flags, F_STACKABLE, NA, 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_DIECONVERT, NA, NA, NA, "large puddle of water");
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);
addflag(lastot->flags, F_STACKABLE, 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_NOPICKUP, B_TRUE, NA, NA, NULL);
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);
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_NOBLESS, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ",");
addflag(lastot->flags, F_STACKABLE, 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_RARITY, H_DUNGEON, 75, NA, NULL);
addflag(lastot->flags, F_RARITY, H_FOREST, 90, 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);
addflag(lastot->flags, F_STACKABLE, 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_FOREST, 90, 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);
addflag(lastot->flags, F_STACKABLE, 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_FOREST, 85, 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_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+2");
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_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_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
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_DIECONVERT, NA, NA, NA, "medium fire");
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_THEREISHERE, B_TRUE, NA, NA, "!");
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_DIECONVERTTEXT, NA, NA, NA, "dies down a little");
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_THEREISHERE, B_TRUE, NA, NA, "!");
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_OBHP, 3, 3, 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, "!");
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_DIECONVERT, NA, NA, NA, "puff of steam");
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, "!");
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_OBHP, 2, 2, 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);
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_OBHP, 10, 10, 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_BLOCKSVIEW, 3, 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_WALKDAMBP, BP_HEAD, 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");
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_OBHP, 4, 4, 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, "!");
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_DIECONVERT, NA, NA, NA, "puff of smoke");
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);
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_OBHP, 2, 2, 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);
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_DIECONVERT, NA, NA, NA, "puff of gas");
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);
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_OBHP, 2, 2, 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, "!");
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_OBHP, 10, 10, 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);
addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "#");
addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL);
addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL);
addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL);
addflag(lastot->flags, F_BLOCKSLOF, 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_PRODUCESLIGHT, 1, NA, NA, NULL);
@ -7292,6 +7560,7 @@ void initobjects(void) {
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_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_USESSKILL, SK_NONE, 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;
}
}
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;
}
@ -9088,7 +9362,7 @@ void obdie(object_t *o) {
}
int obfits(object_t *o, obpile_t *op) {
if (countobs(op) >= MAXPILEOBS) {
if (countobs(op, B_FALSE) >= MAXPILEOBS) {
return B_FALSE;
}
return B_TRUE;
@ -9279,10 +9553,10 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) {
if (isplayer(lf)) {
if (strlen(f->text) > 0) {
where = askcoords(f->text, ttype, lf, UNLIMITED);
where = askcoords(f->text, ttype, lf, UNLIMITED, LOF_NEED, B_TRUE);
} else {
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)) {
// exception - wand of digging doesn't need los
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
willid = B_TRUE;
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)) {
msg("A swarm of butterflies appears!");
}
@ -10147,6 +10421,8 @@ void quaff(lifeform_t *lf, object_t *o) {
int playercansee;
int forcedrop = B_FALSE;
int seen;
int killobwhendone = B_TRUE;
flag_t *drinkflag;
getobname(o, obname, 1);
@ -10210,14 +10486,21 @@ void quaff(lifeform_t *lf, object_t *o) {
if (o->type->obclass->id == OC_POTION) {
potioneffects(lf, o->type->id, o->blessed, &seen);
} else if (hasflag(o->flags, F_DRINKABLE)) {
// drinkable thing which isn't a potion?
flag_t *f;
f = hasflag(o->flags, F_LINKOB);
if (f) {
potioneffects(lf, f->val[0], o->blessed, NULL);
} else {
eat(lf, o);
} else {
drinkflag= hasflag(o->flags, F_DRINKABLE);
if (drinkflag) {
// drinkable thing which isn't a potion?
flag_t *f;
f = hasflag(o->flags, F_LINKOB);
if (f) {
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
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)) {
object_t *newob;
newob = addob(c->obpile, "magical barrier");
addflag(newob->flags, F_OBHP, i, i, NA, NULL);
if (first && haslos(player, c)) {
msg("A magical barrier appears!");
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;
@ -11056,7 +11346,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) {
capitalise(obcaps);
obcaps = strrep(obcaps, "An ", "The ", NULL);
obcaps = strrep(obcaps, "A ", "The ", NULL);
msg("%s shatters!",obcaps);
msg("%s shatter%s!",obcaps, (o->amt == 1) ? "s" : "");
free(obcaps);
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?
f = hasflagval(o->flags, F_DTCONVERT, damtype, NA, NA, NULL);
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);
// effects which have to happen before damage is applied...
// explodes?
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!
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) {
// object was just damaged
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);
} else {
// 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;
@ -11977,24 +12296,42 @@ void timeeffectsob(object_t *o) {
flag_t *f, *nextf;
cell_t *location;
lifeform_t *owner;
char obname[BUFLEN];
object_t *sg;
char obname[BUFLEN],ownername[BUFLEN];
if (hasflag(o->flags, F_DEAD)) return;
getobname(o, obname, o->amt);
location = getoblocation(o);
/*
if (o->pile->where) {
location = o->pile->where;
} else {
location = NULL;
}
*/
if (o->pile->owner) {
owner = o->pile->owner;
getlfname(owner, ownername);
} else {
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
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) {
// does object's material change cell type?
if (o->material->id == MT_FIRE) {
@ -12331,7 +12717,9 @@ void timeeffectsob(object_t *o) {
object_t *splash;
ourcell = getoblocation(o);
// 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);
void brightflash(cell_t *centre, int range, lifeform_t *immunelf);
int canbepoisoned(enum OBTYPE oid);
int canseeob(lifeform_t *lf, object_t *o);
object_t *canstackob(obpile_t *op, object_t *match);
object_t *canstacknewot(obpile_t *op, objecttype_t *match);
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 copyobprops(object_t *dst, object_t *src);
int countnames(char **list);
int countobs(obpile_t *op);
int countnoncosmeticobs(obpile_t *op);
int countobs(obpile_t *op, int onlyifknown);
int countnoncosmeticobs(obpile_t *op, int onlyifknown);
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 explodeob(object_t *o, flag_t *f, int bigness);
void extinguish(object_t *o);
@ -80,6 +81,7 @@ char getnextletter(obpile_t *op, char *wantletter);
int getnumshards(object_t *o);
int getnutritionbase(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 *getobequipinfo(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);
enum SKILLLEVEL gettechlevel(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);
int hasedibleob(obpile_t *op);
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)) {
sprintf(buf, "Charge who (max range %d)?",range);
// TODO: ask for direction
targcell = askcoords(buf, TT_MONSTER, user, range);
targcell = askcoords(buf, TT_MONSTER, user, range, LOF_NEED, B_TRUE);
if (!targcell) {
msg("Cancelled.");
return TRUE;
@ -254,7 +254,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
} else {
sprintf(buf, "Darkwalk to where?");
}
targcell = askcoords(buf, TT_NONE, user, range);
targcell = askcoords(buf, TT_NONE, user, range, LOF_DONTNEED, B_FALSE);
} else {
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)?");
while (!targcell) {
// ask where
targcell = askcoords(buf, TT_NONE, user, 2);
targcell = askcoords(buf, TT_NONE, user, 2, LOF_DONTNEED, B_TRUE);
if (!targcell) {
return B_TRUE;
} 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)) {
sprintf(buf, "Swoop who (max range %d)?",srange);
// TODO: ask for direction
targcell = askcoords(buf, TT_MONSTER, user, srange);
targcell = askcoords(buf, TT_MONSTER, user, srange, LOF_NEED, B_TRUE);
if (!targcell) {
msg("Cancelled.");
return TRUE;
@ -935,13 +935,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
return B_FALSE;
} else if (abilid == OT_A_DEBUG) {
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) {
debug(where->lf);
}
} else if (abilid == OT_A_EMPLOY) {
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) {
char question[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) {
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) {
char ch;
enum ATTRIB att;
@ -1483,7 +1483,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_BLINDNESS) {
int failed = B_FALSE;
// 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)) {
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
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!
for (i = 1; i < nretcell; i++) {
cell_t *c;
@ -1558,24 +1560,31 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (o) {
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)) {
needredraw = B_TRUE;
}
} else if (spellid == OT_S_CALLLIGHTNING) {
int failed = B_FALSE;
// ask for a target cell
@ -1617,13 +1626,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (targcell->obpile->first) {
// select object from cell...
if (countobs(targcell->obpile) == 1) {
targob = targcell->obpile->first;
} else {
targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
if (!targob) {
failed = B_TRUE;
}
targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
if (!targob) {
failed = B_TRUE;
}
} else {
failed = B_TRUE;
@ -2045,7 +2050,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
// add the monster
newlf = addmonster(targcell, r->id, randomjobsok, 1, B_FALSE);
newlf = addmonster(targcell, r->id, randomjobsok, 1, B_FALSE, NULL);
if (newlf) {
// assign job if required
if (forcejob) {
@ -2152,9 +2157,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else if (spellid == OT_S_DIG) {
int numseen = 0;
int maxrange;
cell_t *retcell[MAXRETCELLS];
int nretcell,i;
int ndigs;
// don't need line of fire OR sight!
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,
targcell->x, targcell->y, retcell, &nretcell);
maxrange = power;
ndigs = 0;
// 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) {
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 if any seen
// announce destruction of any walls seen
if (numseen) {
msg("The wall%s crumble%s to dust!",
(numseen == 1) ? "" : "s",
(numseen == 1) ? "s" : ""
);
if (seenbyplayer) *seenbyplayer = B_TRUE;
} else {
} else if (ndigs == 0) {
if (isplayer(caster)) nothinghappens();
}
} 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;
int donesomething = B_FALSE;
if (!validatespellcell(caster, &targcell,TT_MONSTER|TT_OBJECT, spellid, power)) return B_TRUE;
if (!targcell) {
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);
return B_TRUE;
}
@ -2494,7 +2515,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else if (spellid == OT_S_FEEBLEMIND) {
// 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 (cansee(player, target)) {
@ -2588,6 +2610,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
anim(caster->cell, targcell, '^', C_RED);
redrawpause();
// add fires as follows (3 = medium, 2 = medium, 1 = smell)
//
// 1
@ -2642,6 +2665,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
}
redrawresume();
} else {
failed = B_TRUE;
@ -3529,21 +3554,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
}
} else if (spellid == OT_S_MINDSCAN) {
cell_t *where;
int failed = B_FALSE;
if (isplayer(caster)) {
// ask for a target cell
sprintf(buf, "Whose mind will you scan?");
where = askcoords(buf, TT_MONSTER, caster, UNLIMITED);
if (where && haslos(caster, where) && haslf(where)) {
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE;
if (targcell && haslos(caster, targcell) && haslf(targcell)) {
char targname[BUFLEN];
lifeform_t *oldplayer;
// temporarily change player pointer...
oldplayer = player;
player = where->lf;
player = targcell->lf;
//
getlfname(where->lf, targname);
getlfname(targcell->lf, targname);
sprintf(buf, "Mindscanning %s, ESC to quit.", targname);
doexplain(buf);
@ -3585,7 +3608,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_PARALYZE) {
int howlong;
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)) {
fizzle(caster);
@ -3619,7 +3643,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else if (spellid == OT_S_PAIN) {
int failed = B_FALSE;
// 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)) {
fizzle(caster);
@ -3654,7 +3679,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
fizzle(caster);
}
} 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
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
targob = NULL;
// select object from cell...
if (countobs(targcell->obpile) == 1) {
targob = targcell->obpile->first;
} else {
targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
}
targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE);
if (targob) {
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);
knockback(target, dir, 2, caster, 0);
} else {
o = hasobwithflag(targcell->obpile, F_DOOR);
if (o) {
int dooropen;
isdoor(o, &dooropen); // just check whether it's open, we know it's a door
if (dooropen) {
fizzle(caster);
} else {
if (haslos(player, targcell)) {
getobname(o, buf, o->amt);
msg("%s %s!",isplayer(caster) ? "You blast" : "Something blasts", buf);
int donesomething = B_FALSE;
object_t *nexto;
for (o = targcell->obpile->first ; o ; o = nexto) {
nexto = o->next;
if (hasflag(o->flags, F_IMPASSABLE)) {
int gotit = B_FALSE;
int dooropen;
if (isdoor(o, &dooropen)) {
if (!dooropen) {
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);
}
}
} else if (spellid == OT_S_LEVITATION) {
flag_t *f;
@ -4190,7 +4226,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
}
// undead will flee from light
if (lfhasflag(l, F_UNDEAD)) {
if (isundead(l)) {
// runs away from caster
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++) {
target = caster->los[i]->lf;
if (target) {
if (target && areenemies(caster, 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) {
// ask for target
if (!target) {
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 (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE;
if (target) {
int howlong = 15;
@ -4615,7 +4640,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
int donesomething = B_FALSE;
// stop targetting anybody
if (killflagsofid(target->flags, F_TARGET)) {
if (killflagsofid(target->flags, F_TARGETLF)) {
donesomething = B_TRUE;
}
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) {
race_t *r = NULL;
// ask for target if required
if (!target && isplayer(caster)) {
cell_t *where;
where = askcoords("Who will you polymorph?", TT_MONSTER, caster, UNLIMITED);
if (haslos(caster, where)) {
target = where->lf;
} else {
target = NULL;
}
}
if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE;
target = targcell->lf;
if (!target) {
fizzle(caster);
@ -4968,7 +4985,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
f->obfrom = spellid;
} else if (spellid == OT_S_SLEEP) {
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)) {
fizzle(caster);
@ -5023,7 +5041,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
}
} else if (spellid == OT_S_SLOW) {
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 (isplayer(target)) {
@ -5064,7 +5083,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
badoid[0] = OT_MUDPOOL;
badoid[1] = OT_NONE;
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) {
o = addob(c->obpile, "pool of mud");
if (o) {
@ -5296,7 +5315,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
sprintf(buf, "Where will you teleport to?");
while (!c) {
int ch;
c = askcoords(buf, TT_NONE, caster, UNLIMITED);
c = askcoords(buf, TT_NONE, caster, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (!c->known) {
// confirm
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) {
// ask for a target cell (to take objects from)
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->obpile->first) {
// select object from cell...
if (countobs(where->obpile) == 1) {
targob = where->obpile->first;
} else {
targob = askobject(where->obpile, "Target which object", NULL, AO_NONE);
if (!targob) {
failed = B_TRUE;
}
targob = askobject(where->obpile, "Target which object", NULL, AO_NONE);
if (!targob) {
failed = B_TRUE;
}
// TODO: check object weight!
} else {
@ -5489,7 +5504,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
char obname[BUFLEN];
getobname(targob, obname, 1);
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?
@ -5554,7 +5570,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
for (i = 0; i < caster->nlos; i++) {
targcell = caster->los[i];
target = targcell->lf;
if (target && hasflag(target->flags, F_UNDEAD)) {
if (target && isundead(target)) {
int howlong = 10;
int worked = B_TRUE;
// 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) {
// 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 (cansee(player, target)) {
@ -5969,7 +5986,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
if (seenbyplayer) *seenbyplayer = B_TRUE;
// ask for target
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 {
target = caster;
}
@ -6406,6 +6424,9 @@ int getspellrange(enum OBTYPE spellid, int power) {
case OT_S_CALLWIND:
range = (power*2);
break;
case OT_S_DIG:
range = power;
break;
case OT_S_LIGHTNINGBOLT:
range = (power*3);
break;
@ -6612,7 +6633,7 @@ int summonlfs(lifeform_t *caster, enum RACECLASS wantrc, enum LFSIZE wantsize, i
r = findrace(poss[rnd(0,nposs-1)]);
if (r) {
// 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
killflagsofid(newlf->flags, F_XPVAL);
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;
}
// ask for a target lifeform
if (isplayer(user)) {
cell_t *where;
char buf[BUFLEN];
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 (!haslf(where)) {
msg("There is nobody there!");
@ -6781,7 +6801,7 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, e
} else {
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) {
int ch;
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) {
if (!caster) {
return *target;
@ -6888,3 +6909,4 @@ lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **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);
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);
lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);
//lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **lf);
#endif