diff --git a/attack.c b/attack.c index bd07243..85151d5 100644 --- a/attack.c +++ b/attack.c @@ -157,6 +157,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { AT_NONE = 0, AT_LF = 1, AT_OB = 2, + AT_WALL = 3, } attacktype = AT_NONE; void *attacktarget; int attacklfid = -1; @@ -279,31 +280,16 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { attacktype = AT_OB; attacktarget = o; } else { - // TODO: attack wall? if (!lfhasflag(lf, F_HURRICANESTRIKE)) { - /* - flag_t *sf; - lifeform_t *stomachlf = NULL; - sf = hasflag(lf->cell->map->flags, F_STOMACHOF); - if (sf) { - stomachlf = findlf(NULL, sf->val[0]); - } - // we ARE allowed to attack stomach walls. - if (sf && stomachlf && (c->type->id == CT_WALLFLESH)) { - attacktype = AT_LF; - attacktarget = stomachlf; - } else { - // not allowed to attack normal walls + if (c->type->solid) { + attacktype = AT_WALL; + attacktarget = c; + } else { if (isplayer(lf)) { msg("There is nothing there to attack!"); } return B_TRUE; } - */ - if (isplayer(lf)) { - msg("There is nothing there to attack!"); - } - return B_TRUE; } // end if !hurricanestrike } } @@ -450,6 +436,12 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { attacksdone = maxattacks; break; } + } else if (attacktype == AT_WALL) { + if (attackwall(lf, (cell_t *)attacktarget, wep[i], damflag[i])) { + // failed + attacksdone = maxattacks; + break; + } } attacksdone++; @@ -680,7 +672,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) object_t *armour; char noun[BUFLEN]; critpos = getrandomcorebp(victim, lf); - if (critpos != BP_NONE) { + if (critpos == BP_NONE) { + strcpy(victimbpname, victimname); + } else { armour = getequippedob(victim->pack, critpos); if (armour) { char armname[BUFLEN]; @@ -711,7 +705,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) getlfname(victim, victimname); } - // weapon passing through ghosts etc? if (hit) { if (lfhasflag(victim, F_NONCORPOREAL) && @@ -1402,12 +1395,16 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { if (isplayer(lf) && hasflag(o->flags, F_LOCKED)) { angergodmaybe(R_GODTHIEVES, 25, GA_MONEY); } - + if (isdeadob(o)) { + break; + } } // end foreach damtype - // special weapon effects, as long as you're not doing a heavy blow - if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) { - wepeffects(wep->flags, obloc, damflag, dam[0]); + if (!isdeadob(o)) { + // special weapon effects, as long as you're not doing a heavy blow + if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) { + wepeffects(wep->flags, obloc, damflag, dam[0]); + } } if (isunarmed) { @@ -1426,6 +1423,169 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { return B_FALSE; } +int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) { + int dam[100]; + enum DAMTYPE damtype[100]; + int ndam = 0; + char attackername[BUFLEN]; + char obname[BUFLEN]; + int isunarmed = B_FALSE; + char buf[BUFLEN]; + int i; + int maxhp; + + moveeffects(lf); + if (isdead(lf)) return B_TRUE; + + maxhp = c->type->hp; + + // get names + getlfname(lf, attackername); + + // don't need to figure out accuracy - we always hit. + + // determine damage + ndam = 0; + //if (unarmedflag && (unarmedflag->val[0] != NA)) { + dam[ndam] = getdamroll(wep, NULL, damflag); + + // modify for strength + if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { + dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf)); + } + + // damtype? + damtype[ndam] = getdamtype(wep); + ndam++; + + // don't need to check for blessed vs mosnters + + // determine extra damage + getextradamwep(wep, &dam[0], &damtype[0], &ndam); + getextradamlf(lf, &dam[0], &damtype[0], &ndam); + + + for (i = 0; i < ndam; i++) { + // announce the hit + construct_hit_string(lf, NULL, attackername, c->type->name, NULL, wep, damtype[i], dam[i], maxhp, i, B_FALSE, B_FALSE, B_FALSE, isunarmed, buf); + + if (strlen(buf)) { + msg("%s", buf); + } + if (!isplayer(lf) && !cansee(player, lf)) { + char noisebuf[BUFLEN]; + int vol; + switch (c->type->material->id) { + case MT_METAL: + strcpy(noisebuf, "a metallic clanging."); + vol = 4; + break; + case MT_GLASS: + strcpy(noisebuf, "cracking glass."); + vol = 4; + break; + case MT_WOOD: + case MT_DRAGONWOOD: + strcpy(noisebuf, "splintering wood."); + vol = 4; + break; + case MT_BONE: + case MT_STONE: + strcpy(noisebuf, "a dull thumping."); + vol = 3; + break; + case MT_GOLD: + case MT_SILVER: + case MT_LEATHER: + strcpy(noisebuf, "a dull thumping."); + vol = 2; + break; + case MT_PAPER: + case MT_WETPAPER: + case MT_RUBBER: + strcpy(noisebuf, "a dull thumping."); + vol = 1; + break; + default: + strcpy(noisebuf, "something being hit."); + vol = 3; + break; + } + noise(c, NULL, NC_OTHER, vol, noisebuf, NULL); + } + + if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(c->type->material->flags, F_HARDNESS)) { + object_t *gloves; + gloves = getequippedob(lf->pack, BP_HANDS); + if (gloves && hasflag(gloves->flags, F_HARDNESS)) { + // ok + } else if ((c->type->material->id == MT_WOOD) && (getskill(lf, SK_UNARMED) >= PR_ADEPT)) { + // ok + } else { + char buf[BUFLEN]; + snprintf(buf, BUFLEN, "punching %s", obname); + if ( losehp(lf, 1, DT_BASH, lf, buf)) { + if (isplayer(lf)) { + msg("^bOw!"); + } + } + } + } + + // smash wood bonus + if ((wep->type->id == OT_FISTS) && + (c->type->material->id == MT_WOOD) && + (getskill(lf, SK_UNARMED) >= PR_ADEPT)) { + dam[i] += rnd(1,6); + } + + // adjust dam + adjustdammaterial(&dam[i], damtype[i], c->type->material->id); + + if (dam[i] > 0) { + // wall loses hp + c->hp -= dam[i]; + if (c->hp <= 0) { + char cellname[BUFLEN]; + int shattered = B_FALSE; + enum MATERIAL cellmat; + // remember cell properties + sprintf(cellname, "%s %s", needan(c->type->name) ? "An" : "A", c->type->name); + cellmat = c->type->material->id; + // cell dies (have to do this before calling fragments()) + setcelltype(c, c->map->habitat->emptycelltype); + // announce + if (haslos(player, c)) { + msg("%s %s!", cellname, shattered ? "shatters" : "is destroyed"); + } + // shatter? + if (willshatter(cellmat)) { + char what[BUFLEN]; + shattered = B_TRUE; + noise(c, NULL, NC_OTHER, SV_CAR, "something shattering.", NULL); + if (getshardobname(cellmat, what)) { + fragments(c, what, 0, 3); // TODO: use speed so shards will hit lfs + } + } + break; + } + } + + } // end foreach damtype + + // no special weapon effects on cells. + + // weapon gets damaged ? + if (wep && (ndam > 0)) { + if (wepdullable(wep)) { + // weapon gets duller + if (rnd(1,2)) makeduller(wep, 1); + } + } + + return B_FALSE; +} + enum DAMTYPE basedamagetype(enum DAMTYPE dt) { switch (dt) { case DT_HEAT: diff --git a/attack.h b/attack.h index 371465f..249d5b9 100644 --- a/attack.h +++ b/attack.h @@ -5,6 +5,7 @@ void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int * int attackcell(lifeform_t *lf, cell_t *c, int force); int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag); int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag); +int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag); enum DAMTYPE basedamagetype(enum DAMTYPE dt); int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname); //void confereffects(flagpile_t *fp, lifeform_t *victim); diff --git a/data.c b/data.c index 50613b8..fd9e967 100644 --- a/data.c +++ b/data.c @@ -2189,6 +2189,9 @@ void initobjects(void) { addflag(lastot->flags, F_VALUE, 10, NA, NA, NULL); addot(OT_POT_CANINETRACKING, "potion of canine tracking", "Mimics the effects of a 'canine tracking' spell.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addot(OT_POT_GROWTH, "potion of growth", "A magical liquid which causes the imbiber's body to instantly undergo rapid growth.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-10 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, NA, NULL); @@ -2830,7 +2833,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); // l2 - addot(OT_S_BLADEBURN, "bladeburn", "Ignites the target's bladed weapon, causing it to temporarily deal fire damage. The spell's power determines how long it will last.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_BLADEBURN, "bladeburn", "Ignites the caster's weapon, causing it to temporarily deal fire damage. The spell's power determines how long it will last.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its duration."); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); @@ -3467,6 +3470,14 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); // l2 + addot(OT_S_SIZEUP, "unnatural growth", "Causes the caster's body to grow in size.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addot(OT_S_SIZEDOWN, "unnatural shrinkage", "Causes the caster's body to shrink in size.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addot(OT_S_DARKNESS, "darkness", "Permenantly darkens the area around the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power III, you can control where the darkness appears."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VIII, the darkness becomes permenant."); @@ -3485,6 +3496,7 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); + // l3 addot(OT_S_INVISIBILITY, "invisibility", "Temporarily renders the target invisible.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how long the invisibility will last."); @@ -5290,7 +5302,6 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FIRE, NA, NULL); addflag(lastot->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); @@ -5781,9 +5792,10 @@ void initobjects(void) { addflag(lastot->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 350, NA, NA, NULL); - addot(OT_RING_INVIS, "ring of invisibility", "Renders the wearer invisible.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addot(OT_RING_INVIS, "ring of invisibility", "Renders the wearer invisible - but drains the wearer's health at the same time.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); addflag(lastot->flags, F_EQUIPCONFER, F_INVISIBLE, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_HPDRAIN, 1, DT_DIRECT, "life force draining"); addflag(lastot->flags, F_VALUE, 400, NA, NA, NULL); addot(OT_RING_INVULN, "ring of invulnerability", "Grants the caster complete immunity to physical harm.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_EQUIPCONFER, F_INVULNERABLE, NA, NA, NULL); @@ -6984,6 +6996,7 @@ void initobjects(void) { void initoptions(void) { addoption(OPT_ALWAYSSHOWTRAILS, "always show trail objects", B_FALSE); + addoption(OPT_STOPRUNONNOISE, "stop running if sound heard", B_TRUE); } void initrace(void) { @@ -8871,7 +8884,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slurping"); addflag(lastrace->flags, F_DTIMMUNE, DT_ACID, B_TRUE, NA, NULL); addflag(lastrace->flags, F_AUTOCREATEOB, 0, NA, NA, "puddle of acid"); - addflag(lastrace->flags, F_DIESPLATTER, 3, NA, NA, "splash of acid"); + addflag(lastrace->flags, F_DIESPLATTER, 3, 0, NA, "splash of acid"); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOFLEE, 5, NA, NA, NULL); @@ -9008,6 +9021,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_REVIVETIMER, 0, 25, R_TROLL, NULL); addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL, "Xats are wild pigs with the claws of a dog."); setbodytype(lastrace, BT_QUADRAPED); @@ -9875,7 +9889,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slurping"); addflag(lastrace->flags, F_DTIMMUNE, DT_ACID, B_TRUE, NA, NULL); addflag(lastrace->flags, F_AUTOCREATEOB, 0, NA, NA, "puddle of acid"); - addflag(lastrace->flags, F_DIESPLATTER, 3, NA, NA, "splash of acid"); + addflag(lastrace->flags, F_DIESPLATTER, 3, 0, NA, "splash of acid"); addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); @@ -9908,7 +9922,7 @@ void initrace(void) { addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_AUTOCREATEOB, 0, NA, NA, "puddle of slime"); - addflag(lastrace->flags, F_DIESPLATTER, 3, NA, NA, "puddle of slime"); + addflag(lastrace->flags, F_DIESPLATTER, 3, 0, NA, "puddle of slime"); addrace(R_SNAKE, "brown snake", 3, 's', C_BROWN, MT_FLESH, RC_ANIMAL, "Common venomous snakes."); setbodytype(lastrace, BT_SNAKE); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index 82c907c..7395068 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 2e57ca5..be08078 100644 --- a/defs.h +++ b/defs.h @@ -65,6 +65,8 @@ // Booleans #define B_FALSE (0) #define B_TRUE (-1) +#define B_MAYBE (-2) + #define B_FORCE (-2) #define B_ONPURPOSE (-1) #define B_CHANGEDIR (-1) @@ -1213,6 +1215,7 @@ enum OBTYPE { OT_POT_EXPERIENCE, OT_POT_FURY, OT_POT_GASEOUSFORM, + OT_POT_GROWTH, OT_POT_HEALING, OT_POT_HEALINGMIN, OT_POT_HEALINGMAJ, @@ -1394,6 +1397,8 @@ enum OBTYPE { OT_S_POLYMORPH, OT_S_POLYMORPHRND, OT_S_QUICKENSTONE, + OT_S_SIZEUP, + OT_S_SIZEDOWN, // nature / enviromancy OT_S_BARKSKIN, OT_S_CALLLIGHTNING, @@ -2083,6 +2088,9 @@ enum FLAG { F_NOQUALITY, // can't be masterwork / shoddy F_CORPSEOF, // this is a corpse of montype val0. // text is how it died. + F_REVIVETIMER, // v0 = cur, v1 = max. v0 incremenets each tick. + // when v0 == v1, this object changes into lf of race + // v2. F_DTCONVERT, // damtype val0 converts this to f->text F_DTCREATEOB, // damtype val0 creates object f->text here // v1 = radius to burst in @@ -2392,8 +2400,12 @@ enum FLAG { // v0 is the order in which these are displayed (0-5) F_BONDESC, // text=extra description for playable races. // v0 is the display order. + // v1=true means 'don't display this one during + // player race selection) F_PENDESC, // text=extra description for playable races. // v0 is the display order. + // v1=true means 'don't display this one during + // player race selection) //F_SPELLLETTER, // text[0] = letter to cast this spell F_AICASTTOFLEE, // AI can cast this spell to help flee/heal // v0 is who to target @@ -2435,6 +2447,9 @@ enum FLAG { // unconscious. announce it when you wake up. F_TURNED, // lf turned this turn. F_PRAYEDTO, // player has prayed to this god before. + F_HPDRAIN, // lf loses v0 hit points eath turn. + // v1 = damtype + // text = killer damage string F_GAVEMONEY, // v0 tracks how much money we gave away this turn // used for r_godgreed anger effects. F_CLIMBING, // lf is currently climbing a wall @@ -2600,6 +2615,8 @@ enum FLAG { // e = exits // s = shops // t = traps + // o = rare Objects + // m = rare Monsters // eg: text=="st" means they know of shops+traps F_NOJOBTEXT, // this lf's name is 'a xxx', not 'a xxx wizard' etc F_LASTDIR, // this is the last direction we moved. @@ -2707,6 +2724,7 @@ enum FLAG { F_DIESPLATTER, // this lf will splatter objcets of type 'text' // when it dies. // v0 = max distance to splatter (or UNLIMITED) + // v1 = how fast to shoot objects (0 = just place them) // text = type of object to splatter F_OBESE, // double base weight for race! F_ORIGRACE, // original player race (if you polymorphed) @@ -2967,6 +2985,9 @@ enum FLAG { // v0 is pct chance of door (as opposed to empty // doorway with no door). F_AUTOPOPULATE, // fill this vault with obs/mons/pillars like normal rooms + F_MAINTAINEDGE, // when calling fixreachability(), only allow + // corridors to enter this vault through cells + // marked as exits. F_NORANDOM, // this vault does not randomly appear // OR this spell doesn't apear in books F_VAULTATOB, // v0/1=x/y, v2=pctchance, text=obname @@ -3262,6 +3283,7 @@ typedef struct warning_s { enum OPTION { OPT_ALWAYSSHOWTRAILS, + OPT_STOPRUNONNOISE, }; typedef struct option_s { diff --git a/flag.c b/flag.c index 20d3da9..180a658 100644 --- a/flag.c +++ b/flag.c @@ -469,8 +469,10 @@ int fpisbad(flagpile_t *fp) { } -void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id) { +// returns # of flags copied +int copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id) { flag_t *f; + int ndone = 0; for (f = src->first ; f ; f = f->next) { // gone past the requrested id's number - ie. it's not there. if (f->id > id) break; @@ -487,8 +489,10 @@ void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id) { f->altval->val[2], f->altval->text); } + ndone++; } } + return ndone; } void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime) { diff --git a/flag.h b/flag.h index 0ec3251..5ea70d4 100644 --- a/flag.h +++ b/flag.h @@ -14,7 +14,7 @@ void changeflagtext(flag_t *f, char *newtext); void checkmapflags(map_t *m); int fpisbad(flagpile_t *fp); void checkflagpile(flagpile_t *fp); -void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id); +int copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id); void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime); int countflags(flagpile_t *fp); int flagcausesloscalc(enum FLAG fid); diff --git a/io.c b/io.c index 9e4a348..7df43e1 100644 --- a/io.c +++ b/io.c @@ -3472,6 +3472,7 @@ void describeob(object_t *o) { void describerace(enum RACE rid) { char buf[BUFLEN]; char *buf2; + char ch; int x,y; race_t *r; cls(); @@ -3487,16 +3488,18 @@ void describerace(enum RACE rid) { wmove(mainwin, 2, 0); buf2 = malloc(HUGEBUFLEN * sizeof(char)); - makedesc_race(rid, buf2, B_TRUE); + makedesc_race(rid, buf2, B_TRUE, B_FALSE); //textwithcol(mainwin, buf2); getyx(mainwin,y,x); - wrapprint(mainwin, &y, &x, "%s", buf2); + ch = wrapprint(mainwin, &y, &x, "%s", buf2); free(buf2); wrefresh(mainwin); - // wait for key - getch(); + // wait for key, unless we quit from the 'more' prompt + if (ch != 27) { + getch(); + } real_clearmsg(B_TRUE); restoregamewindows(); } @@ -4163,22 +4166,24 @@ void docomms_areainfo(char *who, flagpile_t *fp, lifeform_t *lf) { } } // veryrare objects - ndone = 0; - for (y = 0; y < player->cell->map->h ; y++) { - for (x = 0; x < player->cell->map->w; x++) { - c = getcellat(player->cell->map, x,y); - for (o = c->obpile->first ; o ; o = o->next) { - if (hasflag(o->flags, F_SHOP)) continue; // shops were already handled - f = hasflag(o->type->flags, F_RARITY); - if (f && (f->val[2] == RR_VERYRARE)) { - msg("\"I hear there is a rare %s nearby...\"", o->type->name); more(); - setcellknown(c, PR_MASTER); - ndone++; + if (strchr(knowflag->text, 'o')) { + ndone = 0; + for (y = 0; y < player->cell->map->h ; y++) { + for (x = 0; x < player->cell->map->w; x++) { + c = getcellat(player->cell->map, x,y); + for (o = c->obpile->first ; o ; o = o->next) { + if (hasflag(o->flags, F_SHOP)) continue; // shops were already handled + f = hasflag(o->type->flags, F_RARITY); + if (f && (f->val[2] == RR_VERYRARE)) { + msg("\"I hear there is a rare %s nearby...\"", o->type->name); more(); + setcellknown(c, PR_MASTER); + ndone++; + } } } } + if (ndone) needredraw = B_TRUE; } - if (ndone) needredraw = B_TRUE; // staircases if (strchr(knowflag->text, 'e')) { ndone = 0; @@ -4252,37 +4257,39 @@ void docomms_areadangers(char *who, flagpile_t *fp, lifeform_t *lf) { totdone += ndone; } // veryrare monsters - gethitdicerange(getmapdifficulty(player->cell->map), &min,&max, RARITYVARIANCELF, B_FALSE); + if (strchr(knowflag->text, 'm')) { + gethitdicerange(getmapdifficulty(player->cell->map), &min,&max, RARITYVARIANCELF, B_FALSE); - ndone = 0; - for (y = 0; y < player->cell->map->h ; y++) { - for (x = 0; x < player->cell->map->w; x++) { - c = getcellat(player->cell->map, x,y); - if (c->lf && !isplayer(c->lf) && (c->lf != lf) && areenemies(c->lf, player)) { - int showit = B_FALSE; - enum RARITY rr; - getracerarity(NULL, c->lf->race->id, &rr); - if (rr == RR_VERYRARE) { - showit = B_TRUE; - } else { - // out of depth monsters? - int hd; - hd = gethitdicerace(c->lf->race); - if (hd > max) { + ndone = 0; + for (y = 0; y < player->cell->map->h ; y++) { + for (x = 0; x < player->cell->map->w; x++) { + c = getcellat(player->cell->map, x,y); + if (c->lf && !isplayer(c->lf) && (c->lf != lf) && areenemies(c->lf, player)) { + int showit = B_FALSE; + enum RARITY rr; + getracerarity(NULL, c->lf->race->id, &rr); + if (rr == RR_VERYRARE) { showit = B_TRUE; + } else { + // out of depth monsters? + int hd; + hd = gethitdicerace(c->lf->race); + if (hd > max) { + showit = B_TRUE; + } } - } - if (showit) { - char lfname[BUFLEN]; - real_getlfnamea(c->lf, lfname, B_FALSE, B_TRUE); - msg("\"There is %s living nearby...\"", lfname); more(); - ndone++; + if (showit) { + char lfname[BUFLEN]; + real_getlfnamea(c->lf, lfname, B_FALSE, B_TRUE); + msg("\"There is %s living nearby...\"", lfname); more(); + ndone++; + } } } } + totdone += ndone; } - totdone += ndone; msg("\"I know of no %sdangers in this area.\"", (totdone) ? "other " : ""); @@ -6110,7 +6117,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { return retbuf; } -char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { +char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel) { race_t *r; char buf[HUGEBUFLEN]; flag_t *retflag[MAXCANDIDATES],*f; @@ -6176,8 +6183,11 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { for (i = 0; i < nretflags; i++) { f = retflag[i]; if (f->val[0] == curidx) { - snprintf(buf, HUGEBUFLEN, "@- %s\n", f->text); - strncat(retbuf, buf, HUGEBUFLEN); + if ((f->val[1] == B_TRUE) && forplayersel) { + } else { + snprintf(buf, HUGEBUFLEN, "@- %s\n", f->text); + strncat(retbuf, buf, HUGEBUFLEN); + } donesomething = B_TRUE; curidx++; break; @@ -6264,7 +6274,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { case F_ENHANCESMELL: sprintf(buf, "Enhanced sense of smell (range %d)", f->val[0]); break; case F_FLYING: sprintf(buf, "Can fly at will"); break; case F_HEAVYBLOW: sprintf(buf, "Attacks will knock enemies backwards"); break; - case F_HUMANOID: sprintf(buf, "Can use weapons and armour."); break; + case F_HUMANOID: if (!forplayersel) sprintf(buf, "Can use weapons and armour."); break; case F_LEVITATING: sprintf(buf, "Can levitate at will"); break; case F_MEDITATES: sprintf(buf, "Meditates to retain awareness while sleeping."); break; case F_MPMOD: if (f->val[0] > 0) sprintf(buf, "+%d Mana", f->val[0]); break; @@ -6313,8 +6323,11 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { for (i = 0; i < nretflags; i++) { f = retflag[i]; if (f->val[0] == curidx) { - snprintf(buf, HUGEBUFLEN, "@- %s\n", f->text); - strncat(retbuf, buf, HUGEBUFLEN); + if ((f->val[1] == B_TRUE) && forplayersel) { + } else { + snprintf(buf, HUGEBUFLEN, "@- %s\n", f->text); + strncat(retbuf, buf, HUGEBUFLEN); + } donesomething = B_TRUE; curidx++; break; @@ -6330,7 +6343,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { switch (f->id) { case F_CARNIVORE: sprintf(buf, "Will only eat meat."); break; case F_DEAF: sprintf(buf, "Deaf"); break; - case F_DIURNAL: sprintf(buf, "Sleeps at night."); break; + case F_DIURNAL: if (!forplayersel) sprintf(buf, "Sleeps at night."); break; case F_DTVULN: if (!hasflag(doneflags, F_DTVULN)) { if (f->val[0] == DT_ALL) { @@ -6362,7 +6375,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { break; case F_MPMOD: if (f->val[0] < 0) sprintf(buf, "%d Mana", f->val[0]); break; case F_NEEDSWATER: sprintf(buf, "Will suffocate without water"); break; - case F_NOCTURNAL: sprintf(buf, "Sleeps during the day."); break; + case F_NOCTURNAL: if (!forplayersel) sprintf(buf, "Sleeps during the day."); break; case F_NOPACK: sprintf(buf, "Cannot carry objects."); break; case F_SIZE: if (hasflag(r->flags, F_HUMANOID) && (f->val[0] != SZ_HUMAN)) { @@ -6373,7 +6386,9 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra) { sprintf(buf, "Will not leave its home territory."); break; break; case F_TAMABLE: - sprintf(buf, "Susceptible to bribery."); break; + if (!forplayersel) { + sprintf(buf, "Susceptible to bribery."); + } break; case F_VEGETARIAN: sprintf(buf, "Will not eat meat."); break; case F_VISRANGEMOD: if (f->val[0] < 0) sprintf(buf, "Reduced vision range (%d)", f->val[0]); break; @@ -8331,7 +8346,9 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { // only print if on the page if ((i >= first) && !atbottom) { // show heading first + wattron(mainwin, A_REVERSE); mvwprintw(mainwin, y, 0, "%s", curheading); + wattroff(mainwin, A_REVERSE); y++; } doneheading = B_TRUE; @@ -12064,20 +12081,21 @@ int warnabout(char *what) { } // @ = tab -void wrapprint(WINDOW *win, int *y, int *x, char *format, ... ) { +char wrapprint(WINDOW *win, int *y, int *x, char *format, ... ) { char word[HUGEBUFLEN],buf[HUGEBUFLEN]; char *p; va_list args; - int w,nspaces = 0; + int w,nspaces = 0,h; int first = B_TRUE; va_start(args, format); vsnprintf( buf, HUGEBUFLEN, format, args ); va_end(args); - if (!strlen(buf)) return; + if (!strlen(buf)) return '\0'; w = getmaxx(win); + h = getmaxy(win); // remember the amount of spaces at the end p = buf + strlen(buf) - 1; @@ -12105,7 +12123,25 @@ void wrapprint(WINDOW *win, int *y, int *x, char *format, ... ) { *x = 0; } } + + if (gamemode == GM_GAMESTARTED) { + if (*y >= h-2) { + char ch; + centre(win,C_WHITE, h-1, "--More--"); + ch = getch(); + if (ch == 27) { // esc + return ch; + } else { + // clear window + wclear(win); + *y = 0; + *x = 0; + } + } + } + wmove(win, *y, *x); + if (first) { first = B_FALSE; } else if (*x != 0) { @@ -12137,6 +12173,8 @@ void wrapprint(WINDOW *win, int *y, int *x, char *format, ... ) { //wattroff(win, A_BOLD); setcol(win, C_GREY); getyx(win, *y, *x); + + return '\0'; } diff --git a/io.h b/io.h index 3a5cd15..867d022 100644 --- a/io.h +++ b/io.h @@ -106,7 +106,7 @@ int keycodetokey(int keycode, int escseqok); void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int firstob, int *counter, int lastline, int *y, char *myletters, int forpickup, int showpoints); char *makedesc_god(lifeform_t *god, char *retbuf); char *makedesc_ob(object_t *o, char *retbuf); -char *makedesc_race(enum RACE rid, char *retbuf, int showextra); +char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel); char *makedesc_skill(enum SKILL skid, char *retbuf, enum SKILLLEVEL levhilite); char *makedesc_spell(objecttype_t *ot, char *retbuf); void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown, int wantlowmp, int wanttoohard,int mpcutoff); @@ -136,4 +136,4 @@ void tombstone(lifeform_t *lf); void updatestatus(void); int updateviewfor(cell_t *cell); int warnabout(char *what); -void wrapprint(WINDOW *win, int *y, int *x, char *format, ... ); +char wrapprint(WINDOW *win, int *y, int *x, char *format, ... ); diff --git a/lf.c b/lf.c index 333fa5c..99e9a1a 100644 --- a/lf.c +++ b/lf.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -2546,10 +2547,10 @@ void die(lifeform_t *lf) { if (vaporised) { switch (rnd(1,2)) { case 1: - fragments(corpsecell, "chunk of flesh", 2, UNLIMITED); + fragments(corpsecell, "chunk of flesh", 0, UNLIMITED); break; case 2: - fragments(corpsecell, "pool of blood", 2, UNLIMITED); + fragments(corpsecell, "pool of blood", 0, UNLIMITED); break; } } else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { @@ -2620,6 +2621,11 @@ void die(lifeform_t *lf) { copyflag(corpse->flags, lf->flags, F_KNOWSABOUT); copyflag(corpse->flags, lf->flags, F_HOMEMAP); + // some corpses will regenerate... + if (copyflag(corpse->flags, lf->flags, F_REVIVETIMER)) { + killflagsofid(corpse->flags, F_OBHPDRAIN); + } + // corpse of a player pet? if (ispetof(lf, player)) { addflag(corpse->flags, F_PETOF, player->id, NA, NA, NULL); @@ -2634,6 +2640,14 @@ void die(lifeform_t *lf) { } } + // inherit size from lf + f = hasflag(corpse->flags, F_SIZE); + if (f) { + f->val[0] = getlfsize(lf); + } else { + addflag(corpse->flags, F_SIZE, getlfsize(lf), NA, NA, NULL); + } + // remember what killed us. f = hasflag(corpse->flags, F_CORPSEOF); if (f) { @@ -2659,7 +2673,7 @@ void die(lifeform_t *lf) { flag_t *f; f = lfhasflag(lf, F_DIESPLATTER); if (f) { - fragments(corpsecell, f->text, 1, f->val[0]); + fragments(corpsecell, f->text, f->val[1], f->val[0]); } } } // end if corpsecell @@ -2754,6 +2768,13 @@ void genareaknowledge(flagpile_t *fp, int chancemod) { if (pctchance(75 + chancemod)) { strcat(knownstuff, "e"); } + // rare monsters/objects? (highish chance) + if (pctchance(60 + chancemod)) { + strcat(knownstuff, "o"); + } + if (pctchance(60 + chancemod)) { + strcat(knownstuff, "m"); + } // shops? (med chance) if (pctchance(50 + chancemod)) { strcat(knownstuff, "s"); @@ -4664,34 +4685,37 @@ void gainxp(lifeform_t *lf, long amt) { lf->xp += amt; if (isplayer(lf)) statdirty = B_TRUE; assert(lf->xp >= 0); - } - // skill xp - if (isplayer(lf)) { - int amtneeded; + // skill xp + if (isplayer(lf)) { + long amtneeded; - amtneeded = getspforpoint(lf); + amtneeded = getspforpoint(lf); + assert(amtneeded > 0); - lf->skillxp += amt; + lf->skillxp += amt; - assert(lf->skillxp >= 0); - while (lf->skillxp >= amtneeded) { - newskillpoints++; - lf->skillxp -= amtneeded; - if (isplayer(lf)) statdirty = B_TRUE; + assert(lf->skillxp >= 0); + while (lf->skillxp >= amtneeded) { + newskillpoints++; + lf->skillxp -= amtneeded; + if (isplayer(lf)) statdirty = B_TRUE; + } + // debug! + if (newskillpoints >= 3) { + raise(SIGINT); + } } - } - if (doxp) { // ready for next level? can only go up ONE level. if (lf->xp >= getxpforlev(lf->level + 1)) { gainlevel(lf, B_FALSE); // this will increment 'newlevel' } - } - if (newskillpoints) { - lf->skillpoints += newskillpoints; - msg("^GYou feel ready to learn a new skill!"); - lf->totskillpoints += newskillpoints; + if (newskillpoints) { + lf->skillpoints += newskillpoints; + msg("^GYou feel ready to learn a new skill!"); + lf->totskillpoints += newskillpoints; + } } } @@ -6610,6 +6634,7 @@ glyph_t *getlfglyph(lifeform_t *lf) { tempglyph.colour = lf->race->glyph.colour; } else if ((f = lfhasflag(lf, F_GLYPH)) != NULL) { tempglyph.ch = f->val[1]; + tempglyph.colour = f->val[0]; } else { tempglyph = lf->race->glyph; } @@ -7030,6 +7055,7 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis, int showall) { char lname[BUFLEN]; job_t *j; flag_t *f; + enum LFSIZE size,racesize; // 'the' or 'your' ? @@ -7051,6 +7077,24 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis, int showall) { // construct description string strcpy(descstring, ""); + + // has their size changed? + f = hasflag(lf->race->flags, F_SIZE); + if (f) { + racesize = f->val[0]; + } else { + racesize = SZ_HUMAN; // default + } + size = getlfsize(lf); + if (size != racesize) { + if (size == SZ_HUMAN) { + strcat(descstring, "human-sized "); + } else { + strcat(descstring, getsizetext(size)); + strcat(descstring, " "); + } + } + if (lfhasflag(lf, F_FROZEN)) { strcat(descstring, "frozen "); } @@ -10557,6 +10601,8 @@ void killlf(lifeform_t *lf) { } int isdeaf(lifeform_t *lf) { + if (lfhasflag(lf, F_TREMORSENSE)) return B_FALSE; + if (lfhasflag(lf, F_DEAF)) return B_TRUE; if (isresting(lf) && lfhasflag(lf, F_RESTINGINMOTEL)) return B_TRUE; if (lfhasflagval(lf, F_INJURY, IJ_EARSRINGING, NA, NA, NULL)) return B_TRUE; @@ -13257,6 +13303,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, // you can see the cell which made the noise if (seetext) { msg("%s", seetext); + rv = B_TRUE; } } else if (text && !isdeaf(l) && ((nclass != NC_MOVEMENT) || !lfhasflag(l, F_DONELISTEN))) { // this means you can only hear one 'walk' sound per turn @@ -13328,7 +13375,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, rv = B_TRUE; } // can only hear one 'walk' sound per turn. - if (isplayer(l) && (nclass == NC_MOVEMENT)) { + if (nclass == NC_MOVEMENT) { addflag(l->flags, F_DONELISTEN, B_TRUE, NA, NA, NULL); practice(l, SK_LISTEN, 1); } @@ -13415,6 +13462,12 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, } else { // can't hear the sound. } } // end for each lf on map + + if (rv == B_TRUE) { + if (getoption(OPT_STOPRUNONNOISE)) { + stoprunning(player); + } + } return rv; } @@ -16009,7 +16062,6 @@ void startlfturn(lifeform_t *lf) { } // sixth sense spell warnings - f = hasactivespell(lf, OT_S_SIXTHSENSE); if (f) { cell_t *retcell[MAXCANDIDATES]; @@ -16559,7 +16611,7 @@ void startlfturn(lifeform_t *lf) { // effects for/on your own flags getflags(lf->flags, retflag, &nretflags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_CLIMBING, F_FEIGNFOOLEDBY,F_FLEEFROM, - F_GRABBEDBY, F_GRABBING, F_GUNTARGET, F_BOOSTSPELL, F_FEIGNINGDEATH, F_INJURY, + F_GRABBEDBY, F_GRABBING, F_GUNTARGET, F_BOOSTSPELL, F_FEIGNINGDEATH, F_HPDRAIN, F_INJURY, F_NOFLEEFROM, F_PETOF, F_SPOTTED, F_STABBEDBY, F_TARGETCELL, F_TARGETLF, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -16696,6 +16748,14 @@ void startlfturn(lifeform_t *lf) { } } } // end if f_target or f_targetcell + + // hp drain + if (f->id == F_HPDRAIN) { + losehp(lf, f->val[0], DT_DIRECT, NULL, f->text); + if (isdead(lf)) { + break; + } + } } // end loop through lf flags } @@ -17004,7 +17064,6 @@ lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, char *ra int takeoff(lifeform_t *lf, object_t *o) { - flag_t *f; char obname[BUFLEN]; char buf[BUFLEN]; @@ -17066,19 +17125,7 @@ int takeoff(lifeform_t *lf, object_t *o) { } - // lose flags - loseobflags(lf, o, F_EQUIPCONFER); - - f = hasflag(o->flags, F_CREATEDBYSPELL); - if (f) stopspell(lf, f->val[0]); - - if (obproduceslight(o)) { - calclight((getoblocation(o))->map); - setlosdirty(lf); - //precalclos(lf); - drawscreen(); - } - + unequipeffects(lf, o); return B_FALSE; } @@ -17432,6 +17479,29 @@ void turntoface(lifeform_t *lf, cell_t *dstcell) { setfacing(lf, getdirtowards(lf->cell, dstcell, NULL, B_FALSE, DT_ORTH) ); } +void unequipeffects(lifeform_t *lf, object_t *o) { + flag_t *f; + // lose flags + loseobflags(lf, o, F_EQUIPCONFER); + + if (obproduceslight(o)) { + calclight((getoblocation(o))->map); + setlosdirty(lf); + //precalclos(lf); + drawscreen(); + } + + if (o->type->id == OT_ENERGYBLADE) { + stopspell(lf, OT_S_SUMMONWEAPON); + // object might be dead now, so stop. + return; + } + + f = hasflag(o->flags, F_CREATEDBYSPELL); + if (f) { + stopspell(lf, f->val[0]); + } +} void unsummon(lifeform_t *lf, int vanishobs) { lifeform_t *creator = NULL; @@ -17530,19 +17600,7 @@ int unweild(lifeform_t *lf, object_t *o) { } } - // lose flags - loseobflags(lf, o, F_EQUIPCONFER); - - if (obproduceslight(o)) { - calclight((getoblocation(o))->map); - setlosdirty(lf); - //precalclos(lf); - drawscreen(); - } - - if (o->type->id == OT_ENERGYBLADE) { - stopspell(lf, OT_S_SUMMONWEAPON); - } + unequipeffects(lf, o); return B_FALSE; } @@ -18109,6 +18167,72 @@ int validateraces(void) { return goterror; } +// returns TRUE on error +int resizelf(lifeform_t *lf, enum LFSIZE newsize) { + flag_t *f; + enum LFSIZE origsize; + int changedir; + char lfname[BUFLEN]; + object_t *o,*nexto; + getlfname(lf, lfname); + f = hasflag(lf->flags, F_SIZE); + if (f) { + origsize = f->val[0]; + } else { + origsize = SZ_HUMAN; // default + } + + if (origsize == newsize) { + return B_TRUE; + } else if (newsize > origsize) { + changedir = 1; + } else { + changedir = -1; + } + + if (f) { + f->val[0] = newsize; + } else { + addflag(lf->flags, F_SIZE, newsize, NA, NA, NULL); + } + + // announce + if (isplayer(lf)) { + msg("Your body %s unnaturally!", (changedir == 1) ? "grows" : "shrinks"); + } else if (cansee(player, lf)) { + msg("%s %s unnaturally!", lfname, (changedir == 1) ? "grows" : "shrinks"); + } + + // effects on objects, armour etc + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + + // object is now the wrong size? + if (isequipped(o) && isarmour(o)) { + if (!armourfits(lf, o, NULL)) { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + if (isplayer(lf)) { + msg("Your %s no longer fits!", noprefix(obname)); + } else if (cansee(player, lf)) { + msg("%s%s %s no longer fits!", lfname, getpossessive(lfname), noprefix(obname)); + } + killflagsofid(o->flags, F_EQUIPPED); + unequipeffects(lf, o); + if (isplayer(lf)) statdirty = B_TRUE; // might have impacted AR + } + } + + // object is now too big to hold? + if (canpickup(lf, o, o->amt) == E_TOOBIG) { + drop(o, o->amt); + continue; + } + } + + return B_FALSE; +} + int rest(lifeform_t *lf, int onpurpose) { flag_t *f; flag_t *ff; diff --git a/lf.h b/lf.h index 06a3856..af398ee 100644 --- a/lf.h +++ b/lf.h @@ -368,6 +368,7 @@ int readytotrain(lifeform_t *lf); int recruit(lifeform_t *lf); void refreshlevelabilities(lifeform_t *lf); void relinklf(lifeform_t *src, map_t *dst); +int resizelf(lifeform_t *lf, enum LFSIZE newsize); int rest(lifeform_t *lf, int onpurpose); void setskillused(lifeform_t *lf, enum SKILL skid); int startclimbing(lifeform_t *lf); @@ -416,6 +417,7 @@ void timeeffectslf(lifeform_t *lf); int tryclimb(lifeform_t *lf, cell_t *where, char *towhat); int touch(lifeform_t *lf, object_t *o); void turntoface(lifeform_t *lf, cell_t *dstcell); +void unequipeffects(lifeform_t *lf, object_t *o); void unpoison(lifeform_t *lf); void unsummon(lifeform_t *lf, int vanishobs); int unweild(lifeform_t *lf, object_t *o); diff --git a/map.c b/map.c index d80f8fd..fbdedee 100644 --- a/map.c +++ b/map.c @@ -805,6 +805,7 @@ void adjustcellglyphforlight(cell_t *c, glyph_t *g) { int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int doorpct, int dooropenchance) { int i,d; cell_t *poss[MAXCANDIDATES], *cell[MAXCANDIDATES]; // TODO: should this be maxroomw * maxroomh ? + int possdir[MAXCANDIDATES]; int ncells = 0, npossible = 0; int doorsadded = 0; int db = B_TRUE; @@ -835,11 +836,13 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in makedoor(cell[i], dooropenchance); } else { setcelltype(cell[i], cell[i]->habitat->emptycelltype); + cell[i]->isroomwall = compassdir(d); addflag(map->flags, F_ROOMEXIT, roomid, cell[i]->x, cell[i]->y, "from autodoors, only way out"); } } else { // otherwise mark this as a _potential_ door location. poss[npossible] = cell[i]; + possdir[npossible] = d; npossible++; } } @@ -857,6 +860,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in setcelltype(poss[sel], poss[sel]->habitat->emptycelltype); addflag(map->flags, F_ROOMEXIT, roomid, poss[sel]->x, poss[sel]->y, "from autodoors, potential location"); } + poss[sel]->isroomwall = compassdir(possdir[sel]); doorsadded++; } @@ -888,7 +892,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in } sel = rnd(0,nposs-1); used[poss[sel]] = B_TRUE; - dodoor[ndodoors++] = poss[sel]; + dodoor[ndodoors] = poss[sel]; } // actually make the doors @@ -906,6 +910,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in addflag(map->flags, F_ROOMEXIT, roomid, cell[sel]->x, cell[sel]->y, "from autodoors, forced at end"); doorsadded++; } + cell[sel]->isroomwall = d; } } } @@ -1041,6 +1046,63 @@ int cellhaslos(cell_t *c1, cell_t *dest) { return B_TRUE; } +// is the given cell a wall of a vault with maintain_edge, and not marked as an exit? +int cellisfixedvaultwall(cell_t *c) { + if ( getcellvault(c) && + c->type->solid && + hasflag(c->room->vault->flags, F_MAINTAINEDGE) && + !hasflagval(c->map->flags, F_ROOMEXIT, c->room->id, c->x, c->y, NULL) ) { + return B_TRUE; + } + return B_FALSE; +} + +// returns B_TRUE, B_FALSE or B_MAYBE +int cellokforreachability(cell_t *startcell, cell_t *c, int srcroomid, int dir, int wantfilled, int *insameroom) { + int db = B_TRUE; + if ((srcroomid >= 0) && (getroomid(c) == srcroomid) && c->type->solid && startcell->type->solid) { + // hits a wall of the same room, + // and start cell NOT one inside the room. + + // invalid + if (insameroom) *insameroom = B_TRUE; + if (db) dblog(" going %s hits wall of same room. invalid.", getdirname(dir)); + return B_FALSE; + } else if (isroom(c) && (getroomid(c) != srcroomid) && (c->isroomwall != diropposite(dir))) { + // cell is in a different room, but not the correct edge + // invalid + if (insameroom) *insameroom = B_FALSE; + if (db) dblog(" going %s hits wrong wall of different room. invalid.", getdirname(dir)); + return B_FALSE; + } else if (cellisfixedvaultwall(c)) { + // cell is a wall of a maintain_edge vault, and not an exit cell + // invalid + if (insameroom) *insameroom = B_FALSE; + if (db) dblog(" going %s hits non-exit wall maintain_edge vault. invalid.", getdirname(dir)); + return B_FALSE; + } else if (isroom(c) && (getroomid(c) != srcroomid) && c->type->solid && countadjdoors(c) ) { + // cell is the wall of a different room, and adjacent to a door. + // invalid + if (insameroom) *insameroom = B_FALSE; + if (db) dblog(" going %s hits wall adjacent to door. invalid.", getdirname(dir)); + return B_FALSE; + } else if (cellwalkable(NULL, c, NULL)) { + if (getroomid(c) == srcroomid) { + // invalid + if (insameroom) *insameroom = B_TRUE; + if (db) dblog(" going %s hits empty cell of same room. invalid.", getdirname(dir)); + return B_FALSE; + } else { + if (!wantfilled || c->filled) { + // walkable and not in this vault. finished. + // valid. + return B_TRUE; + } + } + } + return B_MAYBE; +} + void clearcell(cell_t *c) { // kill everything there - (lifeforms && objects) if (c->lf && !isplayer(c->lf)) { @@ -1820,6 +1882,20 @@ int countadjrooms(cell_t *cell) { return count; } +int countadjdoors(cell_t *cell) { + int d; + int doors = 0; + + for (d = DC_N; d <= DC_NW; d++) { + cell_t *newcell; + newcell = getcellindir(cell, d); + if (newcell || hasobwithflag(newcell->obpile, F_DOOR)) { + doors++; + } + } + return doors; +} + int countadjwalls(cell_t *cell) { int d; int walls = 0; @@ -3742,64 +3818,57 @@ void killmap(map_t *m) { // 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 db = B_TRUE; + int d, roomid,startd,endd; int poss2[MAXCANDIDATES],nposs2; int dist[MAXDIR_ORTH],hitsedge[MAXDIR_ORTH], sameroom[MAXDIR_ORTH]; cell_t *directendcell[MAXDIR_ORTH]; int mindist = 999,maxdist = -1; cell_t *c; + int forcedir = D_NONE; if (ncellsadded) *ncellsadded = 0; - if (db) dblog(" calling linkexit() for cell at %d,%d", startcell->x, startcell->y); - roomid = getroomid(startcell); + if (db) dblog(" calling linkexit() for cell at %d,%d in roomid %d", startcell->x, startcell->y, roomid); + for (d = D_N; d <= D_W; d++) { hitsedge[d] = B_TRUE; directendcell[d] = NULL; } - // link it. starting from the door, count the number of cells in + // link it. + // if our cell is marked specifically as a room exit, our first direction MUST be out the + // door. + if (startcell->isroomwall != D_NONE) { + forcedir = startcell->isroomwall; + startd = forcedir; + endd = forcedir; + } else { + startd = D_N; endd = D_W; + } + + // otherwise, 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++) { + for (d = startd; d <= endd; d++) { dist[d] = 0; hitsedge[d] = B_FALSE; sameroom[d] = B_FALSE; c = getcellindir(startcell, d); while (c) { + int rv; dist[d]++; - if ((roomid >= 0) && getroomid(c) == roomid) { // same room - //if (wantfilled && c->type->solid) { - if (c->type->solid) { - // This is an exception: - // if startcell is 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; - sameroom[d] = B_TRUE; - if (db) dblog(" going %s hits same room. invalid.", getdirname(d)); - break; - } - } else if (isroom(c) && (getroomid(c) != roomid) && (c->isroomwall != diropposite(d))) { - // cell is in a different room, but not the correct edge - // mark dir as invalid + + rv = cellokforreachability(startcell, c, roomid, d, wantfilled, &(sameroom[d])); + if (rv == B_FALSE) { dist[d] = 999; - sameroom[d] = B_FALSE; - if (db) dblog(" going %s hits wrong wall of different room. invalid.", getdirname(d)); break; - } else if (cellwalkable(NULL, c, NULL)) { - if (!wantfilled || c->filled) { - // walkable and not in this vault. finished. - directendcell[d] = c; - if (db) dblog(" can make %s path (hits empty cell at dist %d)", getdirname(d), dist[d]); - break; - } - } else { + } else if (rv == B_TRUE) { + directendcell[d] = c; + if (db) dblog(" can make %s path (hits empty cell at dist %d)", getdirname(d), dist[d]); + } else { // ie. rv == B_MAYBE int perpdir[2],n; cell_t *pcell = NULL; perpdir[0] = d - 1; if (perpdir[0] < D_N) perpdir[0] = D_W; @@ -3813,6 +3882,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { proomid = getroomid(pcell); if (((roomid == -1 ) || (proomid != roomid)) && cellwalkable(NULL, pcell, NULL)) { if ((proomid >= 0) && (pcell->isroomwall != diropposite(perpdir[n]))) { + } else if (cellisfixedvaultwall(pcell)) { } else { if (!wantfilled || c->filled) { // finished. @@ -3855,23 +3925,29 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { int nstartposs = 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 that doesn't go through same room - for (d = D_N; d <= D_W; d++) { - if (!sameroom[d] && (dist[d] > maxdist2)) { - maxdist2 = dist[d]; + + if (forcedir != D_NONE) { + startdir = forcedir; + } else { + // starting at the LONGEST distance, traverse up each dir, + // branching off looking for rooms. + + // find longest distance that doesn't go through same room + for (d = D_N; d <= D_W; d++) { + if (!sameroom[d] && (dist[d] > maxdist2)) { + maxdist2 = dist[d]; + } } - } - // pick one randomly - for (d = D_N; d <= D_W; d++) { - if (dist[d] == maxdist2) { - startposs[nstartposs++] = d; + // pick one randomly + for (d = D_N; d <= D_W; d++) { + if (dist[d] == maxdist2) { + startposs[nstartposs++] = d; + } + } + if (nstartposs) { + startdir = startposs[rnd(0,nstartposs-1)]; } - } - if (nstartposs) { - startdir = startposs[rnd(0,nstartposs-1)]; } if (wantfilled) { @@ -3902,6 +3978,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { while (c2) { int gotsolution = B_FALSE; + int rv; turndist++; perpcell[nperpcells] = c2; // this will be used if we need to make 2 turns @@ -3909,25 +3986,12 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { perpturndir1[nperpcells] = perpdir[n]; nperpcells++; - 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 (isroom(c2) && (c2->isroomwall != diropposite(perpdir[n]))) { - // wrong wall of room - // mark dir as invalid - dist[d] = 999; - sameroom[d] = B_FALSE; - if (db) dblog(" going %s hits wrong wall of different room. invalid.", getdirname(d)); + rv = cellokforreachability(startcell, c2, roomid, perpdir[n], wantfilled, NULL); + + if (rv == B_FALSE) { break; + } else if (rv == B_TRUE) { + gotsolution = B_TRUE; } else if (turndist > 1) { // check l/r too int perpdir2[2],nn; @@ -3942,6 +4006,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { if ( ((roomid == -1) || (proomid != roomid)) && cellwalkable(NULL, pcell, NULL)) { if ((proomid >= 0) && (pcell->isroomwall != diropposite(perpdir2[n]))) { + } else if (cellisfixedvaultwall(pcell)) { } else { if (!wantfilled || pcell->filled) { // finished. @@ -4013,27 +4078,16 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { c2 = getcellindir(perpcell[i], dir3[n]); while (c2) { int gotsolution = B_FALSE; + int rv; turndist++; if (db) dblog_nocr("(%d,%d)",c2->x,c2->y); - 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 (isroom(c2) && (c2->isroomwall != diropposite(dir3[n]))) { - // wrong wall of room - // mark dir as invalid - dist[d] = 999; - sameroom[d] = B_FALSE; - if (db) dblog(" going %s hits wrong wall of different room. invalid.", getdirname(d)); + + rv = cellokforreachability(startcell, c2, roomid, perpdir[n], wantfilled, NULL); + + if (rv == B_FALSE) { break; + } else if (rv == B_TRUE) { + gotsolution = B_TRUE; } else if (turndist > 1) { // check l/r too int perpdir2[2],nn; @@ -4049,6 +4103,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { cellwalkable(NULL, pcell, NULL)) { if ((proomid >= 0) && (pcell->isroomwall != diropposite(perpdir2[nn]))) { // different room and hits wrong wall. + } else if (cellisfixedvaultwall(pcell)) { } else { if (!wantfilled || pcell->filled) { // finished. @@ -4167,7 +4222,7 @@ int linkexits(map_t *m, int roomid) { int x,y,i; cell_t *poss[MAXCANDIDATES],*c; int nposs = 0; - int db = B_FALSE; + int db = B_TRUE; int nadded = 0; int minx = -1, miny = -1, maxx = -1, maxy = -1; int roomidx = -1; @@ -4225,15 +4280,14 @@ int linkexits(map_t *m, int roomid) { for (i = 0; i < nposs; i++) { int ncorridors = 0,d; - if (db) dblog("exit at %d,%d:",poss[i]->x, poss[i]->y); + if (db) dblog("exit #%d at %d,%d: (%s)",i, poss[i]->x, poss[i]->y, + (poss[i]->isroomwall != D_NONE) ? getdirname(poss[i]->isroomwall) : "nodir"); // if exit is solid and COMPLETELY surrounded by solid, ignore it. if (poss[i]->type->solid && (countcellexits(poss[i], DT_ORTH) == 0)){ if (db) dblog("cell is solid and surrounded by solids. ignoring."); continue; } - 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)) { @@ -5595,6 +5649,20 @@ cell_t *getrandomcelloftype(map_t *map, enum CELLTYPE id) { return cell; } +int compassdir(int orthdir) { + switch (orthdir) { + case D_N: + return DC_N; + case D_S: + return DC_S; + case D_E: + return DC_E; + case D_W: + return DC_W; + } + return D_NONE; +} + int getrandomdir(int dirtype) { if (dirtype == DT_ORTH) { diff --git a/map.h b/map.h index 60351a5..3aca3d1 100644 --- a/map.h +++ b/map.h @@ -14,6 +14,8 @@ regiontype_t *addregiontype(enum REGIONTYPE id, char *name, int pluralname, enum void adjustcellglyphforlight(cell_t *c, glyph_t *col); int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int doorpct, int dooropenchance); int cellhaslos(cell_t *c1, cell_t *dest); +int cellisfixedvaultwall(cell_t *c); +int cellokforreachability(cell_t *startcell, cell_t *c, int srcroomid, int dir, int wantfilled, int *insameroom); void clearcell(cell_t *c); void clearcell_exceptflags(cell_t *c, ...); int doelementspread(cell_t *c); @@ -39,9 +41,11 @@ void getroomedge(map_t *m, int roomid, int minx, int miny, int maxx, int maxy, i object_t *gettopobject(cell_t *where, int forglyph); void calclight(map_t *map); int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int *by, int force); +int compassdir(int orthdir); int countadjcellsoftype(cell_t *cell, int id); int countadjrooms(cell_t *cell); int countadjcellswithflag(cell_t *cell, enum FLAG fid, int dirtype); +int countadjdoors(cell_t *cell); int countadjwalls(cell_t *cell); int countcellexits(cell_t *cell, int dirtype); int countcellexitsfor(lifeform_t *lf); diff --git a/nexus.c b/nexus.c index b9c010b..5dcc537 100644 --- a/nexus.c +++ b/nexus.c @@ -215,7 +215,7 @@ int main(int argc, char **argv) { if (hasflag(r->flags, F_PLAYABLE)) { char *longdesc; longdesc = malloc(HUGEBUFLEN * sizeof(char)); - makedesc_race(r->id, longdesc, B_TRUE ); + makedesc_race(r->id, longdesc, B_TRUE, B_TRUE ); addchoice(&prompt, ch++, r->name, NULL, r, longdesc); free(longdesc); } @@ -355,6 +355,7 @@ int main(int argc, char **argv) { } if (sb1) { addflag(player->flags, F_CANCAST, sb1->contents->first->type->id, NA, NA, NULL); + addflag(sb1->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); } initprompt(&prompt, "Select your secondary spell school:"); @@ -388,6 +389,7 @@ int main(int argc, char **argv) { } if (sb2) { addflag(player->flags, F_CANCAST, sb2->contents->first->type->id, NA, NA, NULL); + addflag(sb2->flags, F_NOPOINTS, B_TRUE, NA, NA, NULL); } identify(sb1); identify(sb2); diff --git a/objects.c b/objects.c index 1a3c24b..1cd204b 100644 --- a/objects.c +++ b/objects.c @@ -3378,8 +3378,15 @@ void fragments(cell_t *centre, char *what, int speed, int howfar) { done = B_FALSE; while (!done) { c = getcellindir(c, dir); - if (c && cellwalkable(NULL, c, NULL)) { - maxdist++; + if (c) { + if (cellwalkable(NULL, c, NULL)) { + maxdist++; + } else { + if (c->lf && !c->type->solid) { + maxdist++; + } + done = B_TRUE; + } } else { done = B_TRUE; } @@ -3412,8 +3419,17 @@ void fragments(cell_t *centre, char *what, int speed, int howfar) { break; } } - // add object - addob(dst->obpile, what); + if (speed) { + object_t *o; + // add object then fire it + o = addob(centre->obpile, what); + if (o) { + fireat(NULL, o, o->amt, dst, speed, NULL); + } + } else { + // add object + addob(dst->obpile, what); + } } } @@ -4576,6 +4592,20 @@ cell_t *getobpilelocation(obpile_t *op) { return NULL; } +// note: should have an entry here for everything which willshatter() +char *getshardobname(enum MATERIAL mid, char *buf) { + switch (mid) { + case MT_GLASS: + strcpy(buf, "piece of broken glass"); + break; + case MT_ICE: + strcpy(buf, "chunk of ice"); + break; + default: return NULL; + } + return buf; +} + char *getshopobname(object_t *o, char *buf, int count) { if (gettechlevel(o->type->id) > getskill(player, SK_TECHUSAGE)) { // unidentified tech - hide the name @@ -9765,6 +9795,13 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE case OT_POT_GASEOUSFORM: dospelleffects(lf, OT_S_GASEOUSFORM, (potblessed) ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE); break; + case OT_POT_GROWTH: + if (iscursed(o)) { + dospelleffects(lf, OT_S_SIZEDOWN, 1, lf, NULL, lf->cell, B_UNCURSED, seen, B_TRUE); + } else { + dospelleffects(lf, OT_S_SIZEUP, 1, lf, NULL, lf->cell, B_UNCURSED, seen, B_TRUE); + } + break; case OT_POT_HEALING: dospelleffects(lf, OT_S_HEALING,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE); break; @@ -10933,6 +10970,7 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { case OT_POT_ELEMENTIMMUNE: case OT_POT_ETHEREALNESS: case OT_POT_GASEOUSFORM: + case OT_POT_GROWTH: case OT_POT_LEVITATION: case OT_POT_POISON: case OT_POT_POLYMORPH: @@ -12390,7 +12428,8 @@ void timeeffectsob(object_t *o) { // check each flag for this object... - getflags(o->flags, retflag, &nretflags, F_ACTIVATED, F_EDIBLE, F_MATCONVERT, F_OBHPDRAIN, F_ONFIRE, F_RECHARGE, F_WALKDAM, F_WET, F_NONE); + getflags(o->flags, retflag, &nretflags, F_ACTIVATED, F_EDIBLE, F_MATCONVERT, F_OBHPDRAIN, F_ONFIRE, + F_RECHARGE, F_REVIVETIMER, F_WALKDAM, F_WET, F_NONE); for (i = 0; i < nretflags; i++) { object_t *oo,*nextoo; f = retflag[i]; @@ -12531,6 +12570,44 @@ void timeeffectsob(object_t *o) { } } } + // regenerates into a lf? + if (f->id == F_REVIVETIMER) { + cell_t *obloc = NULL; + obloc = getoblocation(o); + f->val[0]++; + limit(&f->val[0], 0, f->val[1]); + if (f->val[0] >= f->val[1]) { + lifeform_t *lf; + cell_t *lfloc = NULL; + if (obloc) { + if (obloc->lf) { + lfloc = getrandomadjcell(obloc, WE_WALKABLE, B_NOEXPAND); + } else { + lfloc = obloc; + } + } + + if (lfloc) { + // revive! + lf = addmonster(lfloc, f->val[2], NULL, B_FALSE, 1, B_FALSE, NULL); + // corpse vanishes + removeob(o, o->amt); + // announce + if (haslos(player, lfloc) || haslos(player, obloc)) { + msg("%s comes to life!", obname); + interrupt(player); + } + return; + } + } else if ((f->val[1] - f->val[0]) <= 10) { + if (haslos(player, obloc)) { + // pass a perception chekc to see it moving... + if (skillcheck(player, SC_SEARCH, 20, 0)) { + msg("%s twitches.", obname); + } + } + } + } // damaging objects here will damage other objects if (f->id == F_WALKDAM) { diff --git a/objects.h b/objects.h index 5a2bc99..310f383 100644 --- a/objects.h +++ b/objects.h @@ -122,6 +122,7 @@ char *getobextrainfo(object_t *o, char *buf); cell_t *getoblocation(object_t *o); cell_t *getobpilelocation(obpile_t *op); char *getobname(object_t *o, char *buf, int count); +char *getshardobname(enum MATERIAL mid, char *buf); char *getshopobname(object_t *o, char *buf, int count); char *getobnametrue(object_t *o, char *buf, int count); char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wantcondition, int adjustforblind, int wantblesscurse, int showall); diff --git a/spell.c b/spell.c index 4bb304f..4b1635a 100644 --- a/spell.c +++ b/spell.c @@ -8772,6 +8772,30 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster)) { msg("You will now be warned of creatures behind you."); } + } else if ((spellid == OT_S_SIZEUP) || (spellid == OT_S_SIZEDOWN)) { + enum LFSIZE origsize,newsize; + origsize = getlfsize(caster); + if (spellid == OT_S_SIZEUP) { + if (origsize >= SZ_ENORMOUS) { + fizzle(caster); + return B_TRUE; + } + newsize = origsize + 1; + } else { // ie. sizedown + if (origsize <= SZ_MINI) { + fizzle(caster); + return B_TRUE; + } + newsize = origsize - 1; + } + if (resizelf(caster, newsize)) { + // failed + fizzle(caster); + return B_TRUE; + } + if (isplayer(caster) || cansee(player, caster)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } } else if (spellid == OT_S_SLEEP) { int howlong; target = targcell->lf; diff --git a/vault.c b/vault.c index 727d0b4..22da33d 100644 --- a/vault.c +++ b/vault.c @@ -1330,6 +1330,9 @@ int handleline(vault_t *v, char *line) { } else { dblog("invalid goesin() definition: '%s'", line); } + } else if (streq(line, "maintainedge")) { + addflag(v->flags, F_MAINTAINEDGE, B_TRUE, NA, NA, NULL); + ok = B_TRUE; } else if (strstarts(line, "margin")) { char *p; p = line + 6; diff --git a/vaults/bazaar.vlt b/vaults/bazaar.vlt index fe2bc52..ca30f41 100644 --- a/vaults/bazaar.vlt +++ b/vaults/bazaar.vlt @@ -21,5 +21,6 @@ X:exit goesin:dungeon mayrotate rarity:vrare +maintainedge @end diff --git a/vaults/cave_bear.vlt b/vaults/cave_bear.vlt index b80efbb..fff96a3 100644 --- a/vaults/cave_bear.vlt +++ b/vaults/cave_bear.vlt @@ -22,5 +22,6 @@ scatter(3,1,-4,-2) mon:bear cub:1-3:50 goesin:dungeon mayrotate rarity:uncommon +maintainedge @end diff --git a/vaults/caveboss1.vlt b/vaults/caveboss1.vlt index d34bb05..0ebfafd 100644 --- a/vaults/caveboss1.vlt +++ b/vaults/caveboss1.vlt @@ -35,5 +35,6 @@ scatter(1,1,-2,-2) ob:wooden footstool:0-3 scatter(1,1,-2,-2) ob:random food:0-2 mayflipx tag:caveboss +maintainedge @end diff --git a/vaults/cell.vlt b/vaults/cell.vlt index bd0f879..95a14b3 100644 --- a/vaults/cell.vlt +++ b/vaults/cell.vlt @@ -16,5 +16,6 @@ m:mon:sleeping random goesin:dungeon mayrotate rarity:uncommon +maintainedge @end diff --git a/vaults/circle.vlt b/vaults/circle.vlt index 7bd27f7..9a25c73 100644 --- a/vaults/circle.vlt +++ b/vaults/circle.vlt @@ -19,8 +19,8 @@ @flags goesin:dungeon -autodoors:50 autopop rarity:frequent +maintainedge @end diff --git a/vaults/crossroads.vlt b/vaults/crossroads.vlt index a9017b6..a4b2369 100644 --- a/vaults/crossroads.vlt +++ b/vaults/crossroads.vlt @@ -17,5 +17,6 @@ x:exit @flags goesin:dungeon rarity:frequent +maintainedge @end diff --git a/vaults/glasscorner.vlt b/vaults/glasscorner.vlt index e162aae..988984e 100644 --- a/vaults/glasscorner.vlt +++ b/vaults/glasscorner.vlt @@ -17,4 +17,5 @@ x:exit goesin:dungeon rarity:frequent mayrotate +maintainedge @end diff --git a/vaults/godshrine1.vlt b/vaults/godshrine1.vlt index b2d6323..842ded9 100644 --- a/vaults/godshrine1.vlt +++ b/vaults/godshrine1.vlt @@ -26,5 +26,6 @@ shrine norandom mayrotate goesin:dungeon +maintainedge @end diff --git a/vaults/jimbo.vlt b/vaults/jimbo.vlt index e890608..aeaf3d2 100644 --- a/vaults/jimbo.vlt +++ b/vaults/jimbo.vlt @@ -33,5 +33,6 @@ atoneof(10,1)(10,3)(10,5) ob:portal to lv1 scatter(1,1,-2,-2) ob:wooden footstool:0-3 scatter(1,1,-2,-2) ob:random food:0-2 mayrotate +maintainedge @end diff --git a/vaults/labyrinth.vlt b/vaults/labyrinth.vlt index 0ddf98c..fb8705f 100644 --- a/vaults/labyrinth.vlt +++ b/vaults/labyrinth.vlt @@ -42,5 +42,6 @@ scatter(0,0,-1,-1) ob:common weapon:4-5 mayrotate ! mayscale rarity:rare +maintainedge @end diff --git a/vaults/supplycloset.vlt b/vaults/supplycloset.vlt index 312cac1..9ec90d2 100644 --- a/vaults/supplycloset.vlt +++ b/vaults/supplycloset.vlt @@ -15,5 +15,6 @@ o:ob:1-5 random tools @flags goesin:dungeon rarity:uncommon +maintainedge @end diff --git a/vaults/supplycloset_tech.vlt b/vaults/supplycloset_tech.vlt index 82953e5..378ee3d 100644 --- a/vaults/supplycloset_tech.vlt +++ b/vaults/supplycloset_tech.vlt @@ -15,5 +15,6 @@ o:ob:1-5 random technology @flags goesin:dungeon rarity:uncommon +maintainedge @end diff --git a/vaults/vault.vlt b/vaults/vault.vlt index 9198f5c..09a17a8 100644 --- a/vaults/vault.vlt +++ b/vaults/vault.vlt @@ -20,5 +20,6 @@ mayrotate rarity:vrare ! don't link to rest of map. ie this can be in the middle of nowhere. nolink +maintainedge @end