diff --git a/ai.c b/ai.c index cf7e4e2..3669081 100644 --- a/ai.c +++ b/ai.c @@ -528,7 +528,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // reset F_TARGET lifetime to full. if (targetflag) { if (targetflag->id == F_TARGETLF) { - targetflag->lifetime = AI_FOLLOWTIME; + targetflag->lifetime = DEF_AIFOLLOWTIME; } if (db) dblog(".oO { i can see my target (at %d,%d). might move towards it. }",target->cell->x,target->cell->y); // remember their location @@ -818,7 +818,7 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) { if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y); // moved towards it. // reset lifetime - f->lifetime = AI_FOLLOWTIME; + f->lifetime = DEF_AIFOLLOWTIME; // are we there yet? if (lf->cell == c) { @@ -1382,7 +1382,7 @@ void aiturn(lifeform_t *lf) { } if (newtarget) { - if (aiattack(lf, newtarget, AI_FOLLOWTIME)) { + if (aiattack(lf, newtarget, DEF_AIFOLLOWTIME)) { // failed for some reason. maybe target was feigning // death? } else { @@ -2030,7 +2030,7 @@ int lookforobs(lifeform_t *lf) { } } // start walking towards target cell - if (aigoto(lf, c, MR_OB, o, AI_FOLLOWTIME)) { + if (aigoto(lf, c, MR_OB, o, DEF_AIFOLLOWTIME)) { return B_FALSE; } } diff --git a/defs.h b/defs.h index 4f495df..87f4df2 100644 --- a/defs.h +++ b/defs.h @@ -8,17 +8,292 @@ // #define PRACTICETIME 15 // #attempts it takes to learn new weapon skill -#define WETTIME 10 // how long it takes for things to dry -#define DRUNKTIME 10 // how long it takes for alcohol to wear off - -// chances of things happening +// Probabilities #define ONEIN_FOUNTAINDRYUP 3 +#define PCTCH_PILLAR 5 -#define SHOPIDENTPRICE 50 // cost to identify a just-purchased item +// Defaults +#define DEF_AIFOLLOWTIME (50) // if target lf is out of view + // for this many turns, abandon chase +#define DEF_ANIMDELAY (1000000 / 50) // 1/100 of a second +#define DEF_RESTHEALTIME (3) +#define DEF_SCREENW 80 +#define DEF_SCREENH 24 +#define DEF_SHOPIDENTPRICE (50) // cost to identify a just-purchased item +#define DEF_VAULTMARGIN (3) + +// Map building defaults +#define DEF_LOOPPCT 95 +#define DEF_SPARSENESS 20 +#define DEF_TURNPCT 40 +#define DEF_WINDOWPCT 5 + +// getrandomemptycell() params +#define WE_WALKABLE 1 +#define WE_EMPTY 2 +#define WE_PORTAL 3 +#define WE_NOTWALL 4 +#define WE_NOLF 5 + +// Booleans +#define B_FALSE (0) +#define B_TRUE (-1) +#define B_VIS (1) +#define B_UNKNOWN (0) +#define B_NOVIS (-1) +#define B_KEEPLOF (-1) +#define B_MALE (0) +#define B_FEMALE (-1) +#define B_MAYCHASE (-1) +#define B_NODOORS (0) +#define B_DONTKILL (-1) + +//#define B_TEMP (-1) +//#define B_PERM (-2) +//#define B_NOT (-3) + +#define B_DIEONFAIL (-1) +#define B_BLUNTONFAIL (-2) + +#define B_COVETS (-1) +#define B_ANY (0) + +#define B_SINGLE (0) +#define B_MULTI (-1) +#define B_MULTIPLE (-1) + +#define B_NOOBS (0) +#define B_WITHOBS (-1) + +#define B_UNKNOWN (0) +#define B_KNOWN (-1) +#define B_TRIED (1) + +#define B_NOBADMOVES (0) +#define B_BADMOVESOK (1) + +#define B_NOSTACK (0) +#define B_STACK (-1) +#define B_STACKOK (-1) + +#define NOOWNER (NULL) +#define NOLOC (NULL) +#define NOOB (NULL) + +#define B_NOTSOLID (0) +#define B_EMPTY (0) +#define B_SOLID (-1) + +#define B_OPAQUE (0) +#define B_TRANSPARENT (-1) +#define B_TRANS (-1) + +#define B_ALLOWEXPAND (-1) +#define B_NOEXPAND (0) + +#define B_IFACTIVATED (-1) + +#define B_BIG (-1) + +// Limits +#define MAXCANDIDATES 200 +#define MAXCHOICES 400 +#define MAXDEPTH 25 // max dungeon depth +#define MAXDIR_ORTH 4 +#define MAXDIR_COMPASS 8 +#define MAXFLAGS 500 +#define MAXHISTORY 20 // max lines of history to keep +#define MAX_MAPW 80 +#define MAX_MAPH 20 +#define MAXPILEOBS 52 +#define MAXRANDOMOBCANDIDATES 100 +#define MAXRANDOMLFCANDIDATES 100 +#define MAXRETCELLS 80 +#define MAXSPELLLEV 6 +#define MAXVISRANGE 10 // max visible range in full light +#define MAXVISLIMIT (MAXVISRANGE*8) + +#define MINCLEARINGRADIUS 2 +#define MAXCLEARINGRADIUS 5 + +#define MINROOMS 5 +#define MAXROOMS 10 +#define MIN_ROOMH 4 +#define MIN_ROOMW 4 +#define MAX_ROOMW (MAX_MAPW / 3) +#define MAX_ROOMH (MAX_MAPH / 3) + +// askobject options +#define AO_NONE 0 +#define AO_INCLUDENOTHING 1 +#define AO_ONLYEQUIPPED 2 +#define AO_EDIBLE 4 +#define AO_NOTIDENTIFIED 8 +#define AO_WEARABLE 16 +#define AO_OPERABLE 32 +#define AO_POURABLE 64 +#define AO_EQUIPPEDNONWEAPON 128 +#define AO_WEILDABLE 256 +#define AO_SPECIFIED 512 +#define AO_READABLE 1024 +#define AO_ARMOUR 2048 +#define AO_NOTKNOWN 4096 +#define AO_DAMAGED 8192 +#define AO_DRINKABLE 16384 + +// askcoords target types +#define TT_NONE 0 +#define TT_MONSTER 1 +#define TT_OBJECT 2 +#define TT_DOOR 4 +#define TT_PLAYER 8 +#define TT_ALLY 16 +#define TT_IMPASSABLE 32 + +// target requirements +#define TR_NONE 0 +#define TR_NEEDLOS 1 +#define TR_NEEDLOF 2 + +// CONTROLLERS +#define C_AI 0 +#define C_PLAYER 1 + +// speeds +#define SP_GODLIKE 1 +#define SP_ULTRAFAST 5 +#define SP_VERYFAST 10 +#define SP_FAST 15 +#define SP_NORMAL 20 +#define SP_SLOW 25 +#define SP_VERYSLOW 30 +#define SP_ULTRASLOW 35 +#define SP_SLOWEST 40 + +#define SPEEDUNIT 5 + +// speed settings (lower is faster) +#define SPEED_ATTACK SP_NORMAL +#define SPEED_DEAD 50 +#define SPEED_ACTION SP_NORMAL +#define SPEED_MOVE SP_NORMAL +#define SPEED_DROP SP_FAST +#define SPEED_PICKUP SP_FAST +#define SPEED_THROW SP_FAST +#define SPEED_WAIT SP_NORMAL +#define SPEED_READ SP_NORMAL +#define SPEED_DRINK SP_FAST + + +// DIRECTION TYPES +#define DT_ORTH 0 +#define DT_COMPASS 1 + +// DIRECTIONS +#define D_NONE -1 +#define D_UNKNOWN -2 + +// Orthogonal directions +#define D_N 0 +#define D_E 1 +#define D_S 2 +#define D_W 3 + +// Compass directions +#define DC_N 4 +#define DC_NE 5 +#define DC_E 6 +#define DC_SE 7 +#define DC_S 8 +#define DC_SW 9 +#define DC_W 10 +#define DC_NW 11 + +// altitude directions +#define D_UP 12 +#define D_DOWN 13 +#define D_IN 14 + +#define MAXDIR_MAP 15 + +/////////////////////////////////////// +// STRINGS +/////////////////////////////////////// +// String buffer lengths +#define BUFLENTINY 10 +#define BUFLENSMALL 64 +#define BUFLEN 128 +#define BIGBUFLEN 512 +#define HUGEBUFLEN 1024 +#define MAXPNAMELEN 12 // max player name length +// file i/o +#define DATADIR "data" +#define MAPDIR "data/maps" +#define SAVEDIR "data/save" +#define VAULTDIR "vaults" // rank, score, name, job, killer #define HISCOREFORMAT "%-6s%-7s%-14s%-18s%s" +// game strings +#define MORESTRING "--More--" +#define MSGMORESTRING "^n--More--" +#define SOLDOUTSTRING "--SOLD OUT--" + +// SPECIAL NUMBERS/CONSTANTS +#define DUMMYCELLTYPE 0xabcd +#define UNLIMITED (-9876) +#define ALL (-9875) +#define NA (-9874) +#define NOBODY (-1) +#define ALLCONFERRED (-9873) +#define PCT (65432) // must be POSITIVE +#define RANDOM (-2610) +#define AUTO (-7654) + +// Time periods +#define TM_DRUNKTIME (10) // how long it takes for alcohol to wear off +#define TM_WETTIME (10) // how long it takes for things to dry +#define TM_SCENT (15) // how long scents take to fade +#define TM_FOOTPRINT (20) // how long footprints take to fade + +// object conditions for random objects +#define RO_NONE 0 +#define RO_DAMTYPE 1 +#define RO_OBCLASS 2 +#define RO_HOLDABLE 3 + +// flag lifetimes +#define PERMENANT (-9873) +#define FROMSPELL (-9863) +#define FROMPOISON (-9862) + +// flag lifetimes - external sources (ie. don't kill them) +#define FROMEXTERNAL_HIGH (-7000) +#define FROMRACE (-7872) +#define FROMJOB (-7871) +#define FROMOBEQUIP (-7870) +#define FROMOBHOLD (-7869) +#define FROMOBACTIVATE (-7868) +#define FROMMAT (-7867) +#define FROMBLESSING (-9866) +#define FROMBRAND (-7865) +#define FROMOBMOD (-7864) +#define FROMSKILL (-7863) +#define FROMGODGIFT (-7862) +#define FROMEXTERNAL_LOW (-7999) +#define LEVABILITYDONE (-8000) + +#define IFKNOWN (-9772) // used by f_xxconfer. only confer a flag if item is known. +#define IFACTIVE (-9771) // used by f_prodeuceslight. only does so if object is activated + +// Misc constants +#define ANYROOM (-9770) +#define FALLTHRU (-8765) // for walkdambp +#define TICK_INTERVAL (20) + + + // ncurses colours #define C_NONE (-1) enum COLOUR { @@ -147,24 +422,6 @@ enum SKILLLEVEL { #define MAXSKILLLEVEL 7 -// save/load -#define DATADIR "data" -#define MAPDIR "data/maps" -#define SAVEDIR "data/save" -#define VAULTDIR "vaults" -#define DUMMYCELLTYPE 0xabcd - -// SPECIAL NUMBERS/CONSTANTS -#define UNLIMITED (-9876) -#define ALL (-9875) -#define NA (-9874) -#define NOBODY (-1) -#define ALLCONFERRED (-9873) -#define PCT (65432) // must be POSITIVE -#define RANDOM (-2610) - -#define AUTO (-7654) - enum GAMEMODE { GM_FIRST, GM_INIT, @@ -237,76 +494,12 @@ enum SENSE { S_TOUCH, }; -// AI defs - -// if target lf is out of view for this many turns, abandon chase -#define AI_FOLLOWTIME (50) - -#define DEFAULTRESTHEALTIME (3) - - -// object confitions for random objects -#define RO_NONE 0 -#define RO_DAMTYPE 1 -#define RO_OBCLASS 2 -#define RO_HOLDABLE 3 - -// flag lifetimes -#define PERMENANT (-9873) -#define FROMSPELL (-9863) -#define FROMPOISON (-9862) - -// external sources (ie. don't kill them) -#define FROMEXTERNAL_HIGH (-7000) -#define FROMRACE (-7872) -#define FROMJOB (-7871) -#define FROMOBEQUIP (-7870) -#define FROMOBHOLD (-7869) -#define FROMOBACTIVATE (-7868) -#define FROMMAT (-7867) -#define FROMBLESSING (-9866) -#define FROMBRAND (-7865) -#define FROMOBMOD (-7864) -#define FROMSKILL (-7863) -#define FROMGODGIFT (-7862) -#define FROMEXTERNAL_LOW (-7999) - - -#define LEVABILITYDONE (-8000) - -#define IFKNOWN (-9772) // used by f_xxconfer. only confer a flag if item is known. -#define IFACTIVE (-9771) // used by f_prodeuceslight. only does so if object is activated enum FLAGCONDITION { FC_NOCONDITION = 0, FC_IFPLAYER, FC_IFMONSTER, }; -//#define NOCONDITION (0) -//#define IFMONSTER (-9769) // used in v2 of f_ifpct job flags -//#define IFPLAYER (-9768) // used in v2 of f_ifpct job flags - -#define ANYROOM (-9770) - -#define TICK_INTERVAL (20) - - -#define SCENTTIME (15) -#define FOOTPRINTTIME (20) - -// STRINGS -#define BUFLENTINY 10 -#define BUFLENSMALL 64 -#define BUFLEN 128 -#define BIGBUFLEN 512 -#define HUGEBUFLEN 1024 - -#define MAXPNAMELEN 12 - - -#define MORESTRING "--More--" -#define MSGMORESTRING "^n--More--" -#define SOLDOUTSTRING "--SOLD OUT--" enum MSGCHARCOL { CC_VBAD, @@ -326,100 +519,6 @@ enum MODTYPE { }; -// LIMITS - - -#define DEF_SCREENW 80 -#define DEF_SCREENH 24 - -#define MAXPILEOBS 52 - -#define MAXSPELLLEV 6 - -#define MAXRETCELLS 80 - -#define MAXFLAGS 500 - -#define MAXCHOICES 400 - -#define MAXDEPTH 25 // max dungeon depth - -#define MAXRANDOMOBCANDIDATES 100 -#define MAXRANDOMLFCANDIDATES 100 -#define MAXCANDIDATES 200 - -//#define MAX_MAPW 80 -//#define MAX_MAPH 50 -#define MAX_MAPW 80 -#define MAX_MAPH 20 - - -#define MINCLEARINGRADIUS 2 -#define MAXCLEARINGRADIUS 5 - -//#define MAX_MAPROOMS 10 - -#define MIN_ROOMH 4 -#define MIN_ROOMW 4 -#define MAX_ROOMW (MAX_MAPW / 3) -#define MAX_ROOMH (MAX_MAPH / 3) - -#define MAXDIR_ORTH 4 -#define MAXDIR_COMPASS 8 - -#define MAXHISTORY 20 // max lines of history to keep - -// MAP BUILDING -#define DEF_TURNPCT 40 -//#define DEF_SPARSENESS 14 -#define DEF_SPARSENESS 20 -//#define DEF_SPARSENESS 0 -//#define DEF_LOOPPCT 70 -#define DEF_LOOPPCT 95 -//#define DEF_LOOPPCT 0 -#define MINROOMS 5 -#define MAXROOMS 10 -#define DEF_WINDOWPCT 5 - -// -//#define ANIMDELAY (1000000 / 100) // 1/100 of a second -#define ANIMDELAY (1000000 / 50) // 1/100 of a second - -#define MAXVISRANGE 10 // max visible range in full light -#define MAXVISLIMIT (MAXVISRANGE*8) - - -// askobject options -#define AO_NONE 0 -#define AO_INCLUDENOTHING 1 -#define AO_ONLYEQUIPPED 2 -#define AO_EDIBLE 4 -#define AO_NOTIDENTIFIED 8 -#define AO_WEARABLE 16 -#define AO_OPERABLE 32 -#define AO_POURABLE 64 -#define AO_EQUIPPEDNONWEAPON 128 -#define AO_WEILDABLE 256 -#define AO_SPECIFIED 512 -#define AO_READABLE 1024 -#define AO_ARMOUR 2048 -#define AO_NOTKNOWN 4096 -#define AO_DAMAGED 8192 -#define AO_DRINKABLE 16384 - -// askcoords target types -#define TT_NONE 0 -#define TT_MONSTER 1 -#define TT_OBJECT 2 -#define TT_DOOR 4 -#define TT_PLAYER 8 -#define TT_ALLY 16 -#define TT_IMPASSABLE 32 - -// target requirements -#define TR_NONE 0 -#define TR_NEEDLOS 1 -#define TR_NEEDLOF 2 // line of fire args enum LOFTYPE { @@ -429,74 +528,6 @@ enum LOFTYPE { LOF_NEED = 6, // walls AND lfs block }; -// CONTROLLERS -#define C_AI 0 -#define C_PLAYER 1 - -// deafult -//#define DEF_HEALTIME 100 // time to heal 1 hp - -// speeds -#define SP_GODLIKE 1 -#define SP_ULTRAFAST 5 -#define SP_VERYFAST 10 -#define SP_FAST 15 -#define SP_NORMAL 20 -#define SP_SLOW 25 -#define SP_VERYSLOW 30 -#define SP_ULTRASLOW 35 -#define SP_SLOWEST 40 - -#define SPEEDUNIT 5 - -// speed settings (lower is faster) -#define SPEED_ATTACK SP_NORMAL -#define SPEED_DEAD 50 -#define SPEED_ACTION SP_NORMAL -#define SPEED_MOVE SP_NORMAL -#define SPEED_DROP SP_FAST -#define SPEED_PICKUP SP_FAST -#define SPEED_THROW SP_FAST -#define SPEED_WAIT SP_NORMAL -#define SPEED_READ SP_NORMAL -#define SPEED_DRINK SP_FAST - - -// DIRECTION TYPES -#define DT_ORTH 0 -#define DT_COMPASS 1 - -// DIRECTIONS - - -#define D_NONE -1 -#define D_UNKNOWN -2 - -// Orthogonal directions -#define D_N 0 -#define D_E 1 -#define D_S 2 -#define D_W 3 - -// Compass directions -#define DC_N 4 -#define DC_NE 5 -#define DC_E 6 -#define DC_SE 7 -#define DC_S 8 -#define DC_SW 9 -#define DC_W 10 -#define DC_NW 11 - -// altitude directions -#define D_UP 12 -#define D_DOWN 13 -#define D_IN 14 - -#define MAXDIR_MAP 15 - - - // Cell types enum CELLTYPE { CT_NONE = 0, @@ -1486,13 +1517,6 @@ enum DEPTH { DP_NONE = 0, }; -// empty types -#define WE_WALKABLE 1 -#define WE_EMPTY 2 -#define WE_PORTAL 3 -#define WE_NOTWALL 4 -#define WE_NOLF 5 - enum NOISETYPE { N_GETANGRY, N_WALK, @@ -1608,6 +1632,8 @@ enum FLAG { F_ATTACKABLE, // can attack this with 'A' F_IMPASSABLE, // cannot walk past this if your size is between v0 and v1 // (inclusive) + F_REALLYIMPASSABLE, // even gaseous form etc won't let you get through + // this. F_CRUSHABLE, // if you are bigger than size v0, walking on this crushes it F_CAUSESCOUGH, // being in this ob's cell will make you cough unless // immune to gas. @@ -2354,37 +2380,6 @@ enum PIETYLEV { PL_ECSTATIC = 3, }; -// probabilities -//#define CH_DEADENDOB 35 -//#define CH_EMPTYCELLOB 3 -#define CH_PILLAR 5 - - -// Booleans -#define B_FALSE (0) -#define B_TRUE (-1) - -#define B_VIS (1) -#define B_UNKNOWN (0) -#define B_NOVIS (-1) - -#define B_KEEPLOF (-1) - -#define B_MALE (0) -#define B_FEMALE (-1) - -#define B_MAYCHASE (-1) - -#define B_NODOORS (0) - -#define B_DONTKILL (-1) - -#define FALLTHRU (-8765) - -//#define B_TEMP (-1) -//#define B_PERM (-2) -//#define B_NOT (-3) - enum LIGHTLEV { L_PERMDARK = -1, L_NOTLIT = 0, @@ -2404,49 +2399,6 @@ enum SPELLTARGET { }; -#define B_DIEONFAIL (-1) -#define B_BLUNTONFAIL (-2) - -#define B_COVETS (-1) -#define B_ANY (0) - -#define B_SINGLE (0) -#define B_MULTI (-1) -#define B_MULTIPLE (-1) - -#define B_NOOBS (0) -#define B_WITHOBS (-1) - -#define B_UNKNOWN (0) -#define B_KNOWN (-1) -#define B_TRIED (1) - -#define B_NOBADMOVES (0) -#define B_BADMOVESOK (1) - -#define B_NOSTACK (0) -#define B_STACK (-1) -#define B_STACKOK (-1) - -#define NOOWNER (NULL) -#define NOLOC (NULL) -#define NOOB (NULL) - -#define B_NOTSOLID (0) -#define B_EMPTY (0) -#define B_SOLID (-1) - -#define B_OPAQUE (0) -#define B_TRANSPARENT (-1) -#define B_TRANS (-1) - -#define B_ALLOWEXPAND (-1) -#define B_NOEXPAND (0) - -#define B_IFACTIVATED (-1) - -#define B_BIG (-1) - // errors enum ERROR { E_OK = 0, @@ -2657,6 +2609,7 @@ typedef struct map_s { int nrooms; // how many rooms on this map char *name; // name of this map habitat_t *habitat; + long lastplayervisit; unsigned int seed; int w,h; // width/height of this map struct cell_s *cell[MAX_MAPW*MAX_MAPH]; // list of cells in this map @@ -2747,6 +2700,7 @@ typedef struct cell_s { // FOR CONSTRUCTION int visited; + int filled; } cell_t; typedef struct celltype_s { diff --git a/doc/criticals.txt b/doc/criticals.txt new file mode 100644 index 0000000..1181328 --- /dev/null +++ b/doc/criticals.txt @@ -0,0 +1,12 @@ +Critical effects: + attack.c: + update damtypecausescriteffects() + update criticalhit() + put replacements for similar damage types at the top + lf.c: + update injure() with special effects for bp_head + text.c: + update getinjuryname() + update getinjurydesc() + + ... then implement effects for f_injury bp_xxx dt_xxx diff --git a/flag.c b/flag.c index 874ef26..e5c9a96 100644 --- a/flag.c +++ b/flag.c @@ -1100,7 +1100,7 @@ void timeeffectsflag(flag_t *f, int howlong) { return; } else { // reset timer - f->val[1] = WETTIME; + f->val[1] = TM_WETTIME; // TODO: announce } } diff --git a/io.c b/io.c index 1dbf2c4..9407ec5 100644 --- a/io.c +++ b/io.c @@ -221,7 +221,7 @@ void anim(cell_t *src, cell_t *dst, char ch, int colour) { //mvwprintw(gamewin, cell->y - viewy, cell->x - viewx, "%c", gl.ch); wmove(gamewin, cell->y - viewy, cell->x - viewx); wrefresh(gamewin); - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); } // move to next cell @@ -279,13 +279,13 @@ void animcells(cell_t *src, cell_t **dst, int ndst, int gradual, char ch, char c if (gradual) { wrefresh(gamewin); - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); } } if (!gradual) { wrefresh(gamewin); - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); } // show cursor curs_set(1); @@ -332,13 +332,13 @@ void animline(cell_t *src, cell_t *dst, int gradual, char ch, char ch2, int colo if (gradual) { wrefresh(gamewin); - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); } } if (!gradual) { wrefresh(gamewin); - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); } // show cursor curs_set(1); @@ -378,7 +378,7 @@ void animradial(cell_t *src, int radius, char ch, int colour) { wrefresh(gamewin); if (drawn) { - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); } } // show cursor @@ -420,7 +420,7 @@ void animradialorth(cell_t *src, int radius, char ch,int colour) { wrefresh(gamewin); if (drawn) { - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); } } // show cursor @@ -453,7 +453,7 @@ void animsky(cell_t *src, char ch, int colour) { drawglyph(&gl, src->x - viewx, y); } wrefresh(gamewin); - usleep(ANIMDELAY); + usleep(DEF_ANIMDELAY); // show cursor curs_set(1); @@ -4212,7 +4212,7 @@ void docomms(lifeform_t *lf) { } else { // stop attacking all current targets first... killflagsofid(lf->flags, F_TARGETLF); - aiattack(lf, lf2, AI_FOLLOWTIME); + aiattack(lf, lf2, DEF_AIFOLLOWTIME); } break; case 'c': @@ -4220,7 +4220,7 @@ void docomms(lifeform_t *lf) { // find adjacent cell c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND); if (c) { - aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME); + aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME); } break; case 'd': // donate @@ -4345,7 +4345,7 @@ void docomms(lifeform_t *lf) { // stop attacking all current targets first... killflagsofid(lf->flags, F_TARGETLF); msg("You say \"Go over there!\" to %s.", lfname); - aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME); + aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME); break; case 'j': // charisma check to see if they'll join you. @@ -4372,19 +4372,19 @@ void docomms(lifeform_t *lf) { msg("You buy %s.", buf); angeramt += 25; // get it identified? - if (!isknown(o) && (countmoney(player) >= SHOPIDENTPRICE)) { + if (!isknown(o) && (countmoney(player) >= DEF_SHOPIDENTPRICE)) { char buf2[BUFLEN]; char ch2; - sprintf(buf2, "Pay $%d to identify %s?",(int)SHOPIDENTPRICE, buf); + sprintf(buf2, "Pay $%d to identify %s?",(int)DEF_SHOPIDENTPRICE, buf); ch2 = askchar(buf2, "yn","n", B_TRUE); if (ch2 == 'y') { - if (givemoney(player, lf, SHOPIDENTPRICE)) { + if (givemoney(player, lf, DEF_SHOPIDENTPRICE)) { angeramt += 25; identify(o); real_getobname(o, buf, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness msgnocap("%c - %s",o->letter, buf); } else { - msg("You can't afford to pay $%d.", SHOPIDENTPRICE); + msg("You can't afford to pay $%d.", DEF_SHOPIDENTPRICE); } } } @@ -7139,15 +7139,6 @@ void dblog(char *format, ... ) { vsprintf( buf, format, args ); va_end(args); - /* - if (gamestarted) { - fprintf(logfile, "%s\n", buf); - fflush(logfile); - } else { - printf("%s\n", buf); - fflush(stdout); - } - */ if (logfile) { fprintf(logfile, "%s\n", buf); fflush(logfile); @@ -7157,6 +7148,23 @@ void dblog(char *format, ... ) { } } +void dblog_nocr(char *format, ... ) { + char buf[HUGEBUFLEN]; + va_list args; + + va_start(args, format); + vsprintf( buf, format, args ); + va_end(args); + + if (logfile) { + fprintf(logfile, "%s", buf); + fflush(logfile); + } else { + fprintf(stdout, "%s", buf); + fflush(stdout); + } +} + // force a '--more--' prompt void more(void) { //msg("^"); diff --git a/io.h b/io.h index 173a297..731578b 100644 --- a/io.h +++ b/io.h @@ -101,6 +101,7 @@ void msg_real(char *format, ... ); int needsbold(enum COLOUR col); void nothinghappens(void); void dblog(char *format, ... ); +void dblog_nocr(char *format, ... ); void redraw(void); void redrawpause(void); void redrawresume(void); diff --git a/lf.c b/lf.c index 009900d..bac53d3 100644 --- a/lf.c +++ b/lf.c @@ -3199,14 +3199,14 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) { if (!isplayer(attacker)) return; } - aiattack(lf, attacker, AI_FOLLOWTIME); + aiattack(lf, attacker, DEF_AIFOLLOWTIME); // any nearby monsters which will help out? if (getallegiance(lf) != AL_FRIENDLY) { for (l = lf->cell->map->lf ; l ; l = l->next) { if (!isdead(l) && areallies(l,lf)) { if (cansee(l, attacker)) { - aiattack(l, attacker, AI_FOLLOWTIME); + aiattack(l, attacker, DEF_AIFOLLOWTIME); } } } @@ -4257,6 +4257,7 @@ int getevasion(lifeform_t *lf) { int ev = 0,i; flag_t *retflag[MAXCANDIDATES]; int nretflags; + double level_ev = 0, skillpctmod; // no evasion if you can't move! if (isimmobile(lf)) { @@ -4270,30 +4271,11 @@ int getevasion(lifeform_t *lf) { ev += (f->val[0]); } - // level based evasion - ev += gethitdice(lf); - - // skill based - //ev += (getskill(lf, SK_EVASION)*10); - ev += (getskill(lf, SK_EVASION)*5); - - // now get object penalties/bonuses - /* - for (o = lf->pack->first ; o ; o = o->next) { - // armour/weapons must be worn to do anything - if (hasflag(o->flags, F_EQUIPPED)) { - f = hasflag(o->flags, F_EVASION); - if (f) { - if (isarmour(o)) { - // adjust penalties based on armour skill. - ev += adjustarmourpenalty(lf, f->val[0]); - } else { - ev += (f->val[0]); - } - } - } - } - */ + // level based evasion (modified by evasion skill) + level_ev = gethitdice(lf); + skillpctmod = (getskill(lf, SK_EVASION) + 1) * 40; + level_ev = pctof(skillpctmod, level_ev); + ev += level_ev; // adjust for bulky armour/shield getflags(lf->flags, retflag, &nretflags, F_ARMOURPENALTY, F_SHIELDPENALTY, F_NONE); @@ -4556,7 +4538,7 @@ object_t *getfirearm(lifeform_t *lf) { int getfootprinttime(lifeform_t *lf) { int time; - time = FOOTPRINTTIME; + time = TM_FOOTPRINT; switch (getlfsize(lf)) { case SZ_MINI: time = 1; break; case SZ_TINY: time -= 15; break; @@ -4842,7 +4824,7 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { f = isdrunk(lf); if (f) { int amt; - amt = (f->lifetime/DRUNKTIME)+1; + amt = (f->lifetime/TM_DRUNKTIME)+1; if (hasjob(lf, J_PIRATE)) { acc += (10*amt); } else { @@ -11887,12 +11869,12 @@ void addtrail(lifeform_t *lf, int dir) { scent = hastrailof(lf->cell->obpile, lf, OT_SCENT, &fpflag, NULL); if (scent) { assert(fpflag); - fpflag->lifetime = SCENTTIME; + fpflag->lifetime = TM_SCENT; } else { char buf[BUFLENTINY]; sprintf(buf, "%d", lf->id); scent = addobfast(lf->cell->obpile, OT_SCENT); - addtempflag(scent->flags, F_TRAIL, lf->race->id, dir, S_SMELL, buf, SCENTTIME); + addtempflag(scent->flags, F_TRAIL, lf->race->id, dir, S_SMELL, buf, TM_SCENT); } } @@ -17602,7 +17584,7 @@ int rest(lifeform_t *lf, int onpurpose) { healtime = ff->val[0]; } else { // 3 turns = heal 1 hp - healtime = DEFAULTRESTHEALTIME; + healtime = DEF_RESTHEALTIME; } // modify via restob if resting using 'R' diff --git a/map.c b/map.c index 3af29e2..536426c 100644 --- a/map.c +++ b/map.c @@ -40,6 +40,8 @@ extern enum GAMEMODE gamemode; extern int needredraw; +extern long curtime; + cell_t *addcell(map_t *m, int x, int y) { cell_t *cell; m->cell[(y*m->w)+x] = malloc(sizeof(cell_t)); @@ -49,7 +51,6 @@ cell_t *addcell(map_t *m, int x, int y) { cell->y = y; cell->habitat = m->habitat; setcelltype(cell, cell->habitat->solidcelltype); - cell->visited = B_FALSE; cell->obpile = addobpile(NOOWNER, cell, NOOB); cell->lf = NULL; cell->room = NULL; @@ -61,6 +62,8 @@ cell_t *addcell(map_t *m, int x, int y) { cell->known = B_FALSE; cell->knownglyph.ch = ' '; cell->knownglyph.colour = C_GREY; + cell->visited = B_FALSE; + cell->filled = B_FALSE; return cell; } @@ -148,6 +151,7 @@ map_t *addmap(void) { a->flags = addflagpile(NULL, NULL); a->beingcreated = B_TRUE; a->habitat = findhabitat(H_DUNGEON); // default!!! + a->lastplayervisit = -1; return a; } @@ -1029,6 +1033,67 @@ int dowaterspread(cell_t *c) { return B_FALSE; } +void fix_reachability(map_t *m) { + int i,keepgoing = B_TRUE, nfixed = 0; + int db = B_TRUE; + cell_t *c = NULL; + if (db) dblog("fix_reachability starting."); + // find first non-empty cell + for (i = 0; i < m->w * m->h; i++) { + if (!m->cell[i]->type->solid) { + c = m->cell[i]; + break; + } + } + // no empty cells in map? + if (!c) return; + while (keepgoing) { + keepgoing = B_FALSE; + // mark all cells as non-filled + for (i = 0; i < m->w * m->h; i++) { + m->cell[i]->filled = FALSE; + } + // floodfill + floodfill(c); + // any remaining non-filled empty cells? + for (i = 0; i < m->w * m->h; i++) { + if (!m->cell[i]->type->solid && !m->cell[i]->filled) { + int nadded = 0; + // found an unreachable cell! link it back to a filled cell. + if (db) dblog(" found unreachable area at %d,%d. will fix it.", + m->cell[i]->x, m->cell[i]->y); + + linkexit(m->cell[i], B_TRUE, &nadded); + if (db) dblog(" fixed unreachable area by added %d cells.", nadded); + + + // now run the test again. + // 'c' will be where the next flood will will happen. + keepgoing = B_TRUE; + c = m->cell[i]; + nfixed++; + break; + } + } + } + if (db) dblog(" fix_reachability complete. fixed %d unreachable areas.", nfixed); +} + + +void floodfill(cell_t *startcell) { + int d; + if (startcell && // not off the map + !startcell->type->solid && // empty cell + !startcell->filled) { // not already filled + startcell->filled = B_TRUE; + } else { + return; + } + for (d = DC_N; d <= DC_NW; d++) { + floodfill(getcellindir(startcell, d)); // recursive call + } +} + cell_t *getcellat(map_t *map, int x, int y) { if (!isonmap(map, x, y)) return NULL; return map->cell[y*map->w + x]; @@ -1310,6 +1375,7 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int cell_t *cell; int sel; int db = B_FALSE; + int foundvalid = B_FALSE; // init coords list for (y = 1 + ymargin; y < (map->h - ymargin); y++) { @@ -1377,6 +1443,7 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int if (valid) { if (score < bestscore) { bestscore = score; + foundvalid = B_TRUE; } } else { score = 9999; @@ -1386,12 +1453,16 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int if (db) dblog("cell %d,%d - score %d",x,y,score); } - // now go through and make a list of all BEST positions - nposs = 0; - for (i = 0; i < ncoords; i++) { - if (coordscore[i] == bestscore) { - poss[nposs++] = coord[i]; + if (foundvalid) { + // now go through and make a list of all BEST positions + nposs = 0; + for (i = 0; i < ncoords; i++) { + if (coordscore[i] == bestscore) { + poss[nposs++] = coord[i]; + } } + } else { + nposs = 0; } if (nposs == 0) { @@ -1652,17 +1723,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } // use sparseness to cut down dead ends - for (i = 0; i < sparseness; i++) { - for (y = 0; y < map->h; y++) { - for (x = 0; x < map->w; x++) { - cell = getcellat(map, x,y); - if (countcellexits(cell) == 1) { - // erase this cell - setcelltype(cell, CT_WALL); - } - } - } - } + remove_deadends(map, sparseness); // introduce loops for (y = 0; y < map->h; y++) { @@ -1757,6 +1818,8 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ linkexits(map, map->room[i].id); } + // now clear up dead ends again. + remove_deadends(map, sparseness); // add staircases. // first dungeon level has 1 up stairs, 3 down. @@ -1814,7 +1877,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ //dblog("Adding obs to room %d/%d",i+1,numrooms); maxpillars = (roomw[i] / 4) + (roomh[i] / 4); // add pillars first - if ((maxpillars > 0) && (rnd(1,100) <= CH_PILLAR)) { + if ((maxpillars > 0) && pctchance(PCTCH_PILLAR)) { int n; int numpillars; numpillars = rnd(1,maxpillars); @@ -1849,7 +1912,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ while (!done) { c = getrandomroomcell(map, i); // if nothing there - //if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) { if (c && cellwalkable(NULL, c, NULL)) { int obchance; @@ -1880,9 +1942,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } // end if !vault } // end foreach room } // end if wantrooms & nrooms>0 - - - if (db) dblog("Finished adding objects."); + if (db) dblog("Finished adding stuff to rooms."); // now do a border y = 0; @@ -1906,6 +1966,9 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ clearcell(c); setcelltype(c,solidcell); } + + // ensure there are no unreachable areas + fix_reachability(map); } void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings) { @@ -2529,7 +2592,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *retx, int *rety) { int w,h,x,y; - int xmargin = 0,ymargin = 0; + int xmargin = DEF_VAULTMARGIN,ymargin = DEF_VAULTMARGIN; // defaults int minx,miny,maxx,maxy; int db = B_FALSE; int rotation = 0; @@ -2577,7 +2640,7 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r // forced calcroompos should never fail since it's // allowed to overlap other rooms. dblog("** couldn't make vault room!\n"); - msg("** ALERT: couldn't make vault room!\n"); + //msg("** ALERT: couldn't make vault room!\n"); return B_TRUE; } maxx = minx + (w-1); @@ -2633,6 +2696,229 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r return B_FALSE; } +// link a single cell up to the rest of the map. +// make sure it links to an empty cell of a DIFFERENT roomid. +// if 'wantfilled' is set, only link to "filled" cells. +// return TRUE on failure. +int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { + int db = B_FALSE; + int d, roomid; + int poss2[MAXCANDIDATES],nposs2; + int dist[MAXDIR_ORTH]; + int hitsedge[MAXDIR_ORTH]; + int mindist = 999,maxdist = -1; + cell_t *c; + + if (ncellsadded) *ncellsadded = 0; + + if (db) dblog(" calling linkexit() for cell at %d,%d", startcell->x, startcell->y); + + roomid = getroomid(startcell); + + // link it. starting from the door, count the number of cells in + // each direction until we hit an empty (walkable) cell which isn't a room. + + // if we hit a cell of this roomid, mark this dir as invalid. + for (d = D_N; d <= D_W; d++) { + dist[d] = 0; + hitsedge[d] = B_TRUE; + c = getcellindir(startcell, d); + while (c) { + dist[d]++; + if ((roomid >= 0) && getroomid(c) == roomid) { // same room + if (wantfilled && c->type->solid) { + // EXCEPTION: + // if we are calling this function from fix_reachability, then + // startcell will actually be a cell _inside_ the room as opposed to + // a cell inside the room's walls. + // in this case, we ARE allowed to travel through the room's walls. + } else { + // mark dir as invalid + dist[d] = 999; + if (db) dblog(" going %s hits same room. invalid.", getdirname(d)); + break; + } + } else if (cellwalkable(NULL, c, NULL)) { + if (!wantfilled || c->filled) { + // walkable and not in this vault. finished. + hitsedge[d] = B_FALSE; + if (db) dblog(" can make %s path (hits empty cell at dist %d)", getdirname(d), dist[d]); + break; + } + } else { + int perpdir[2],n; + cell_t *pcell = NULL; + perpdir[0] = d - 1; if (perpdir[0] < D_N) perpdir[0] = D_W; + perpdir[1] = d + 1; if (perpdir[1] > D_W) perpdir[1] = D_N; + // is there an adjacent walkable cell in a perpendicular direction + // which isn't from the starting room? + for (n = 0; n <= 1; n++) { + pcell = getcellindir(c, perpdir[n]); + if (pcell) { + if (((roomid == -1 ) || (getroomid(pcell) != roomid)) && + cellwalkable(NULL, pcell, NULL)) { + if (!wantfilled || c->filled) { + // finished. + hitsedge[d] = B_FALSE; + if (db) dblog(" can make %s path (hits adjacent empty cell at dist %d)", getdirname(d), dist[d]); + break; + } + } + } + } + } + // check next cell + c = getcellindir(c, d); // getting the same cell! + } + if (dist[d] != 999) { + if (!hitsedge[d]) { + if (dist[d] < mindist) mindist = dist[d]; + } + if (dist[d] > maxdist) maxdist = dist[d]; + } + } + + if (mindist == 999) { + cell_t *turncell = NULL,*endcell = NULL; + int perpdir[2]; + int startdir = D_NONE; + int turndir = D_NONE; + int startdist = 0; + // no good directions. + if (db) dblog(" No directions lead to valid cells. Trying turns."); + // starting at the LONGEST distance, traverse up each dir, + // branching off looking for rooms. + + // find longest distance + for (d = D_N; d <= D_W; d++) { + if (dist[d] == maxdist) { + startdir = d; + break; + } + } + assert(startdir != D_NONE); + // figure out perpendicular dirs + perpdir[0] = startdir - 1; if (perpdir[0] < D_N) perpdir[0] = D_W; + perpdir[1] = startdir + 1; if (perpdir[1] > D_W) perpdir[1] = D_N; + + if (db) dblog(" Will walk %s (dist %d), checking %s and %s.", getdirname(startdir), maxdist, + getdirname(perpdir[0]), getdirname(perpdir[1])); + + // check in startdir + c = getcellindir(startcell, startdir); + while (c && !turncell) { + int n; + cell_t *c2; + startdist++; + // check left/right from this door for rooms + for (n = 0; n <= 1; n++) { + int turndist = 0; + c2 = getcellindir(c, perpdir[n]); + while (c2) { + int gotsolution = B_FALSE; + turndist++; + if ((roomid >= 0) && (getroomid(c2) == roomid)) { + if (wantfilled && c2->type->solid) { + // see EXCEPTION above. + } else { + // hits same room, not ok. + break; + } + } else if (cellwalkable(NULL, c2, NULL)) { + if (!wantfilled || c2->filled) { + if (db) dblog(" Got to an empty cell here."); + gotsolution = B_TRUE; + } + } else if (turndist > 1) { + // check l/r too + int perpdir2[2],nn; + cell_t *pcell = NULL; + perpdir2[0] = perpdir[n] - 1; if (perpdir2[0] < D_N) perpdir2[0] = D_W; + perpdir2[1] = perpdir[n] + 1; if (perpdir2[1] > D_W) perpdir2[1] = D_N; + for (nn = 0; nn <= 1; nn++) { + pcell = getcellindir(c2, perpdir2[nn]); + if (pcell) { + if ( ((roomid == -1) || (getroomid(pcell) != roomid)) && + cellwalkable(NULL, pcell, NULL)) { + if (!wantfilled || pcell->filled) { + // finished. + if (db) dblog(" Got to an empty cell next to us."); + gotsolution = B_TRUE; + break; + } + } + } + } + } + + if (gotsolution) { + if (db) dblog(" Solution found: Walk %d %s, then %d %s.", + startdist, getdirname(startdir), + turndist, getdirname(perpdir[n])); + // walkable and not in this roomid. ok! + turncell = c; + endcell = c2; + turndir = perpdir[n]; + break; + } + // check next cell + c2 = getcellindir(c2, perpdir[n]); + } + if (turncell) break; + } + // now keep going in main direction. + c = getcellindir(c, startdir); + } + + if (turncell) { + // make a path up to the turn point. + if (db) dblog(" Making path from vault to corner, initdir=%s", getdirname(startdir)); + c = getcellindir(startcell, startdir); + while (c != turncell) { + setcelltype(c, c->habitat->emptycelltype); + if (ncellsadded) (*ncellsadded)++; + c = getcellindir(c, startdir); + } + // clear the corner cell + setcelltype(c, c->habitat->emptycelltype); + if (db) dblog(" Making path from corner to rest of map, turndir=%s", getdirname(turndir)); + // now turn and clear up to the next room/empty cell + c = getcellindir(c, turndir); + while (c != endcell) { + setcelltype(c, c->habitat->emptycelltype); + if (ncellsadded) (*ncellsadded)++; + c = getcellindir(c, turndir); + } + } else { + // give up?? + if (db) dblog(" Cannot find a way to link up."); + return B_TRUE; + } + } else { + int whichway,sel; + // now pick the shortest one which doesn't hits the edge + // get list of all the minimums and randomly tie-break + nposs2 = 0; + for (d = D_N; d <= D_W; d++) { + if (dist[d] == mindist) { + poss2[nposs2++] = d; + } + } + sel = rnd(0,nposs2-1); + whichway = poss2[sel]; + + // now create a path + if (db) dblog(" Linking %s (distance %d).", getdirname(whichway), mindist); + c = getcellindir(startcell, whichway); + while (c && !cellwalkable(NULL, c, NULL)) { + setcelltype(c, c->habitat->emptycelltype); + if (ncellsadded) (*ncellsadded)++; + c = getcellindir(c, whichway); + } + } + return B_FALSE; +} + // make sure exits/doors in a given room link up to the rest of the map. int linkexits(map_t *m, int roomid) { int x,y,i; @@ -2687,202 +2973,25 @@ int linkexits(map_t *m, int roomid) { // for each door, make sure it links to at least one cell which isn't // part of this room for (i = 0; i < nposs; i++) { - int d; - int ncorridors = 0; + int ncorridors = 0,d; + if (db) dblog("linking exit #%d",i); + for (d = D_N; d <= D_W; d++) { c = getcellindir(poss[i], d); if (c && cellwalkable(NULL, c, NULL) && (getroomid(c) != roomid)) { ncorridors++; } } - if (db) dblog("Door #%d leads to %d corridors. ",i, ncorridors); + if (db) dblog(" This exit leads to %d corridors. ", ncorridors); // no corridors? if (ncorridors == 0) { - int poss2[MAXCANDIDATES],nposs2; - int dist[MAXDIR_ORTH]; - int hitsedge[MAXDIR_ORTH]; - int mindist = 999,maxdist = -1; if (db) dblog(" Need to link."); - // link it. starting from the door, count the number of cells in - // each direction until we hit an empty (walkable) cell which isn't a room. - - // if we hit a cell of this roomid, mark this dir as invalid. - for (d = D_N; d <= D_W; d++) { - dist[d] = 0; - hitsedge[d] = B_TRUE; - c = getcellindir(poss[i], d); - while (c) { - dist[d]++; - if (getroomid(c) == roomid) { - // mark dir as invalid - dist[d] = 999; - break; - } else if (cellwalkable(NULL, c, NULL)) { - // walkable and not in this vault. finished. - hitsedge[d] = B_FALSE; - break; - } else { - int perpdir[2],n; - cell_t *pcell = NULL; - perpdir[0] = d - 1; if (perpdir[0] < D_N) perpdir[0] = D_W; - perpdir[1] = d + 1; if (perpdir[1] > D_W) perpdir[1] = D_N; - // is there an adjacent walkable cell in a perpendicular direction - // which isn't from the starting room? - for (n = 0; n <= 1; n++) { - pcell = getcellindir(c, perpdir[n]); - if (pcell) { - if ((getroomid(pcell) != roomid) && cellwalkable(NULL, pcell, NULL)) { - // finished. - hitsedge[d] = B_FALSE; - break; - } - } - } - - } - // check next cell - c = getcellindir(c, d); // getting the same cell! - } - if (dist[d] != 999) { - if (!hitsedge[d]) { - if (dist[d] < mindist) mindist = dist[d]; - } - if (dist[d] > maxdist) maxdist = dist[d]; - } - } - - if (mindist == 999) { - cell_t *turncell = NULL,*endcell = NULL; - int perpdir[2]; - int startdir = D_NONE; - int turndir = D_NONE; - int startdist = 0; - // no good directions. - if (db) dblog(" No directions lead to rooms. Trying turns."); - // starting at the LONGEST distance, traverse up each dir, - // branching off looking for rooms. - - // find longest distance - for (d = D_N; d <= D_W; d++) { - if (dist[d] == maxdist) { - startdir = d; - break; - } - } - assert(startdir != D_NONE); - // figure out perpendicular dirs - perpdir[0] = startdir - 1; if (perpdir[0] < D_N) perpdir[0] = D_W; - perpdir[1] = startdir + 1; if (perpdir[1] > D_W) perpdir[1] = D_N; - - if (db) dblog(" Will walk %s (dist %d), checking %s and %s.", getdirname(startdir), maxdist, - getdirname(perpdir[0]), getdirname(perpdir[1])); - - // check in startdir - c = getcellindir(poss[i], startdir); - while (c && !turncell) { - int n; - cell_t *c2; - startdist++; - // check left/right from this door for rooms - for (n = 0; n <= 1; n++) { - int turndist = 0; - c2 = getcellindir(c, perpdir[n]); - while (c2) { - int gotsolution = B_FALSE; - turndist++; - if (getroomid(c2) == roomid) { - // hits same room, not ok. - break; - } else if (cellwalkable(NULL, c2, NULL)) { - if (db) dblog(" Got to an empty cell here."); - gotsolution = B_TRUE; - } else if (turndist > 1) { - // check l/r too - int perpdir2[2],nn; - cell_t *pcell = NULL; - perpdir2[0] = perpdir[n] - 1; if (perpdir2[0] < D_N) perpdir2[0] = D_W; - perpdir2[1] = perpdir[n] + 1; if (perpdir2[1] > D_W) perpdir2[1] = D_N; - for (nn = 0; nn <= 1; nn++) { - pcell = getcellindir(c2, perpdir2[nn]); - if (pcell) { - if ((getroomid(pcell) != roomid) && - cellwalkable(NULL, pcell, NULL)) { - // finished. - if (db) dblog(" Got to an empty cell next to us."); - gotsolution = B_TRUE; - break; - } - } - } - } - - if (gotsolution) { - if (db) dblog(" Solution found: Walk %d %s, then %d %s.", - startdist, getdirname(startdir), - turndist, getdirname(perpdir[n])); - // walkable and not in this roomid. ok! - turncell = c; - endcell = c2; - turndir = perpdir[n]; - break; - } - // check next cell - c2 = getcellindir(c2, perpdir[n]); - } - if (turncell) break; - } - // now keep going in main direction. - c = getcellindir(c, startdir); - } - - if (turncell) { - // make a path up to the turn point. - if (db) dblog(" Making path from vault to corner, initdir=%s", getdirname(startdir)); - nadded++; - c = getcellindir(poss[i], startdir); - while (c != turncell) { - setcelltype(c, c->habitat->emptycelltype); - c = getcellindir(c, startdir); - } - // clear the corner cell - setcelltype(c, c->habitat->emptycelltype); - if (db) dblog(" Making path from corner to rest of map, turndir=%s", getdirname(turndir)); - // now turn and clear up to the next room/empty cell - c = getcellindir(c, turndir); - while (c != endcell) { - setcelltype(c, c->habitat->emptycelltype); - c = getcellindir(c, turndir); - } - } else { - // give up?? - if (db) dblog(" Cannot find a way to link up."); - } - } else { - int whichway,sel; - // now pick the shortest one which hits the edge - // get list of all the minimums and randomly tie-break - nposs2 = 0; - for (d = D_N; d <= D_W; d++) { - if (dist[d] == mindist) { - poss2[nposs2++] = d; - } - } - sel = rnd(0,nposs2-1); - whichway = poss2[sel]; - - // now create a path - if (db) dblog(" Linking %s (distance %d).", getdirname(whichway), mindist); - nadded++; - c = getcellindir(poss[i], whichway); - while (c && !cellwalkable(NULL, c, NULL)) { - setcelltype(c, c->habitat->emptycelltype); - c = getcellindir(c, whichway); - } - } - } // end if ncorridors = 0 + nadded += linkexit(poss[i], B_FALSE, NULL); + } } // end for each door - if (db) dblog("linkexits complete."); + + if (db) dblog("linkexits complete (%d added).", nadded); return nadded; } @@ -3075,13 +3184,27 @@ int dirtoy(int dt, int dir) { void dumpmap(map_t *map) { int x,y; cell_t *cell; + char ch; printf("dump of map '%s' (%d x %d):\n",map->name, map->w, map->h); + + // top reference row + dblog_nocr(" "); + for (x = 0; x < map->w; x++) { + dblog_nocr("%d",x % 10); + } + dblog_nocr("\n"); + for (y = 0; y < map->h; y++) { + dblog_nocr("%d",y % 10); for (x = 0; x < map->w; x++) { cell = getcellat(map, x, y); - printf("%c",cell->type->glyph.ch); + ch = cell->type->glyph.ch; + if ((ch == '.') && cell->filled) { + ch = 'o'; + } + dblog_nocr("%c",ch); } - printf("\n"); + dblog_nocr("\n"); } } @@ -3258,7 +3381,6 @@ cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf) { cell_t *selection = NULL; cell_t *bestcell = NULL; int closest = 999; -// oooooo TODO handle side being diagonal switch (side) { case D_N: case DC_N: @@ -4576,6 +4698,16 @@ void mapentereffects(map_t *m) { addflag(lf->flags, F_STAYINROOM, getroomid(c), B_MAYCHASE, NA, NULL); } } + + // monsters on the new level now get a bunch of turns to simulate them moving about when the player wasn't there. + if (m->lastplayervisit != -1) { + int nturns; + nturns = (curtime - m->lastplayervisit) / TICK_INTERVAL; + //nturns *= countlfs(m); + for (i = 0; i < nturns; i++) { + donextturn(m); + } + } } enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob) { @@ -4624,6 +4756,28 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob) { return R_NONE; } +// returns # of dead ends removed. +int remove_deadends(map_t *m, int howmuch) { + enum CELLTYPE solidcell; + int i,n,count = 0; + + solidcell = m->habitat->solidcelltype; + + for (i = 0; i < howmuch; i++) { + for (n = 0; n < m->w * m->h; n++) { + cell_t *c; + c = m->cell[n]; + if (countcellexits(c) == 1) { + // erase this cell + setcelltype(c, solidcell); + count++; + } + } + } + return count; +} + + void setcellknown(cell_t *cell, int forcelev) { enum SKILLLEVEL slev; object_t *o; diff --git a/map.h b/map.h index 596ec97..5c78a38 100644 --- a/map.h +++ b/map.h @@ -15,6 +15,9 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in int cellhaslos(cell_t *c1, cell_t *dest); void clearcell(cell_t *c); int dowaterspread(cell_t *c); +void fix_reachability(map_t *m); +int fix_unreachable_cell(cell_t *badcell); +void floodfill(cell_t *startcell); cell_t *getcellat(map_t *map, int x, int y); int getcelldist(cell_t *src, cell_t *dst); int getcelldistorth(cell_t *src, cell_t *dst); @@ -106,6 +109,7 @@ int isonmap(map_t *map, int x, int y); int isoutdoors(map_t *m); int isroom(cell_t *c); int iswallindir(cell_t *cell, int dir); +int linkexit(cell_t *c, int wantfilled, int *ncellsadded); int linkexits(map_t *m, int roomid); int linkholes(map_t *map); int linkstairs(object_t *o, object_t *o2); @@ -114,6 +118,7 @@ void makelit(cell_t *c, enum LIGHTLEV how, int howlong); void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong); void mapentereffects(map_t *m); enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob); +int remove_deadends(map_t *m, int howmuch); void setcellknown(cell_t *cell, int forcelev); void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype); void setcelltype(cell_t *cell, enum CELLTYPE id); diff --git a/move.c b/move.c index b3dd51d..1f9cffc 100644 --- a/move.c +++ b/move.c @@ -31,6 +31,8 @@ extern void *rdata; extern flag_t *retflag[]; extern int nretflags; +extern long curtime; + extern WINDOW *gamewin, *msgwin; int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) { @@ -148,7 +150,7 @@ int canswapwith(lifeform_t *lf, lifeform_t *lf2) { // onlyifknown = true means "check for _known_ dangerous objects" // onlyifknown = false means "check for _any dangerous objects, doesn't matter if we know about them" int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *error) { - enum ATTRBRACKET iq; + enum ATTRBRACKET wis; int include_nonobvious = B_FALSE; flag_t *f; object_t *o; @@ -177,7 +179,6 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err } } - for (o = cell->obpile->first ; o ; o = o->next) { if (onlyifknown && !canseeob(lf, o)) continue; if (hasflag(o->flags, F_TRAP)) { @@ -239,8 +240,8 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err if (!onlyifknown) { include_nonobvious = B_TRUE; } else { - iq = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); - if ((iq >= AT_AVERAGE) && haslos(lf, cell)) { + wis = getattrbracket(getattr(lf, A_WIS), A_WIS, NULL); + if ((wis >= AT_AVERAGE) && haslos(lf, cell)) { if (!lfhasflag(lf, F_UNDEAD)) { include_nonobvious = B_TRUE; } @@ -311,7 +312,7 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) { if ((mid == MT_GAS) || (mid == MT_SLIME)) { // ok - } else if (lfhasflag(lf, F_NONCORPOREAL)) { + } else if (lfhasflag(lf, F_NONCORPOREAL) && !hasflag(o->flags, F_REALLYIMPASSABLE)) { // ok but still set error *error = E_OBINWAY; } else { @@ -945,9 +946,13 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (newcell->map != lf->cell->map) { changedlev = B_TRUE; + if (isplayer(lf)) { + // remember the time which we exitted this map. + lf->cell->map->lastplayervisit = curtime; + } } - // update current cell + room id + // remember current cell + room id prespeed = getmovespeed(lf); preroom = getroomid(lf->cell); v = getcellvault(lf->cell); @@ -960,6 +965,25 @@ int movelf(lifeform_t *lf, cell_t *newcell) { prewater = B_TRUE; } + // special effects when the player moves to a new map + if (changedlev && isplayer(lf)) { + object_t *o; + long barrierid = -1; + // mapentereffects will give all monster on the new map + // a bunch of turns to simulate time passing while the player + // was away. to prevent them from blocking off the staircase cell + // where the player is about to arrive, place a magic barrier over it. + o = addobfast(newcell->obpile, OT_MAGICBARRIER); + if (o) barrierid = o->id; + + mapentereffects(newcell->map); + + // now remove the barrier + o = hasobid(newcell->obpile, barrierid); + if (o) killob(o); + } + + // move out... lf->cell->lf = NULL; @@ -992,13 +1016,6 @@ int movelf(lifeform_t *lf, cell_t *newcell) { // update new cell newcell->lf = lf; - /* - // update light - if (lfproduceslight(lf) || (changedlev && isplayer(lf))) { - calclight(lf->cell->map); - precalclos(lf); - } - */ // update light if (lfproduceslight(lf)) { calclight(lf->cell->map); @@ -1009,11 +1026,6 @@ int movelf(lifeform_t *lf, cell_t *newcell) { needredraw = B_TRUE; } - // special effects when the player moves to a new map - if (changedlev && isplayer(lf)) { - mapentereffects(newcell->map); - } - didmsg = moveeffects(lf); killflagsofid(lf->flags, F_HIDING); @@ -1339,7 +1351,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { if (getlfmaterial(lf) == MT_GAS) { char obname[BUFLEN]; for (o = newcell->obpile->first ; o ; o = o->next) { - if (isimpassableob(o, lf)) { + if (isimpassableob(o, lf) && !hasflag(o->flags, F_REALLYIMPASSABLE)) { getobname(o, obname, o->amt); if (isplayer(lf)) { msg("You seep around %s.", obname); @@ -2087,7 +2099,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { f = isdrunk(lf); if (f) { if (!hasjob(lf, J_PIRATE)) { - if (rnd(1,6) <= ((f->lifetime/DRUNKTIME)+1)) { + if (rnd(1,6) <= ((f->lifetime/TM_DRUNKTIME)+1)) { // randomize move dir = rnd(DC_N, DC_NW); drunk = B_TRUE; // ie. you can walk into walls now. @@ -2099,22 +2111,20 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { if (isplayer(lf) && !lfhasflag(lf, F_SNEAK)) { if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) { - if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { - char ques[BUFLEN]; - char ch; - if ((errcode == E_AVOIDOB) && rdata) { - char obname[BUFLEN]; - object_t *avoidob; - avoidob = (object_t *)rdata; - getobname(avoidob, obname, avoidob->amt); - sprintf(ques, "Really %s into %s?", getmoveverb(lf), obname); - } else { - sprintf(ques, "Really %s there?", getmoveverb(lf)); - } - ch = askchar(ques, "yn","n", B_TRUE); - if (ch != 'y') { - return B_TRUE; - } + char ques[BUFLEN]; + char ch; + if ((errcode == E_AVOIDOB) && rdata) { + char obname[BUFLEN]; + object_t *avoidob; + avoidob = (object_t *)rdata; + getobname(avoidob, obname, avoidob->amt); + sprintf(ques, "Really %s into %s?", getmoveverb(lf), obname); + } else { + sprintf(ques, "Really %s there?", getmoveverb(lf)); + } + ch = askchar(ques, "yn","n", B_TRUE); + if (ch != 'y') { + return B_TRUE; } } } diff --git a/nexus.c b/nexus.c index 152b392..2f92de5 100644 --- a/nexus.c +++ b/nexus.c @@ -375,22 +375,17 @@ int main(int argc, char **argv) { needredraw = B_FALSE; numdraws = 0; - // someone has a turn - this will then call taketime -> timehappens(); + // someone has a turn - this will then call taketime donextturn(curmap); - // update lifeform structue to figure out who goes next - //timehappens(curmap); - // show level (if required) //if (haslos(player, curmap->lf->cell)) { drawscreen(); //dblog("**** END of turn, numdraws = %d", numdraws); - // check end of game checkendgame(); - } // identify all objects @@ -559,143 +554,154 @@ void donextturn(map_t *map) { oldpmap = player->cell->map; who = map->lf; - if (db) dblog("**** donextturn for: id %d %s", who->id, who->race->name); + + if (who) { + if (db) dblog("**** donextturn for: id %d %s", who->id, who->race->name); - assert(who->timespent == 0); + assert(who->timespent == 0); - turneffectslf(who); + turneffectslf(who); - // calculate light - calclight(map); - // pre-calculate line of sight for this lifeform - precalclos(who); + // calculate light + calclight(map); + // pre-calculate line of sight for this lifeform + precalclos(who); - /* - if (isplayer(who) || cansee(player, who)) { - needredraw = B_TRUE; - drawscreen(); - } - */ + // update gun targets + autotarget(who); - // update gun targets - autotarget(who); + // keep looping until they actually do something or are dead! + while (who->timespent == 0) { + if (isdead(who)) { + // skip turn + taketime(who, SPEED_DEAD); + } else { + // do we need to run away from something? + if (!flee(who)) { + int donormalmove = B_TRUE; + flag_t *f; + + // casting a spell? + if (donormalmove) { + f = lfhasflag(who, F_CASTINGSPELL); + if (f) { + donormalmove = B_FALSE; + + f->val[2]--; + if (f->val[2] <= 0) { + char *p; + char buf[BUFLEN]; + int lfid,mapid,x,y,power; + long obid; + lifeform_t *targlf; + object_t *targob; + cell_t *targcell; + map_t *targmap; + enum OBTYPE sid; + + sid = f->val[0]; + power = f->val[1]; - // keep looping until they actually do something or are dead! - while (who->timespent == 0) { - if (isdead(who)) { - // skip turn - taketime(who, SPEED_DEAD); - } else { - // do we need to run away from something? - if (!flee(who)) { - int donormalmove = B_TRUE; - flag_t *f; + // finished! + p = f->text; + p = readuntil(buf, p, ';'); + lfid = atoi(p); + p = readuntil(buf, p, ';'); + obid = atol(p); + p = readuntil(buf, p, ';'); + mapid = atoi(p); + p = readuntil(buf, p, ';'); + x = atoi(p); + p = readuntil(buf, p, ';'); + y = atoi(p); - // casting a spell? - if (donormalmove) { - f = lfhasflag(who, F_CASTINGSPELL); - if (f) { - donormalmove = B_FALSE; - - f->val[2]--; - if (f->val[2] <= 0) { - char *p; - char buf[BUFLEN]; - int lfid,mapid,x,y,power; - long obid; - lifeform_t *targlf; - object_t *targob; - cell_t *targcell; - map_t *targmap; - enum OBTYPE sid; - - sid = f->val[0]; - power = f->val[1]; - - - // finished! - p = f->text; - p = readuntil(buf, p, ';'); - lfid = atoi(p); - p = readuntil(buf, p, ';'); - obid = atol(p); - p = readuntil(buf, p, ';'); - mapid = atoi(p); - p = readuntil(buf, p, ';'); - x = atoi(p); - p = readuntil(buf, p, ';'); - y = atoi(p); - - if (lfid >= 0) { - targlf = findlf(NULL, lfid); - } else { - targlf = NULL; - } - if (obid >= 0) { - targob = findobidinmap(who->cell->map, obid); - } else { - targob = NULL; - } - if (mapid >= 0) { - targmap = findmap(mapid); - targcell = getcellat(targmap, x, y); - } - taketime(who, getspellspeed(who)); - dospelleffects(who, sid, power, targlf, targob, targcell, B_UNCURSED, NULL, B_FALSE); - killflagsofid(who->flags, F_CASTINGSPELL); - } else { - if (isplayer(who)) { - objecttype_t *sp; - sp = findot(f->val[0]); - msg("You continue casting %s.", sp->name); - } else if (cansee(player, who)) { - flag_t *f2; - char lfname[BUFLEN]; - // still going... - getlfname(who, lfname); - f2 = lfhasflag(who,F_SPELLCASTTEXT); - if (f2 && strlen(f2->text)) { - msg("%s %s.", lfname, f2->text); + if (lfid >= 0) { + targlf = findlf(NULL, lfid); } else { - msg("%s continues casting a spell.", lfname); + targlf = NULL; + } + if (obid >= 0) { + targob = findobidinmap(who->cell->map, obid); + } else { + targob = NULL; + } + if (mapid >= 0) { + targmap = findmap(mapid); + targcell = getcellat(targmap, x, y); + } + taketime(who, getspellspeed(who)); + dospelleffects(who, sid, power, targlf, targob, targcell, B_UNCURSED, NULL, B_FALSE); + killflagsofid(who->flags, F_CASTINGSPELL); + } else { + if (isplayer(who)) { + objecttype_t *sp; + sp = findot(f->val[0]); + msg("You continue casting %s.", sp->name); + } else if (cansee(player, who)) { + flag_t *f2; + char lfname[BUFLEN]; + // still going... + getlfname(who, lfname); + f2 = lfhasflag(who,F_SPELLCASTTEXT); + if (f2 && strlen(f2->text)) { + msg("%s %s.", lfname, f2->text); + } else { + msg("%s continues casting a spell.", lfname); + } } } } } - } - // eating? - if (donormalmove) { - f = lfhasflag(who, F_EATING); - if (f) { - object_t *o; - o = findobbyid(who->pack, atol(f->text)); - if (!o) { - o = findobidinmap(who->cell->map, atol(f->text)); - } - if (o && caneat(who, o) && (getoblocation(o) == who->cell)) { - eat(who,o); - donormalmove = B_FALSE; - } else { - killflag(f); + // eating? + if (donormalmove) { + f = lfhasflag(who, F_EATING); + if (f) { + object_t *o; + o = findobbyid(who->pack, atol(f->text)); + if (!o) { + o = findobidinmap(who->cell->map, atol(f->text)); + } + if (o && caneat(who, o) && (getoblocation(o) == who->cell)) { + eat(who,o); + donormalmove = B_FALSE; + } else { + killflag(f); + } } } - } - // resting? - if (donormalmove) { - f = isresting(who); - if (!f) { - f = lfhasflag(who, F_TRAINING); + // resting? + if (donormalmove) { + f = isresting(who); + if (!f) { + f = lfhasflag(who, F_TRAINING); + } + if (f) { + // check for interrupt of resting... + if (isplayer(who) && checkforkey()) { + msg("Stopped %s.",(f->id == F_TRAINING) ? "training" : "resting"); + killflag(f); + } else { + if (isplayer(who)) { + if (++who->turnsskipped >= 10) { + //msg("Time passes..."); + msg("."); + who->turnsskipped = 0; + } + } + rest(who, B_TRUE); + donormalmove = B_FALSE; + } + } } - if (f) { - // check for interrupt of resting... - if (isplayer(who) && checkforkey()) { - msg("Stopped %s.",(f->id == F_TRAINING) ? "training" : "resting"); - killflag(f); - } else { + + + if (donormalmove) { + // paralyzed etc? + if (isimmobile(who)) { if (isplayer(who)) { if (++who->turnsskipped >= 10) { //msg("Time passes..."); @@ -703,54 +709,34 @@ void donextturn(map_t *map) { who->turnsskipped = 0; } } - rest(who, B_TRUE); + rest(who, B_FALSE); donormalmove = B_FALSE; } - } - } - - - if (donormalmove) { - // paralyzed etc? - if (isimmobile(who)) { - if (isplayer(who)) { - if (++who->turnsskipped >= 10) { - //msg("Time passes..."); - msg("."); - who->turnsskipped = 0; - } - } - rest(who, B_FALSE); - donormalmove = B_FALSE; } - } - if (donormalmove) { - if (isplayer(who)) { - drawcursor(); - // find out what player wants to do - handleinput(); - } else { - //char lfname[BUFLEN]; - //char buf[BUFLEN]; - // do ai move - //real_getlfname(who, lfname, B_FALSE); - //sprintf(buf, "aimove %s",lfname); - //dbtimestart(buf); - aiturn(who); - //dbtimeend(buf); + if (donormalmove) { + if (isplayer(who)) { + drawcursor(); + // find out what player wants to do + handleinput(); + } else { + //char lfname[BUFLEN]; + //char buf[BUFLEN]; + // do ai move + //real_getlfname(who, lfname, B_FALSE); + //sprintf(buf, "aimove %s",lfname); + //dbtimestart(buf); + aiturn(who); + //dbtimeend(buf); + } } } } } - } - if (hasflag(player->flags, F_ASLEEP)) { - needredraw = B_FALSE; - /* - } else if (isdead(who) || cansee(player, who)) { - needredraw = B_TRUE; - */ + if (hasflag(player->flags, F_ASLEEP)) { + needredraw = B_FALSE; + } } // check for death etc @@ -764,7 +750,8 @@ void donextturn(map_t *map) { // note: can't use 'who->' below since 'who' might have died // and been de-alloced during checkdeath() above if they // died. - timeeffectsworld(player->cell->map); + //timeeffectsworld(player->cell->map); + timeeffectsworld(map, B_TRUE); // the previous call to timeeffectsworld might cause the player to // change levels (ie. falling down through one or more pits). @@ -773,7 +760,7 @@ void donextturn(map_t *map) { // values don't get out of whack. while (player->cell->map != oldpmap) { oldpmap = player->cell->map; - timeeffectsworld(player->cell->map); + timeeffectsworld(player->cell->map, B_FALSE); } } @@ -1425,7 +1412,7 @@ void sortcommands(void) { -void timeeffectsworld(map_t *map) { +void timeeffectsworld(map_t *map, int updategametime) { flag_t *retflag[MAXCANDIDATES]; int nretflags; lifeform_t *l; @@ -1544,8 +1531,10 @@ void timeeffectsworld(map_t *map) { //dumplf(); } // end if timespent - // inc game time - curtime += firstlftime; + if (updategametime) { + // inc game time + curtime += firstlftime; + } if (db) dblog("cur time is %ld\n",curtime); } diff --git a/nexus.h b/nexus.h index 6815c5b..4f528ec 100644 --- a/nexus.h +++ b/nexus.h @@ -33,5 +33,5 @@ int rollhitdice(lifeform_t *lf); int rollmpdice(lifeform_t *lf); //void sortlf(map_t *map); void sortcommands(void); -void timeeffectsworld(map_t *map); +void timeeffectsworld(map_t *map, int updategametime); void usage(char *progname); diff --git a/objects.c b/objects.c index 53b532a..c48c370 100644 --- a/objects.c +++ b/objects.c @@ -2196,7 +2196,7 @@ int canseeob(lifeform_t *lf, object_t *o) { case PR_INEPT: cutoffpct = 200; break; } - cutoff = pctof(cutoffpct, FOOTPRINTTIME); + cutoff = pctof(cutoffpct, TM_FOOTPRINT); if (f->lifetime >= cutoff) { return B_TRUE; @@ -4129,7 +4129,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan char adjective[BUFLEN]; lifeform_t *who = NULL; - pct = ((float)f->lifetime / (float)SCENTTIME)*100; + pct = ((float)f->lifetime / (float)TM_SCENT)*100; if (pct >= 66) { strcpy(adjective, "strong "); } else if (pct >= 33) { @@ -4161,7 +4161,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan // adept and upwards gets depth if (slev >= PR_BEGINNER) { float pct; - pct = ((float)f->lifetime / (float)FOOTPRINTTIME)*100; + pct = ((float)f->lifetime / (float)TM_FOOTPRINT)*100; if (pct >= 66) { strcpy(basename, "fresh "); } else if (pct >= 33) { @@ -8573,6 +8573,7 @@ void initobjects(void) { addot(OT_MAGICBARRIER, "magical barrier", "A glowing, impassable barrier of magical energy.", MT_MAGIC, 0, OC_EFFECT, SZ_LARGE); addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "#"); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); + addflag(lastot->flags, F_REALLYIMPASSABLE, NA, NA, NA, NULL); addflag(lastot->flags, F_BLOCKSLOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "vanishes"); @@ -10560,10 +10561,10 @@ void makewet(object_t *o, int amt) { } */ f->val[0] += amt; - f->val[1] = WETTIME; + f->val[1] = TM_WETTIME; } else { // jsut reset wettime - f->val[1] = WETTIME; + f->val[1] = TM_WETTIME; } } else { @@ -10571,7 +10572,7 @@ void makewet(object_t *o, int amt) { if (haslos(player, loc) && !isdead(player)) { msg("%s get%s wet.",obnamefull, (o->amt == 1) ? "s" : ""); } - f = addflag(o->flags, F_WET, amt, WETTIME, NA, NULL); + f = addflag(o->flags, F_WET, amt, TM_WETTIME, NA, NULL); } } } @@ -12565,9 +12566,9 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } else if (cansee(player, lf)) { msg("%s looks more tipsy.", lfname); } - f->lifetime += DRUNKTIME; + f->lifetime += TM_DRUNKTIME; } else { - addtempflag(lf->flags, F_DRUNK, 1, NA, NA, NULL, DRUNKTIME); + addtempflag(lf->flags, F_DRUNK, 1, NA, NA, NULL, TM_DRUNKTIME); } } break; diff --git a/save.c b/save.c index 5b7b550..63d0e9f 100644 --- a/save.c +++ b/save.c @@ -308,6 +308,7 @@ map_t *loadmap(char *basefile) { fscanf(f, "habitat:%d\n",(int *)&habitatid); // habitat m->habitat = findhabitat(habitatid); fscanf(f, "seed:%d\n",&m->seed); // seed + fscanf(f, "lastplayervisit:%ld\n",&m->lastplayervisit); fscanf(f, "dims:%d,%d\n",&m->w, &m->h); // map dimensons fscanf(f, "nextmaps:\n"); for (i = 0; i < MAXDIR_ORTH; i++) { @@ -859,6 +860,7 @@ int savemap(map_t *m) { fprintf(f, "name:%s\n",m->name); // map name fprintf(f, "habitat:%d\n",m->habitat->id); // habitat fprintf(f, "seed:%d\n",m->seed); // seed + fprintf(f, "lastplayervisit:%ld\n",m->lastplayervisit); fprintf(f, "dims:%d,%d\n",m->w, m->h); // map dimensons fprintf(f, "nextmaps:\n"); for (i = 0; i < MAXDIR_ORTH; i++) { diff --git a/spell.c b/spell.c index 92d46cc..3eb1ba5 100644 --- a/spell.c +++ b/spell.c @@ -2926,12 +2926,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("Couldn't create a vault."); } else { char ch; + cell_t *c; + + // link the new vault to the rest of the map + c = getcellat(caster->cell->map, vx, vy); + linkexits(caster->cell->map, getroomid(c)); + msg("BAM! A vault has appeared nearby."); more(); needredraw = B_TRUE; ch = askchar("Teleport to the new vault", "yn","y", B_TRUE); if (ch == 'y') { int x,y; - cell_t *c; // find it for (y = vy; y < vy+vh; y++) { for (x = vy; x < vx + vw; x++) { diff --git a/text.c b/text.c index 79cf397..98100c9 100644 --- a/text.c +++ b/text.c @@ -241,7 +241,7 @@ char *getpossessive(char *text) { char *getdrunktext(flag_t *drunkflag) { int bracket; - bracket = (drunkflag->lifetime / DRUNKTIME) + 1; + bracket = (drunkflag->lifetime / TM_DRUNKTIME) + 1; if (bracket == 1) { return "tipsy"; } else if (bracket == 2) {