diff --git a/data/hiscores.db b/data/hiscores.db index 9915837..d2e2052 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index a0f9d6c..795ab71 100644 --- a/defs.h +++ b/defs.h @@ -386,6 +386,7 @@ enum MODTYPE { #define ANIMDELAY (1000000 / 50) // 1/100 of a second #define MAXVISRANGE 10 // max visible range in full light +#define MAXVISLIMIT (MAXVISRANGE*8) // askobject options @@ -1589,6 +1590,8 @@ enum FLAG { // causes shops to show (worth $xx) after the ob's name. // also used for detecting theft! F_VALUE, // how much an item is worth (over its base weight+material) + F_NOPOINTS, // object is worth 0 points (but might still have a + // monetary value) // weapon/armour flags F_EQUIPPED, // val0 = where it is equipped. CLEAR WHEN OB MOVED! F_GOESON, // val0 = where it can be equipped. @@ -2078,6 +2081,8 @@ enum FLAG { F_ORIGRACE, // original player race (if you polymorphed) F_ORIGJOB, // original player job (if you polymorphed) F_POLYMORPHED, // lf has been polymorphed + F_RETAINHPMPONPOLY, // don't take on hp/mp of what you polymorph + // into F_SHORTCUT, // spell keyboard shortcut. // v0=slot (0-9) // text=spell text diff --git a/flag.c b/flag.c index 05ac29b..352855d 100644 --- a/flag.c +++ b/flag.c @@ -17,6 +17,7 @@ int nretflags; extern enum GAMEMODE gamemode; extern int needredraw; extern int statdirty; +extern void (*precalclos)(lifeform_t *); extern lifeform_t *godlf[]; extern int ngodlfs; diff --git a/io.c b/io.c index 6bfc816..e597c22 100644 --- a/io.c +++ b/io.c @@ -2319,7 +2319,7 @@ void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int fi if (showpoints && (mylist[i]->type->id != OT_GOLD)) { long points; - points = getobvalue(mylist[i]); + points = getobpoints(mylist[i]); sprintf(pointsbuf, " [%ld points]", points); } else { strcpy(pointsbuf, ""); diff --git a/lf.c b/lf.c index f62b457..28de526 100644 --- a/lf.c +++ b/lf.c @@ -18,8 +18,12 @@ #include "spell.h" #include "text.h" +extern double presin[]; +extern double precos[]; + extern FILE *logfile; +extern void (*precalclos)(lifeform_t *); extern map_t *firstmap; extern race_t *firstrace, *lastrace; @@ -239,7 +243,7 @@ long calcscore(lifeform_t *lf) { } // objects for (o = lf->pack->first ; o ; o = o->next) { - points += getobvalue(o); + points += getobpoints(o); } // points for xp points += (lf->xp / 10); @@ -1324,6 +1328,63 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar return rv; } +int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange) { + // too far away + if (maxvisrange != UNLIMITED) { + if (getcelldist(lf->cell, c) > maxvisrange) { + return B_FALSE; + } + } + + // outside the range of our light, and not lit + if (nightvisrange != UNLIMITED) { + if (getcelldist(lf->cell, c) > nightvisrange) { + if (!islit(c)) { + return B_FALSE; + } + } else { + // inside our nightvis range and magically dark + if (c->lit == L_PERMDARK) { + return B_FALSE; + } + } + } + + return B_TRUE; +} + +int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod) { + object_t *o; + flag_t *f; + + if (rangemod) *rangemod = 0; + + // solid cells stop los + if (!c->type->transparent) { + if (xray && *xray) (*xray)--; + else return B_FALSE; + } + + // check for objects which block view + for (o = c->obpile->first ; o ; o = o->next) { + f = hasflag(o->flags, F_BLOCKSVIEW); + if (f) { + if (!lfhasflagval(lf, F_CANSEETHROUGHMAT, o->material->id, NA, NA, NULL)) { + if (xray && *xray) { + (*xray)--; + } else { + if (f->val[0] == B_TRUE) { + return B_FALSE; + } else { + if (rangemod) *rangemod += f->val[0]; + } + } + } + } + } + return B_TRUE; +} + // returns TRUE if something happened. int checkfordrowning(lifeform_t *lf, object_t *o) { int depth,i; @@ -1708,6 +1769,7 @@ void die(lifeform_t *lf) { } } + if ((lf->race->id == R_VAMPIRE) && !hasflag(lf->flags, F_ORIGRACE)) { // if are asleep or killed by running water/sunlight, we will die normally if (lfhasflag(lf, F_ASLEEP) || (lf->lastdamtype == DT_DIRECT)) { @@ -1738,7 +1800,6 @@ void die(lifeform_t *lf) { } } - if (!willbecomeghost) { lf->alive = B_FALSE; } @@ -6796,6 +6857,7 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { object_t *o; // give that weapon o = addobfast(lf->pack, ot->id); + if (isplayer(lf)) addflag(o->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); // give one extra rank of skill in this weapon sk = getobskill(o); @@ -6920,6 +6982,10 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { if (isplayer(lf) || (o->pile->parentob && isplayer(o->pile->parentob->pile->owner))) { identify(o); } + if (isplayer(lf)) { + // not worth any points + addflag(o->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); + } } } } @@ -7697,7 +7763,6 @@ int haslos(lifeform_t *viewer, cell_t *dest) { int i; int x1,y1; int maxvisrange; - int nightvisrange; int xray = 0; //int wentuphill = B_FALSE; //int origheight; @@ -7705,7 +7770,6 @@ int haslos(lifeform_t *viewer, cell_t *dest) { flag_t *f; int x2,y2; map_t *map; - object_t *o; int currange; cell_t *retcell[MAXRETCELLS]; @@ -7722,7 +7786,8 @@ int haslos(lifeform_t *viewer, cell_t *dest) { // can we use pre-calced los? // - if ((viewer->cell->map->lf == viewer) && viewer->los) { + //if ((viewer->cell->map->lf == viewer) && viewer->los) { + if (viewer->los) { for (i = 0;i < viewer->nlos; i++) { if (viewer->los[i] == dest) { return B_TRUE; @@ -7754,32 +7819,12 @@ int haslos(lifeform_t *viewer, cell_t *dest) { calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels); maxvisrange = getvisrange(viewer); - nightvisrange = getnightvisrange(viewer); - //origheight = getheight(x1,y1,z); - - // too far away - if (maxvisrange != UNLIMITED) { - if (getcelldist(viewer->cell, dest) > maxvisrange) { - return B_FALSE; - } + if (!celllitfor(viewer, dest, maxvisrange, getnightvisrange(viewer))) { + return B_FALSE; } - // outside the range of our light, and not lit - if (nightvisrange != UNLIMITED) { - if (getcelldist(viewer->cell, dest) > nightvisrange) { - if (!islit(dest)) { - return B_FALSE; - } - } else { - // inside our nightvis range and magically dark - if (dest->lit == L_PERMDARK) { - return B_FALSE; - } - } - } - //shopwall = B_FALSE; currange = 0; for (i = 0; i < numpixels ; i++) { @@ -7793,6 +7838,8 @@ int haslos(lifeform_t *viewer, cell_t *dest) { // you can always see your own cell if (i != 0) { + int rangemod; + currange++; if (currange > maxvisrange) { return B_FALSE; @@ -7804,39 +7851,12 @@ int haslos(lifeform_t *viewer, cell_t *dest) { } */ - /* - if (debug) { - printf("checking LOS at %d,%d going (%d,%d)\n",x,y,xinc,yinc); - fflush(stdout); + if (!celltransparentfor(viewer, cell, &xray, &rangemod)) { + return B_FALSE; } - */ - // solid cells stop los - but if you are standing on a solid - // cell you can still see out. - if (!cell->type->transparent) { - if (xray) xray--; - else return B_FALSE; - } + currange += rangemod; - // check for objects which block view - for (o = cell->obpile->first ; o ; o = o->next) { - f = hasflag(o->flags, F_BLOCKSVIEW); - if (f) { - if (!lfhasflagval(viewer, F_CANSEETHROUGHMAT, o->material->id, NA, NA, NULL)) { - if (xray) { - xray--; - } else { - if (f->val[0] == B_TRUE) { - return B_FALSE; - } else { - currange += f->val[0]; - } - } - } - } - } - - // xray vision decreases by one if (xray) xray--; @@ -11014,6 +11034,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4+3"); addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_RETAINHPMPONPOLY, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;"); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 5, 5, "range:3;"); addflag(lastrace->flags, F_CANWILL, OT_S_STUN, 5, 5, "pw:1;"); @@ -11021,6 +11042,7 @@ void initrace(void) { addflag(lastrace->flags, F_FORCEPOLY, R_BATVAMPIRE, 20, 20, "pw:3;"); addflag(lastrace->flags, F_DETECTOBS, 10, OT_COFFIN, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash"); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "gestures"); addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "hisses angrily^an angry hiss"); // special: change to gas cloud with 1 hp on death, if not asleep @@ -13684,7 +13706,8 @@ void practice(lifeform_t *lf, enum SKILL skid, int amt) { } } -void precalclos(lifeform_t *lf) { +/* +void precalclos_old(lifeform_t *lf) { int x,y; cell_t *c; cell_t **los; @@ -13694,7 +13717,6 @@ void precalclos(lifeform_t *lf) { los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); - // free existing structures if (lf->los) { free(lf->los); lf->los = NULL; @@ -13722,6 +13744,189 @@ void precalclos(lifeform_t *lf) { lf->nlos = nlos; free(los); } +*/ + +void precalclos_new(lifeform_t *lf) { + cell_t *c; + int startxray,rangemod; + int maxvisrange,nightvisrange; + cell_t **los; + int *blocker; + int nlos = 0,i,nn; + int ix,iy; + flag_t *f; + cell_t *endcell[MAXVISLIMIT]; + int nendcells = 0; + cell_t *retcell[MAXRETCELLS]; + int numpixels; + int db = B_FALSE; + int start,end; + + f = hasflag(lf->flags, F_XRAYVIS); + if (f) { + startxray = f->val[0]; + } else { + startxray = 0; + } + + + los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); + blocker = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); + nlos = 0; + if (lf->los) { + free(lf->los); lf->los = NULL; + } + + maxvisrange = getvisrange(lf); + nightvisrange = getnightvisrange(lf); + + // find all cells at max fov + nendcells = 0; + + // n + iy = lf->cell->y - maxvisrange; + limit(&iy,0,lf->cell->map->h-1); + start = lf->cell->x - maxvisrange; + end = lf->cell->x + maxvisrange; + limit(&start,0,lf->cell->map->w-1); + limit(&end,0,lf->cell->map->w-1); + if (db) dblog("North::%d,%d - %d,%d",start,iy,end,iy); + for (ix = start; ix < end; ix++) { + c = getcellat(lf->cell->map, ix, iy); + if (c) { + if (db) dblog("N:endcell[%d] = %d,%d",nn,c->x, c->y); + endcell[nendcells++] = c; + } + assert(nendcells < MAXVISLIMIT); + } + // e + ix = lf->cell->x + maxvisrange; + limit(&ix,0,lf->cell->map->w-1); + start = lf->cell->y - maxvisrange; + end = lf->cell->y + maxvisrange; + limit(&start,0,lf->cell->map->h-1); + limit(&end,0,lf->cell->map->h-1); + if (db) dblog("East::%d,%d - %d,%d",ix,start,ix,end); + for (iy = start; iy < end; iy++) { + c = getcellat(lf->cell->map, ix, iy); + if (c) { + if (db) dblog("E:endcell[%d] = %d,%d",nn,c->x, c->y); + endcell[nendcells++] = c; + } + assert(nendcells < MAXVISLIMIT); + } + // s + iy = lf->cell->y + maxvisrange; + limit(&iy,0,lf->cell->map->h-1); + start = lf->cell->x + maxvisrange; + end = lf->cell->x - maxvisrange; + limit(&start,0,lf->cell->map->w-1); + limit(&end,0,lf->cell->map->w-1); + if (db) dblog("South::%d,%d - %d,%d",start,iy,end,iy); + for (ix = start; ix > end; ix--) { + c = getcellat(lf->cell->map, ix, iy); + if (c) { + if (db) dblog("S:endcell[%d] = %d,%d",nn,c->x, c->y); + endcell[nendcells++] = c; + } + assert(nendcells < MAXVISLIMIT); + } + // w + ix = lf->cell->x - maxvisrange; + limit(&ix,0,lf->cell->map->w-1); + start = lf->cell->y + maxvisrange; + end = lf->cell->y - maxvisrange; + limit(&start,0,lf->cell->map->h-1); + limit(&end,0,lf->cell->map->h-1); + if (db) dblog("West::%d,%d - %d,%d",ix,start,ix,end); + for (iy = start; iy > end; iy--) { + c = getcellat(lf->cell->map, ix, iy); + if (c) { + if (db) dblog("W:endcell[%d] = %d,%d",nn,c->x, c->y); + endcell[nendcells++] = c; + } + assert(nendcells < MAXVISLIMIT); + } + + + assert(nendcells < MAXVISLIMIT); + + // look in circle around lf + //for (ang = 0; ang < 360; ang += 30) { + for (nn = 0; nn < nendcells; nn++) { + int keepgoing = B_TRUE; + int currange,xray; + int n; + // start at lf's cell + //c = lf->cell; + //x = c->x; + //y = c->y; + xray = startxray; + currange = 0; + // calc path to end cell + calcbresnham(lf->cell->map, lf->cell->x, lf->cell->y, endcell[nn]->x, endcell[nn]->y, retcell, &numpixels ); + // keep going until we lose los + for (n = 0; keepgoing && (n < numpixels); n++) { + /* + // calc x/y change + xd = precos[ang]; + yd = presin[ang]; + //limitd(&xd, -1, 1); + //limitd(&yd, -1, 1); + // get new cell + x += xd; + y += yd; + */ + c = retcell[n]; + if (n != 0) currange++; + if (currange > maxvisrange) c = NULL; + if (c) { + int found = B_FALSE; + // have we already marked it as seen? + for (i = 0; i < nlos; i++) { + if (los[i] == c) { + if (blocker[i]) { + keepgoing = B_FALSE; + } + found = B_TRUE; + break; + } + } + if (!found) { + // can we see it? + if (!celllitfor(lf, c, maxvisrange, nightvisrange)) { + keepgoing = B_FALSE; + } + if (!celltransparentfor(lf, c, &xray, &rangemod)) { + keepgoing = B_FALSE; + } + currange += rangemod; + if (currange > maxvisrange) keepgoing = B_FALSE; + + // if keepgoing was false, still count it + // BUT then stop looking. + los[nlos] = c; + blocker[nlos] = keepgoing ? B_FALSE : B_TRUE; + nlos++; + } + } else { // ie. if !c + keepgoing = B_FALSE; + } + } // end foreach cell and while keepgoing + } + + assert(nlos < (MAX_MAPW * MAX_MAPH)); + + // now fill in lifeform structure + lf->los = malloc(sizeof(cell_t *) * nlos); + for (i = 0; i < nlos; i++) { + lf->los[i] = los[i]; + } + lf->nlos = nlos; + + free(los); + free(blocker); +} int push(lifeform_t *lf, object_t *o, int dir) { cell_t *obcell, *dstcell; @@ -14345,7 +14550,7 @@ void setguntarget(lifeform_t *lf, lifeform_t *targ) { void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { flag_t *f,*nextf; - int i; + int i,retainhpmp = B_FALSE; int nkilled = 0; race_t *newrace; char buf[BUFLEN]; @@ -14356,6 +14561,10 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { statdirty = B_TRUE; } + if (lfhasflag(lf, F_RETAINHPMPONPOLY)) { + retainhpmp = B_TRUE; + } + if (frompolymorph && (gamemode == GM_GAMESTARTED) && lf->race) { race_t *origrace; @@ -14436,7 +14645,6 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { killflagsofid(lf->flags, F_RARITY); // certain other flags are rnadom - getflags(lf->flags, F_RNDHOSTILE, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -14454,27 +14662,28 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { lf->baseatt[i] = lf->att[i]; } - // generate hp/maxhp from hit dice - lf->maxhp = 0; - for (i = 0; i < lf->level; i++) { - lf->maxhp += rollhitdice(lf); - assert(lf->maxhp > 0); - } - lf->hp = lf->maxhp; - - // generate mp, if you have it. - f = hasflag(lf->flags, F_MPDICE); - if (f) { - lf->maxmp = f->val[0] * 4; - if (f->val[1] != NA) lf->maxmp += f->val[1]; - for (i = 0; i < lf->level-1; i++) { - lf->maxmp += rollmpdice(lf); + if (!retainhpmp) { + // generate hp/maxhp from hit dice + lf->maxhp = 0; + for (i = 0; i < lf->level; i++) { + lf->maxhp += rollhitdice(lf); + assert(lf->maxhp > 0); } - } else { - lf->maxmp = 0; - } - lf->mp = lf->maxmp; + lf->hp = lf->maxhp; + // generate mp, if you have it. + f = hasflag(lf->flags, F_MPDICE); + if (f) { + lf->maxmp = f->val[0] * 4; + if (f->val[1] != NA) lf->maxmp += f->val[1]; + for (i = 0; i < lf->level-1; i++) { + lf->maxmp += rollmpdice(lf); + } + } else { + lf->maxmp = 0; + } + lf->mp = lf->maxmp; + } lf->born = B_TRUE; diff --git a/lf.h b/lf.h index f1e774c..e59a18b 100644 --- a/lf.h +++ b/lf.h @@ -43,6 +43,8 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where); int canweild(lifeform_t *lf, object_t *o); int cantakeoff(lifeform_t *lf, object_t *o); int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell); +int celllitfor(lifeform_t *lf, cell_t *c, int maxvisrange, int nightvisrange); +int celltransparentfor(lifeform_t *lf, cell_t *c, int *xray, int *rangemod); int checkfordrowning(lifeform_t *lf, object_t *o); //void checkxp(enum RACE rid); float comparelfs(lifeform_t *lf1, lifeform_t *lf2); @@ -283,7 +285,8 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char int poisoncausesvomit(enum POISONTYPE ptype); int poisonthreatenslife(lifeform_t *lf, flag_t *f); void practice(lifeform_t *lf, enum SKILL skid, int amt); -void precalclos(lifeform_t *lf); +void precalclos_old(lifeform_t *lf); +void precalclos_new(lifeform_t *lf); int push(lifeform_t *lf, object_t *o, int dir); int readytotrain(lifeform_t *lf); int recruit(lifeform_t *lf); diff --git a/move.c b/move.c index 55e2651..7619302 100644 --- a/move.c +++ b/move.c @@ -23,6 +23,8 @@ extern int needredraw; extern enum GAMEMODE gamemode; +extern void (*precalclos)(lifeform_t *); + extern enum ERROR reason; extern void *rdata; diff --git a/nexus.c b/nexus.c index c28bb77..6197860 100644 --- a/nexus.c +++ b/nexus.c @@ -42,6 +42,11 @@ hiddenname_t *firsthiddenname = NULL, *lasthiddenname = NULL; npcname_t *npcname; int numnpcnames; +double presin[360]; +double precos[360]; + +void (*precalclos)(lifeform_t *) = NULL; + extern vault_t *firstvault; extern flag_t *retflag[]; @@ -853,9 +858,20 @@ void getrarityrange(int depth, int *min, int *max, int range, int oodok) { } int init(void) { + int i; // random numbers srand(time(NULL)); + // precalc sin/cos + for (i = 0; i < 360; i++) { + double rads; + rads = i * (M_PI / 180); + presin[i] = sin(rads); + precos[i] = cos(rads); + } + + precalclos = precalclos_new; + gamemode = GM_INIT; playerglyph.ch = '@'; @@ -1042,6 +1058,23 @@ int limitf(float *what, float min, float max) { return limited; } +int limitd(double *what, double min, double max) { + int limited = B_FALSE; + if (min != NA) { + if (*what < min) { + *what = min; + limited = B_TRUE; + } + } + if (max != NA) { + if (*what > max) { + *what = max; + limited = B_TRUE; + } + } + return limited; +} + int loadnpcnames(void) { FILE *f; char buf[BUFLEN]; diff --git a/nexus.h b/nexus.h index d76fa64..6815c5b 100644 --- a/nexus.h +++ b/nexus.h @@ -20,6 +20,7 @@ void initcommands(void); int isplayerturn(void); int limit(int *what, int min, int max); int limitf(float *what, float min, float max); +int limitd(double *what, double min, double max); int loadnpcnames(void); int onein(int howmany); int parseplayerfile(FILE *f, lifeform_t *lf); diff --git a/objects.c b/objects.c index 45e6d08..20f208e 100644 --- a/objects.c +++ b/objects.c @@ -29,6 +29,7 @@ extern skill_t *firstskill, *lastskill; extern flag_t *retflag[]; extern int nretflags; +void (*precalclos)(lifeform_t *); extern object_t *retobs[MAXPILEOBS+1]; extern int retobscount[MAXPILEOBS+1]; @@ -3064,6 +3065,13 @@ int getobbonus(object_t *o) { return bonus; } +int getobpoints(object_t *o) { + if (hasflag(o->flags, F_NOPOINTS)) { + return 0; + } + return getobvalue(o); +} + // returns the skill associated with this object skill_t *getobskill(object_t *o) { flag_t *f; diff --git a/objects.h b/objects.h index 5cc7c72..b955a5b 100644 --- a/objects.h +++ b/objects.h @@ -65,6 +65,7 @@ enum MATSTATE getmaterialstate(enum MATERIAL mat); int getmissileaccuracy(lifeform_t *thrower, cell_t *where, object_t *missile, object_t *firearm, enum ATTRIB whichatt); int getobaccuracy(object_t *wep, lifeform_t *weilder); int getobbonus(object_t *o); +int getobpoints(object_t *o); skill_t *getobskill(object_t *o); enum LFSIZE getobsize(object_t *o); int getobspellpower(object_t *o, lifeform_t *lf);