- [+] don't show 'the xxx look exhausted' for monsters

- [+] The giant blowfly (null).
- [+] instant disrobe spell - tleports armour to the side
- [+] why did a monk recognise a grenade? bug in conferobjectflags.
- [+] adept nature lore should identify bad mushrooms too
- [+] draining/vampiric brand - gives hp to user.  
- [+] ways to check stairs before travelling
    - [+] make getstairdestination() be the place where new maps are
          generated
    - [+] move getnoisedetails into new function
    - [+] ability to listen down stairs with adept listen skill
        - [+] atomatically trigger walknoise for all lfs within los of
              stairs, and you always pass the check.
        - [+] at expert listn you get names
        - [+] otherwise just get 'slithering' etc
        - [+] test......
    - [+] "check stairs" ability ???
        - [+] this then prompts for various methods
    - [+] smell down stairs with enhancesmell
        - [+] say "you see xxx scent" for all lfs within los of other
              end
    - [+] use perception to check stairs
        - [+] say "you see xxx footprints" for all lfs within los of
              other end
    - [+] ability to peek down stairs with adept stealth skill?
        - [+] temporarily put you there
        - [+] precaclc los with awareness in all directions from there
        - [+] show view
        - [+] wait for key
        - [+] move you back, remove temporary awareness
    - [+] add help for these skills
This commit is contained in:
Rob Pearce 2011-10-16 22:45:36 +00:00
parent 0d663e81b3
commit a297a3c180
12 changed files with 747 additions and 205 deletions

19
data.c
View File

