diff --git a/ai.c b/ai.c index 90b11c8..8eb3c68 100644 --- a/ai.c +++ b/ai.c @@ -153,6 +153,29 @@ int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { return B_FALSE; } +void ailoscheck(lifeform_t *lf) { + int i,ok = B_TRUE; + cell_t *c; + for (i = 0; i < lf->nlos; i++) { + c = lf->los[i]; + if (c->known != B_TRUE) { + if ((c->known < PR_INEPT) || (c->known > PR_MASTER)) { + ok = B_FALSE; break; + } + } + if ((c->visited != B_FALSE) && (c->visited != B_TRUE)) { + ok = B_FALSE; break; + } + if (c->lf && (c->lf->id == 65432)) { // ie. will crash if c->lf is invalid + ok = B_FALSE; break; + } + } + if (!ok) { + msg("FATAL: corrupt los[] array for %s",lf->race->id); + assert("Corrupt los array" == 0); + } +} + // A* algorithm. Returns F_AIPATH flag. flag_t *ai_createpathto(lifeform_t *lf, cell_t *targcell) { char *pathbuf; @@ -821,7 +844,8 @@ int aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim // cell in sight and adjacent? aispellok() should have already confirmed // that there will be at least one of these. for (i = 1; i < lf->nlos; i++) { - if (!lf->los[i]->lf && lf->los[i]->type->solid && (getcelldist(lf->cell, lf->los[i]) == 1)) { + // using getcelldirorth to make sure direction is orthogonal + if (!lf->los[i]->lf && lf->los[i]->type->solid && (getcelldistorth(lf->cell, lf->los[i]) == 1)) { poss[nposs++] = lf->los[i]; } } @@ -2542,51 +2566,69 @@ void aiturn(lifeform_t *lf) { master = findlf(lf->cell->map, f->val[0]); } + + ailoscheck(lf); + /////////////////////////////////////////////// // emergencies / fixing up /////////////////////////////////////////////// if (ai_handle_emergencies(lf, iqb)) return; + ailoscheck(lf); + /////////////////////////////////////////////// // housekeeping - weapon changes, drop/pickup, // use items, talk,etc /////////////////////////////////////////////// if (ai_housekeeping(lf, master)) return; + ailoscheck(lf); + /////////////////////////////////////////////// // healing /////////////////////////////////////////////// if (ai_healing(lf)) return; + ailoscheck(lf); + /////////////////////////////////////////////// // inventory management /////////////////////////////////////////////// if (ai_inventory_mgt(lf, &icanattack)) return; + ailoscheck(lf); + /////////////////////////////////////////////// // attacking existing targets /////////////////////////////////////////////// if (ai_attack_existing_target(lf)) return; + ailoscheck(lf); + /////////////////////////////////////////////// // generic pre-movement actions. /////////////////////////////////////////////// if (ai_premovement(lf)) return; + ailoscheck(lf); + /////////////////////////////////////////////// // movement /////////////////////////////////////////////// if (ai_movement(lf)) return; + ailoscheck(lf); /////////////////////////////////////////////// // look for something to do (objects, things // to attack, etc) /////////////////////////////////////////////// if (ai_bored(lf, master, icanattack)) return; + ailoscheck(lf); // DEFAULT - try to move in a random direction if (db) dblog(".oO { default - moving randomly }"); dorandommove(lf, B_NOBADMOVES, B_TRUE, B_FALSE); // this function will call rest() if we cant move + ailoscheck(lf); // somehow still here? if (!lf->timespent) { @@ -3199,6 +3241,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG specificcheckok = B_FALSE; } } + if (ot->id == OT_S_SUCK) { + if (getcelldist(lf->cell, victim->cell) <= 1) { + specificcheckok = B_FALSE; + } + } if (ot->id == OT_S_SUMMONWEAPON) { if (getweapon(lf)) { specificcheckok = B_FALSE; diff --git a/ai.h b/ai.h index 66e5590..1cfc71d 100644 --- a/ai.h +++ b/ai.h @@ -2,8 +2,7 @@ void addignorecell(lifeform_t *lf, cell_t *c); int aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit); -int calcheuristic(cell_t *c, cell_t *end); -int calcg(lifeform_t *lf, cell_t *thiscell, node_t *parent, int dirfromparent); +void ailoscheck(lifeform_t *lf); flag_t *ai_createpathto(lifeform_t *lf, cell_t *targcell); cell_t *ai_getnextcellinpath(lifeform_t *lf); int ai_popnextcellinpath(lifeform_t *lf); diff --git a/data.c b/data.c index fae0b8c..db8803b 100644 --- a/data.c +++ b/data.c @@ -1959,7 +1959,6 @@ void initobjects(void) { addmaterial(MT_FIRE, "fire", 0); addmaterial(MT_GAS, "gas", 0.5); addmaterial(MT_WIRE, "wire", 1); - addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_PROJECTILE, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_HOLY, NA, NA, NULL); @@ -2036,7 +2035,6 @@ void initobjects(void) { addmaterial(MT_SLIME, "slime", 9); addmaterial(MT_STONE, "stone", 10); addflag(lastmaterial->flags, F_HARDNESS, 4, NA, NA, NULL); - addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); addmaterial(MT_SILVER, "silver", 11); @@ -2051,7 +2049,6 @@ void initobjects(void) { addflag(lastmaterial->flags, F_DTVULN, DT_COLD, NA, NA, NULL); addmaterial(MT_BRICK, "brick", 14); addflag(lastmaterial->flags, F_HARDNESS, 4, NA, NA, NULL); - addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); addflag(lastmaterial->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); addmaterial(MT_GOLD, "gold", 16); @@ -2168,7 +2165,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_OBHP, 50, 50, NA, NULL); // will be overridden when making a corpse addflag(lastobjectclass->flags, F_DECAY, 0, NA, 1, NULL); // decay increases by 1 each turn. //addflag(lastobjectclass->flags, F_OBHPDRAIN, 1, DT_DECAY, NA, NULL); // ie. corpses last for 50 turns - addoc(OC_TECH, "Technology", "A strange piece of futuristic equipment. Perhaps someone with more skill in Technology could recognise it...", '[', C_GREY, RR_RARE); + addoc(OC_TECH, "Technology", "A strange piece of futuristic equipment. Perhaps someone with more skill in Technology could recognise it...", '[', C_GREY, RR_UNCOMMON); addocnoun(lastobjectclass, "technology"); addocnoun(lastobjectclass, "tech"); addflag(lastobjectclass->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); @@ -7021,7 +7018,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_YELLOW, '(', 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, 6, 6, NA, NULL); + addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); @@ -7038,7 +7035,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_LIGHTYELLOW, '(', 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); + addflag(lastot->flags, F_OBHP, 100, 100, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index 7b6c331..2547cef 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index a46c175..d2e4697 100644 --- a/defs.h +++ b/defs.h @@ -4548,6 +4548,7 @@ enum ERROR { E_LFINWAY, E_NOSPACE, E_BADCLIMBDIR, + E_BADCLIMBDIR2, E_STOPCLIMBING, E_SELNOTHING, E_ALREADYUSING, diff --git a/lf.c b/lf.c index 2fd10dd..3f07ffd 100644 --- a/lf.c +++ b/lf.c @@ -866,6 +866,10 @@ int cancook(lifeform_t *lf, recipe_t *rec, enum ERROR *reason) { int canclimb(lifeform_t *lf, enum ERROR *reason) { cell_t *cc; + if (!isorthogonal(lf->facing)) { + if (reason) *reason = E_BADCLIMBDIR2; + return B_FALSE; + } cc = getcellindir(lf->cell, lf->facing); if (isclimbing(lf)) { if (reason) *reason = E_CLIMBING; @@ -1956,6 +1960,13 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar casttype = getcasttype(lf, sid); } + // override 'fromob' based on conferred flags + if (willflag && (willflag->obfrom != NA)) { + fromob = findobbyid(lf->pack, willflag->obfrom); + } else if (castflag && (castflag->obfrom != NA)) { + fromob = findobbyid(lf->pack, castflag->obfrom); + } + sp = findot(sid); if (!fromob) { @@ -23912,7 +23923,7 @@ void startlfturn(lifeform_t *lf) { } } else if (f->val[0] == P_MIGRAINE) { // sleeping will avoid all migraine effects - if (!asleep && !ko) { + if (!asleep && !ko && !isblind(lf)) { object_t *lamp = NULL; int amt; amt = lfproduceslight(lf, &lamp); @@ -24122,7 +24133,7 @@ void startlfturn(lifeform_t *lf) { } amt = obproduceslight(o); - if (amt) { + if (amt && !isblind(lf)) { if (lighthurtseyes(lf)) { int min=2,max; if (isplayer(lf)) { diff --git a/map.c b/map.c index bd466d3..67b67f3 100644 --- a/map.c +++ b/map.c @@ -7510,7 +7510,6 @@ int finalisemap(map_t *map, object_t *entryob, int exitdir) { c = getcell_cond(map, &okforstairs); } if (c) { - o = addobfast(c->obpile, entryoppositetype->id); // DONT let addobject create maplinks, because we want to force it to // link to entry object. o = addobject(c->obpile, entryoppositetype->name, B_FALSE, B_FALSE, entryoppositetype->id); diff --git a/objects.c b/objects.c index 0539f63..7531602 100644 --- a/objects.c +++ b/objects.c @@ -1701,8 +1701,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum // fountain flags if (o && (o->type->id == OT_FOUNTAIN)) { - f = hasflag(o->flags, F_LINKOB); if (wantfountaintype != OT_NONE) { + f = hasflag(o->flags, F_LINKOB); assert(f); + f->val[0] = wantfountaintype; + f = hasflag(o->flags, F_FILLPOT); assert(f); f->val[0] = wantfountaintype; } else if (where->where && (where->where->habitat->id != H_VILLAGE)) { if (onein(3)) { @@ -1712,9 +1714,15 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum getrarityrange(where->where->map->depth, &min, &max, RARITYVARIANCEOB, B_FALSE); ot = getrandomobofclass(OC_POTION, min, max, NULL, NULL); if (ot) { + f = hasflag(o->flags, F_LINKOB); assert(f); + f->val[0] = ot->id; + f = hasflag(o->flags, F_FILLPOT); assert(f); f->val[0] = ot->id; } } else { + f = hasflag(o->flags, F_LINKOB); assert(f); + f->val[0] = OT_POT_WATER; + f = hasflag(o->flags, F_FILLPOT); assert(f); f->val[0] = OT_POT_WATER; } } @@ -10220,7 +10228,11 @@ int obsfallthrough(cell_t *c, object_t *pit) { if (belowcell) { char oid[BUFLENSMALL]; sprintf(oid, "%ld",pit->id); - uphole = findmapobwithflagval(belowcell->map, F_MAPLINK, NA, NA, NA, oid); + //uphole = findmapobwithflagval(belowcell->map, F_MAPLINK, NA, NA, NA, oid); + uphole = hasobwithflagval(belowcell->obpile, F_MAPLINK, NA, NA, NA, oid); + if (!uphole) { + uphole = hasobwithflagval(belowcell->obpile, F_MAPLINK, NA, c->x, c->y, NULL); + } assert(uphole); getobname(uphole,upholename, 1); } @@ -15831,8 +15843,16 @@ void timeeffectsob(object_t *o) { // object makes noise? getflags(o->flags, retflag, &nretflags, F_MAKESNOISE, F_NONE); if (nretflags) { + int chance; f = retflag[rnd(0,nretflags-1)]; - if (pctchance(f->val[0])) { + + chance = f->val[0]; + // closed shops don't make cash register noises! + if (hasflag(o->flags, F_SHOP) && shopisclosed(o)) { + chance = 0; + } + + if (pctchance(chance)) { // these are generally just to notify the player that something // is nearby, so don't make noises the the player is already there. if (location != player->cell) { diff --git a/shops.c b/shops.c index 395cfd3..0485c6a 100644 --- a/shops.c +++ b/shops.c @@ -179,14 +179,9 @@ void shop(lifeform_t *lf, object_t *vm) { } // closed? - f = hasflag(vm->flags, F_OPENHOURS); - if (f) { - int h = -1,m = -1,s = -1; - splittime(&h, &m, &s); - if (!timeisbetween(h, f->val[0], f->val[1])) { - sayphrase(NULL, f->val[2], SV_TALK, hoursto12(f->val[0]), NULL, player); - return; - } + if (shopisclosed(vm)) { + sayphrase(NULL, f->val[2], SV_TALK, hoursto12(f->val[0]), NULL, player); + return; } if (lfhasflag(lf, F_STENCH)) { @@ -805,6 +800,18 @@ enum SHOPRETURN shopid(lifeform_t *lf, object_t *vm, int starty, char *toptext, return SR_CONTINUE; } +int shopisclosed(object_t *shop) { + flag_t *f; + f = hasflag(shop->flags, F_OPENHOURS); + if (f) { + int h = -1,m = -1,s = -1; + splittime(&h, &m, &s); + if (!timeisbetween(h, f->val[0], f->val[1])) { + return B_TRUE; + } + } + return B_FALSE; +} enum SHOPRETURN shopmiracle(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *ndonated) { char ch; diff --git a/shops.h b/shops.h index 733e0c5..4f76195 100644 --- a/shops.h +++ b/shops.h @@ -12,6 +12,7 @@ enum SHOPRETURN shopbless(lifeform_t *lf, object_t *vm, int starty, char *toptex enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased); enum SHOPRETURN shopdetectcurse(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased); enum SHOPRETURN shopid(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *nid); +int shopisclosed(object_t *shop); enum SHOPRETURN shopmiracle(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased); enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased); enum SHOPRETURN shoprepair(lifeform_t *lf, object_t *vm, int starty, char *toptext, int *npurchased); diff --git a/spell.c b/spell.c index c59509d..82d3df8 100644 --- a/spell.c +++ b/spell.c @@ -820,11 +820,24 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef taketime(user, getactspeed(user)*2); } else if (abilid == OT_A_CLIMB) { enum ERROR why; + int origdir = D_NONE; // for ai only: turn to face target cell first. if (!isplayer(user) && targcell) { turntoface(user, targcell); } + if (isplayer(user) && !isorthogonal(user->facing)) { + int dir; + dir = askdir("Climb in which direction (orthogonal only, - to cancel)", B_TRUE, B_FALSE); + if ((dir == D_NONE) || (dir == D_MYSELF) || !isorthogonal(dir)) { + msg("You can only climb in orthogonal directions."); + return B_TRUE; + } else { + origdir = user->facing; + setfacing(user, dir); + targcell = getcellindir(user->cell, user->facing); + } + } if (!canclimb(user, &why)) { if (isplayer(user)){ @@ -832,6 +845,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef case E_CLIMBING: msg("You are already climbing!"); break; case E_CANTMOVE: msg("You can't move!"); break; case E_BADCLIMBDIR: msg("There is no wall to climb in front of you!"); break; + case E_BADCLIMBDIR2: msg("You can only climb in orthogonal directions."); break; case E_LFINWAY: msg("Something is in the way!"); break; case E_SWIMMING: msg("You can't climb while swimming!"); break; case E_TOOHEAVY: msg("Your load is too heavy to climb with!"); break; @@ -839,6 +853,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef default: msg("For some reason, you can't climb."); break; } } + if (origdir != D_NONE) { + setfacing(user, origdir); + } return B_TRUE; } @@ -883,7 +900,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (corpse) { getobname(corpse, obname, o->amt); if (getobsize(corpse) > (getskill(user, SK_COOKING)+1)) { - msg("%s is too large for you to cook at the moment.", obname); + msg("%s is too large for you to cook (Cooking skill too low).", obname); ncooked++; break; } else if (isimmuneto(corpse->flags, DT_FIRE, B_FALSE)) {