From a763c3c4b101063759bc8bcbfa3816aaca208d8f Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Thu, 19 May 2011 20:30:58 +0000 Subject: [PATCH] - [+] issues with drawing off edge of map. - [+] should ALWAYS be blank (' ') - [+] The fire giant forgecaller incinerates you with a flaming morningstar.--More-- HP:-115193/139 - [+] barbarian should start with a heavy weapon (to do heavy blow with) - [+] chang epegasus symbol to Q - [+] stop sprinting when you open a door, attack, etc - [+] "the darkmantle vanishes" "the darkmantle appearS" "the darkmantle steps though the shadows" - [+] when generating humanoid monsters on dark levels without seeindark, high chance of them having a torch/candle - [+] all undead should seeindark - [+] major healing pot doesn't work - [+] crossbow should do more damage * [+] aiming skill - determines accuracy of firearms * [+] change spellbooks to be a single object ("spellbook") - [+] call wind spell - [+] make plants boost power of druid spells - [+] secret iron door showing up as '.' - [+] table shoudl be misc, not dfeature * [+] implement sound volume. 1 - xx * [+] some monsers have f_varlevel. v0 = max. - [+] implement 'say' * [+] bandits should demand a bribe (based on their hit dice) * [+] replace graph paper with cartography skill - [+] lightning bolt (air, goes THROUGH all lfs until the target one. less damage than fireball though.) - [+] no casting spells while prone Initial world map implemention. - [+] maps need flags. * [+] when in world map, calculate rarity differently based on distance from 0,0 * [+] allow walking off edge of forest to new map areas --- ai.c | 25 ++ attack.c | 24 +- defs.h | 43 +++- doc/add_spells.txt | 1 - doc/volumes.txt | 7 + io.c | 168 +++++++++----- io.h | 4 +- lf.c | 565 ++++++++++++++++++++++++++++++++++----------- lf.h | 9 +- log.txt | 359 ++++++++++++++++++++++++++++ map.c | 465 +++++++++++++++++++++++++++++++------ map.h | 8 +- move.c | 164 ++++++++++--- move.h | 1 + nexus.c | 14 +- objects.c | 281 +++++++++++++++++----- save.c | 14 +- spell.c | 238 ++++++++++++++++--- spell.h | 3 + text.c | 2 +- 20 files changed, 1979 insertions(+), 416 deletions(-) create mode 100644 doc/volumes.txt diff --git a/ai.c b/ai.c index 01c2852..42158e7 100644 --- a/ai.c +++ b/ai.c @@ -828,6 +828,24 @@ void aiturn(lifeform_t *lf) { } } + + /////////////////////////////////////////////// + // generic pre-movement actions. + /////////////////////////////////////////////// + if (!haslos(lf, lf->cell)) { + object_t *lamp; + lamp = hasobwithflagval(lf->pack, F_ACTIVATECONFER, F_PRODUCESLIGHT, NA, NA, NULL); + if (lamp && !isactivated(lamp)) { + if (db) dblog(".oO { it's dark and i have an inactive light source (%s) }", lamp->type->name); + if (!operate(lf, lamp, NULL)) { + if (db) dblog(".oO { successfully turned it on. }"); + return; + } else { + if (db) dblog(".oO { failed to turn it on. }"); + } + } + } + /////////////////////////////////////////////// // movement /////////////////////////////////////////////// @@ -1581,6 +1599,13 @@ int lookforobs(lifeform_t *lf, int covetsonly) { if (gothere) { + // cast a spell? + if (cancast(lf, OT_S_CALLWIND, NULL) && haslof(lf->cell, c, LOF_NEED, NULL)) { + if (!castspell(lf, OT_S_CALLWIND, NULL, o, c)) { + // successful + return B_TRUE; + } + } // start walking towards target cell if (aigoto(lf, c, MR_OB, o, AI_FOLLOWTIME)) { return B_FALSE; diff --git a/attack.c b/attack.c index 9f4bee6..ab12379 100644 --- a/attack.c +++ b/attack.c @@ -125,6 +125,7 @@ int attackcell(lifeform_t *lf, cell_t *c) { int gotweapon = B_FALSE; int maxattacks = ALL; int lastweaponidx = -1; + flag_t *sf; // anyone there? if so just attack. if (c->lf) { @@ -166,6 +167,23 @@ int attackcell(lifeform_t *lf, cell_t *c) { } } + // stop sprinting + sf = lfhasflag(lf, F_SPRINTING); + if (sf && sf->val[0]) { + killflag(sf); + } + + // ai code... + if (lfhasflag(lf, F_DEMANDSBRIBE)) { + if (!isplayer(lf) && (attacktype == AT_LF) && isplayer((lifeform_t *)attacktarget)) { + if (demandbribe(lf)) { + // ie. player paid. + taketime(lf, getactspeed(lf)); + return B_FALSE; + } + } + } + // first use our weapon... nweps = 0; wep[nweps] = getweapon(lf); @@ -622,7 +640,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) needses(attackverb) ? "es" : "s", victimname,withwep, nodamstr); } - noise(lf->cell, lf, "sounds of fighting.", NULL); + noise(lf->cell, lf, 3, "sounds of fighting.", NULL); } @@ -938,7 +956,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { msg("%s %ss %s%s.", attackername, getattackverb(lf, wep, damtype[i],dam[i],maxhp), obname,withwep); } else { - noise(lf->cell, NULL, "sounds of fighting.", NULL); + noise(lf->cell, NULL, 3, "sounds of fighting.", NULL); } if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(o->flags, F_HARD)) { @@ -1236,7 +1254,7 @@ int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam) { flag_t *f; for (f = wep->flags->first ; f ; f = f->next) { if (f->id == F_ONFIRE) { - if (f->text) { + if (strlen(f->text)) { *(dam + *ndam) = roll(f->text); } else { *(dam + *ndam) = rolldie(2,6); diff --git a/defs.h b/defs.h index 13050f8..c4325a0 100644 --- a/defs.h +++ b/defs.h @@ -39,11 +39,13 @@ enum SKILL { SK_ARMOUR = 1, SK_ATHLETICS, SK_BACKSTAB, + SK_CARTOGRAPHY, + SK_CHANNELING, SK_COOKING, SK_FIRSTAID, SK_LISTEN, SK_LOCKPICKING, - SK_CHANNELING, + SK_RANGED, SK_SHIELDS, SK_SPELLCASTING, SK_SPOTHIDDEN, @@ -81,7 +83,7 @@ enum SKILL { SK_SS_TRANSLOCATION, SK_SS_WILD, }; -#define MAXSKILLS 42 +#define MAXSKILLS 44 // proficiency levels enum SKILLLEVEL { @@ -248,6 +250,9 @@ enum LFCONDITION { #define MAX_MAPH 20 +#define MINCLEARINGRADIUS 2 +#define MAXCLEARINGRADIUS 5 + //#define MAX_MAPROOMS 10 #define MIN_ROOMH 4 @@ -574,6 +579,8 @@ enum RACECLASS { enum RACE { R_NONE, R_RANDOM, R_HUMAN, + // human monsters + R_BANDIT, // monsters R_BEHOLDER, R_BUGBEAR, @@ -794,6 +801,7 @@ enum OBTYPE { OT_POT_RESTORATION, OT_POT_RUM, OT_POT_SANCTUARY, + OT_POT_SLEEP, OT_POT_SPEED, OT_POT_WATER, OT_POT_JUICE, @@ -821,6 +829,9 @@ enum OBTYPE { OT_SCR_TURNUNDEAD, OT_SCR_WISH, // BOOKS + OT_MANUAL, + OT_SPELLBOOK, + /* OT_MAN_ARMOUR, OT_MAN_ATHLETICS, OT_MAN_BACKSTAB, @@ -829,6 +840,7 @@ enum OBTYPE { OT_MAN_LISTEN, OT_MAN_LOCKPICKING, OT_MAN_MAGITEMUSAGE, + OT_MAN_RANGED, OT_MAN_SHIELDS, OT_MAN_SPELLCASTING, OT_MAN_SPOTHIDDEN, @@ -959,6 +971,7 @@ enum OBTYPE { OT_SB_TELEPORT, OT_SB_TWIDDLE, // -- wild can't be learned from books + */ // spells // -- allomancy OT_S_ABSORBMETAL, @@ -1052,6 +1065,7 @@ enum OBTYPE { // nature OT_S_BARKSKIN, OT_S_CALLLIGHTNING, + OT_S_CALLWIND, OT_S_CALMANIMALS, OT_S_CALMINGSCENT, OT_S_CHARMANIMAL, @@ -1062,6 +1076,7 @@ enum OBTYPE { OT_S_ENDUREELEMENTS, OT_S_ENTANGLE, OT_S_HAILSTORM, + OT_S_LIGHTNINGBOLT, OT_S_LIGHTNINGSTORM, OT_S_PURIFYFOOD, OT_S_QUENCH, @@ -1306,6 +1321,7 @@ enum OBTYPE { OT_HANDAXE, OT_BATTLEAXE, OT_GREATAXE, + OT_WARAXE, // short blades OT_COMBATKNIFE, OT_DAGGER, @@ -1423,6 +1439,8 @@ enum POISONTYPE { enum FLAG { F_NONE, // dummy flag + // map flags + F_MAPCOORDS, // v0+v1 are x/y coords for this map area // object flags F_DEAD, // object will be removed F_CREATEDBY, // object was made by lf id v0, text=real lfname @@ -1737,11 +1755,17 @@ enum FLAG { F_LOSLOF, // v0 = whether this spell needs line of sight // v1 = whether this spell needs line of fire // MONSTER AI FLAGS + F_DEMANDSBRIBE, // lf will demand gold from the player. + F_VARLEVEL, // lf is generated with random level between + // 1 and its map dificulty/depth. + // if v0 is set, this is the max level. + F_MINION, // v0=lfid of minion F_XPVAL, // force xp val for killing this lf to v0 // ...OR if applied to an ability... // monsters with this abil/spell are worth // v0 more xp. 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 // when we could see them. @@ -1779,6 +1803,7 @@ enum FLAG { F_KILLEDBYPLAYER, // did the player kill this lf? // monster noise flags F_NOISETEXT, // val0 is a enum NOISETYPE + // val1 is the volume of the noise // text is "verb^noun" // eg. "shouts^a shout" F_SPELLCASTTEXT, // text is announcement for spellcast @@ -2138,6 +2163,7 @@ enum ERROR { E_CARNIVORE = 51, E_NOOB = 52, E_LEVITATING = 53, + E_PRONE = 54, }; @@ -2204,9 +2230,16 @@ typedef struct map_s { struct lifeform_s *lf,*lastlf; + struct flagpile_s *flags; + struct map_s *next, *prev; } map_t; //////////////// remember to modify save/load for new props!! +typedef struct glyph_s { + int ch; + int colour; +} glyph_t; + typedef struct cell_s { map_t *map; // pointer back to map int x,y; // map coords @@ -2225,16 +2258,12 @@ typedef struct cell_s { struct lifeform_s *lf; // known to player? int known; + struct glyph_s knownglyph; // FOR CONSTRUCTION int visited; } cell_t; -typedef struct glyph_s { - int ch; - int colour; -} glyph_t; - typedef struct celltype_s { int id; // eg. dungeonfloor, wall, door struct glyph_s glyph; diff --git a/doc/add_spells.txt b/doc/add_spells.txt index 1e47b3c..071cc5e 100644 --- a/doc/add_spells.txt +++ b/doc/add_spells.txt @@ -8,7 +8,6 @@ objects.c: remember to have spelllevel (optional) add a scroll to do the same effect, use F_LINKSPELL (optional) add a potion to do the same effect - (optional) add a spellbook to learn it assign AI hint flags so it knows how to cast it spell.c: diff --git a/doc/volumes.txt b/doc/volumes.txt new file mode 100644 index 0000000..ce08a23 --- /dev/null +++ b/doc/volumes.txt @@ -0,0 +1,7 @@ +0 = tiny/mini walking +1 = light footsteps +2 = footsteps, door opening +3 = heavy footsteps, shout, instruments, fighting +4 = extremely loud thumping, war cry +5 = footsteps of SZ_ENORMOUS, explosion +6 = footsteps of SZ_MAX, big explosion diff --git a/io.c b/io.c index 42ba4f5..1d47604 100644 --- a/io.c +++ b/io.c @@ -234,6 +234,55 @@ void anim(cell_t *src, cell_t *dst, char ch, int colour) { needredraw = B_TRUE; } +void animcells(cell_t *src, cell_t **dst, int ndst, int gradual, char ch, char ch2, int colour) { + glyph_t gl; + int i; + + gl.ch = ch; + gl.colour = colour; + + // hide cursor + curs_set(0); + for (i = 0; i < ndst; i++) { + int n; + + if ((i % 2) == 0) { + gl.ch = ch; + } else { + gl.ch = ch2; + } + + if (gradual) { + // update screen each time + updateviewfor(src); + drawlevelfor(player); + } + + if (gradual) { + // draw one at a time + for (n = 0; n <= i; n++) { + drawglyph(&gl, dst[n]->x - viewx, dst[n]->y - viewy); + } + } else { + drawglyph(&gl, dst[i]->x - viewx, dst[i]->y - viewy); + } + + if (gradual) { + wrefresh(gamewin); + usleep(ANIMDELAY); + } + } + + if (!gradual) { + wrefresh(gamewin); + usleep(ANIMDELAY); + } + // show cursor + curs_set(1); + + needredraw = B_TRUE; +} + void animradial(cell_t *src, int radius, char ch, int colour) { glyph_t gl; int i; @@ -399,7 +448,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars) { return ch; } -cell_t *askcoords(char *prompt, int targettype) { +cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange) { static int startlf = -1; int finished = B_FALSE; int moved = B_FALSE; @@ -721,6 +770,11 @@ cell_t *askcoords(char *prompt, int targettype) { } // dont use msg() to avoid 'more's capitalise(buf); + if (srclf && (maxrange != UNLIMITED)) { + if (getcelldist(srclf->cell, c) > maxrange) { + strcat(buf, " [outofrange]"); + } + } wclear(msgwin); mvwprintw(msgwin, 0, 0, "%s",buf); wrefresh(msgwin); @@ -810,6 +864,20 @@ void announceob(enum OBTYPE oid) { } */ +void announcearrival(lifeform_t *lf, map_t *newmap) { + if (isplayer(lf)) { + if (newmap->region == RG_WORLDMAP) { + if (lf->cell->map->region == RG_WORLDMAP) { + msg("You arrive in a new area."); + } else { + msg("You arrive at the surface."); + } + } else if (newmap->habitat == H_DUNGEON) { + msg("You arrive at dungeon level %d.", newmap->depth); + } + } +} + int announceflaggain(lifeform_t *lf, flag_t *f) { int donesomething = B_FALSE; lifeform_t *lf2; @@ -2018,9 +2086,7 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int centre(mainwin, getmaxy(mainwin)-1, "[Press any key]"); getch(); - needredraw = B_TRUE; - clearmsg(); - drawscreen(); + restoregamewindows(); return NULL; } @@ -2056,22 +2122,6 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int break; } } - if (ok) { - if (opts & AO_SPECIFIED) { - int n; - int found = B_FALSE; - // does retlist contain this? - for (n = 0; n < nretobs; n++) { - if (retobs[n] == o) { - found = B_TRUE; - break; - } - } - if (!found) { - ok = B_FALSE; - } - } - } if (ok) { ok = obmatchescondition(o, opts); @@ -2162,18 +2212,14 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int *count = o->amt; } // display game windows again - needredraw = B_TRUE; clearmsg(); - drawscreen(); restoregamewindows(); return o; } } else if ((ch == '-') && (opts & AO_INCLUDENOTHING)) { // select nothing reason = E_SELNOTHING; // display game windows again - needredraw = B_TRUE; - clearmsg(); - drawscreen(); + restoregamewindows(); return NULL; } else if (isdigit(ch) && count) { char temp[2]; @@ -3329,7 +3375,7 @@ void docomms(void) { char ch; flag_t *f; - where = askcoords("Talk to who?", TT_MONSTER); + where = askcoords("Talk to who?", TT_MONSTER, player, UNLIMITED); if (where && where->lf && cansee(player, where->lf)) { lf = where->lf; } @@ -3370,7 +3416,7 @@ void docomms(void) { char lfname2[BUFLEN]; case 'a': sprintf(buf, "Tell %s to attack who?",lfname); - c = askcoords(buf, TT_MONSTER); + c = askcoords(buf, TT_MONSTER, player, UNLIMITED); if (c && c->lf && cansee(player, c->lf)) { lf2 = c->lf; @@ -3445,7 +3491,7 @@ void docomms(void) { break; case 'y': msg("You shout at %s!", lfname); - noise(where, player, "someone shouting!", NULL); + noise(where, player, 3, "someone shouting!", NULL); break; } taketime(player, getactspeed(player)); @@ -3746,6 +3792,7 @@ void dovendingmachine(lifeform_t *lf, object_t *vm) { } killobpile(op); + restoregamewindows(); } @@ -4288,7 +4335,7 @@ void doexplain(char *question) { while (!done) { //sprintf(buf, "Select glyph to explain (ESC to cancel):"); - where = askcoords(question, TT_NONE); + where = askcoords(question, TT_NONE, player, UNLIMITED); if (!where) { clearmsg(); break; @@ -4668,7 +4715,7 @@ void doselguntarget(void) { getobname(gun, gunname, 1); sprintf(buf, "Aim %s where?",gunname); - where = askcoords(buf, TT_MONSTER); + where = askcoords(buf, TT_MONSTER, player, UNLIMITED); if (where) { if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) { setguntarget(player, where->lf); @@ -4740,7 +4787,7 @@ void dothrow(obpile_t *op) { // ask where to throw it sprintf(buf2, "Throw %s where?",buf); - where = askcoords(buf2, TT_MONSTER); + where = askcoords(buf2, TT_MONSTER, player, UNLIMITED); if (where) { cell_t *newwhere = NULL; @@ -4913,39 +4960,36 @@ 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; cell = getcellat(map, x + viewx, y + viewy); + if (cell) { - glyph_t glyph,screenglyph; - int needdraw = B_FALSE; - getcellglyph(&glyph, cell, player); - //drawglyph(&glyph, x - viewx, y - viewy); + } else { + glyph.ch = ' '; + glyph.colour = C_GREY; + } - // only draw if screen char/colour is different - /* - if (cell == player->cell) { - dblog("test"); - } - */ - screenglyph.ch = mvwinch(gamewin, y, x) & A_CHARTEXT; - if (screenglyph.ch != glyph.ch) { + // 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; - } else { - screenglyph.colour = PAIR_NUMBER(mvwinch(gamewin, y, x) & A_COLOR); - if (screenglyph.colour != glyph.colour) { - needdraw = B_TRUE; - } } - if (needdraw) { - drawglyph(&glyph, x, y); - 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++; + } + if (needdraw) { + 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++; } } } @@ -7637,6 +7681,10 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s %s missing one eye.", you(lf), is(lf)); y++; } + if (hasjob(lf, J_DRUID)) { + mvwprintw(mainwin, y, 0, "%s spells are boosted by nearby plants.", isplayer(lf) ? "Your" : "Its"); + y++; + } // flags which aren't really intrinsics if (lfhasflag(lf, F_VEGETARIAN)) { @@ -8092,7 +8140,11 @@ void tombstone(lifeform_t *lf) { centre(mainwin, y, "R.I.P."); y++; //printf("%s\n",lf->name); centre(mainwin, y, "%s (%ld points)",pname, calcscore(lf)); y++; - centre(mainwin, y, "Died on level %d of the dungeon.", lf->cell->map->depth); y++; + if (lf->cell->map->region == RG_WORLDMAP) { + centre(mainwin, y, "Died in the forest."); + } else { + centre(mainwin, y, "Died on level %d of the dungeon.", lf->cell->map->depth); y++; + } p = strtok_r(lf->lastdam,"^", &dummy); if (p) { diff --git a/io.h b/io.h index 4371f3d..8f3f952 100644 --- a/io.h +++ b/io.h @@ -5,10 +5,12 @@ void addheading(prompt_t *p, char *text); void addmsghist(char *text); void addpromptq(prompt_t *p, char *q); void anim(cell_t *src, cell_t *dst, char ch, int colour); +void animcells(cell_t *src, cell_t **dst, int ndst, int gradual, char ch, char ch2, int colour); void animradial(cell_t *src, int radius, char ch, int colour); void animradialorth(cell_t *src, int radius, char ch, int colour); void animsky(cell_t *src, char ch, int colour); //void announceob(enum OBTYPE oid); +void announcearrival(lifeform_t *lf, map_t *newmap); int announceflaggain(lifeform_t *lf, flag_t *f); int announceflagloss(lifeform_t *lf, flag_t *f); int announceobflaggain(object_t *o, flag_t *f); @@ -18,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); +cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange); char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def); void centre(WINDOW *win, int y, char *format, ... ); int chartodir(char ch); diff --git a/lf.c b/lf.c index e8a21d5..e911441 100644 --- a/lf.c +++ b/lf.c @@ -412,6 +412,11 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { objecttype_t *ot; // TODO: check for mute? + if (isprone(lf)) { + reason = E_PRONE; + return B_FALSE; + } + reason = E_OK; ot = findot(oid); @@ -580,6 +585,7 @@ int canhear(lifeform_t *lf, cell_t *dest) { // and you're not blind. // (you're too engrossed in the battle) if (isplayer(lf) && isinbattle(lf)) { + if (getcelldist(lf->cell, dest) != 1) return B_FALSE; } @@ -1006,6 +1012,9 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar case E_LOWIQ: msg("You are not smart enough to cast spells."); break; + case E_PRONE: + msg("You can't cast spells while prone."); + break; default: msg("For some reason, you can't cast that."); break; @@ -1016,7 +1025,6 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar willflag = lfhasflagval(lf, F_CANWILL, sid, NA, NA, NULL); - // special case if (!willflag) { f = lfhasflag(lf, F_NEEDOBFORSPELLS); @@ -1094,6 +1102,21 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } } + // boost power? + if (hasjob(lf, J_DRUID)) { + int n; + int boost = 0; + for (n = 0; n < lf->nlos; n++) { + if (lf->los[n]->lf && getraceclass(lf->los[n]->lf) == RC_PLANT) { + boost++; + } else if (hasobofclass(lf->los[n]->obpile, OC_FLORA)) { + boost++; + } + } + power += boost; + limit(&power, NA, 10); + } + // cast the spell addflag(lf->flags, F_CASTINGSPELL, sid, NA, NA, NULL); rv = dospelleffects(lf, sid, power, targlf, targob, targcell, B_UNCURSED, NULL); @@ -1249,6 +1272,98 @@ void debug(lifeform_t *lf) { } } +// returns true if the player pays. +int demandbribe(lifeform_t *lf) { + char lfname[BUFLEN]; + int amtwanted,amtgiven,totmoney; + int hd; + char buf[BUFLEN], answer[BUFLEN]; + object_t *gold, *mongold; + int satisfied = B_FALSE; + int nminions; + int i,heard; + lifeform_t *minion[MAXCANDIDATES]; + + hd = gethitdice(lf); + gold = hasob(player->pack, OT_GOLD); + if (gold) { + totmoney = countmoney(player); + } else { + totmoney = 0; + } + mongold = hasob(lf->pack, OT_GOLD); + amtwanted = rnd(hd*25, hd*100); + + getlfname(lf, lfname); + if (say(lf, "Hand over all your gold!", 2)) { + heard = B_TRUE; + } else { + heard = B_FALSE; + } + + if (heard) { + int doagain = B_TRUE; + more(); + while (doagain) { + sprintf(buf, "How much gold will you give %s (you have $%d)", lfname, totmoney); + askstring(buf, '?', answer, BUFLEN, NULL); + amtgiven = atoi(answer); + if (amtgiven > totmoney) { + msg("You don't have that much gold!"); more(); + doagain = B_TRUE; + } else if (amtgiven < 0) { + msg("Please enter a valid number."); more(); + doagain = B_TRUE; + } else { + doagain = B_FALSE; + } + } + limit(&amtgiven, 0, totmoney); + } else { + amtgiven = 0; + } + + if (gold && (amtgiven > 0)) { + gold->amt -= amtgiven; + + if (mongold) { + mongold->amt += amtgiven; + } else { + char gbuf[BUFLEN]; + sprintf(gbuf, "%d gold", amtgiven); + mongold = addob(lf->pack, gbuf); + } + + if ((amtgiven == totmoney) || (amtgiven >= amtwanted)) { + // always succeed + say(lf, "Pleasure doing business with you!", 2); + satisfied = B_TRUE; + } else { + say(lf, "Then die!", 3); + satisfied = B_FALSE; + } + } else { + // TODO: luck check to receive money ? + say(lf, "Then die!", 3); + satisfied = B_FALSE; + } + + + // if you gave the gold, mosnter becomes peaceful + if (satisfied) { + makepeaceful(lf); + // also make any of its minions peaceful + for (i = 0; i < nminions; i++) { + makepeaceful(minion[i]); + } + } + + // either way, kill bribe flag + killflagsofid(lf->flags, F_DEMANDSBRIBE); + + return satisfied; +} + void die(lifeform_t *lf) { char buf[BUFLEN]; flag_t *f; @@ -2296,7 +2411,7 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) { } } if (nposs) { - teleportto(lf, poss[rnd(0,nposs-1)], B_FALSE); // no smoke + //teleportto(lf, poss[rnd(0,nposs-1)], B_FALSE); // no smoke abilityeffects(lf, OT_A_DARKWALK, poss[rnd(0,nposs-1)], NULL, NULL); } } @@ -2393,6 +2508,9 @@ skill_t *findskillbyname(char *name) { for (s = firstskill ; s ; s = s->next) { if (!strcasecmp(s->name, name)) return s; } + for (s = firstskill ; s ; s = s->next) { + if (!strcasestr(s->name, name)) return s; + } return NULL; } @@ -2752,6 +2870,22 @@ int getactspeed(lifeform_t *lf) { return speed; } +void getadjallies(lifeform_t *lf, lifeform_t **adjally, int *nadjallies) { + int d; + for (d = DC_N; d <= DC_NW; d++) { + cell_t *c; + c = getcellindir(lf->cell, d); + if (c && c->lf) { + if (areallies(lf, c->lf) || areenemies(lf, c->lf)) { + if (!isimmobile(c->lf)) { + adjally[*nadjallies] = c->lf; + (*nadjallies)++; + } + } + } + } +} + enum ALLEGIENCE getallegiance(lifeform_t *lf) { flag_t *f; f = lfhasflag(lf, F_CHARMEDBY); @@ -3389,6 +3523,9 @@ int gethidemodifier(lifeform_t *lf) { } int gethitdice(lifeform_t *lf) { + if (isplayer(lf) || lfhasflag(lf, F_VARLEVEL)) { + return lf->level; + } return (lf->maxhp / 4); } @@ -3584,6 +3721,21 @@ enum LFCONDITION getlfcondition(lifeform_t *lf) { return C_DEAD; } +int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions) { + flag_t *f; + lifeform_t *min; + *nminions = 0; + for (f = lf->flags->first ; f ; f = f->next) { + if (f->id == F_MINION) { + min = findlf(lf->cell->map, f->val[0]); + if (min) { + (minion[*nminions]) = min; + (*nminions)++; + } + } + } + return *nminions; +} int getnightvisrange(lifeform_t *lf) { int range = -1; // default @@ -4027,10 +4179,12 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) { // construct job string strcpy(jobstring, ""); - j = getjob(lf); - if (j) { - sprintf(jobstring, " %s", j->name); - jobstring[1] = tolower(jobstring[1]); + if (!lfhasflag(lf, F_NOJOBTEXT)) { + j = getjob(lf); + if (j) { + sprintf(jobstring, " %s", j->name); + jobstring[1] = tolower(jobstring[1]); + } } if (isplayer(lf)) { @@ -4331,16 +4485,18 @@ object_t *getrandomarmour(lifeform_t *lf) { return o; } -/* -int getrandommonlevel(int depth) { - int lev; - int max; - max = (depth / 3); - if (max < 1) max = 1; - lev = rnd(1,max); - return lev; +int getrandommonlevel(race_t *r, map_t *m) { + flag_t *f; + int wantlev = 1; + f = hasflag(r->flags, F_VARLEVEL); + if (f) { + wantlev = rnd(1, getmapdifficulty(m)); + if (f->val[0] > 0) { + limit(&wantlev, 1, f->val[0]); + } + } + return wantlev; } -*/ race_t *getrandomrace(map_t *map, int forcedepth) { //int rarity; @@ -4353,14 +4509,10 @@ race_t *getrandomrace(map_t *map, int forcedepth) { int raritymin,raritymax; // determine rarity of lf to generate - if (forcedepth > 0) { + if (forcedepth != NA) { depth = forcedepth; } else { - if (map) { - depth = map->depth; - } else { - depth = rnd(1,MAXDEPTH); - } + depth = getmapdifficulty(map); } getrarity(depth, &raritymin, &raritymax, RARITYVARIANCELF, B_TRUE); @@ -4453,6 +4605,17 @@ race_t *getreallyrandomrace(void) { return r; } +enum SKILL getrandomskill(void) { + int sel,count = 0; + skill_t *sk; + sel = rnd(0,MAXSKILLS-1); + for (sk = firstskill ; sk ; sk = sk->next) { + if (count == sel) return sk->id; + count++; + } + return SK_NONE; +} + object_t *getrestob(lifeform_t *lf) { object_t *o,*bestob = NULL; int bestval = -1; @@ -5062,13 +5225,28 @@ int giveskill(lifeform_t *lf, enum SKILL id) { newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL); newf->lifetime = FROMJOB; } + } else if (id == SK_CARTOGRAPHY) { + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { + if (f->val[1] == PR_NOVICE) { + msg("You now make basic maps of your surroundings."); + } else if (f->val[1] == PR_BEGINNER) { + msg("Your map will now show the location of staircases."); + } else if (f->val[1] == PR_ADEPT) { + msg("Your map will now show the location of doors."); + } else if (f->val[1] == PR_SKILLED) { + msg("You will no longer forget your surroundings."); + } else if (f->val[1] == PR_EXPERT) { + msg("Your map will now show the location of objects."); + } else if (f->val[1] == PR_MASTER) { + } + } } else if (id == SK_COOKING) { if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { if (f->val[1] == PR_NOVICE) { msg("You can now recognise rotting food."); } else if (f->val[1] == PR_BEGINNER) { msg("You can now recognise all kinds of bad food."); - } else if (f->val[2] == PR_BEGINNER) { + } else if (f->val[1] == PR_ADEPT) { newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); newf->lifetime = FROMJOB; } @@ -5087,9 +5265,15 @@ int giveskill(lifeform_t *lf, enum SKILL id) { } else if (f->val[1] == PR_ADEPT) { msg("You can now determine the direction sounds are coming from."); } else if (f->val[1] == PR_EXPERT) { - msg("You can now recognise monsters based on sound."); + msg("You can now identify monsters based on sound."); } else if (f->val[1] == PR_MASTER) { - msg("You can now accurately locate monsters based on sound."); + msg("You can now locate monsters based on sound."); + } + } + } else if (id == SK_RANGED) { + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { + if (f->val[1] == PR_MASTER) { + msg("Your no longer suffer ranged-based accuracy penalties when firing."); } } } else if (id == SK_STEALTH) { @@ -5184,9 +5368,6 @@ int giveskill(lifeform_t *lf, enum SKILL id) { int giveskilllev(lifeform_t *lf, enum SKILL id, enum SKILLLEVEL slev) { flag_t *f; - if (id == SK_AXES) { - dblog("xxx"); - } f = lfhasflagval(lf, F_HASSKILL, id, NA, NA, NULL); if (!f) { // give one rank of the skill @@ -5935,7 +6116,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_MENTAL, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_MASTER, NA, NULL); - addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); + //addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); for (i = 1; i < MAXSKILLS; i++) { addflag(lastjob->flags, F_CANLEARN, i, NA, NA, NULL); } @@ -5959,8 +6140,9 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 potions of healing"); addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); @@ -5982,6 +6164,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastjob->flags, F_DETECTMETAL, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_ALLOMANCY, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_NOVICE, NA, NULL); mayusespellschool(lastjob->flags, SS_ALLOMANCY, F_CANCAST); @@ -6000,18 +6183,19 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CON, CN_FIT, NA, NULL); addflag(lastjob->flags, F_HITDICE, 1, 6, NA, NULL); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "hand axe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "axe"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); addflag(lastjob->flags, F_STARTSKILL, SK_AXES, PR_BEGINNER, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LOCKPICKING, NA, NA, NULL); @@ -6051,6 +6235,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); @@ -6068,6 +6253,7 @@ void initjobs(void) { // skills addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); @@ -6113,6 +6299,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LORE_ARCANA, NA, NA, NULL); @@ -6140,6 +6327,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "300-350 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 potions of rum"); // skills + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_UNARMED, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); @@ -6157,6 +6345,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins"); addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LISTEN, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_BACKSTAB, PR_BEGINNER, NA, NULL); @@ -6202,6 +6391,7 @@ void initjobs(void) { addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); //addflag(lastjob->flags, F_MPREGEN, 1, SK_SPELLCASTING, 35, NULL); // can detect magic objects + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_ARCANA, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CHANNELING, PR_NOVICE, NA, NULL); @@ -6277,10 +6467,39 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_SCROLL, NA, NULL); // TODO: humans start with a random job sometimes? - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); // addflag(lastrace->flags, F_RESTHEALMPAMT, 1, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + // human monsters... + addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL); + addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); + addflag(lastrace->flags, F_DEMANDSBRIBE, NA, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 2, 2, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "1-100 gold coins"); + addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_WEAPON, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_ARMOUR, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_ARMOUR, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_SCROLL, NA, NULL); + //addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); + addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOJOBTEXT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTJOB, 15, J_WIZARD, NA, NULL); + addflag(lastrace->flags, F_STARTJOB, 50, J_ROGUE, NA, NULL); + // monsters addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_GENIUS, NA, NULL); @@ -6324,7 +6543,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "roars^a roars"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roars"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, 2, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6432,7 +6651,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addrace(R_GIANTHILL, "hill giant", 160, 'H', C_BROWN, MT_FLESH, RC_HUMANOID); @@ -6457,7 +6676,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); addflag(lastrace->flags, F_WANTS, OT_BOULDER, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); @@ -6489,7 +6708,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6517,7 +6736,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); addflag(lastrace->flags, F_MPDICE, 0, 9, NA, NULL); addflag(lastrace->flags, F_MPREGEN, 1, NA, NA, NULL); @@ -6549,8 +6768,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_STR, ST_TITANIC, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, DX_SWIFT, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "bellows^a bellow"); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^crackling flames."); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 3, NA, "^crackling flames."); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); addflag(lastrace->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_BURNINGWAVE, 3, 3, "pw:6;"); @@ -6577,7 +6796,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-40 gold coins"); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6602,7 +6821,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10-20 arrows"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "hand axe"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-40 gold coins"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll"); @@ -6626,7 +6845,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "spear"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "buckler"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_QUICKBITE, 1, 6, 2, NULL); addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); @@ -6650,7 +6869,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 40, OC_POTION, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); //addflag(lastrace->flags, F_STARTJOB, 25, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); @@ -6676,7 +6895,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "1-5 javelins"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-50 gold coins"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); @@ -6702,7 +6921,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "1-15 bolts"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-25 gold coins"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); @@ -6727,7 +6946,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL); addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "club"); addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "leather armour"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); @@ -6761,7 +6980,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_PHALANX, 5, NA, 1, "hobgoblin"); addflag(lastrace->flags, F_MINIONS, 50, 1, 2, "goblin"); @@ -6790,7 +7009,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 30, OC_POTION, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_PHALANX, 8, NA, 1, "hobgoblin"); addflag(lastrace->flags, F_MINIONS, 50, 1, 4, "goblin"); @@ -6822,7 +7041,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 33, NA, NA, "buckler"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-10 gold coins"); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -6901,6 +7120,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 66, NA, NULL); addflag(lastrace->flags, F_HITDICE, 7, 0, NA, NULL); addflag(lastrace->flags, F_EVASION, -5, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); @@ -6930,6 +7150,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 55, NA, NULL); addflag(lastrace->flags, F_HITDICE, 13, 8, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -6958,6 +7179,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 50, NA, NULL); addflag(lastrace->flags, F_HITDICE, 35, 0, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -6986,6 +7208,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL); addflag(lastrace->flags, F_HITDICE, 1, 3, NA, NULL); addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL); @@ -7004,7 +7227,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); //addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL); @@ -7015,6 +7238,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL); addflag(lastrace->flags, F_HITDICE, 2, 3, NA, NULL); addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL); @@ -7034,7 +7258,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); //addflag(lastrace->flags, F_STARTJOB, 20, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); @@ -7045,6 +7269,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 81, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 81, NA, NULL); addflag(lastrace->flags, F_HITDICE, 3, 3, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -7062,12 +7287,13 @@ void initrace(void) { addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_OPERABLE, B_COVETS, NA, NULL); // ie. tech addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, B_COVETS, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addrace(R_PEGASUS, "pegasus", 130, 'H', C_GREY, MT_FLESH, RC_MAGIC); + addrace(R_PEGASUS, "pegasus", 130, 'Q', C_GREY, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 57, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 57, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL); @@ -7086,7 +7312,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 2, 2, NULL); addflag(lastrace->flags, F_SWOOPRANGE, 4, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screams in pain^screams of pain"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 4, NA, "screams in pain^screams of pain"); addflag(lastrace->flags, F_RESISTMAG, 5, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 25, NA, NA, NULL); @@ -7122,6 +7348,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 72, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL); addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); @@ -7132,7 +7359,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 75, NA, NA, "1-10 arrows"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-30 gold coins"); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "shouts^a shout"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "plays its pipes"); addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -7156,7 +7383,7 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "hisses^a hiss"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "hisses^a hiss"); addflag(lastrace->flags, F_SEEINDARK, 8, NA, NA, NULL); addflag(lastrace->flags, F_CANSEETHROUGHMAT, MT_GAS, NA, NA, NULL); addflag(lastrace->flags, F_AUTOCREATEOB, 1, NA, NA, "cloud of smoke"); @@ -7183,7 +7410,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_ACIDATTACK, NA, NA, "1d6+5"); addflag(lastrace->flags, F_TREMORSENSE, 5, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^slurping"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slurping"); addflag(lastrace->flags, F_DTIMMUNE, DT_ACID, B_TRUE, NA, NULL); addflag(lastrace->flags, F_AUTOCREATEOB, 0, NA, NA, "puddle of acid"); addflag(lastrace->flags, F_DIESPLATTER, 3, NA, NA, "splash of acid"); @@ -7209,7 +7436,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^crackling flames"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^crackling flames"); addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SS_FIRE, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -7220,6 +7447,7 @@ void initrace(void) { addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 70, NA, NULL); addflag(lastrace->flags, F_HITDICE, 3, 0, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -7328,7 +7556,7 @@ void initrace(void) { // animals addrace(R_BAT, "giant bat", 3, 'B', C_BROWN, MT_FLESH, RC_ANIMAL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, ""); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 88, NA, ""); addflag(lastrace->flags, F_RARITY, H_FOREST, 95, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -7347,11 +7575,11 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_FOREST, 63, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 73, NA, ""); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 3, 3, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -7363,14 +7591,14 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "roars^a roars"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d4;"); addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 52, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_FOREST, 52, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 62, NA, ""); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 5, 5, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -7382,7 +7610,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "roars^a roars"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); @@ -7451,7 +7679,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:2d4;"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "roars^a roars"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); addrace(R_DOGBLINK, "blink dog", 35, 'd', C_YELLOW, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); @@ -7471,7 +7699,7 @@ void initrace(void) { addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_BLINK, 2, 2, "pw:1;"); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 1, NA, "whines in pain^whining"); addrace(R_DOGDEATH, "death hound", 40, 'd', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -7493,7 +7721,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 24, "10-15"); addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL); addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); @@ -7517,12 +7745,12 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, ""); - addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, IQ_AVERAGE, NA, NULL); @@ -7540,14 +7768,16 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL); addflag(lastrace->flags, F_SWOOPRANGE, 2, NA, NA, NULL); addflag(lastrace->flags, F_LEVRACE, 4, R_HAWK, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain"); addrace(R_HAWK, "hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 77, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); @@ -7568,12 +7798,14 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL); addflag(lastrace->flags, F_SWOOPRANGE, 3, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_LEVRACE, 8, R_HAWKBLOOD, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain"); addrace(R_HAWKBLOOD, "blood hawk", 1, 'A', C_RED, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 65, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); @@ -7593,8 +7825,9 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, 3, 3, NULL); addflag(lastrace->flags, F_SWOOPRANGE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 7, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain"); addrace(R_HAWKFROST, "frost hawk", 1, 'A', C_CYAN, MT_FLESH, RC_ANIMAL); // 'A' for Avian addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -7619,13 +7852,15 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_S_COLDBURST, 2, 2, "pw:2;"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "screeches"); addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "screeches in pain^screeches of pain"); + addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 3, NA, "screeches in pain^screeches of pain"); addrace(R_LEECH, "giant leech", 10, 'j', C_MAGENTA, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 81, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 84, NA, ""); addflag(lastrace->flags, F_HITDICE, 3, 1, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); @@ -7665,6 +7900,7 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, 1, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); @@ -7696,6 +7932,7 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addrace(R_SNAKE, "brown snake", 3, 's', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, ""); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -7715,7 +7952,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addrace(R_SNAKECARPET, "carpet snake", 3, 's', C_GREY, MT_FLESH, RC_ANIMAL); @@ -7736,7 +7973,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addrace(R_SNAKETREE, "tree snake", 3, 's', C_GREEN, MT_FLESH, RC_ANIMAL); @@ -7758,7 +7995,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 2, 2, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); @@ -7781,7 +8018,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing"); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "spits"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); @@ -7807,7 +8044,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); @@ -7894,7 +8131,7 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, ""); - addflag(lastrace->flags, F_RARITY, H_FOREST, 87, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 97, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, 2, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); @@ -7908,14 +8145,14 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 8, 8, NULL); addflag(lastrace->flags, F_LEVRACE, 5, R_WOLF, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addrace(R_WOLF, "wolf", 25, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); - addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 90, NA, ""); addflag(lastrace->flags, F_HITDICE, 3, 3, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d5"); @@ -7930,7 +8167,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); // insects addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL); @@ -7972,8 +8209,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); - addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "buzzes angrily^an angry buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addrace(R_GIANTBLOWFLY, "giant blowfly", 2, 'i', C_WHITE, MT_FLESH, RC_INSECT); @@ -7996,8 +8233,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); - addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "buzzes angrily^an angry buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addrace(R_STIRGE, "stirge", 10, 'i', C_BROWN, MT_FLESH, RC_INSECT); @@ -8017,8 +8254,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); - addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "buzzes angrily^an angry buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing"); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); @@ -8044,7 +8281,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^scuttling"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^scuttling"); addflag(lastrace->flags, F_TREMORSENSE, 3, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addrace(R_GLOWBUG, "glowbug", 1, 'i', C_WHITE, MT_FLESH, RC_INSECT); @@ -8055,7 +8292,7 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, ""); - addflag(lastrace->flags, F_RARITY, H_FOREST, 87, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 97, NA, ""); addflag(lastrace->flags, F_HITDICE, 1, 0, NA, ""); addflag(lastrace->flags, F_EVASION, 60, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, NA, NA, "1d2-1"); @@ -8067,7 +8304,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 2, NA, "^buzzing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); // undead @@ -8112,7 +8349,6 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); - addrace(R_GHAST, "ghast", 50, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD); addflag(lastrace->flags, F_UNDEAD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_SMART, NA, NULL); @@ -8129,6 +8365,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -8171,6 +8408,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); // special monsters @@ -9118,16 +9356,19 @@ void autoskill(lifeform_t *lf) { } nweps++; } + if (isfirearm(o) && canweild(lf, o)) { + giveskilllev(lf, SK_RANGED, slev); + } if (isarmour(o) && canwear(lf, o, BP_NONE)) { flag_t *f; // evasion penalty? f = hasflag(o->flags, F_EVASION); if (f && (f->val[0] < 0)) { - giveskilllev(lf, SK_ARMOUR, PR_NOVICE); + giveskilllev(lf, SK_ARMOUR, slev); } } if (isshield(o) && canwear(lf, o, BP_NONE)) { - giveskilllev(lf, SK_SHIELDS, PR_NOVICE); + giveskilllev(lf, SK_SHIELDS, slev); } } } @@ -9575,6 +9816,7 @@ int makenauseated(lifeform_t *lf, int amt, int howlong) { void makenoise(lifeform_t *lf, enum NOISETYPE nid) { flag_t *f; char *verb = NULL, *noun = NULL; + int volume; if (lfhasflag(lf, F_FROZEN)) { // can't make noise if frozen! @@ -9586,6 +9828,8 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { char *dummy; char noisetext[BUFLEN]; + volume = f->val[1]; + if (f->text[0] == '^') { verb = NULL; noun = strtok_r(f->text, "^", &dummy); @@ -9595,39 +9839,52 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { } sprintf(noisetext, "%s.",noun); - noise(lf->cell, lf, noisetext, verb); + noise(lf->cell, lf, volume, noisetext, verb); } else { // some defaults if (nid == N_WALK) { + enum LFSIZE sz; char movetext[BUFLEN]; strcpy(movetext, ""); - switch (getlfsize(lf)) { + sz = getlfsize(lf); + switch (sz) { case SZ_MINI: case SZ_TINY: + volume = 0; break; case SZ_SMALL: - noise(lf->cell, lf, "light footsteps.", NULL); + volume = 1; + strcpy(movetext, "light footsteps."); break; case SZ_MEDIUM: case SZ_HUMAN: - noise(lf->cell, lf, "footsteps.", NULL); + volume = 2; + strcpy(movetext, "footsteps."); break; case SZ_LARGE: - noise(lf->cell, lf, "heavy footsteps.", NULL); + 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: - noise(lf->cell, lf, "extremely loud thumping.", NULL); + volume = 6; + strcpy(movetext, "extremely loud thumping."); break; default: break; } if (strlen(movetext)) { - noise(lf->cell, lf, movetext, NULL); + noise(lf->cell, lf, volume, movetext, NULL); } } else if (nid == N_WARCRY) { - noise(lf->cell, lf, "a blood-curdling war cry!", "shouts a blood-curdling war-cry!"); + noise(lf->cell, lf, 4, "a blood-curdling war cry!", "shouts a blood-curdling war-cry!"); } } @@ -9865,20 +10122,43 @@ int needstorest(lifeform_t *lf, char *validchars) { return need; } -void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { +// returns TRUE if the player heard it. +int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seetext) { lifeform_t *l; + int sounddist; + int rv = B_FALSE; + if (gamemode != GM_GAMESTARTED) { + return B_FALSE; + } + + // sound will travel 2*volume cells + sounddist = 2 * volume; + + if (noisemaker && (noisemaker->race->id == R_BANDIT)) { + dblog("xxx"); + } + // if anything nearby hears it, it might respond for (l = c->map->lf; l ; l = l->next) { + int dist; // if you make a noise while swapping position with // something, its ->cell will be null here! + dist = getcelldist(l->cell, c); + if ((l != noisemaker) && (l->cell)) { int difficulty; //if (canhear(l, c) && haslos(l, c)) { + if (isplayer(l)) { + dblog("xxx"); + } // listen check difficulty is based on sound distance vs max hearing distance - difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 18); + difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); + // listen bonus is the sound volume - if (canhear(l, c) && (haslos(l, c) || skillcheck(l, SC_LISTEN, difficulty, 0))) { + if (canhear(l, c) && + (haslos(l, c) || + ((dist <= sounddist) && skillcheck(l, SC_LISTEN, difficulty, volume)))) { flag_t *f; // announce? if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) { @@ -9888,6 +10168,7 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { char lfname[BUFLEN]; getlfname(noisemaker, lfname); msg("%s %s.", lfname, seetext); + rv = B_TRUE; } } else if (text && !lfhasflag(l, F_DONELISTEN)) { char textnopunc[BUFLEN]; @@ -9940,15 +10221,20 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { } } else if (slev >= PR_EXPERT) { msg("You hear %s%s to the %s%c", lfname, distbuf, dirbuf, punc); + rv = B_TRUE; } else if (slev >= PR_ADEPT) { msg("You hear %s%s to the %s%c", textnopunc, distbuf, dirbuf, punc); + rv = B_TRUE; } else if (slev >= PR_BEGINNER) { msg("You hear %s%s%c", textnopunc, distbuf, punc); + rv = B_TRUE; } else { msg("You hear %s", text); + rv = B_TRUE; } } else { msg("You hear %s", text); + rv = B_TRUE; } // only hear one thing per turn. addflag(l->flags, F_DONELISTEN, B_TRUE, NA, NA, NULL); @@ -9964,6 +10250,7 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { // wake up! if (isplayer(l)) { msg("A nearby noise awakens you!"); + rv = B_TRUE; } killflag(f); } else { @@ -9973,6 +10260,7 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { // wake up! if (isplayer(l)) { msg("A nearby noise awakens you!"); + rv = B_TRUE; } killflag(f); } @@ -9995,6 +10283,7 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { } } } + return rv; } @@ -10641,6 +10930,31 @@ int safetorest(lifeform_t *lf) { return B_TRUE; } +int say(lifeform_t *lf, char *text, int volume) { + char buf[BUFLEN]; + char verb[BUFLEN]; + char noun[BUFLEN]; + if (volume < 2) { + strcpy(verb, "whispers"); + strcpy(noun, "whispering."); + } else if (volume == 2) { + strcpy(verb, "says"); + strcpy(noun, "voices."); + } else if (volume == 3) { + strcpy(verb, "shouts"); + strcpy(noun, "raised voices."); + } else if (volume == 4) { + strcpy(verb, "roars"); + strcpy(noun, "roaring voices!"); + } else if (volume > 4) { + strcpy(verb, "bellows"); + strcpy(noun, "bellowing voices!"); + } + + sprintf(buf, "%s \"%s\"", verb, text); + + return noise(lf->cell, lf, volume, noun, buf); +} // returns TRUE if something happened int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus) { @@ -10986,18 +11300,20 @@ void initskills(void) { addskill(SK_ARMOUR, "Armour", "Helps maintain armour, reducing evasion penalties and armour damage."); addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery."); addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen."); + addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps."); addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals."); addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison."); addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds."); addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks."); addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items."); - addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once."); + addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun."); addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block projectiles."); addskill(SK_SPELLCASTING, "Sorcery", "Determines your ability to cast spells from all schools."); addskill(SK_SPOTHIDDEN, "Searching", "Helps you to spot hidden traps or creatures."); addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently."); addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items."); addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps."); + addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once."); // knowledge addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising magical objects and creatures."); addskill(SK_LORE_DEMONS, "Lore:Demonology", "Determines your knowledge about demons."); @@ -11159,7 +11475,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r if (lfhasflag(lf, F_ASLEEP)) { attrib = 0; } else { - attrib = (getskill(lf, SK_LISTEN)*2); + attrib = getskill(lf, SK_LISTEN); } break; case SC_RESISTMAG: @@ -11594,7 +11910,7 @@ int takeoff(lifeform_t *lf, object_t *o) { } void taketime(lifeform_t *lf, long howlong) { - int db = B_FALSE; + int db = B_TRUE; map_t *map; if (lfhasflag(lf, F_NOTIME)) { @@ -11625,7 +11941,7 @@ void taketime(lifeform_t *lf, long howlong) { // if you don't have a map, start forgetting the dungeon if (isplayer(lf)) { - if (!lfhasflag(lf, F_PHOTOMEM)) { + if (!lfhasflag(lf, F_PHOTOMEM) && (getskill(lf, SK_CARTOGRAPHY) < PR_SKILLED)) { lf->forgettimer += ((float)howlong / 500.0); if (lf->forgettimer > 1) { int amt; @@ -11640,8 +11956,6 @@ void taketime(lifeform_t *lf, long howlong) { // now move player up in linked list... sortlf(map, lf); - - } int throwat(lifeform_t *thrower, object_t *o, cell_t *where) { @@ -12565,19 +12879,7 @@ int usestairs(lifeform_t *lf, object_t *o) { // find adjacent allies or enemies which will follow you if (isplayer(lf)) { - int d; - for (d = DC_N; d <= DC_NW; d++) { - cell_t *c; - c = getcellindir(lf->cell, d); - if (c && c->lf) { - if (areallies(lf, c->lf) || areenemies(lf, c->lf)) { - if (!isimmobile(c->lf)) { - adjally[nadjallies] = c->lf; - nadjallies++; - } - } - } - } + getadjallies(lf, adjally, &nadjallies); } // do stairs go somewhere? @@ -12629,15 +12931,7 @@ int usestairs(lifeform_t *lf, object_t *o) { } // announce if (isplayer(lf)) { - if (newcell->map->region == RG_WORLDMAP) { - if (lf->cell->map->region == RG_WORLDMAP) { - msg("You arrive in a new area."); - } else { - msg("You arrive at the surface."); - } - } else if (newcell->map->habitat == H_DUNGEON) { - msg("You arrive at dungeon level %d.", newcell->map->depth); - } + announcearrival(lf, newcell->map); f = hasflag(o->flags, F_MAPLINK); if (f) f->known = B_KNOWN; } @@ -12731,6 +13025,7 @@ int validateraces(void) { addflag(r->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); addflag(r->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); addflag(r->flags, F_DTVULN, DT_HOLY, NA, NA, NULL); + addflag(r->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_PLANT) { addflag(r->flags, F_DTRESIST, DT_BASH, NA, NA, NULL); addflag(r->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); @@ -12832,6 +13127,10 @@ int validateraces(void) { } } + if (f->val[1] == NA) { + printf("ERROR in race '%s' - has NOISETEXT but no volume.", r->name); + goterror = B_TRUE; + } } } diff --git a/lf.h b/lf.h index 615b497..2651a99 100644 --- a/lf.h +++ b/lf.h @@ -42,6 +42,7 @@ int countmoney(lifeform_t *lf); int countnearbyallies(lifeform_t *lf); int countnearbyhurtallies(lifeform_t *lf); void debug(lifeform_t *lf); +int demandbribe(lifeform_t *lf); void die(lifeform_t *lf); void dumplev(void); void dumplf(void); @@ -70,6 +71,7 @@ void gainmp(lifeform_t *lf, int amt); void gainxp(lifeform_t *lf, long amt); void genxplist(void); int getactspeed(lifeform_t *lf); +void getadjallies(lifeform_t *lf, lifeform_t **adjally, int *nadjallies); enum ALLEGIENCE getallegiance(lifeform_t *lf); int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs); object_t *getarmour(lifeform_t *lf, enum BODYPART bp); @@ -103,6 +105,7 @@ job_t *getjob(lifeform_t *lf); int getlastdir(lifeform_t *lf); int getlfaccuracy(lifeform_t *lf, object_t *wep); enum LFCONDITION getlfcondition(lifeform_t *lf); +int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions); int getnightvisrange(lifeform_t *lf); char *getlfconditionname(enum LFCONDITION cond); object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp); @@ -140,9 +143,10 @@ char *getpoisonname(enum POISONTYPE ptype); int getraceclass(lifeform_t *lf); int getracerarity(map_t *map, enum RACE rid); object_t *getrandomarmour(lifeform_t *lf); -//int getrandommonlevel(int depth); +int getrandommonlevel(race_t *r, map_t *m); race_t *getrandomrace(map_t *map, int forcedepth); race_t *getreallyrandomrace(void); +enum SKILL getrandomskill(void); object_t *getrestob(lifeform_t *lf); enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id); char *getspeedname(int speed, char *buf); @@ -230,7 +234,7 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt); void modhunger(lifeform_t *lf, int amt); float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); int needstorest(lifeform_t *lf, char *validchars); -void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext); +int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seetext); void outfitlf(lifeform_t *lf); int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground); void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat); @@ -250,6 +254,7 @@ int rolliq(enum IQBRACKET bracket); int rollstr(enum STRBRACKET bracket); int rollstat(lifeform_t *lf, enum ATTRIB attr); int safetorest(lifeform_t *lf); +int say(lifeform_t *lf, char *text, int volume); int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus); int setammo(lifeform_t *lf, object_t *o); void setattr(lifeform_t *lf, enum ATTRIB attr, int val); diff --git a/log.txt b/log.txt index 9ed9d1f..5949e2f 100644 --- a/log.txt +++ b/log.txt @@ -4,3 +4,362 @@ ====== 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 +xxx diff --git a/map.c b/map.c index 5833ec4..6292bc1 100644 --- a/map.c +++ b/map.c @@ -15,6 +15,7 @@ extern map_t *firstmap,*lastmap; extern celltype_t *firstcelltype, *lastcelltype; +extern objecttype_t *objecttype,*lastobjecttype; extern int viewx,viewy,vieww,viewh; extern lifeform_t *player; @@ -46,6 +47,8 @@ cell_t *addcell(map_t *m, int x, int y) { cell->origlittimer = 0; cell->writing = NULL; cell->known = B_FALSE; + cell->knownglyph.ch = ' '; + cell->knownglyph.colour = C_GREY; return cell; } @@ -102,6 +105,7 @@ map_t *addmap(void) { for (i = 0; i < MAXDIR_ORTH; i++) { a->nextmap[i] = -1; } + a->flags = addflagpile(NULL, NULL); a->beingcreated = B_TRUE; return a; } @@ -132,23 +136,23 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto if (db) dblog("adding rand lf %s to cell %d,%d",r->name,c->x,c->y); if (r) { - //lf = addlf(c, r->id, getrandommonlevel(c->map->depth)); - lf = addlf(c, r->id, 1); + lf = addlf(c, r->id, getrandommonlevel(r, c->map)); if (lf) { flag_t *f; lf->born = B_FALSE; if (jobok) { - // has a job? - f = hasflag(lf->flags, F_STARTJOB); - if (f) { - if (rnd(1,100) <= f->val[0]) { - givejob(lf, f->val[1]); + for (f = lf->flags->first ; f ; f = f->next) { + // has a job? + if (f->id == F_STARTJOB) { + if (rnd(1,100) <= f->val[0]) { + givejob(lf, f->val[1]); + break; + } } } } - //if (lf->cell->map->beingcreated) { if (autogen) { // sometimes start off asleep in new maps if (!lfhasflag(lf, F_DEAF) && cansleep(lf)) { @@ -188,12 +192,23 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto // did we find one? if (!adjcell) break; - newlf = addlf(adjcell, r->id, 1); + newlf = addlf(c, r->id, getrandommonlevel(r, adjcell->map)); if (!newlf) { break; } newlf->born = B_FALSE; - if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + + // initial monster shoudl remember its minions + addflag(lf->flags, F_MINION, newlf->id, NA, NA, NULL); + + // if master is asleep, minions will also be asleep + if (lfhasflag(lf, F_ASLEEP)) { + addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + } + + // minions never have certain flags. + killflagsofid(newlf->flags, F_DEMANDSBRIBE); + newlf->born = B_TRUE; } } @@ -220,7 +235,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto newr = findracebyname(f->text); if (!newr) break; - newlf = addlf(adjcell, newr->id, 1); + newlf = addlf(adjcell, newr->id, getrandommonlevel(newr, adjcell->map)); if (!newlf) break; newlf->born = B_FALSE; @@ -250,6 +265,31 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto } } } + + // 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)) { + if (lfhasflag(lf, F_HUMANOID)) { + objecttype_t *ot, *poss[MAXCANDIDATES]; + int nposs = 0; + // get a random light-producing object + for (ot = objecttype ; ot ; ot = ot->next) { + if (hasflag(ot->flags, F_OPERABLE) && + hasflagval(ot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, NA, NA, NULL)) { + poss[nposs++] = ot; + } + } + if (nposs > 0) { + ot = poss[rnd(0,nposs-1)]; + } else { + ot = NULL; + } + if (ot) { + addob(lf->pack, ot->name); + } + } + } + lf->born = B_TRUE; } // end if lf } @@ -257,30 +297,38 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto return lf; } -void addrandomob(cell_t *c) { +object_t *addrandomob(cell_t *c) { char buf[BUFLEN]; int db = B_FALSE; + object_t *o = NULL; if (c->type->solid) { - return; + return NULL; } if (getrandomob(c->map, buf)) { if (db) dblog("adding rand obj %s to cell %d,%d",buf,c->x,c->y); - addob(c->obpile, buf); + o = addob(c->obpile, buf); } + return o; } -void addrandomthing(cell_t *c, int obchance) { +int addrandomthing(cell_t *c, int obchance) { + int rv = TT_NONE; // if there's already someone there, // then add an object. if (c->lf || (rnd(1,100) <= obchance)) { // object - addrandomob(c); + if (addrandomob(c)) { + rv = TT_OBJECT; + } } else { // monster - addmonster(c, R_RANDOM, B_TRUE, 1, B_TRUE); + if (addmonster(c, R_RANDOM, B_TRUE, 1, B_TRUE)) { + rv = TT_MONSTER; + } } + return rv; } int cellhaslos(cell_t *c1, cell_t *dest) { @@ -493,28 +541,14 @@ void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) { break; default: if (c->known) { - //drawunviscell(cell, x-viewx, y-viewy); - object_t *o; - // copy from cell + /* *g = c->type->glyph; + */ + *g = c->knownglyph; if (g->ch == '.') { g->ch = ' '; } - - // show staircases... - o = hasobwithflag(c->obpile, F_CLIMBABLE); - if (o) { - *g = *(getglyph(o)); - } - // show dungeon features - for (o = c->obpile->first ; o ; o = o->next) { - if (o->type->obclass->id == OC_DFEATURE) { - if (!issecretdoor(o)) { - *g = *(getglyph(o)); - } - } - } } break; } @@ -543,18 +577,58 @@ enum CELLTYPE getwallcelltype(enum HABITAT hab) { return CT_WALL; } +flag_t *getmapcoords(map_t *m, int *x, int *y) { + flag_t *f; + f = hasflag(m->flags, F_MAPCOORDS); + if (f) { + if (x) *x = f->val[0]; + if (y) *y = f->val[1]; + return f; + } + if (x) *x = -999; + if (y) *y = -999; + return NULL; +} + + +int getmapdifficulty(map_t *m) { + int diff = 1; + if (m) { + if (m->region == RG_WORLDMAP) { + int x,y; + // depth is distance from 0,0 + getmapcoords(m, &x, &y); + diff = (abs(x) + abs(y))+1; + } else { + diff = m->depth; + } + } else { + diff = rnd(1,MAXDEPTH); + } + return diff; +} + object_t *gettopobject(cell_t *where) { - object_t *o; + object_t *o,*oo = NULL; + enum LFSIZE largest = SZ_MINI; int c; - // draw impassable objects first... - o = hasobwithflag(where->obpile, F_IMPASSABLE); - if (o) { + + // get largest known impassable object first + for (o = where->obpile->first ; o ; o = o->next) { + flag_t *f; // ignore hidden traps, but not secret doors if (hasflag(o->flags, F_SECRET) && !isdoor(o, NULL)) { } else { - return o; + f = hasflag(o->flags, F_IMPASSABLE); + if (f && (f->val[0] > largest)) { + largest = f->val[0]; + oo = o; + } } } + if (oo) { + return oo; + } // otherwise draw highest object in sort order c = 0; @@ -1074,14 +1148,26 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) { if (db) dblog("--> Will add %d objects to room %d (of %d)",numobs,i,numrooms); for (n = 0 ; n < numobs; n++) { int ntries = 0; + int nmonsters = 0; cell_t *c; done = B_FALSE; while (!done) { c = getrandomroomcell(map, i); // if nothing there if (c && isempty(c) && !countobs(c->obpile)) { - // slightly more chance of objects in rooms - addrandomthing(c,60); + int obchance; + + // limit # monster per room to depth+1 + if (nmonsters >= (depth+1)) { + obchance = 100; + } else { + // slightly more chance of objects in rooms + obchance = getobchance(map->habitat) + 10; + } + + if (addrandomthing(c,obchance) == TT_MONSTER) { + nmonsters++; + } done = B_TRUE; } else { ntries++; @@ -1106,6 +1192,8 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir) { int ntrees; int density; cell_t *c; + char buf[BUFLEN]; + int nclearings; //object_t *o; // what kind of cells will 'empty' ones be? @@ -1118,7 +1206,6 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir) { } } - // determine density density = rnd(40,70); // add a plant to density percent of cells @@ -1128,7 +1215,44 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir) { while (c->lf) { c = getrandomcell(map); } - addob(c->obpile, "tree"); + switch (rnd(0,1)) { + default: case 0: strcpy(buf, "tree"); break; + case 1: strcpy(buf, "shrub"); break; + } + addob(c->obpile, buf); + } + + // clearings + nclearings = rnd(0,5); + for (i = 0; i < nclearings; i++) { + int w; + c = getrandomcell(map); + w = rnd(MINCLEARINGRADIUS,MAXCLEARINGRADIUS); + for (y = c->y - w; y <= c->y + w; y++) { + for (x = c->x - w; x <= c->x + w; x++) { + cell_t *newc; + int dist = 999; + newc = getcellat(map, x, y); + + + if (newc) { + dist = getcelldistorth(newc, c); + if (dist <= w) { + int dirtchance; + // kill all obs here + while (newc->obpile->first) killob(newc->obpile->first); + + // change it into dirt. + // ie. at centre (dist=0) dirt chance is 100% + // ie. at max distance, dirt chance is 30% + dirtchance = 100 - (((float)dist / (float)w) * 70); + if (rnd(1,100) <= dirtchance) { + setcelltype(newc, CT_DIRT); + } + } + } + } + } } // add monsters @@ -1143,8 +1267,10 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir) { */ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, int exitdir) { lifeform_t *lf; + map_t *m; char buf[BUFLEN]; int i,x,y; + int firstworldmap = B_FALSE; // determine habitat? if (habitat == AUTO) { if (depth > 0) { @@ -1154,6 +1280,21 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, } } + if (region == RG_WORLDMAP) { + int found = B_FALSE; + + for (m = firstmap ; m ; m = m->next) { + if ((m != map) && (m->region == RG_WORLDMAP)) { + found = B_TRUE; + break; + } + } + + if (!found) { + firstworldmap = B_TRUE; + } + } + map->beingcreated = B_TRUE; map->depth = depth; @@ -1169,7 +1310,7 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, map->nextmap[i] = -1; } - // look for adjacent maps in this region + // look for adjacent maps above/below this one for (i = depth-1; i <= depth+1; i += 2) { map_t *othermap; othermap = findregionmap(map->region, i); @@ -1204,6 +1345,62 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, map->seed = rand() % 65535; srand(map->seed); + // set map coords + if (firstworldmap) { + addflag(map->flags, F_MAPCOORDS, 0, 0, NA, NULL); + } else { + // set mapcoords if not already done. + if (!hasflag(map->flags, F_MAPCOORDS)) { + x = -999; + y = -999; + if (parentmap) { + getmapcoords(parentmap, &x, &y); + assert((x != -999) && (y != -999)); + switch (exitdir) { + case D_N: + y--; + break; + case D_E: + x++; + break; + case D_S: + y++; + break; + case D_W: + x--; + break; + default: + // no change + break; + } + addflag(map->flags, F_MAPCOORDS, x, y, NA, NULL); + } else { + // set it based on something else... + if (region == RG_FIRSTDUNGEON) { + x = 0; + y = 0; + } else { + // find another map of this region and set it. + for (m = firstmap ; m ; m = m->next) { + if ((m != map) && (m->region == region)) { + flag_t *ff; + ff = hasflag(m->flags, F_MAPCOORDS); + if (ff) { + x = ff->val[0]; + y = ff->val[1]; + break; + } + } + } + + } + } + assert(x != -999); + assert(y != -999); + addflag(map->flags, F_MAPCOORDS, x, y, NA, NULL); + } + } + // build it... if (habitat == H_DUNGEON) { createdungeon(map, depth, parentmap, exitdir); @@ -1216,36 +1413,28 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, addhomeobs(lf); } + + // if this is the first world map, add stairs to the dungeon - if (region == RG_WORLDMAP) { - map_t *m; - int found = B_FALSE; + if (firstworldmap) { + // ie. this is the first forest map + map_t *firstdungeon; - for (m = firstmap ; m ; m = m->next) { - if ((m != map) && (m->region == 0)) { - found = B_TRUE; - break; - } - } - if (!found) { - map_t *firstdungeon; - - // link to first dungeon map - firstdungeon = findregionmap(RG_FIRSTDUNGEON, 1); - assert(firstdungeon); - map->nextmap[D_DOWN] = firstdungeon->id; - - // add stairs going down to dungeon - for (i = 0; i < 3; i++) { - cell_t *c; - object_t *o; - c = NULL; - while (!c || !cellwalkable(NULL, c, NULL)) { - c = getrandomcell(map); - } - o = addob(c->obpile, "staircase going down"); - linkstairs(o); + // link to first dungeon map + firstdungeon = findregionmap(RG_FIRSTDUNGEON, 1); + assert(firstdungeon); + map->nextmap[D_DOWN] = firstdungeon->id; + + // add stairs going down to dungeon + for (i = 0; i < 3; i++) { + cell_t *c; + object_t *o; + c = NULL; + while (!c || !cellwalkable(NULL, c, NULL)) { + c = getrandomcell(map); } + o = addob(c->obpile, "staircase going down"); + linkstairs(o); } } @@ -1275,6 +1464,29 @@ void createmap(map_t *map, int depth, int region, int habitat, map_t *parentmap, } } + // look for adjacent maps + getmapcoords(map, &x, &y); + assert(x != -999); + assert(y != -999); + for (m = firstmap ; m ; m = m->next) { + if ((m != map) && (m->region == map->region)) { + int thisx,thisy; + getmapcoords(m, &thisx, &thisy); + if (map->nextmap[D_N] == -1) { + if (thisy == (y - 1)) map->nextmap[D_N] = m->id; + } + if (map->nextmap[D_E] == -1) { + if (thisx == (x + 1)) map->nextmap[D_E] = m->id; + } + if (map->nextmap[D_S] == -1) { + if (thisy == (y + 1)) map->nextmap[D_S] = m->id; + } + if (map->nextmap[D_W] == -1) { + if (thisx == (x - 1)) map->nextmap[D_W] = m->id; + } + } + } + map->beingcreated = B_FALSE; } @@ -1522,7 +1734,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int msg("You see %s explosion!", (range > 0) ? "a huge" : "an"); } } else { - noise(c, NULL, "an explosion!", NULL); + noise(c, NULL, (range > 0) ? 6 : 5, "an explosion!", NULL); } for (y = c->y - range ; y <= c->y + range ; y++) { @@ -1615,6 +1827,63 @@ map_t *findmapofdepth(int depth) { return NULL; } +cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) { + int x,y,xinc,yinc; + + cell_t *selection = NULL; + cell_t *bestcell = NULL; + int closest = 999; + switch (side) { + case D_N: + x = 0; + y = 0; + xinc = 1; + yinc = 0; + bestcell = getcellat(m, lf->cell->x, 0); + break; + case D_E: + x = m->w-1; + y = 0; + xinc = 0; + yinc = 1; + bestcell = getcellat(m, m->w - 1, lf->cell->y); + break; + case D_S: + x = 0; + y = m->h - 1; + xinc = 1; + yinc = 0; + bestcell = getcellat(m, lf->cell->x, m->h - 1); + break; + case D_W: + x = 0; + y = 0; + xinc = 0; + yinc = 1; + bestcell = getcellat(m, 0, lf->cell->y); + break; + } + + for (;(x < m->w) && (y < m->h);) { + cell_t *c; + // check cell + c = getcellat(m, x, y); + if (c && cellwalkable(lf, c, NULL)) { + int dist; + dist = getcelldist(c, bestcell); + if (dist < closest) { + selection = c; + closest = dist; + } + } + // go to next one + x += xinc; + y += yinc; + } + + return selection; +} + // find the object with id 'id' in map 'm' object_t *findobidinmap(map_t *m, long id) { cell_t *c; @@ -1844,7 +2113,7 @@ int getthingchance(int habitat) { case H_DUNGEON: return 3; case H_FOREST: - return 5; + return 3; } // default of no objects return 0; @@ -2503,6 +2772,52 @@ void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong) { } } +void setcellknown(cell_t *cell, int forcelev) { + enum SKILLLEVEL slev; + object_t *o; + + if (forcelev > 0) { + slev = forcelev; + } else { + slev = getskill(player, SK_CARTOGRAPHY); + } + + // photographic memory counts as novice level + if ((slev == PR_INEPT) && lfhasflag(player, F_PHOTOMEM)) { + slev = PR_NOVICE; + } + + + if (slev >= PR_NOVICE) { + cell->known = B_TRUE; + // default to remembering the cell's glyph + cell->knownglyph = cell->type->glyph; + // high cartography skill lets us remember certain objects... + if (slev >= PR_EXPERT) { + o = gettopobject(cell); + if (o) { + cell->knownglyph = *(getglyph(o)); + } + } + if (slev >= PR_ADEPT) { + for (o = cell->obpile->first ; o ; o = o->next) { + if (o->type->obclass->id == OC_DFEATURE) { + if (!issecretdoor(o)) { + cell->knownglyph = *(getglyph(o)); + } + } + } + } + if (slev >= PR_BEGINNER) { + o = hasobwithflag(cell->obpile, F_CLIMBABLE); + if (o) { + cell->knownglyph = *(getglyph(o)); + } + } + } + //getcellglyph(&(cell->knownglyph), cell, player); +} + void setcelltype(cell_t *cell, int id) { assert(cell); cell->type = findcelltype(id); @@ -2528,9 +2843,7 @@ void updateknowncells(void) { if (cell) { //if ((player->cell == cell) || haslos(player, cell)) { if (haslos(player, cell)) { - if (!cell->known) { - cell->known = B_TRUE; - } + setcellknown(cell, B_FALSE); if (cell->lf && lfhasflag(cell->lf, F_UNDEAD)) { seenundead = B_TRUE; } diff --git a/map.h b/map.h index e9a7356..0dc43a8 100644 --- a/map.h +++ b/map.h @@ -4,8 +4,8 @@ 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); -void addrandomob(cell_t *c); -void addrandomthing(cell_t *c, int obchance); +object_t *addrandomob(cell_t *c); +int addrandomthing(cell_t *c, int obchance); 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); @@ -13,6 +13,8 @@ int getcelldistorth(cell_t *src, cell_t *dst); void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer); enum CELLTYPE getemptycelltype(enum HABITAT hab); enum CELLTYPE getwallcelltype(enum HABITAT hab); +flag_t *getmapcoords(map_t *m, int *x, int *y); +int getmapdifficulty(map_t *m); object_t *gettopobject(cell_t *where); void calclight(map_t *map); int calcroompos(map_t *map, int w, int h, int *bx, int *by); @@ -31,6 +33,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int celltype_t *findcelltype(enum CELLTYPE cid); map_t *findmap(int mid); map_t *findmapofdepth(int depth); +cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf); object_t *findobidinmap(map_t *m, long id); cell_t *findobinmap(map_t *m, enum OBCLASS oid); map_t *findregionmap(int region, int depth); @@ -68,5 +71,6 @@ int linkstairs(object_t *o); void makedoor(cell_t *cell); void makelit(cell_t *c, enum LIGHTLEV how, int howlong); void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong); +void setcellknown(cell_t *cell, int forcelev); void setcelltype(cell_t *cell, int id); void updateknowncells(void); diff --git a/move.c b/move.c index fc859d6..6ee5911 100644 --- a/move.c +++ b/move.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -24,7 +25,7 @@ extern enum GAMEMODE gamemode; extern enum ERROR reason; extern void *rdata; -extern WINDOW *gamewin; +extern WINDOW *gamewin, *msgwin; int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) { if (isplayer(lf)) { @@ -544,8 +545,15 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc if (reason != E_OK) { // failed to move switch (reason) { - case E_WALLINWAY: case E_OFFMAP: + if (lf->cell->map->region == RG_WORLDMAP) { + if (!walkoffmap(lf, dir, B_FALSE)) { + // successful + break; + } + } + // fall through + case E_WALLINWAY: if (seen) msg("%s slam%s into a wall!",lfname,isplayer(lf) ? "" : "s"); losehp(lf, rnd(1,6), DT_BASH, pusher, "slamming into a wall"); // stop moving @@ -830,29 +838,32 @@ int movelf(lifeform_t *lf, cell_t *newcell) { // haslos() code to handle looking along walls // instead. // if you walked into a new fully lit room, reveal it - if ((postroom > 0) && (postroom != preroom)) { - cell_t *c[MAX_MAPW*MAX_MAPH]; - int ncells; - int i,alllit = B_TRUE,allknown = B_TRUE; - // is the whole room lit? - getroomcells(lf->cell->map, postroom, c, &ncells); - for (i = 0; i < ncells; i++) { - if (!islit(c[i])) { - alllit = B_FALSE; - } - if (!c[i]->known) { - allknown = B_FALSE; - } - } + if (getskill(lf, SK_CARTOGRAPHY) >= PR_NOVICE) { + if ((postroom > 0) && (postroom != preroom)) { + cell_t *c[MAX_MAPW*MAX_MAPH]; + int ncells; + int i,alllit = B_TRUE,allknown = B_TRUE; - if (alllit && !allknown) { - // make the all known + // is the whole room lit? + getroomcells(lf->cell->map, postroom, c, &ncells); for (i = 0; i < ncells; i++) { - c[i]->known = B_TRUE; + if (!islit(c[i])) { + alllit = B_FALSE; + } + if (!c[i]->known) { + allknown = B_FALSE; + } } + + if (alllit && !allknown) { + // make the all known + for (i = 0; i < ncells; i++) { + setcellknown(c[i], B_FALSE); + } + } + } - } } @@ -1116,8 +1127,15 @@ int opendoor(lifeform_t *lf, object_t *o) { return B_TRUE; } else { if (lf) { + flag_t *sf; taketime(lf, getactspeed(lf)); touch(lf, o); + + // stop sprinting + sf = lfhasflag(lf, F_SPRINTING); + if (sf && sf->val[0]) { + killflag(sf); + } } // locked? @@ -1180,7 +1198,7 @@ int opendoor(lifeform_t *lf, object_t *o) { // checking if we have LOS to the lifeform making // sound, but in this case it's the door making // the sound, not the lf. - noise(where, NULL, "a door opening.", NULL); + noise(where, NULL, 2, "a door opening.", NULL); } if (player && haslos(player, where)) { needredraw = B_TRUE; @@ -1657,12 +1675,10 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { reason = errcode; switch (errcode) { case E_OFFMAP: - if (isplayer(lf)) { - msg("You can't go any further in that direction."); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s %ss around randomly.", buf, getmoveverb(lf)); - } + if (lf->cell->map->region == RG_WORLDMAP) { + // we are allowed to walk off the edge + walkoffmap(lf, dir, B_TRUE); + } break; case E_WALLINWAY: if (isplayer(lf)) { @@ -1679,7 +1695,8 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { sprintf(buf, "%sing into a wall", getmoveverb(lf)); losehp(lf, 1, DT_BASH, NULL, buf); // we now know there is a wall there. - cell->known = B_TRUE; + setcellknown(cell, B_FALSE); + if (onpurpose) taketime(lf, getmovespeed(lf)); } } else { @@ -1701,7 +1718,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { opendoor(lf, inway); } else { msg("Ouch! You %s into a door.", getmoveverb(lf)); - cell->known = B_TRUE; + 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)); @@ -1829,6 +1846,95 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { return B_FALSE; } +int walkoffmap(lifeform_t *lf, int dir, int onpurpose) { + map_t *adjmap = NULL, *thismap; + cell_t *dst = NULL; + lifeform_t *adjally[8]; + int nadjallies = 0; + int n; + + // announce + if (isplayer(lf)) { + char dirname[BUFLEN]; + curs_set(1); + strcpy(dirname, getdirname(dir)); + dirname[0] = tolower(dirname[0]); + msg("You %s to the %s...", getmoveverb(lf), getdirname(dir)); + // move cursor to msgwindow while we create the new level... + wrefresh(msgwin); + } else if (cansee(player, lf)) { + char dirname[BUFLEN]; + char lfname[BUFLEN]; + getlfname(lf, lfname); + curs_set(1); + strcpy(dirname, getdirname(dir)); + dirname[0] = tolower(dirname[0]); + msg("%s %s to the %s...", lfname, getmoveverbother(lf), getdirname(dir)); + wrefresh(msgwin); + } + + // is there a map in that direction ? + thismap = lf->cell->map; + adjmap = findmap(lf->cell->map->nextmap[dir]); + if (!adjmap) { + // make one + adjmap = addmap(); + createmap(adjmap, thismap->depth, thismap->region, AUTO, thismap, dir); + } + + if (adjmap) { + // find an empty cell in the next map + dst = findmapentrypoint(adjmap, diropposite(dir), lf); + } + + if (!dst) { + // failed + if (isplayer(lf)) { + msg("Your path seems to be blocked."); + } + return B_TRUE; + } + + if (onpurpose) { + // get list of adjacent allies + if (isplayer(lf)) { + getadjallies(lf, adjally, &nadjallies); + } + } + + // announce + announcearrival(lf, dst->map); + + // move there + moveto(lf, dst, onpurpose, B_TRUE); + if (onpurpose) { + taketime(lf, getmovespeed(lf)); + } + + // move adjacent allies + if (onpurpose) { + for (n = 0; n < nadjallies; n++) { + cell_t *c; + c = getrandomadjcell(dst, WE_WALKABLE, B_ALLOWEXPAND); + if (c) { + if (!initiatemove(adjally[n], NULL, NULL)) { + movelf(adjally[n], c); + taketime(adjally[n], getmovespeed(adjally[n])); + } + } + } + } + + if (isplayer(lf)) { + statdirty = B_TRUE; + needredraw = B_TRUE; + calclight(player->cell->map); + precalclos(lf); + drawscreen(); + } + + return B_FALSE; +} int willmove(lifeform_t *lf, int dir, enum ERROR *error) { cell_t *cell; diff --git a/move.h b/move.h index 07f37ca..78a4c2a 100644 --- a/move.h +++ b/move.h @@ -25,4 +25,5 @@ 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); int tryrun(lifeform_t *lf, int dir); +int walkoffmap(lifeform_t *lf, int dir, int onpurpose); int willmove(lifeform_t *lf, int dir, enum ERROR *error); diff --git a/nexus.c b/nexus.c index 1f01144..9861988 100644 --- a/nexus.c +++ b/nexus.c @@ -264,7 +264,6 @@ int main(int argc, char **argv) { // start game - this will cause debug messages to now // go to the log file instead of stdout. - gamemode = GM_GAMESTARTED; timeleft = 0; // reset game timer // calculate initial light @@ -287,6 +286,13 @@ int main(int argc, char **argv) { needredraw = B_TRUE; statdirty = B_TRUE; + // start game + gamemode = GM_GAMESTARTED; + + // redo light and player los + calclight(player->cell->map); + precalclos(player); + // show level drawscreen(); @@ -541,7 +547,8 @@ void donextturn(map_t *map) { } else { if (isplayer(who)) { if (++who->turnsskipped >= 10) { - msg("Time passes..."); + //msg("Time passes..."); + msg("."); who->turnsskipped = 0; } } @@ -557,7 +564,8 @@ void donextturn(map_t *map) { if (isimmobile(who)) { if (isplayer(who)) { if (++who->turnsskipped >= 10) { - msg("Time passes..."); + //msg("Time passes..."); + msg("."); who->turnsskipped = 0; } } diff --git a/objects.c b/objects.c index ed1ea41..61da7a3 100644 --- a/objects.c +++ b/objects.c @@ -404,6 +404,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { obmod_t *wantom[MAXOBMODS]; int nom = 0; int n; + int bookcontents = -1; localname = strdup(name); @@ -530,6 +531,28 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { corpserace = findracebyname(racename); ot = findot(OT_HEAD); + } else if (strstr(p, "spellbook of ")) { + char *pp; + pp = p + 13; + if (*pp) { + objecttype_t *spelltype = NULL; + spelltype = findspelln(pp); + if (spelltype) { + bookcontents = spelltype->id; + } + } + ot = findot(OT_SPELLBOOK); + } else if (strstr(p, "manual of ")) { + char *pp; + pp = p + 10; + if (*pp) { + skill_t *sk; + sk = findskillbyname(pp); + if (sk) { + bookcontents = sk->id; + } + } + ot = findot(OT_MANUAL); } else { // make sure we can find the requested object type if (db) dblog("DB: Looking for object name '%s'", p ); @@ -564,7 +587,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { canstack = B_FALSE; } - // special checks for unique objects if (hasflag(ot->flags, F_UNIQUE)) { // does this unique ob already exist? @@ -579,6 +601,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { if (db) dblog("DB: '%s' -> adding %d x %s",name, howmany, ot->name); + for (i = 0; i < howmany; i++) { int added = B_FALSE; if (canstack) { @@ -694,6 +717,52 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { } } + // fill in book types + if (o && (o->type->obclass->id == OC_BOOK)) { + hiddenname_t *hn,*selhn = NULL; + int numhiddennames; + int n,sel; + if (bookcontents == -1) { + if (o->type->id == OT_SPELLBOOK) { + bookcontents = getrandomspell(); + while (!schoolappearsinbooks(getspellschool(bookcontents))) { + bookcontents = getrandomspell(); + } + } else { // ie. manual + bookcontents = getrandomskill(); + } + } + + // link + if (o->type->id == OT_SPELLBOOK) { + addflag(o->flags, F_LINKSPELL, bookcontents, NA, NA, NULL); + } else { + addflag(o->flags, F_MANUALOF, bookcontents, NA, NA, NULL); + } + + + // count hidden names + numhiddennames = 0; + for (hn = firsthiddenname ; hn ; hn = hn->next) { + if (hn->obclass == o->type->obclass->id) { + numhiddennames++; + } + } + // assign hidden name + sel = rnd(0,numhiddennames-1); + n = 0; + for (hn = firsthiddenname ; hn ; hn = hn->next) { + if (hn->obclass == o->type->obclass->id) { + if (n == sel) { + selhn = hn; + break; + } + n++; + } + } + addflag(o->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, selhn->text); + } + // other special changes we need to make based on what was // asked for @@ -3134,6 +3203,28 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan strcpy(basename,gethiddenname(o)); } + if (o->type->obclass->id == OC_BOOK) { + if (!strcmp(basename, o->type->name)) { + if (o->type->id == OT_SPELLBOOK) { + f = hasflag(o->flags, F_LINKSPELL); + if (f) { + objecttype_t *st; + st = findot(f->val[0]); + strcat(basename, " of "); + strcat(basename, st->name); + } + } else { + f = hasflag(o->flags, F_MANUALOF); + if (f) { + skill_t *sk; + sk = findskill(f->val[0]); + strcat(basename, " of "); + strcat(basename, sk->name); + } + } + } + } + if (!showall) { if ((gamemode == GM_GAMESTARTED) && adjustforblind && !haslos(player, where) ) { // override with obclass names @@ -3600,10 +3691,8 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth if (forcedepth != NA) { depth = forcedepth; - } else if (map) { - depth = map->depth; } else { - depth = rnd(1,MAXDEPTH); + depth = getmapdifficulty(map); } getrarity(depth, &raritymin, &raritymax, RARITYVARIANCEOB, B_TRUE); @@ -3811,7 +3900,8 @@ 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); + //return real_getrandomob(map, buf, RO_OBCLASS, cid, map->depth + depthmod); + return real_getrandomob(map, buf, RO_OBCLASS, cid, getmapdifficulty(map) + depthmod); } int getobrarity(object_t *o) { @@ -4090,7 +4180,7 @@ object_t *hasobid(obpile_t *op, int id) { // fully identify a single object. void identify(object_t *o) { flag_t *f; - if (!isknown(o)) { + if (!isknown(o) && (o->type->obclass->id != OC_BOOK)) { makeknown(o->type->id); } addflag(o->flags, F_IDENTIFIED, B_TRUE, -1, -1, NULL); @@ -4151,7 +4241,6 @@ void ignite(object_t *o) { void initobjects(void) { //int ch; int i,n; - objecttype_t *ot; // generate hidden names for (n = 0; strlen(colour[n].name); n++) { @@ -4503,18 +4592,6 @@ void initobjects(void) { addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL); addflag(lastot->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL); - addot(OT_WOODENTABLE, "wooden table", "A waist-height wooden table.", MT_WOOD, 25, OC_DFEATURE); - addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); - addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "\\"); - addflag(lastot->flags, F_IMPASSABLE, SZ_HUMAN, NA, NA, NULL); - addflag(lastot->flags, F_CRUSHABLE, SZ_LARGE, NA, NA, NULL); - addflag(lastot->flags, F_PUSHABLE, 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); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); - addflag(lastot->flags, F_DTVULN, DT_BASH, NA, NA, NULL); - addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL); addot(OT_BOULDER, "boulder", "A massive stone boulder.", MT_STONE, 80, OC_ROCK); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, ""); @@ -4564,13 +4641,13 @@ void initobjects(void) { addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addot(OT_VENDINGMACHINE, "vending machine", "A gold-operated vending machine.", MT_METAL, 500, OC_MISC); + 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_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addot(OT_PORTAL, "magic portal", "A magical portal to a different place...", MT_MAGIC, 0, OC_MISC); + 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); @@ -4579,7 +4656,7 @@ void initobjects(void) { // 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); - addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); 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); @@ -4587,7 +4664,7 @@ void initobjects(void) { addflag(lastot->flags, F_SECRET, 25, NA, NA, NULL); addot(OT_TRAPROCK, "falling rock trap", "A pressure plate which causes heavy rocks to drop from the ceiling.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_TRAP, 20, B_TRUE, 22, NULL); - addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); 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); @@ -4596,7 +4673,7 @@ void initobjects(void) { addot(OT_TRAPARROW, "arrow trap", "A pressure plate which causes arrows to shoot at you.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL); addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_ALL, 76, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, NA, NULL); 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); @@ -4605,7 +4682,7 @@ void initobjects(void) { addot(OT_TRAPARROWP, "poison arrow trap", "A pressure plate which causes poisoned arrows to shoot at you.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL); addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_ALL, 69, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL); 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); @@ -4614,7 +4691,7 @@ void initobjects(void) { addot(OT_TRAPGAS, "gas trap", "A pressure plate which releases poisonous gas.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_TRAP, 27, B_TRUE, NA, NULL); addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_ALL, 69, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL); 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); @@ -4623,7 +4700,7 @@ void initobjects(void) { addot(OT_TRAPFIRE, "fire trap", "A pressure plate which fires a pillar of flame.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_ALL, 59, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 59, NA, NULL); 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); @@ -4632,7 +4709,8 @@ void initobjects(void) { addot(OT_TRAPMINE, "landmine trap", "A buried, pressure-sensitive explosive device.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 20, NA, NULL); 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); @@ -4707,6 +4785,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, ""); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); addflag(lastot->flags, F_IMPASSABLE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastot->flags, F_REDUCEMOVEMENT, 1, 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, 20, 20, NA, NULL); @@ -4831,6 +4910,9 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL); addot(OT_POT_RESTORATION, "potion of restoration", "Restores lost abilities to the drinker.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addot(OT_POT_SLEEP, "potion of sleep", "Puts the drinker into a deep sleep.", MT_GLASS, 1, OC_POTION); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addot(OT_POT_SPEED, "potion of haste", "Temporarily increasees the drinker's speed.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); @@ -5144,6 +5226,11 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_ADJSELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_CALLWIND, "call wind", "Conjures a friendly wind, carrying a single object to the caster's hands.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); // l2 addot(OT_S_GUSTOFWIND, "gust of wind", "Causes a gust of wind to blow the target's objects away.", MT_NOTHING, 0, OC_SPELL); @@ -5332,6 +5419,11 @@ void initobjects(void) { 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_LIGHTNINGBOLT, "lightning bolt", "Fires electricity through multiple enemies.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, 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_WALLSTOP, NA, NULL); addot(OT_S_ENDUREELEMENTS, "endure elements", "Provides resistance to fire and cold.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); @@ -5521,7 +5613,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - addot(OT_S_LIGHT, "light", "Creates a temporary light source centred on the caster.\nAt Power III, you can control where the light appears.\nAt Power VIII, the light becomes permenant.", MT_NOTHING, 0, OC_SPELL); + addot(OT_S_LIGHT, "light area", "Creates a temporary light source centred on the caster.\nAt Power III, you can control where the light appears.\nAt Power VIII, the light becomes permenant.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); @@ -5738,7 +5830,12 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); - // manuals + // books + addot(OT_MANUAL, "manual", "Teaches you one level of its subject matter.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 48, NA, NULL); + addot(OT_SPELLBOOK, "spellbook", "Teaches you the spell contained within.", MT_PAPER, 1.5, OC_BOOK); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + /* addot(OT_MAN_ARMOUR, "manual of armour", "Teaches you the skill 'armour'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_ARMOUR, NA, NA, NULL); addot(OT_MAN_ATHLETICS, "manual of athletics", "Teaches you the skill 'athletics'.", MT_PAPER, 3, OC_BOOK); @@ -5755,6 +5852,8 @@ void initobjects(void) { addflag(lastot->flags, F_MANUALOF, SK_LOCKPICKING, NA, NA, NULL); addot(OT_MAN_MAGITEMUSAGE, "manual of channeling", "Teaches you the skill 'channeling'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_CHANNELING, NA, NA, NULL); + addot(OT_MAN_RANGED, "manual of ranged weapons", "Teaches you the skill 'ranged weapons'.", MT_PAPER, 3, OC_BOOK); + addflag(lastot->flags, F_MANUALOF, SK_RANGED, NA, NA, NULL); addot(OT_MAN_SHIELDS, "manual of shields", "Teaches you the skill 'shields'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SHIELDS, NA, NA, NULL); addot(OT_MAN_SPELLCASTING, "manual of sorcery", "Teaches you the skill 'sorcery'.", MT_PAPER, 3, OC_BOOK); @@ -5824,8 +5923,10 @@ void initobjects(void) { addflag(lastot->flags, F_MANUALOF, SK_SS_TRANSLOCATION, NA, NA, NULL); addot(OT_MAN_SS_WILD, "manual of wild magic", "Teaches you the skill 'wild magic'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SS_WILD, NA, NA, NULL); + */ // spellbooks + /* addot(OT_SB_ANIMATEDEAD, "spellbook of animate dead", "Teaches the spell 'animate dead'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_ANIMATEDEAD, NA, NA, NULL); addot(OT_SB_DRAINLIFE, "spellbook of drain life", "Teaches the spell 'drain life'.", MT_PAPER, 1.5, OC_BOOK); @@ -5993,9 +6094,11 @@ void initobjects(void) { addflag(lastot->flags, F_LINKSPELL, OT_S_TELEPORT, NA, NA, NULL); addot(OT_SB_TWIDDLE, "spellbook of twiddle", "Teaches the spell 'twiddle'.", MT_PAPER, 1.5, OC_BOOK); addflag(lastot->flags, F_LINKSPELL, OT_S_TWIDDLE, NA, NA, NULL); + */ // assign rarity to books + /* for (ot = objecttype ; ot ; ot = ot->next) { if ((ot->obclass->id == OC_BOOK) && !hasflag(ot->flags, F_RARITY)) { flag_t *f; @@ -6025,6 +6128,7 @@ void initobjects(void) { } } + */ // wands @@ -6614,6 +6718,19 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 6, 6, NA, NULL); + addot(OT_WOODENTABLE, "wooden table", "A waist-height wooden table.", MT_WOOD, 25, OC_MISC); + addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "\\"); + addflag(lastot->flags, F_IMPASSABLE, SZ_HUMAN, NA, NA, NULL); + addflag(lastot->flags, F_CRUSHABLE, SZ_LARGE, NA, NA, NULL); + addflag(lastot->flags, F_PUSHABLE, 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); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_DTVULN, DT_BASH, NA, NA, NULL); + addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL); + addot(OT_WOODENSTOOL, "wooden footstool", "A small, wooden footstool.", MT_WOOD, 5, OC_MISC); addflag(lastot->flags, F_RARITY, H_ALL, 83, NA, NULL); addflag(lastot->flags, F_GLYPH, NA, NA, NA, "\\"); @@ -7331,10 +7448,10 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); - addot(OT_BATTLEAXE, "battleaxe", "An axe specifically designed for combat.", MT_METAL, 5, OC_WEAPON); + addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); - addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d9"); + addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+1"); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); @@ -7342,19 +7459,26 @@ void initobjects(void) { addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 8, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); - addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d10"); + addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d9+1"); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 16, NA, NULL); - addot(OT_HANDAXE, "hand axe", "A fast one-handed axe made for combat.", MT_METAL, 2, OC_WEAPON); + addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); - addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d6+1"); + addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7"); addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); + addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 4, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d7+1"); + addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 11, NA, NULL); // short blades addot(OT_COMBATKNIFE, "combat knife", "A sharp knife designed for military use.", MT_METAL, 1, OC_WEAPON); @@ -7551,7 +7675,7 @@ void initobjects(void) { // staves addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 2, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "1d8"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -7582,7 +7706,7 @@ void initobjects(void) { addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 135, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, NA, NA, "3d4+1"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -7667,7 +7791,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 5, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 8, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); @@ -7678,7 +7802,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 9, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 12, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); @@ -7688,7 +7812,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 5, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 6, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); @@ -7697,7 +7821,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 7, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 12, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); @@ -7709,7 +7833,7 @@ void initobjects(void) { addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); //addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); //addflag(lastot->flags, F_DAM, 3, 4, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 10, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 20, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL); @@ -7719,7 +7843,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 3, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 6, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_STONE, NA, NA, NULL); @@ -8161,6 +8285,8 @@ int istried(object_t *o) { int istriedot(objecttype_t *ot) { knowledge_t *k; + if (ot->obclass->id == OC_BOOK) return B_FALSE; + for (k = knowledge; k ; k = k->next) { if (k->id == ot->id) { // it DOES have a hidden name. @@ -9030,6 +9156,20 @@ int obmatchescondition(object_t *o, long opts) { if ((opts & AO_POURABLE) && ispourable(o)) ok = B_TRUE; if ((opts & AO_NOTIDENTIFIED) && !isidentified(o)) ok = B_TRUE; if ((opts & AO_NOTKNOWN) && !isknown(o)) ok = B_TRUE; + if (opts & AO_SPECIFIED) { + int n; + int found = B_FALSE; + // does retlist contain this? + for (n = 0; n < nretobs; n++) { + if (retobs[n] == o) { + found = B_TRUE; + break; + } + } + if (found) { + ok = B_TRUE; + } + } return ok; } @@ -9139,10 +9279,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); + where = askcoords(f->text, ttype, lf, UNLIMITED); } else { sprintf(buf, "Where will you aim %s?",obname); - where = askcoords(buf, ttype); + where = askcoords(buf, ttype, lf, UNLIMITED); if (!haslos(lf, where)) { // exception - wand of digging doesn't need los if (isknown(o) && (o->type->id == OT_WAND_DIGGING)) { @@ -9424,7 +9564,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } // announce if (!seen) { - noise(where, NULL, "something spraying.", NULL); + noise(where, NULL, 0, "something spraying.", NULL); } } else if ((o->type->id == OT_EMPTYFLASK) || (o->type->id == OT_EMPTYVIAL)) { object_t *oo,*nextoo; @@ -9610,7 +9750,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (isplayer(lf)) { msg("You play a few notes on your panpipes."); } else { - noise(lf->cell, lf, "the sound of panpipes.", "plays a tune on its panpipes."); + noise(lf->cell, lf, 3, "the sound of panpipes.", "plays a tune on its panpipes."); } } else if (o->type->id == OT_PICKAXE) { int ch,dir; @@ -10279,6 +10419,9 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i case OT_POT_HEALINGMIN: dospelleffects(lf, OT_S_HEALINGMIN,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen); break; + case OT_POT_HEALINGMAJ: + dospelleffects(lf, OT_S_HEALINGMAJ,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen); + break; case OT_POT_INVIS: dospelleffects(lf, OT_S_INVISIBILITY,potblessed ? 6 : 3, lf, NULL, lf->cell, potblessed, seen); break; @@ -10409,17 +10552,20 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i } } break; + case OT_POT_SLEEP: + dospelleffects(lf, OT_S_SLEEP, 8, lf, NULL, lf->cell, B_UNCURSED, NULL); + if (seen) *seen = B_TRUE; + break; case OT_POT_SPEED: if (potblessed == B_BLESSED) { - dospelleffects(lf, OT_S_HASTE, 1, lf, NULL, lf->cell, B_BLESSED, NULL); + dospelleffects(lf, OT_S_HASTE, 5, lf, NULL, lf->cell, B_BLESSED, NULL); } else if (potblessed == B_CURSED) { - dospelleffects(lf, OT_S_SLOW, 1, lf, NULL, lf->cell, B_UNCURSED, NULL); + dospelleffects(lf, OT_S_SLOW, 5, lf, NULL, lf->cell, B_UNCURSED, NULL); } else { // uncursed - dospelleffects(lf, OT_S_HASTE, 1, lf, NULL, lf->cell, B_UNCURSED, NULL); + dospelleffects(lf, OT_S_HASTE, 5, lf, NULL, lf->cell, B_UNCURSED, NULL); } if (seen) *seen = B_TRUE; break; - case OT_POT_WATER: switch (potblessed) { case B_BLESSED: @@ -10585,8 +10731,12 @@ int readsomething(lifeform_t *lf, object_t *o) { } if (!isknown(o) && willid) { - // id the scroll - makeknown(o->type->id); + // id the object + if (o->type->obclass->id == OC_BOOK) { + identify(o); + } else { + makeknown(o->type->id); + } real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness if (isplayer(lf)) { // tell the player @@ -10911,7 +11061,7 @@ void shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { seen = B_TRUE; } else { - noise(where, NULL, "shattering glass.", NULL); + noise(where, NULL, 3, "shattering glass.", NULL); } if (target) { @@ -11256,7 +11406,7 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno - real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); + real_getobname(o, obname, o->amt, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); getobconditionname(o, predamname); hpflag = hasflag(o->flags, F_OBHP); if (hpflag) { @@ -11342,7 +11492,7 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno return damtaken; } -// throw speed is the damage multiplier +// throw speed/2 is the damage multiplier int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, object_t *firearm) { char throwername[BUFLEN]; char throwernamea[BUFLEN]; @@ -11661,7 +11811,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (shield) { // block chance based on shield skill // ie. ST_AVERAGE = speed3 = 18 - // ie. gun = speed10 = 60 = basically impossible + // ie. gun = speed20 = 120 = impossible if (skillcheck(target, SC_SHIELDBLOCK, speed*6, 0)) { int throwdam,dam; if (seen) { @@ -12453,7 +12603,6 @@ int usecharge(object_t *o) { int validateobs(void) { objecttype_t *ot; - skill_t *sk; int foundspells = B_FALSE; int goterror = B_FALSE; flag_t *f; @@ -12553,6 +12702,7 @@ int validateobs(void) { } } + /* for (sk = firstskill ; sk ; sk = sk->next) { int found = B_FALSE; // make sure every skill have an object providing it @@ -12567,6 +12717,7 @@ int validateobs(void) { goterror = B_TRUE; } } + */ return goterror; } @@ -12670,21 +12821,27 @@ enum MATSTATE getmaterialstate(enum MATERIAL mat) { int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt) { int acc,maxrange,howfar; + enum SKILLLEVEL slev; // figure out if you miss or not, based on distance and // dexterity // base: // if throwing, 50% - // if firing, gun accuracy + // if firing, gun accuracy modified by sk_ranged // adjust for range: // pointblank = +30% // max = -30% // then modify using dexterity/int/whatever // then penalise for throwing non-missiles + // base accuracy if (firearm) { + slev = getskill(thrower, SK_RANGED); acc = getobaccuracy(firearm, thrower); + // ie. inept = -30%, adept = 0%, master = +30% + acc += ((slev - PR_ADEPT) * 10); } else { + slev = PR_INEPT; acc = 50; } @@ -12700,14 +12857,14 @@ int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, ob } howfar = getcelldist(thrower->cell, where); - if (howfar == 1) { acc += 30; } else if (howfar == maxrange) { - acc -= 30; + if (slev != PR_MASTER) { + acc -= 30; + } } - // modify for dexterity if (whichatt != A_NONE) { acc += getstatmod(thrower, whichatt); diff --git a/save.c b/save.c index 48ca2c4..17f1863 100644 --- a/save.c +++ b/save.c @@ -332,8 +332,8 @@ map_t *loadmap(char *basefile) { */ // cell info - fscanf(f, "%d,%d,%d,%d,%d,%d,%d\n", - &c->roomid, &celltypeid, &c->known, &c->visited, &c->lit, &c->origlit, &c->littimer); + fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + &c->roomid, &celltypeid, &c->known, &c->knownglyph.ch, &c->knownglyph.colour, &c->visited, &c->lit, &c->origlit, &c->littimer); ct = findcelltype(celltypeid); @@ -445,6 +445,10 @@ map_t *loadmap(char *basefile) { } } + + // load flags + loadflagpile(f, m->flags); + fclose(f); // move lifeforms to their proper locations @@ -745,8 +749,8 @@ int savemap(map_t *m) { cell_t *c; c = getcellat(m, x, y); // cell info - fprintf(f, "%d,%d,%d,%d,%d,%d,%d\n", - c->roomid, c->type->id, c->known, c->visited,c->lit,c->origlit,c->littimer); + fprintf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + c->roomid, c->type->id, c->known, c->knownglyph.ch, c->knownglyph.colour, c->visited,c->lit,c->origlit,c->littimer); // cell objects for (o = c->obpile->first ; o ; o = o->next) { fprintf(f, "ob:%ld\n",o->id); @@ -769,6 +773,8 @@ int savemap(map_t *m) { } } + saveflagpile(f, m->flags); + fclose(f); return B_FALSE; diff --git a/spell.c b/spell.c index 582dba5..b03976c 100644 --- a/spell.c +++ b/spell.c @@ -27,6 +27,7 @@ extern prompt_t prompt; extern WINDOW *msgwin; extern job_t *firstjob; +extern objecttype_t *objecttype; extern map_t *firstmap; @@ -106,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); + targcell = askcoords(buf, TT_MONSTER, user, range); if (!targcell) { msg("Cancelled."); return TRUE; @@ -253,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); + targcell = askcoords(buf, TT_NONE, user, range); } else { return B_TRUE; } @@ -537,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); + targcell = askcoords(buf, TT_NONE, user, 2); if (!targcell) { return B_TRUE; } else if (getcelldist(user->cell, targcell) > 2) { @@ -800,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); + targcell = askcoords(buf, TT_MONSTER, user, srange); if (!targcell) { msg("Cancelled."); return TRUE; @@ -934,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); + where = askcoords("Debug who?", TT_MONSTER, user, UNLIMITED); if (where && where->lf) { debug(where->lf); } } else if (abilid == OT_A_EMPLOY) { cell_t *where; - where = askcoords("Assign job to who?", TT_MONSTER); + where = askcoords("Assign job to who?", TT_MONSTER, user, UNLIMITED); if (where && where->lf) { char question[BUFLEN]; char lfname[BUFLEN]; @@ -964,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); + where = askcoords("Enhance stats of who?", TT_MONSTER, user, UNLIMITED); if (where && where->lf) { char ch; enum ATTRIB att; @@ -1039,8 +1040,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } makenoise(user, N_WARCRY); - // take a lot of time - taketime(user, getactspeed(user)*4); + // take a lot of time, so that there is a danger in just + // using it all the time. + taketime(user, getactspeed(user)*2); // all in range must pass a morale check or flee for (target = user->cell->map->lf ; target ; target = target->next) { @@ -1601,6 +1603,67 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ failed = B_TRUE; } + if (failed) { + fizzle(caster); + } + } else if (spellid == OT_S_CALLWIND) { + int failed = B_FALSE; + float maxweight; + + // if no target object... + if (!targob) { + // ask for a target cell (to take objects from) + if (!validatespellcell(caster, &targcell, TT_OBJECT, spellid, power)) return B_TRUE; + + 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; + } + } + } else { + failed = B_TRUE; + } + } + + if (!failed) { + targcell = caster->cell; + + // not liftable? + if (hasflag(targob->flags, F_NOPICKUP)) { + if (isplayer(caster)) { + nothinghappens(); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + return B_FALSE; + } + + // too heavy? max weight is now based on our race's weight and intelligence + maxweight = getlfweight(caster, B_NOOBS) + + (getlfweight(caster, B_NOOBS) * (getstatmod(caster, A_IQ) / 100)); + + // modify by power + maxweight += (10*power); + + if (getobweight(targob) > maxweight) { + cell_t *obloc; + char obname[BUFLEN]; + obloc = getoblocation(targob); + getobname(targob, obname, targob->amt); + if (haslos(player, obloc)) { + msg("%s lifts slightly, then drops again.",obname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + return B_FALSE; + } + + pullobto(targob, caster); + } + if (failed) { fizzle(caster); } @@ -2253,7 +2316,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!targcell) { if (isplayer(caster)) { sprintf(buf, "Where will you target your dispersal?"); - targcell = askcoords(buf, TT_MONSTER|TT_OBJECT); + targcell = askcoords(buf, TT_MONSTER|TT_OBJECT, caster, UNLIMITED); if (!targcell) { // no cell fizzle(caster); return B_TRUE; @@ -2962,6 +3025,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_HAILSTORM) { int failed = B_FALSE; + if (isoutdoors(caster->cell->map)) { + power += 3; + limit(&power, NA, 10); + } // ask for a target cell if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; if (targcell) { @@ -3371,9 +3438,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ c = getcellat(m, x, y); if (c) { if (range == UNLIMITED) { - c->known = B_TRUE; + setcellknown(c, PR_ADEPT); } else if (getcelldist(caster->cell, c) <= range) { - c->known = B_TRUE; + setcellknown(c, PR_ADEPT); } } } @@ -3467,7 +3534,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster)) { // ask for a target cell sprintf(buf, "Whose mind will you scan?"); - where = askcoords(buf, TT_MONSTER); + where = askcoords(buf, TT_MONSTER, caster, UNLIMITED); if (where && haslos(caster, where) && haslf(where)) { char targname[BUFLEN]; lifeform_t *oldplayer; @@ -4150,6 +4217,34 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ calclight(targcell->map); needredraw = B_TRUE; drawscreen(); + } else if (spellid == OT_S_LIGHTNINGBOLT) { + cell_t *retcell[MAXRETCELLS]; + int nretcells; + int i; + int nhits = power; + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; + + // create a line of fire towards the target cell + calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcells); + animcells(caster->cell, &retcell[1], nretcells-1, B_FALSE, '/', '\\', C_WHITE); + if (cansee(player, caster)) { + msg("%s shoot%s a bolt of lightning!",castername, isplayer(caster) ? "" : "s"); + } + + // don't hit the caster cell on fire! + for (i = 1; (i < nretcells) && (nhits > 0); i++) { + cell_t *c; + c = retcell[i]; + if (c->lf) { + // hit with lightning + losehp(c->lf, roll("2d6"), DT_ELECTRIC, caster, "a lightning bolt"); + nhits--; + } + if (haslos(player, c)) { + needredraw = B_TRUE; + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } } else if (spellid == OT_S_LIGHTNINGSTORM) { char targname[BUFLEN]; lifeform_t *poss[MAXCANDIDATES], *targ[MAXCANDIDATES]; @@ -4196,7 +4291,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(targ[i],targname); msg("%s %s struck by a bolt of lightning!",targname, is(targ[i])); } - if (isoutdoors(target->cell->map)) { + if (isoutdoors(targ[i]->cell->map)) { losehp(targ[i], rolldie(4,6), DT_ELECTRIC, caster, "a bolt of lightning"); } else { losehp(targ[i], rolldie(3,6), DT_ELECTRIC, caster, "a bolt of lightning"); @@ -4331,7 +4426,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster)) { cell_t *where; sprintf(buf, "Where will you target your spell?"); - where = askcoords(buf, TT_MONSTER); + where = askcoords(buf, TT_MONSTER, caster, UNLIMITED); if (where && haslos(caster, where) && haslf(where)) { target = haslf(where); } else { @@ -4376,6 +4471,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int i; char targname[BUFLEN]; + if (isoutdoors(caster->cell->map)) { + power += 5; + limit(&power, NA, 10); + } + if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_OBJECT, spellid, power)) return B_TRUE; target = targcell->lf; @@ -4552,7 +4652,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // ask for target if required if (!target && isplayer(caster)) { cell_t *where; - where = askcoords("Who will you polymorph?", TT_MONSTER); + where = askcoords("Who will you polymorph?", TT_MONSTER, caster, UNLIMITED); if (haslos(caster, where)) { target = where->lf; } else { @@ -4676,6 +4776,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster)) { char obname[BUFLEN]; flag_t *f; + int donesomething = B_FALSE; getobname(o, obname, o->amt); @@ -4684,27 +4785,37 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ makeknown(o->type->id); // you now know that it was poison. o->type = findot(OT_POT_WATER); makeknown(o->type->id); // you now know what water is too. + donesomething = B_TRUE; } else { f = hasflag(o->flags, F_OBHP); - if (!f) { - nothinghappens(); - return B_TRUE; - } else { - + if (f) { f->val[0] = f->val[1]; - if (isdrinkable(o)) { - msg("Your %s looks more clean now.", noprefix(obname)); - } else { - msg("Your %s looks more fresh now.", noprefix(obname)); - } f = hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL); if (f) { killflag(f); } - if (seenbyplayer) *seenbyplayer = B_TRUE; + donesomething = B_TRUE; } + + f = hasflag(o->flags, F_TAINTED); + if (f) { + killflag(f); + donesomething = B_TRUE; + } + } + + if (donesomething) { + if (isdrinkable(o)) { + msg("Your %s looks more clean now.", noprefix(obname)); + } else { + msg("Your %s looks more fresh now.", noprefix(obname)); + } + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else { + nothinghappens(); + return B_TRUE; } } else { // monsters can't purify things! @@ -4882,6 +4993,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_SLEETSTORM) { int failed = B_FALSE; + if (isoutdoors(caster->cell->map)) { + power += 3; + limit(&power, NA, 10); + } // ask for a target cell if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power)) return B_TRUE; if (targcell) { @@ -5181,7 +5296,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); + c = askcoords(buf, TT_NONE, caster, UNLIMITED); if (!c->known) { // confirm ch = askchar("Are you sure to want to teleport into the unknown?", "yn", "n", B_TRUE); @@ -5337,7 +5452,7 @@ 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); + where = askcoords(buf, TT_OBJECT | TT_DOOR, caster, UNLIMITED); if (where && haslos(caster, where)) { if (where->obpile->first) { // select object from cell... @@ -5374,7 +5489,7 @@ 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); + targcell = askcoords(buf, TT_MONSTER | TT_PLAYER, caster, UNLIMITED); } // not liftable? @@ -5888,7 +6003,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ o = relinkob(o, newloc->obpile); } if (o) { - noise(caster->cell, NULL, "something hitting the ground.", NULL); + noise(caster->cell, NULL, 1, "something hitting the ground.", NULL); if (!isblind(caster)) { msg("%s appear%s on the ground!", obname, (o->amt == 1) ? "s" : ""); } @@ -5909,6 +6024,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return rv; } +objecttype_t *findspelln(char *buf) { + objecttype_t *ot; + for (ot = objecttype ; ot ; ot = ot->next) { + if (ot->obclass->id == OC_SPELL) { + if (!strcasecmp(ot->name, buf)) { + return ot; + } + } + } + return NULL; +} + void fizzle(lifeform_t *caster) { if (isplayer(caster)) { if (lfhasflag(caster, F_CASTINGSPELL)) { @@ -5925,6 +6052,30 @@ void fizzle(lifeform_t *caster) { } } +enum OBTYPE getrandomspell(void) { + int wantlev; + objecttype_t *ot,*poss[MAXCANDIDATES]; + int nposs = 0; + + wantlev = 1; + while (rnd(1,2) == 1) { + wantlev++; + } + + // get list of all spells of this level + for (ot = objecttype ; ot ; ot = ot->next) { + if ((ot->obclass->id == OC_SPELL) && (getspelllevel(ot->id) == wantlev) ) { + poss[nposs++] = ot; + } + } + + if (nposs <= 0) { + return OT_NONE; + } + ot = poss[rnd(0,nposs-1)]; + return ot->id; +} + enum SKILL getschoolskill(enum SPELLSCHOOL ss) { switch (ss) { case SS_ALLOMANCY: @@ -6252,6 +6403,12 @@ int getspellrange(enum OBTYPE spellid, int power) { // base range for this spell is 3 range += (power/3); break; + case OT_S_CALLWIND: + range = (power*2); + break; + case OT_S_LIGHTNINGBOLT: + range = (power*3); + break; default: break; } @@ -6345,6 +6502,19 @@ void stopallspells(lifeform_t *lf) { } } +int schoolappearsinbooks(enum SPELLSCHOOL ss) { + switch (ss) { + case SS_DIVINE: + case SS_ABILITY: + case SS_ALLOMANCY: + case SS_MENTAL: + return B_FALSE; + default: + break; + } + return B_TRUE; +} + void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYPE sid, int power) { int x,y; if (ch != '\0') { @@ -6480,7 +6650,7 @@ lifeform_t *validateabillf(lifeform_t *user, enum OBTYPE aid, lifeform_t **targe cell_t *where; char buf[BUFLEN]; sprintf(buf, "Where will you target your %s?",ot->name); - where = askcoords(buf, TT_MONSTER); + where = askcoords(buf, TT_MONSTER, user, maxrange); if (where) { if (!haslf(where)) { msg("There is nobody there!"); @@ -6611,7 +6781,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); + where = askcoords(buf, targtype, caster, maxrange); if (!where) { int ch; ch = askchar("Abandon your spell?","yn","n", B_TRUE); @@ -6704,7 +6874,7 @@ lifeform_t *validatespelllf(lifeform_t *caster, lifeform_t **target) { cell_t *where; char buf[BUFLEN]; sprintf(buf, "Where will you target your spell?"); - where = askcoords(buf, TT_MONSTER); + where = askcoords(buf, TT_MONSTER, caster, UNLIMITED); if (where && haslos(caster, where) && haslf(where)) { *target = haslf(where); } else { diff --git a/spell.h b/spell.h index 95d1947..4e79d07 100644 --- a/spell.h +++ b/spell.h @@ -4,9 +4,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifeform_t *target, flag_t *cwflag); int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer); +objecttype_t *findspelln(char *buf); void fizzle(lifeform_t *caster); //int getiqreq(enum OBTYPE oid); int getmpcost(lifeform_t *lf, enum OBTYPE oid); +enum OBTYPE getrandomspell(void); enum SKILL getschoolskill(enum SPELLSCHOOL ss); char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf); int getspellduration(int min,int max,int blessed); @@ -19,6 +21,7 @@ enum SPELLSCHOOL getspellschoolknown(lifeform_t *lf, enum OBTYPE spellid); int getspellrange(enum OBTYPE spellid, int power); char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf); void pullobto(object_t *o, lifeform_t *lf); +int schoolappearsinbooks(enum SPELLSCHOOL ss); void spellcloud(cell_t *srcloc, int radius, char ch, enum COLOUR col, enum OBTYPE sid, int power); void stopspell(lifeform_t *caster, enum OBTYPE spellid); void stopallspells(lifeform_t *lf); diff --git a/text.c b/text.c index 96e3af0..3af8499 100644 --- a/text.c +++ b/text.c @@ -328,7 +328,7 @@ char *makeplural(char *text) { if (rv) return newtext; newtext = strrep(newtext, "gem ", "gems ", &rv); if (rv) return newtext; - newtext = strrep(newtext, "leaf ", "leaves ", &rv); + newtext = strrep(newtext, "leaf", "leaves", &rv); if (rv) return newtext; newtext = strrep(newtext, "loaf ", "loaves ", &rv); if (rv) return newtext;