@ -1589,6 +1589,9 @@ void initobjects(void) {
// potions (sorted by rarity) // potions (sorted by rarity)
addot(OT_POT_JUICE, "potion of fruit juice", "Tasty (but not very fresh) fruit juice!", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_JUICE, "potion of fruit juice", "Tasty (but not very fresh) fruit juice!", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addot(OT_POT_CANINETRACKING, "potion of canine tracking", "Mimics the effects of a 'canine tracking' spell.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-10 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY); addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-10 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL);
addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL);
@ -1690,10 +1693,6 @@ void initobjects(void) {
addot(OT_SCR_AWARENESS, "scroll of awareness", "Mimics the effects of a 'heightened awareness' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addot(OT_SCR_AWARENESS, "scroll of awareness", "Mimics the effects of a 'heightened awareness' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL);
addot(OT_SCR_CANINETRACKING, "scroll of canine tracking", "Mimics the effects of a 'canine tracking' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_LINKSPELL, OT_S_CANINETRACKING, NA, NA, NULL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
addot(OT_SCR_REMOVECURSE, "scroll of remove curse", "Removes curses from all weilded equipment.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addot(OT_SCR_REMOVECURSE, "scroll of remove curse", "Removes curses from all weilded equipment.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL);
addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL);
@ -2876,6 +2875,13 @@ void initobjects(void) {
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
addot(OT_S_INSTANTDISROBE, "instant disrobe", "Transports 1-3 pieces of the target's armour to the air next to them.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines number of items affected.");
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL);
addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL);
addflag(lastot->flags, F_MAXPOWER, 8, NA, NA, NULL);
addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL);
// l4 // l4
addot(OT_S_BLINKASS, "assassin blink", "Teleports the caster behind an enemy, ready for a sneak attack.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addot(OT_S_BLINKASS, "assassin blink", "Teleports the caster behind an enemy, ready for a sneak attack.", MT_NOTHING, 0, OC_SPELL, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL);
@ -3007,6 +3013,8 @@ void initobjects(void) {
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL);
addflag(lastot->flags, F_NEEDSGRAB, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NEEDSGRAB, B_TRUE, NA, NA, NULL);
addot(OT_A_CHECKSTAIRS, "check stairs", "Attempt to determine what lies on the other end of a staircase.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_COOK, "cook", "Combine food and water into a healthy meals.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_COOK, "cook", "Combine food and water into a healthy meals.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL);
addot(OT_A_DARKWALK, "darkwalk", "Step between the shadows.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addot(OT_A_DARKWALK, "darkwalk", "Step between the shadows.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY);
@ -8664,6 +8672,7 @@ void initskills(void) {
addskilldesc(SK_LISTEN, PR_NOVICE, "^gYou now gauge the distance of sounds.^n", B_TRUE); addskilldesc(SK_LISTEN, PR_NOVICE, "^gYou now gauge the distance of sounds.^n", B_TRUE);
addskilldesc(SK_LISTEN, PR_BEGINNER, "^gYou now more accurately gauge the distance of sounds.^n", B_TRUE); addskilldesc(SK_LISTEN, PR_BEGINNER, "^gYou now more accurately gauge the distance of sounds.^n", B_TRUE);
addskilldesc(SK_LISTEN, PR_ADEPT, "^gYou can now determine the direction sounds are coming from.^n", B_TRUE); addskilldesc(SK_LISTEN, PR_ADEPT, "^gYou can now determine the direction sounds are coming from.^n", B_TRUE);
addskilldesc(SK_LISTEN, PR_ADEPT, "^gYou can now listen at staircases before descending.^n", B_TRUE);
addskilldesc(SK_LISTEN, PR_EXPERT, "^gYou can now identify monsters based on sound.^n", B_TRUE); addskilldesc(SK_LISTEN, PR_EXPERT, "^gYou can now identify monsters based on sound.^n", B_TRUE);
addskilldesc(SK_LISTEN, PR_MASTER, "^gYou can now locate monsters based on sound.^n", B_TRUE); addskilldesc(SK_LISTEN, PR_MASTER, "^gYou can now locate monsters based on sound.^n", B_TRUE);
addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50); addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50);
@ -8707,6 +8716,7 @@ void initskills(void) {
addskill(SK_PERCEPTION, "Perception", "Your ability to notice hidden details, from simple footprints to sinister traps.", 50); addskill(SK_PERCEPTION, "Perception", "Your ability to notice hidden details, from simple footprints to sinister traps.", 50);
addskilldesc(SK_PERCEPTION, PR_INEPT, "- At higher levels this skill will also let you obscure your own tracks.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_INEPT, "- At higher levels this skill will also let you obscure your own tracks.", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now see footprints.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now see footprints.^n", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now check for trails on staircases before descending.^n", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_BEGINNER, "^gYou can now determine how recently footprints were made.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_BEGINNER, "^gYou can now determine how recently footprints were made.^n", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYou can now identify creatures from their footprints.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYou can now identify creatures from their footprints.^n", B_TRUE);
addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYour field of vision is now wider.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_ADEPT, "^gYour field of vision is now wider.^n", B_TRUE);
@ -8715,6 +8725,7 @@ void initskills(void) {
addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou now have perception of your blind spots.^n", B_TRUE); addskilldesc(SK_PERCEPTION, PR_MASTER, "^gYou now have perception of your blind spots.^n", B_TRUE);
addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable? addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable?
addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou gain the 'hide' ability.^n", B_FALSE); addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou gain the 'hide' ability.^n", B_FALSE);
addskilldesc(SK_STEALTH, PR_SKILLED, "^gYou can now peek down staircases.^n", B_TRUE);
addskilldesc(SK_STEALTH, PR_EXPERT, "^gYou can now hide even when monsters are nearby.^n", B_TRUE); addskilldesc(SK_STEALTH, PR_EXPERT, "^gYou can now hide even when monsters are nearby.^n", B_TRUE);
addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.", 50); addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.", 50);
addskilldesc(SK_SWIMMING, PR_NOVICE, "^gYou can now swim.^n", B_TRUE); addskilldesc(SK_SWIMMING, PR_NOVICE, "^gYou can now swim.^n", B_TRUE);

Binary file not shown.

4
defs.h
View File

@ -1044,6 +1044,7 @@ enum OBTYPE {
OT_POT_AMBROSIA, OT_POT_AMBROSIA,
OT_POT_BLOOD, OT_POT_BLOOD,
OT_POT_BLOODC, OT_POT_BLOODC,
OT_POT_CANINETRACKING,
OT_POT_COFFEE, OT_POT_COFFEE,
OT_POT_COMPETENCE, OT_POT_COMPETENCE,
OT_POT_ELEMENTIMMUNE, OT_POT_ELEMENTIMMUNE,
@ -1072,7 +1073,6 @@ enum OBTYPE {
OT_GRAPHPAPER, OT_GRAPHPAPER,
OT_SCR_AWARENESS, OT_SCR_AWARENESS,
OT_SCR_NOTHING, OT_SCR_NOTHING,
OT_SCR_CANINETRACKING,
OT_SCR_CREATEMONSTER, OT_SCR_CREATEMONSTER,
OT_SCR_DETECTAURA, OT_SCR_DETECTAURA,
OT_SCR_DETECTLIFE, OT_SCR_DETECTLIFE,
@ -1260,6 +1260,7 @@ enum OBTYPE {
OT_S_BLINKASS, OT_S_BLINKASS,
OT_S_DISPERSAL, OT_S_DISPERSAL,
OT_S_GATE, OT_S_GATE,
OT_S_INSTANTDISROBE,
OT_S_PLANESHIFT, OT_S_PLANESHIFT,
OT_S_SUCK, OT_S_SUCK,
OT_S_TELEPORT, OT_S_TELEPORT,
@ -1284,6 +1285,7 @@ enum OBTYPE {
OT_A_LEVELUP, OT_A_LEVELUP,
// abilities // abilities
OT_A_AIMEDSTRIKE, OT_A_AIMEDSTRIKE,
OT_A_CHECKSTAIRS,
OT_A_COOK, OT_A_COOK,
OT_A_DARKWALK, OT_A_DARKWALK,
OT_A_DISARM, OT_A_DISARM,

313
lf.c
View File

@ -2902,7 +2902,7 @@ int eat(lifeform_t *lf, object_t *o) {
addtempflag(lf->flags, F_SEEINDARK, 3, NA, NA, NULL, rnd(20,40)); addtempflag(lf->flags, F_SEEINDARK, 3, NA, NA, NULL, rnd(20,40));
} }
makeknown(o->type->id); if (isplayer(lf)) makeknown(o->type->id);
} // end if fullyeaten } // end if fullyeaten
// take time // take time
@ -5673,6 +5673,130 @@ int getnightvisrange(lifeform_t *lf) {
return range; return range;
} }
// populates heartext, seetext and volume
int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, char *heartext,char *seetext, int *volume) {
flag_t *retflag[MAXCANDIDATES],*nflag[MAXCANDIDATES];
int nretflags, i,nnflags = 0;
// deafults
if (volume) *volume = 0;
if (heartext) strcpy(heartext, "");
if (seetext) strcpy(seetext, "");
if (lfhasflag(lf, F_FROZEN)) {
// can't make noise if frozen!
return B_TRUE;
}
if ((nid == N_WALK) || nid == (N_FLY)) {
if (!movecausesnoise(lf)) {
return B_TRUE;
}
}
getflags(lf->flags, retflag, &nretflags, F_NOISETEXT, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->val[0] == nid) {
nflag[nnflags++] = retflag[i];
}
}
if (nnflags) {
flag_t *f;
char verb[BUFLEN], noun[BUFLEN];
f = nflag[rnd(0,nnflags-1)];
if (volume) *volume = f->val[1];
if (f->text[0] == '^') {
strcpy(verb, "");
//noun = strtok_r(f->text, "^", &dummy);
strcpy(noun, f->text + 1);
} else {
char *p;
p = readuntil(verb, f->text, '^');
readuntil(noun, p, '^'); // ie eol
//verb = strtok_r(f->text, "^", &dummy);
//noun = strtok_r(NULL, "^", &dummy);
}
if (heartext) {
if (strlen(noun)) {
snprintf(heartext, BUFLEN, "%s.",noun);
}
}
if (seetext) {
if (strlen(verb)) {
strcpy(seetext, verb);
}
}
if (nid == N_WALK) {
*volume += getarmournoise(lf);
}
return B_FALSE;
} else {
// some defaults
if (nid == N_WALK) {
enum LFSIZE sz;
char movetext[BUFLEN];
strcpy(movetext, "");
sz = getlfsize(lf);
switch (sz) {
case SZ_MINI:
case SZ_TINY:
if (volume) *volume = 0;
break;
case SZ_SMALL:
if (volume) *volume = 1;
strcpy(movetext, "light footsteps.");
break;
case SZ_MEDIUM:
case SZ_HUMAN:
if (volume) *volume = 2;
strcpy(movetext, "footsteps.");
break;
case SZ_LARGE:
if (volume) *volume = 3;
strcpy(movetext, "heavy footsteps.");
break;
case SZ_HUGE:
if (volume) *volume = 4;
strcpy(movetext, "heavy footsteps.");
break;
case SZ_ENORMOUS:
if (volume) *volume = 5;
strcpy(movetext, "very heavy footsteps.");
break;
case SZ_MAX:
if (volume) *volume = 6;
strcpy(movetext, "extremely loud thumping.");
break;
default:
break;
}
if (strlen(movetext)) {
if (volume) *volume += getarmournoise(lf);
if (heartext) strcpy(heartext, movetext);
return B_FALSE;
}
} else if (nid == N_SONICBOLT) {
if (volume) *volume = 5;
if (heartext) strcpy(heartext, "a ear-splitting burst of sound!");
if (seetext) strcpy(seetext, "emits an ear-splitting burst of sound!");
return B_FALSE;
} else if (nid == N_WARCRY) {
if (volume) *volume = 4;
if (heartext) strcpy(heartext, "a blood-curdling war cry!");
if (seetext) strcpy(seetext, "shouts a blood-curdling war-cry!");
return B_FALSE;
}
return B_TRUE;
}
return B_FALSE;
}
char *getlfconditionname(enum LFCONDITION cond) { char *getlfconditionname(enum LFCONDITION cond) {
switch (cond) { switch (cond) {
case C_CRITICAL: case C_CRITICAL:
@ -7521,10 +7645,10 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) {
// if all conferred flags now known, object is known // if all conferred flags now known, object is known
if (flagsfound && (flagsknown == flagsfound)) { if (flagsfound && (flagsknown == flagsfound)) {
if (isplayer(lf) || cansee(player, lf)) {
makeknown(o->type->id); makeknown(o->type->id);
// in some cases, identify the object fully // in some cases, identify the object fully
// (ie. make +xxx bonuses known too) // (ie. make +xxx bonuses known too)
if (isplayer(lf)) {
if (hasflag(o->flags, F_IDWHENUSED)) { if (hasflag(o->flags, F_IDWHENUSED)) {
identify(o); identify(o);
} }
@ -7633,7 +7757,6 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
makeknown(OT_MUSHROOMTOAD); makeknown(OT_MUSHROOMTOAD);
} }
} }
} else if (id == SK_LORE_ARCANA) { } else if (id == SK_LORE_ARCANA) {
if (f->val[1] == PR_ADEPT) { if (f->val[1] == PR_ADEPT) {
newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL); newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL);
@ -7642,6 +7765,13 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
newf->lifetime = FROMSKILL; newf->lifetime = FROMSKILL;
} }
} }
} else if (id == SK_LORE_NATURE) {
if (f->val[1] == PR_ADEPT) {
if (isplayer(lf)) {
makeknown(OT_MUSHROOMSHI);
makeknown(OT_MUSHROOMTOAD);
}
}
} else if (id == SK_PERCEPTION) { } else if (id == SK_PERCEPTION) {
if ((f->val[1] == PR_ADEPT) || (f->val[1] == PR_MASTER)) { if ((f->val[1] == PR_ADEPT) || (f->val[1] == PR_MASTER)) {
// our FOV gets wider // our FOV gets wider
@ -7659,6 +7789,7 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
newf->lifetime = FROMSKILL; newf->lifetime = FROMSKILL;
} }
} else if (id == SK_TECHUSAGE) { } else if (id == SK_TECHUSAGE) {
if (isplayer(lf)) {
objecttype_t *ot; objecttype_t *ot;
// automatically make known all tech <= our skill level // automatically make known all tech <= our skill level
for (ot = objecttype ; ot ; ot = ot->next) { for (ot = objecttype ; ot ; ot = ot->next) {
@ -7683,6 +7814,7 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) {
} }
} }
} }
}
} else if (id == SK_TWOWEAPON) { } else if (id == SK_TWOWEAPON) {
if (f->val[1] == PR_EXPERT) { if (f->val[1] == PR_EXPERT) {
addflag(lf->flags, F_CANWILL, OT_A_FLURRY, 3, 3, "pw:1;"); addflag(lf->flags, F_CANWILL, OT_A_FLURRY, 3, 3, "pw:1;");
@ -9591,28 +9723,29 @@ void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg) {
sk->nskilldesc++; sk->nskilldesc++;
} }
void addtrail(lifeform_t *lf, int dir) { object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int doscents) {
object_t *footprint, *scent; object_t *footprint, *scent,*retob = NULL;
flag_t *fpflag; flag_t *fpflag;
// no tracks at all? // no tracks at all?
if (lf->cell->type->solid) { if (where->type->solid) {
return; return NULL;
} else if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) { } else if (hasobwithflag(where->obpile, F_DEEPWATER)) {
return; return NULL;
} }
// footprints first // footprints first
if (doprints) {
if (!isairborne(lf) && !lfhasflag(lf, F_NONCORPOREAL)) { if (!isairborne(lf) && !lfhasflag(lf, F_NONCORPOREAL)) {
int fpdir; int fpdir;
if (getskill(lf, SK_PERCEPTION) >= PR_EXPERT) { if (getskill(lf, SK_PERCEPTION) >= PR_EXPERT) {
// no footprints! // no footprints!
return; return NULL;
} else { } else {
fpdir = dir; fpdir = dir;
} }
footprint = hastrailof(lf->cell->obpile, lf, OT_FOOTPRINT, &fpflag, NULL); footprint = hastrailof(where->obpile, lf, OT_FOOTPRINT, &fpflag, NULL);
if (footprint) { if (footprint) {
assert(fpflag); assert(fpflag);
fpflag->lifetime = getfootprinttime(lf); fpflag->lifetime = getfootprinttime(lf);
@ -9620,22 +9753,28 @@ void addtrail(lifeform_t *lf, int dir) {
} else { } else {
char buf[BUFLENTINY]; char buf[BUFLENTINY];
snprintf(buf, BUFLENTINY, "%d", lf->id); snprintf(buf, BUFLENTINY, "%d", lf->id);
footprint = addobfast(lf->cell->obpile, OT_FOOTPRINT); footprint = addobfast(where->obpile, OT_FOOTPRINT);
addtempflag(footprint->flags, F_TRAIL, lf->race->id, fpdir, S_SIGHT, buf, getfootprinttime(lf)); addtempflag(footprint->flags, F_TRAIL, lf->race->id, fpdir, S_SIGHT, buf, getfootprinttime(lf));
} }
retob = footprint;
}
} }
// now smell // now smell
scent = hastrailof(lf->cell->obpile, lf, OT_SCENT, &fpflag, NULL); if (doscents) {
scent = hastrailof(where->obpile, lf, OT_SCENT, &fpflag, NULL);
if (scent) { if (scent) {
assert(fpflag); assert(fpflag);
fpflag->lifetime = TM_SCENT; fpflag->lifetime = TM_SCENT;
} else { } else {
char buf[BUFLENTINY]; char buf[BUFLENTINY];
snprintf(buf, BUFLENTINY, "%d", lf->id); snprintf(buf, BUFLENTINY, "%d", lf->id);
scent = addobfast(lf->cell->obpile, OT_SCENT); scent = addobfast(where->obpile, OT_SCENT);
addtempflag(scent->flags, F_TRAIL, lf->race->id, dir, S_SMELL, buf, TM_SCENT); addtempflag(scent->flags, F_TRAIL, lf->race->id, dir, S_SMELL, buf, TM_SCENT);
} }
retob = scent;
}
return retob;
} }
void adjustspeedforwater(lifeform_t *lf, int *speed) { void adjustspeedforwater(lifeform_t *lf, int *speed) {
@ -10789,96 +10928,15 @@ int makenauseated(lifeform_t *lf, int amt, int howlong) {
return B_FALSE; return B_FALSE;
} }
void makenoise(lifeform_t *lf, enum NOISETYPE nid) { void makenoise(lifeform_t *lf, enum NOISETYPE nid) {
flag_t *retflag[MAXCANDIDATES],*nflag[MAXCANDIDATES]; int volume = 1;
int nretflags, volume = 1, i,nnflags = 0; char hear[BUFLEN], see[BUFLEN];
char *verb = NULL, *noun = NULL;
if (lfhasflag(lf, F_FROZEN)) { if (!getnoisedetails(lf, nid, hear, see, &volume)) {
// can't make noise if frozen! // success
return; noise(lf->cell, lf, noisetypetoclass(nid), volume, strlen(hear) ? hear : NULL, strlen(see) ? see : NULL);
} }
getflags(lf->flags, retflag, &nretflags, F_NOISETEXT, F_NONE);
for (i = 0; i < nretflags; i++) {
if (retflag[i]->val[0] == nid) {
nflag[nnflags++] = retflag[i];
}
}
if (nnflags) {
flag_t *f;
char *dummy;
char noisetext[BUFLEN];
f = nflag[rnd(0,nnflags-1)];
volume = f->val[1];
if (f->text[0] == '^') {
verb = NULL;
noun = strtok_r(f->text, "^", &dummy);
} else {
verb = strtok_r(f->text, "^", &dummy);
noun = strtok_r(NULL, "^", &dummy);
}
snprintf(noisetext, BUFLEN, "%s.",noun);
if (nid == N_WALK) {
volume += getarmournoise(lf);
}
noise(lf->cell, lf, noisetypetoclass(nid), volume, noisetext, verb);
} else {
// some defaults
if (nid == N_WALK) {
enum LFSIZE sz;
char movetext[BUFLEN];
strcpy(movetext, "");
sz = getlfsize(lf);
switch (sz) {
case SZ_MINI:
case SZ_TINY:
volume = 0;
break;
case SZ_SMALL:
volume = 1;
strcpy(movetext, "light footsteps.");
break;
case SZ_MEDIUM:
case SZ_HUMAN:
volume = 2;
strcpy(movetext, "footsteps.");
break;
case SZ_LARGE:
volume = 3;
strcpy(movetext, "heavy footsteps.");
break;
case SZ_HUGE:
volume = 4;
strcpy(movetext, "heavy footsteps.");
break;
case SZ_ENORMOUS:
volume = 5;
strcpy(movetext, "very heavy footsteps.");
break;
case SZ_MAX:
volume = 6;
strcpy(movetext, "extremely loud thumping.");
break;
default:
break;
}
volume += getarmournoise(lf);
if (strlen(movetext)) {
noise(lf->cell, lf, noisetypetoclass(nid), volume, movetext, NULL);
}
} else if (nid == N_SONICBOLT) {
noise(lf->cell, lf, NC_OTHER, 5, "a ear-splitting burst of sound!", "emits an ear-splitting burst of sound!");
} else if (nid == N_WARCRY) {
noise(lf->cell, lf, NC_OTHER, 4, "a blood-curdling war cry!", "shouts a blood-curdling war-cry!");
}
}
} }
void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) { void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) {
@ -11203,13 +11261,14 @@ void modstamina(lifeform_t *lf, float howmuch) {
} else if (orig == 0) { } else if (orig == 0) {
msg("You feel less exhausted now."); msg("You feel less exhausted now.");
} }
} else if (cansee(player, lf)) { }
/*else if (cansee(player, lf)) {
if (getstamina(lf) == 0) { if (getstamina(lf) == 0) {
char lfname[BUFLEN]; char lfname[BUFLEN];
getlfname(lf, lfname); getlfname(lf, lfname);
msg("%s looks exhausted.", lfname); msg("%s looks exhausted.", lfname);
} }
} }*/
} }
if (getstamina(lf) == 0) { if (getstamina(lf) == 0) {
@ -11217,6 +11276,14 @@ void modstamina(lifeform_t *lf, float howmuch) {
} }
} }
int movecausesnoise(lifeform_t *lf) {
if (lfhasflag(lf, F_SILENTMOVE) || lfhasflag(lf, F_SNEAK)) {
return B_FALSE;
}
return B_TRUE;
}
// if validchars is set, we will populate it with a list of valid // if validchars is set, we will populate it with a list of valid
// choice letters for asking the player how to rest. // choice letters for asking the player how to rest.
int needstorest(lifeform_t *lf, char *validchars) { int needstorest(lifeform_t *lf, char *validchars) {
@ -11310,6 +11377,9 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume,
strcat(realseetext, "something"); strcat(realseetext, "something");
} }
msg("%s %s.", lfname, realseetext); msg("%s %s.", lfname, realseetext);
if ((realseetext[0] == '\0') || !strlen(realseetext)) {
dblog("xxx");
}
rv = B_TRUE; rv = B_TRUE;
} }
} else if (text && !isdeaf(l) && ((nclass != NC_MOVEMENT) || !lfhasflag(l, F_DONELISTEN))) { } else if (text && !isdeaf(l) && ((nclass != NC_MOVEMENT) || !lfhasflag(l, F_DONELISTEN))) {
@ -15061,31 +15131,14 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose) {
} }
} }
// do stairs go somewhere? // do stairs go somewhere? generate new maps if required.
newcell = getstairdestination(o); newcell = getstairdestination(o, &madenewmap);
if (!newcell) { if (newcell) {
newmap = newcell->map;
} else {
if (isportal) { if (isportal) {
// unconnected portal // unconnected portal
if (isplayer(lf)) msg("This portal doesn't seem to go anywhere."); if (isplayer(lf)) msg("This portal doesn't seem to go anywhere.");
} else {
// is there already a level of the correct depth?
newmap = findregionmap(newregion->id, newdepth);
if (newmap) {
dblog("ERROR - unlinked stairs!\n");
msg("ERROR - unlinked stairs!\n");
} else {
// generate a new map! this will fill in the destination of our stairs
newmap = addmap();
// first map of a newly created region?
if (newregion->id != curmap->region->id) {
newdepth = 1;
}
createmap(newmap, newdepth, newregion, curmap, dir, o);
// at this point, stairs should have a destination (map creation will
// fill it in)
newcell = getstairdestination(o);
madenewmap = B_TRUE;
}
} }
} }
@ -15112,20 +15165,12 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose) {
} }
// check noone is in the way // check noone is in the way
if (newcell->lf) { if (movelfsoutofway(newcell)) {
cell_t *c;
// if they are, find somewhere to move them.
c = getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND);
if (c) {
// move them there
movelf(newcell->lf, c);
} else {
// TODO: handle this differently - ie always allow the player // TODO: handle this differently - ie always allow the player
// go there? // go there?
if (isplayer(lf)) msg("The stairs seem to be blocked."); if (isplayer(lf)) msg("The stairs seem to be blocked.");
return B_TRUE; return B_TRUE;
} }
}
// announce // announce
if (isplayer(lf)) { if (isplayer(lf)) {
announcearrival(lf, newcell->map); announcearrival(lf, newcell->map);

4
lf.h
View File

@ -7,7 +7,7 @@ race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcol
raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill); raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill);
skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime); skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime);
void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg); void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg);
void addtrail(lifeform_t *lf, int dir); object_t *addtrail(lifeform_t *lf, cell_t *where, int dir, int doprints, int doscents);
void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype); void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype);
void adjustspeedforwater(lifeform_t *lf, int *speed); void adjustspeedforwater(lifeform_t *lf, int *speed);
void age(lifeform_t *lf, int pct); void age(lifeform_t *lf, int pct);
@ -153,6 +153,7 @@ int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions);
int getmiscastchance(lifeform_t *lf); int getmiscastchance(lifeform_t *lf);
int getmorale(lifeform_t *lf); int getmorale(lifeform_t *lf);
int getnightvisrange(lifeform_t *lf); int getnightvisrange(lifeform_t *lf);
int getnoisedetails(lifeform_t *lf, enum NOISETYPE nid, char *heartext,char *seetext, int *volume);
char *getlfconditionname(enum LFCONDITION cond); char *getlfconditionname(enum LFCONDITION cond);
object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp); object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp);
int getowing(lifeform_t *buyer, int shopid, int *retnitems); int getowing(lifeform_t *buyer, int shopid, int *retnitems);
@ -318,6 +319,7 @@ void modhunger(lifeform_t *lf, int amt);
float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); float modifybystat(float num, lifeform_t *lf, enum ATTRIB att);
void modmorale(lifeform_t *lf, int howmuch); void modmorale(lifeform_t *lf, int howmuch);
void modstamina(lifeform_t *lf, float howmuch); void modstamina(lifeform_t *lf, float howmuch);
int movecausesnoise(lifeform_t *lf);
int needstorest(lifeform_t *lf, char *validchars); int needstorest(lifeform_t *lf, char *validchars);
int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext); int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext);
enum NOISECLASS noisetypetoclass(enum NOISETYPE nt); enum NOISECLASS noisetypetoclass(enum NOISETYPE nt);

58
map.c
View File

@ -2782,13 +2782,13 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex
object_t *o; object_t *o;
c = getcellat(map, x, y); c = getcellat(map, x, y);
o = hasobwithflag(c->obpile, F_CLIMBABLE); o = hasobwithflag(c->obpile, F_CLIMBABLE);
if (o && !getstairdestination(o)) { if (o && !getstairdestination(o, NULL)) {
// this will join these stairs to existing ones on // this will join these stairs to existing ones on
// existing adjacent maps // existing adjacent maps
if (!linkstairs(o, NULL)) { if (!linkstairs(o, NULL)) {
if (db) { if (db) {
cell_t *dst; cell_t *dst;
dst = getstairdestination(o); dst = getstairdestination(o, NULL);
dblog(" linked '%s' to map %s",o->type->name, dst->map->name); dblog(" linked '%s' to map %s",o->type->name, dst->map->name);
} }
} else { } else {
@ -4077,7 +4077,7 @@ map_t *findsurfaceexitmap(map_t *m) {
for (o = c->obpile->first ; o ; o = o->next) { for (o = c->obpile->first ; o ; o = o->next) {
if (hasflagval(o->flags, F_CLIMBABLE, D_UP, NA, NA, NULL)) { if (hasflagval(o->flags, F_CLIMBABLE, D_UP, NA, NA, NULL)) {
cell_t *newc; cell_t *newc;
newc = getstairdestination(o); newc = getstairdestination(o, NULL);
if (newc) { if (newc) {
return newc->map; return newc->map;
} }
@ -4554,7 +4554,8 @@ int getslipperyness(cell_t *c, object_t **slipob) {
return totalslip; return totalslip;
} }
cell_t *getstairdestination(object_t *o) { // if madenewmap is passed, then we'll try to make a new map for stairs with no endpoint
cell_t *getstairdestination(object_t *o, int *madenewmap) {
flag_t *f; flag_t *f;
cell_t *newcell = NULL; cell_t *newcell = NULL;
@ -4585,6 +4586,55 @@ cell_t *getstairdestination(object_t *o) {
newcell = getcellat(newmap, newx, newy); newcell = getcellat(newmap, newx, newy);
} }
} }
if (!newcell && madenewmap) {
cell_t *obcell = NULL;
map_t *newmap,*curmap;
region_t *newregion = NULL;
int dir,newdepth;
obcell = getoblocation(o);
curmap = obcell->map;
f = hasflag(o->flags, F_CLIMBABLE);
if (!f) return NULL;
dir = getstairdirection(o);
if ((dir != D_UP) && (dir != D_DOWN)) {
// ie this is a portal
return NULL;
} else {
if (dir == D_UP) newdepth = curmap->depth - 1;
else newdepth = curmap->depth + 1;
if (f->val[1] == NA) {
// use same region
newregion = obcell->map->region;
} else {
newregion = findregion(f->val[1]);
}
}
// is there already a level of the correct depth?
newmap = findregionmap(newregion->id, newdepth);
if (newmap) {
dblog("ERROR - unlinked stairs!\n");
msg("ERROR - unlinked stairs!\n");
return NULL;
} else {
// generate a new map! this will fill in the destination of our stairs
newmap = addmap();
// first map of a newly created region?
if (newregion->id != curmap->region->id) {
newdepth = 1;
}
createmap(newmap, newdepth, newregion, curmap, dir, o);
// at this point, stairs should have a destination (map creation will
// fill it in)
newcell = getstairdestination(o, NULL); // recursive call
*madenewmap = B_TRUE;
}
}
return newcell; return newcell;
} }

2
map.h
View File

@ -95,7 +95,7 @@ int getrandomdirexcept(int dirtype, int exception);
cell_t *getrandomroomcell(map_t *map, int roomid); cell_t *getrandomroomcell(map_t *map, int roomid);
void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells); void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells);
int getslipperyness(cell_t *c, object_t **slipob); int getslipperyness(cell_t *c, object_t **slipob);
cell_t *getstairdestination(object_t *o); cell_t *getstairdestination(object_t *o, int *madenewmap);
object_t *hasenterableobject(cell_t *c); object_t *hasenterableobject(cell_t *c);
object_t *hascloseddoor(cell_t *c); object_t *hascloseddoor(cell_t *c);
lifeform_t *haslf(cell_t *c); lifeform_t *haslf(cell_t *c);

22
move.c
View File

@ -1363,6 +1363,22 @@ int movelf(lifeform_t *lf, cell_t *newcell) {
return didmsg; return didmsg;
} }
int movelfsoutofway(cell_t *newcell) {
// anyone in the way?
if (newcell->lf) {
cell_t *c;
// if they are, find somewhere to move them.
c = getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND);
if (c) {
// move them there
movelf(newcell->lf, c);
} else {
return B_TRUE;
}
}
return B_FALSE;
}
// basically this is a warpper for 'movelf' which // basically this is a warpper for 'movelf' which
// does other game things like telling the player // does other game things like telling the player
// what is here. // what is here.
@ -1466,7 +1482,6 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
// make some noise // make some noise
// (stealth check to avoid this) // (stealth check to avoid this)
if (!lfhasflag(lf, F_SILENTMOVE) && !lfhasflag(lf, F_SNEAK)) {
if (!skillcheck(lf, SC_STEALTH, 20, 0)) { if (!skillcheck(lf, SC_STEALTH, 20, 0)) {
if (isairborne(lf)) { if (isairborne(lf)) {
makenoise(lf, N_FLY); makenoise(lf, N_FLY);
@ -1474,7 +1489,6 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) {
makenoise(lf, N_WALK); makenoise(lf, N_WALK);
} }
} }
}
// slip on blood in new cell? // slip on blood in new cell?
if (!isairborne(lf) && !isswimming(lf)) { if (!isairborne(lf) && !isswimming(lf)) {
@ -2373,8 +2387,8 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) {
killflagsofid(lf->flags, F_LASTDIR); killflagsofid(lf->flags, F_LASTDIR);
addflag(lf->flags, F_LASTDIR, dir, NA, NA, NULL); addflag(lf->flags, F_LASTDIR, dir, NA, NA, NULL);
// add footprints in our current cell. // add footprints/scents in our current cell.
addtrail(lf, dir); addtrail(lf, lf->cell, dir, B_TRUE, B_TRUE);
// do your pets see you move? // do your pets see you move?
if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) { if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) {

1
move.h
View File

@ -18,6 +18,7 @@ int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int st
int moveclear(lifeform_t *lf, int dir, enum ERROR *error); int moveclear(lifeform_t *lf, int dir, enum ERROR *error);
int moveeffects(lifeform_t *lf); int moveeffects(lifeform_t *lf);
int movelf(lifeform_t *lf, cell_t *newcell); int movelf(lifeform_t *lf, cell_t *newcell);
int movelfsoutofway(cell_t *newcell);
int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg); int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg);
int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe); int movetowards(lifeform_t *lf, cell_t *dst, int dirtype, int strafe);
int move_will_hurt(lifeform_t *lf); int move_will_hurt(lifeform_t *lf);

View File

@ -5287,6 +5287,15 @@ float getshopprice(object_t *o, lifeform_t *buyer) {
return val; return val;
} }
int getstairdirection(object_t *o) {
flag_t *f;
f = hasflag(o->flags, F_CLIMBABLE);
if ((f->val[0] == D_UP) || (f->val[0] == D_DOWN)) {
return f->val[0];
}
return D_NONE;
}
enum SKILLLEVEL gettechlevel(enum OBTYPE oid) { enum SKILLLEVEL gettechlevel(enum OBTYPE oid) {
flag_t *f; flag_t *f;
objecttype_t *ot; objecttype_t *ot;
@ -6442,6 +6451,14 @@ void makeknown(enum OBTYPE otid) {
flag_t *retflag[MAXCANDIDATES]; flag_t *retflag[MAXCANDIDATES];
int nretflags = 0; int nretflags = 0;
/*
objecttype_t *ot;
ot = findot(otid);
if (ot && (ot->obclass->id == OC_TECH)) {
dblog("xxx");
}
*/
if (player) { if (player) {
// if player is holding an object of that type with F_CONFER.. IFKNOWN... and isn't known... // if player is holding an object of that type with F_CONFER.. IFKNOWN... and isn't known...
// then by making the object known, we also need to give them the flag. // then by making the object known, we also need to give them the flag.
@ -6597,7 +6614,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) {
pit = hasobwithflagval(dst->where->obpile, F_PIT, D_DOWN, NA, NA, NULL); pit = hasobwithflagval(dst->where->obpile, F_PIT, D_DOWN, NA, NA, NULL);
if (pit) { if (pit) {
cell_t *newcell; cell_t *newcell;
newcell = getstairdestination(pit); newcell = getstairdestination(pit, NULL);
if (newcell) { if (newcell) {
if (haslos(player, dst->where)) { if (haslos(player, dst->where)) {
char obname[BUFLEN]; char obname[BUFLEN];
@ -7092,7 +7109,7 @@ int obsfallthrough(cell_t *c, object_t *pit) {
char obname[BUFLEN],downholename[BUFLEN],upholename[BUFLEN]; char obname[BUFLEN],downholename[BUFLEN],upholename[BUFLEN];
int nfallen = 0; int nfallen = 0;
belowcell = getstairdestination(pit); belowcell = getstairdestination(pit, NULL);
if (!belowcell) return 0; if (!belowcell) return 0;
uphole = hasobwithflagval(belowcell->obpile, F_PIT, D_UP, NA, NA, NULL); uphole = hasobwithflagval(belowcell->obpile, F_PIT, D_UP, NA, NA, NULL);
@ -8492,6 +8509,9 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE
} }
} }
break; break;
case OT_POT_CANINETRACKING:
dospelleffects(lf, OT_S_CANINETRACKING, 5, lf, NULL, lf->cell, potblessed, seen, B_TRUE);
break;
case OT_POT_COFFEE: case OT_POT_COFFEE:
if (isplayer(lf)) { if (isplayer(lf)) {
msg("This tastes like coffee."); msg("This tastes like coffee.");

View File

@ -130,6 +130,7 @@ char *getschoolname(enum SPELLSCHOOL sch);
char *getschoolnameshort(enum SPELLSCHOOL sch); char *getschoolnameshort(enum SPELLSCHOOL sch);
int getshatterdam(object_t *o); int getshatterdam(object_t *o);
float getshopprice(object_t *o, lifeform_t *buyer); float getshopprice(object_t *o, lifeform_t *buyer);
int getstairdirection(object_t *o);
enum SKILLLEVEL gettechlevel(enum OBTYPE oid); enum SKILLLEVEL gettechlevel(enum OBTYPE oid);
int getthrowdam(object_t *o); int getthrowdam(object_t *o);
char *gettopobname(cell_t *c, char *retbuf); char *gettopobname(cell_t *c, char *retbuf);

396
spell.c
View File

@ -25,6 +25,7 @@ extern region_t *firstregion;
extern knowledge_t *knowledge; extern knowledge_t *knowledge;
extern int needredraw; extern int needredraw;
extern int noredraw;
extern prompt_t prompt; extern prompt_t prompt;
@ -215,6 +216,344 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef
// attack // attack
attackcell(user, targcell, B_TRUE); attackcell(user, targcell, B_TRUE);
} }
} else if (abilid == OT_A_CHECKSTAIRS) {
char obname[BUFLEN], buf[BUFLEN],ch;
int madenewmap = B_TRUE;
cell_t *origcell = NULL;
lifeform_t *inway = NULL;
cell_t *c;
object_t *stairs;
int stairdir;
if (!isplayer(user)) {
return B_FALSE;
}
// are there stairs here?
stairs = hasobwithflag(user->cell->obpile, F_CLIMBABLE);
if (!stairs) {
msg("There are no stairs here!");
return B_TRUE;
}
stairdir = getstairdirection(stairs);
if ((stairdir != D_UP) && (stairdir != D_DOWN)) {
// slightly different message from above, for debugging
msg("There are no stairs here to check!");
return B_TRUE;
}
// how can we check the stairs?
getobname(stairs, obname, 1);
sprintf(buf, "How will you check %s", obname);
initprompt(&prompt, buf);
if ((getskill(user, SK_LISTEN) >= PR_ADEPT) && !isdeaf(user)) {
addchoice(&prompt, 'l', "Listen for sounds", NULL, NULL, NULL);
}
if ((getskill(user, SK_PERCEPTION)) && !isblind(user)) {
addchoice(&prompt, 'f', "Check for footprints", NULL, NULL, NULL);
}
if (getskill(user, SK_STEALTH) >= PR_SKILLED) {
addchoice(&prompt, 'p', "Peek at the other end", NULL, NULL, NULL);
}
if (lfhasflag(user, F_ENHANCESMELL)) {
addchoice(&prompt, 's', "Sniff for scents", NULL, NULL, NULL);
}
addchoice(&prompt, '-', "(cancel)", NULL, NULL, NULL);
prompt.maycancel = B_TRUE;
if (prompt.nchoices == 1) {
msg("You have no way to check %s.", obname);
return B_TRUE;
}
ch = getchoice(&prompt);
if ((ch == '-') || (ch == '\0')) {
msg("Cancelled.");
return B_TRUE;
}
c = getstairdestination(stairs, &madenewmap);
if (!c) {
msg("These stairs don't seem to go anywhere!");
return B_TRUE;
}
noredraw = B_TRUE;
// move any lfs at the other end out of the way.
if (movelfsoutofway(c)) {
// can't move them? ie. no adj cells.
inway = c->lf;
}
if (!inway) {
// temporarily put the player at the other end
// purposely not using movelf() because we don't
// want to trigger map enter effects.
origcell = user->cell;
origcell->lf = NULL;
user->cell = c;
c->lf = user;
}
// now actually do the check
if (ch == 'l') {
lifeform_t *lf;
enum SKILLLEVEL slev;
char *movetext[MAXCANDIDATES],thismovetext[BUFLEN];
int nposs = 0,n,movetextcount[MAXCANDIDATES],found,vol;
slev = getskill(user, SK_LISTEN);
msg("You listen at %s...",obname);
more();
if (inway) {
// just get the lf in the way
if (getnoisedetails(inway, N_WALK, thismovetext, NULL, &vol)) {
// doesn't make noise
nposs = 0;
} else {
if (slev >= PR_EXPERT) {
// overwrite name
real_getlfnamea(inway, thismovetext, B_FALSE);
}
movetext[0] = strdup(thismovetext);
movetextcount[0] = 1;
nposs = 1;
}
} else {
// get all lfs within hearing of the other end
for (lf = c->map->lf ; lf ; lf = lf->next) {
if (lf == user) continue;
// get movement text
if (getnoisedetails(lf, N_WALK, thismovetext, NULL, &vol)) continue;
if (slev >= PR_EXPERT) {
// overwrite name
real_getlfnamea(lf, thismovetext, B_FALSE);
}
if (canhear(user, lf->cell, vol)) {
// already have this text?
found = B_FALSE;
for (n = 0; n < nposs; n++) {
if (streq(movetext[n], thismovetext)) {
movetextcount[n]++;
found = B_TRUE;
break;
}
}
if (!found) {
movetext[nposs] = strdup(thismovetext);
movetextcount[nposs] = 1;
nposs++;
}
}
}
}
// announce
if (nposs) {
for (n = 0; n < nposs; n++) {
char amttext[BUFLEN];
if (slev >= PR_EXPERT) { // we're hearing monster names
if (movetextcount[n] == 1) {
strcpy(amttext, "");
} else if (movetextcount[n] <= 3) {
strcpy(amttext, "some ");
} else {
strcpy(amttext, "lots of ");
}
} else { // we're hearing monster sounds
strcpy(amttext, "");
}
if (slev >= PR_EXPERT) {
char *newtext;
if (movetextcount[n] > 1) {
newtext = makeplural(movetext[n]);
msg("You can hear %s%s.", amttext, noprefix(newtext));
free(newtext);
} else {
msg("You can hear %s.", movetext[n]);
}
} else {
msg("You can hear %s%s", amttext, movetext[n]);
}
// free this mem
free(movetext[n]);
}
} else {
msg("You don't hear anything unusual.");
}
} else if (ch == 's') { // smell
lifeform_t *lf;
race_t *smellrace[MAXCANDIDATES];
int nposs = 0,n,smellcount[MAXCANDIDATES], range = 0;
msg("You sniff %s...",obname);
more();
f = lfhasflag(user, F_ENHANCESMELL);
if (f) {
range = f->val[0];
}
if (range) {
// list everyone you can smell.
if (inway) {
// just smell the lf in the way
if (issmellablelf(inway)) {
smellrace[0] = inway->race;
smellcount[0] = 1;
nposs = 1;
} else {
nposs = 0;
}
} else {
// get all lfs you can smell from the other end
for (lf = c->map->lf ; lf ; lf = lf->next) {
int found;
if (lf == user) continue;
if (getcelldist(lf->cell, c) <= range) {
// already have this one?
found = B_FALSE;
for (n = 0; n < nposs; n++) {
if (smellrace[n] == lf->race) {
smellcount[n]++;
found = B_TRUE;
break;
}
}
if (!found) {
smellrace[nposs] = lf->race;
smellcount[nposs] = 1;
nposs++;
}
}
}
}
}
// announce
if (nposs) {
for (n = 0; n < nposs; n++) {
char amttext[BUFLEN];
char *newtext;
if (smellcount[n] == 1) {
strcpy(amttext, "");
} else if (smellcount[n] <= 3) {
strcpy(amttext, "some ");
} else {
strcpy(amttext, "lots of ");
}
if (smellcount[n] > 1) {
newtext = makeplural(smellrace[n]->name);
msg("You can smell %s%s.", amttext, newtext);
free(newtext);
} else {
msg("You can smell %s %s.", needan(smellrace[n]->name) ? "an" : "a", smellrace[n]->name);
}
}
} else {
msg("You don't smell anything unusual.");
}
} else if (ch == 'f') { // footprints
lifeform_t *lf;
object_t *trailob;
char *fpname[MAXCANDIDATES],thisfpname[BUFLEN];
int nposs = 0,n,fpcount[MAXCANDIDATES];
msg("You inspect %s...",obname);
more();
if (inway) {
// just do footprints for the lf in the way
trailob = addtrail(inway, c, inway->facing, B_TRUE, B_FALSE);
if (trailob) {
getobname(trailob, thisfpname, 1);
fpname[0] = strdup(thisfpname);
fpcount[0] = 1;
nposs = 1;
killob(trailob);
} else {
nposs = 0;
}
} else {
// get all lfs which make trails from the other end
for (lf = c->map->lf ; lf ; lf = lf->next) {
if (lf == user) continue;
// within lof of stairs?
if (haslof(lf->cell, c, LOF_WALLSTOP, NULL)) {
trailob = addtrail(lf, c, lf->facing, B_TRUE, B_FALSE);
if (trailob) {
if (canseeob(user, trailob)) {
int found = B_FALSE;
// already a trail like this?
getobname(trailob, thisfpname, 1);
for (n = 0; n < nposs; n++) {
if (streq(fpname[n], thisfpname)) {
fpcount[n]++;
found = B_TRUE;
}
}
if (!found) {
fpname[nposs] = strdup(thisfpname);
fpcount[nposs] = 1;
nposs++;
}
}
killob(trailob);
}
}
}
}
// announce
if (nposs) {
for (n = 0; n < nposs; n++) {
char amttext[BUFLEN];
if (fpcount[n] == 1) {
strcpy(amttext, "");
} else if (fpcount[n] <= 3) {
strcpy(amttext, "several ");
} else { // 4+
strcpy(amttext, "lots of ");
}
msg("You find %s%s.", amttext, fpname[n]);
}
} else {
msg("You don't find any unusual tracks.");
}
} else if (ch == 'p') { // peek
flag_t *awareness;
msg("You peek %s the stairs...", getdirname(stairdir)); more();
// process light sources for the other end (otherwise new
// maps will be dark by default and you might not see anything)
calclight(c->map);
// prevent announcement of the flag we're about to give
user->born = B_FALSE;
// temporarily give the player 360degree sight
awareness = addflag(user->flags, F_AWARENESS, B_TRUE, NA, NA, NULL);
noredraw = B_FALSE; // allow redraws
setlosdirty(user); // this will redraw the screen
askcoords("Peek (ESC when done)->", "Peek (ESC when done)->", TT_NONE, user, UNLIMITED, LOF_DONTNEED, B_FALSE);
killflag(awareness);
user->born = B_TRUE;
} else {
msg("Not implemented yet.");
} // end ways of checking
if (!inway) {
// move user back
user->cell->lf = NULL;
user->cell = origcell;
origcell->lf = user;
}
noredraw = B_FALSE;
if (ch == 'p') {
// if we peeked, then we have to redraw now.
setlosdirty(user);
msg("You return to your original position.");
}
taketime(user, getactspeed(user)*2);
} else if (abilid == OT_A_COOK) { } else if (abilid == OT_A_COOK) {
object_t *water,*o; object_t *water,*o;
race_t *r = NULL; race_t *r = NULL;
@ -5975,6 +6314,63 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_
} else { } else {
// monsters can't cast // monsters can't cast
} }
} else if (spellid == OT_S_INSTANTDISROBE) {
cell_t *newcell = NULL;
int howmany = (power / 4)+1,ndone = 0;
int i,announcethump = B_FALSE;
object_t *o;
target = targcell->lf;
if (!target) {
fizzle(caster);
return B_TRUE;
}
// find cell next to caster
newcell = getrandomadjcell(targcell, WE_WALKABLE, B_NOEXPAND);
if (!newcell) {
fizzle(caster);
return B_TRUE;
}
for (i = 0; i < howmany; i++) {
// pick armour
o = getrandomarmour(target);
if (o) {
char obname[BUFLEN];
// move it
ndone++;
moveob(o, newcell->obpile, o->amt);
if (isplayer(target)) {
getobname(o, obname, o->amt);
if (haslos(player, newcell)) {
msg("Your %s suddenly appears next to you!", noprefix(obname));
} else {
msg("Your %s suddenly vanishes!", noprefix(obname));
announcethump = B_TRUE;
}
} else if (cansee(player, target)) {
char lfname[BUFLEN];
getlfname(target, lfname);
if (haslos(player, newcell)) {
msg("%s%s %s suddenly appears next to it!", lfname, getpossessive(lfname),
noprefix(buf));
} else {
msg("%s%s %s suddenly vanishes!", lfname, getpossessive(lfname),
noprefix(buf));
}
}
} else {
break;
}
}
if (!ndone) {
fizzle(caster);
return B_TRUE;
}
if (announcethump && !isdeaf(player)) {
msg("You hear something hitting the ground next to you.");
}
} else if (spellid == OT_S_INVISIBILITY) { } else if (spellid == OT_S_INVISIBILITY) {
int howlong = 30; int howlong = 30;
int willannounce = B_FALSE; int willannounce = B_FALSE;