diff --git a/attack.c b/attack.c index fac34e5..4fc03b6 100644 --- a/attack.c +++ b/attack.c @@ -28,7 +28,6 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty object_t *o; o = getequippedob(lf->pack, BP_BODY); if (o && (o->type->id == OT_FLAKJACKET)) { - // stop ALL missile damage armour = o; } } @@ -1001,14 +1000,14 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { // returns the amount of damage the armour blocked... int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) { int reduceamt = 0; - float reducepct; int ar; object_t *o; ar = getarmourrating(lf); - reducepct = getdamreducepct(ar); - reduceamt = (int) ceil((reducepct / 100.0) * (float)dam); + //reducepct = getdamreducepct(ar); + //reduceamt = (int) ceil((reducepct / 100.0) * (float)dam); + reduceamt = ar/2; // special case if (damtype == DT_PROJECTILE) { @@ -1455,11 +1454,13 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) { return dam; } +/* float getdamreducepct(float armourrating) { float reducepct; reducepct = (armourrating * 1.5); return reducepct; } +*/ /* int getunarmeddamroll(flag_t *f) { @@ -1659,7 +1660,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) } // victim immobile or asleep? - if (isimmobile(victim)) { + if (isimmobile(victim) || lfhasflag(victim, F_EATING)) { acc += 50; } diff --git a/attack.h b/attack.h index 4d0dada..2c0bb01 100644 --- a/attack.h +++ b/attack.h @@ -15,7 +15,7 @@ int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam); char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp); void getdamrange(flag_t *f, int *min, int *max); //void getdamrangeunarmed(flag_t *f, int *min, int *max); -float getdamreducepct(float armourrating); +//float getdamreducepct(float armourrating); int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag); //int getunarmeddamroll(flag_t *f); float getstrdammod(lifeform_t *lf); diff --git a/defs.h b/defs.h index 23cda2f..afc1d1b 100644 --- a/defs.h +++ b/defs.h @@ -534,27 +534,28 @@ enum DAMTYPE { // Object Classes enum OBCLASS { - OC_TERRAIN, - OC_MONEY, - OC_WEAPON, - OC_ARMOUR, - OC_MISSILE, - OC_RING, - OC_SCROLL, - OC_POTION, - OC_WAND, - OC_FOOD, - OC_CORPSE, - OC_ROCK, - OC_TOOLS, - OC_TECH, - OC_MISC, - OC_FLORA, - OC_SPELL, OC_ABILITY, - OC_EFFECT, - OC_DFEATURE, + OC_ARMOUR, OC_BOOK, + OC_CORPSE, + OC_DFEATURE, + OC_EFFECT, + OC_FLORA, + OC_FOOD, + OC_MISC, + OC_MISSILE, + OC_MONEY, + OC_POTION, + OC_RING, + OC_ROCK, + OC_SCROLL, + OC_TECH, + OC_TERRAIN, + OC_TOOLS, + OC_TRAP, + OC_SPELL, + OC_WAND, + OC_WEAPON, OC_NULL = -999 }; @@ -782,12 +783,13 @@ enum OBTYPE { OT_WATERSHALLOW, OT_WATERDEEP, // traps - OT_TRAPROCK, OT_TRAPARROW, OT_TRAPARROWP, - OT_TRAPGAS, OT_TRAPFIRE, + OT_TRAPGAS, OT_TRAPMINE, + OT_TRAPROCK, + OT_TRAPTELEPORT, OT_TRAPTRIP, // rocks / plants OT_GOLD, @@ -874,147 +876,6 @@ enum OBTYPE { // BOOKS OT_MANUAL, OT_SPELLBOOK, - /* - OT_MAN_ARMOUR, - OT_MAN_ATHLETICS, - OT_MAN_BACKSTAB, - OT_MAN_COOKING, - OT_MAN_FIRSTAID, - OT_MAN_LISTEN, - OT_MAN_LOCKPICKING, - OT_MAN_MAGITEMUSAGE, - OT_MAN_RANGED, - OT_MAN_SHIELDS, - OT_MAN_SPELLCASTING, - OT_MAN_SPOTHIDDEN, - OT_MAN_STEALTH, - OT_MAN_TECHUSAGE, - OT_MAN_TRAPS, - OT_MAN_TWOWEAPON, - // manuals of knowledge - OT_MAN_LORE_ARCANA, - OT_MAN_LORE_DEMONS, - OT_MAN_LORE_HUMANOID, - OT_MAN_LORE_NATURE, - OT_MAN_LORE_UNDEAD, - // manuals of weaponry - OT_MAN_AXES, - OT_MAN_CLUBS, - OT_MAN_LONGBLADES, - OT_MAN_POLEARMS, - OT_MAN_SHORTBLADES, - OT_MAN_STAVES, - OT_MAN_UNARMED, - // manuals of spells - OT_MAN_SS_ALLOMANCY, - OT_MAN_SS_AIR, - OT_MAN_SS_DEATH, - OT_MAN_SS_DIVINATION, - OT_MAN_SS_NATURE, - OT_MAN_SS_FIRE, - OT_MAN_SS_COLD, - OT_MAN_SS_GRAVITY, - OT_MAN_SS_LIFE, - OT_MAN_SS_MODIFICATION, - OT_MAN_SS_MENTAL, - OT_MAN_SS_SUMMONING, - OT_MAN_SS_TRANSLOCATION, - OT_MAN_SS_WILD, - // SPELLBOOKS - // allomancy can't be learned from books - // -- death - OT_SB_ANIMATEDEAD, - OT_SB_DRAINLIFE, - OT_SB_FEAR, - OT_SB_PAIN, - OT_SB_PARALYZE, - OT_SB_POISONBOLT, - OT_SB_INFINITEDEATH, - OT_SB_WEAKEN, - OT_SB_FEEBLEMIND, - OT_SB_BLINDNESS, - OT_SB_POSSESSION, - OT_SB_STENCH, - // -- divination - OT_SB_DETECTAURA, - OT_SB_DETECTLIFE, - OT_SB_DETECTOBS, - OT_SB_LOCATEOBJECT, - OT_SB_LORE, - OT_SB_REVEALHIDDEN, - OT_SB_IDENTIFY, - OT_SB_MAPPING, - OT_SB_SEEINVIS, - // -- elemental - air - OT_SB_AIRBLAST, - OT_SB_CALLLIGHTNING, - OT_SB_CLOUDKILL, - OT_SB_GUSTOFWIND, - OT_SB_LIGHTNINGSTORM, - OT_SB_WINDSHIELD, - // -- elemental - fire - OT_SB_BLADEBURN, - OT_SB_BURNINGWAVE, - OT_SB_FIREDART, - OT_SB_FIREBALL, - OT_SB_FLAMEPILLAR, - OT_SB_FLAMEBURST, - OT_SB_SPARK, - // -- elemental - ice - OT_SB_CHILL, - OT_SB_CONECOLD, - OT_SB_COLDBURST, - OT_SB_FREEZEOB, - OT_SB_FROSTBITE, - OT_SB_ICEEDGE, - OT_SB_ICICLE, - OT_SB_WALLOFICE, - // -- elemental - earth - OT_SB_DIG, - // -- gravity - OT_SB_GRAVLOWER, - OT_SB_GRAVBOOST, - OT_SB_HASTE, - OT_SB_FLIGHT, - OT_SB_SLOW, - OT_SB_LEVITATION, - // -- life - OT_SB_HEALING, - OT_SB_HEALINGMIN, - OT_SB_HEALINGMAJ, - OT_SB_TURNUNDEAD, - // -- mental / psionic - OT_SB_MINDSCAN, - OT_SB_SLEEP, - OT_SB_TELEKINESIS, - OT_SB_PACIFY, - OT_SB_PSYARMOUR, - OT_SB_CHARM, - // -- modification - OT_SB_GASEOUSFORM, - OT_SB_GREASE, - OT_SB_KNOCK, - OT_SB_HOLDPORTAL, - OT_SB_INSCRIBE, - OT_SB_INVISIBILITY, - OT_SB_LIGHT, - OT_SB_DARKNESS, - OT_SB_MENDING, - OT_SB_PASSWALL, - OT_SB_PETRIFY, - OT_SB_POLYMORPH, - OT_SB_STICKTOSNAKE, - // -- summoning - OT_SB_CREATEMONSTER, - OT_SB_SUMMONWEAPON, - // -- translocation - OT_SB_BLINK, - OT_SB_DISPERSAL, - OT_SB_GATE, - OT_SB_TELEPORT, - OT_SB_TWIDDLE, - // -- wild can't be learned from books - */ // spells // -- allomancy OT_S_ABSORBMETAL, @@ -1051,6 +912,7 @@ enum OBTYPE { // -- elemental - air OT_S_JOLT, OT_S_AIRBLAST, + OT_S_CHAINLIGHTNING, OT_S_CLOUDKILL, OT_S_GUSTOFWIND, OT_S_MIST, @@ -1506,6 +1368,7 @@ enum FLAG { F_NONE, // dummy flag // map flags F_MAPCOORDS, // v0+v1 are x/y coords for this map area + F_ROOMEXIT, // there is an exit from room v0 at x=v1,y=v2 // object flags F_DEAD, // object will be removed F_CREATEDBY, // object was made by lf id v0, text=real lfname @@ -1525,6 +1388,7 @@ enum FLAG { // v2 = enum sense used to see this (ie. s_smell, s_sight) // (optional) text = lfid of lf who left this. // should only be used for SCENT, not footprints. + F_NOFEEL, // when blind, don't show "you can feel xxx" // for items in shops F_SHOPITEM, // causes shops to show this item as identified F_VALUE, // how much an item is worth (over its base weight+material) @@ -1946,7 +1810,8 @@ enum FLAG { // next to the attacker F_PHALANX, // gain v0 AR if v2 or more adj monsters matching f->text F_MORALE, // gain +v0 in morale checks. - F_SPOTTED, // you have spotted hiding lf id v0 + F_SPOTTED, // you have spotted hiding lf id v0. you lsoe this if they + // go out of sight. // INTRINSICS F_MAGICARMOUR,// armour is magically boosted. f->text is the description // ie 'magic armour', 'force field' @@ -2107,6 +1972,7 @@ enum FLAG { F_VAULTATLF, // v0/1=x/y, v1=pctchance, text=lfname F_VAULTATCELL, // v0/1=x/y, v1=pctchance, text=cellname F_VAULTBOX, // v0=thingtype, v1=pctchance, v2=fill?, text=x1,y1,x2,y2,thingname + F_VAULTEXIT, // v0/1=x,y for exit. F_VAULTSCATTER, // v0=thingtype, v1=pctchance // text=x1,y1,x2,y2,mincount-maxcount,thingname // if maxcount is PCT, mincount is a percentage @@ -2363,6 +2229,7 @@ enum VAULTSTATE { enum VAULTTHING { VT_NONE, + VT_EXIT, VT_OB, VT_LF, VT_CELL, diff --git a/doc/glyphs.txt b/doc/glyphs.txt index 8068048..4c3059f 100644 --- a/doc/glyphs.txt +++ b/doc/glyphs.txt @@ -38,3 +38,13 @@ Z = undead --- C hybrid human animal? + +---------- +~ = deep liquid (water / lava) +[ = tool +] = armour +} = gas +, = small puddle +{ = large puddle/pool +( = barrel +\ = furniture diff --git a/doc/vaults.txt b/doc/vaults.txt index aa8e17d..0084e25 100644 --- a/doc/vaults.txt +++ b/doc/vaults.txt @@ -17,6 +17,9 @@ General format: Legend is: c:type:what[:pct] + OR + c:exit + c = any letter type = ob, mon or cell @@ -28,6 +31,8 @@ Flags can be: 'type' can be: ob, mon, cell coords can be negative ("count back from right/bottom") + exitat(x,y) // vault exit is at position x,y + box(x,y,x2,y2) type:what[:pct] // outline box with what fill(x,y,x2,y2) type:what[:pct] // filled box with what coords can be negative ("count back from right/bottom") diff --git a/io.c b/io.c index 0d7858d..c9ffbcb 100644 --- a/io.c +++ b/io.c @@ -285,6 +285,59 @@ void animcells(cell_t *src, cell_t **dst, int ndst, int gradual, char ch, char c needredraw = B_TRUE; } +void animline(cell_t *src, cell_t *dst, int gradual, char ch, char ch2, int colour) { + glyph_t gl; + int i; + cell_t *retcell[MAXRETCELLS]; + int ndst; + + calcbresnham(src->map, src->x, src->y, dst->x, dst->y, retcell, &ndst); + + gl.ch = ch; + gl.colour = colour; + + // hide cursor + curs_set(0); + for (i = 0; i < ndst; i++) { + int n; + + if ((i % 2) == 0) { + gl.ch = ch; + } else { + gl.ch = ch2; + } + + if (gradual) { + // update screen each time + updateviewfor(src); + drawlevelfor(player); + } + + if (gradual) { + // draw one at a time + for (n = 0; n <= i; n++) { + drawglyph(&gl, retcell[n]->x - viewx, retcell[n]->y - viewy); + } + } else { + drawglyph(&gl, retcell[i]->x - viewx, retcell[i]->y - viewy); + } + + if (gradual) { + wrefresh(gamewin); + usleep(ANIMDELAY); + } + } + + if (!gradual) { + wrefresh(gamewin); + usleep(ANIMDELAY); + } + // show cursor + curs_set(1); + + needredraw = B_TRUE; +} + void animradial(cell_t *src, int radius, char ch, int colour) { glyph_t gl; int i; @@ -759,7 +812,7 @@ cell_t *askcoords(char *prompt, int targettype, lifeform_t *srclf, int maxrange, gettopobname(c, buf); } } else { - // can't see objects or lf there + // can't see this cell void *thing; char desc[BUFLEN]; switch (isinscanrange(c, &thing, desc, NULL)) { @@ -7106,11 +7159,14 @@ void showlfstats(lifeform_t *lf, int showall) { if (lorelev >= PR_NOVICE) setcol(mainwin, lorecol); mvwprintw(mainwin, y2, x2, ftext, "Armour Rating"); + /* if (arating > 0) { wprintw(mainwin, "%d (-%0.0f%% dmg)", arating, getdamreducepct(arating)); y2++; } else { wprintw(mainwin, "%d", arating); y2++; } + */ + wprintw(mainwin, "%d", arating); y2++; if (lorelev >= PR_NOVICE) unsetcol(mainwin, lorecol); } diff --git a/io.h b/io.h index 223764d..f8065d0 100644 --- a/io.h +++ b/io.h @@ -5,6 +5,7 @@ void addheading(prompt_t *p, char *text); void addmsghist(char *text); void addpromptq(prompt_t *p, char *q); void anim(cell_t *src, cell_t *dst, char ch, int colour); +void animline(cell_t *src, cell_t *dst, int gradual, char ch, char ch2, int colour); void animcells(cell_t *src, cell_t **dst, int ndst, int gradual, char ch, char ch2, int colour); void animradial(cell_t *src, int radius, char ch, int colour); void animradialorth(cell_t *src, int radius, char ch, int colour); diff --git a/lf.c b/lf.c index 0f05885..04feb70 100644 --- a/lf.c +++ b/lf.c @@ -4005,11 +4005,13 @@ int getmaxattacks(lifeform_t *lf) { // if we have high unarmed skill and our second hand is free, // we get one more attack - if (getskill(lf, SK_UNARMED) >= PR_ADEPT) { - if (!getequippedob(lf->pack, BP_SECWEAPON)) { - maxattacks++; - } - } + if (lfhasflag(lf, F_HUMANOID)) { + if (getskill(lf, SK_UNARMED) >= PR_SKILLED) { + if (hasbp(lf, BP_SECWEAPON) && !getequippedob(lf->pack, BP_SECWEAPON)) { + maxattacks++; + } + } + } if (getskill(lf, SK_TWOWEAPON) && isdualweilding(lf)) { maxattacks++; @@ -5504,6 +5506,14 @@ int giveskill(lifeform_t *lf, enum SKILL id) { msg("You can now deflect attacks with your second weapon."); } } + } else if (id == SK_UNARMED) { + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { + if (f->val[1] == PR_SKILLED) { + if (hasbp(lf, BP_SECWEAPON)) { + msg("You can now make melee attacks with your off-hand."); + } + } + } } else if (id == SK_SS_ALLOMANCY) { // give all allomantic spells mayusespellschool(lf->flags, SS_ALLOMANCY, F_CANCAST); @@ -7268,7 +7278,6 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 40, OC_POTION, NA, NULL); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-3 darts"); addflag(lastrace->flags, F_STARTOB, 33, NA, NA, "javelin"); - addflag(lastrace->flags, F_STARTOB, 33, NA, NA, "leather armour"); addflag(lastrace->flags, F_STARTOB, 33, NA, NA, "buckler"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-10 gold coins"); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); @@ -10089,12 +10098,9 @@ flag_t *levelabilityready(lifeform_t *lf) { } void loseconcentration(lifeform_t *lf) { - flag_t *f; // stop sprinting - f = lfhasflag(lf, F_SPRINTING); - if (f && f->val[0]) { - killflag(f); - } + stopsprinting(lf); + // boost spells end stopallspells(lf); @@ -12393,6 +12399,11 @@ void stoprunning(lifeform_t *lf) { if (f) { killflag(f); } + +} + +void stopsprinting(lifeform_t *lf) { + flag_t *f; f = lfhasflag(lf, F_SPRINTING); if (f && f->val[0]) { killflag(f); @@ -12863,7 +12874,7 @@ void turneffectslf(lifeform_t *lf) { } // secret doors, traps, etc? - if (isplayer(lf) && !isinbattle(lf) && !isblind(lf)) { + if (isplayer(lf) && !isinbattle(lf) && !isblind(lf) && !lfhasflag(lf, F_TRAINING)) { for (i = 0; i < lf->nlos; i++) { if (!lf->los[i]->lf) { object_t *o; @@ -13548,6 +13559,7 @@ int usestairs(lifeform_t *lf, object_t *o) { // move player to new map moveto(lf, newcell, B_TRUE, B_TRUE); if ((dir == D_UP) && !isairborne(lf)) { + stopsprinting(adjally[n]); // you can sprint down stairs, but not up taketime(lf, getmovespeed(lf)*2); // takes longer to climb } else { taketime(lf, getmovespeed(lf)); @@ -13559,6 +13571,7 @@ int usestairs(lifeform_t *lf, object_t *o) { c = getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND); if (c) { if (!initiatemove(adjally[n], NULL, NULL)) { + stopsprinting(adjally[n]); movelf(adjally[n], c); if ((dir == D_UP) && !isairborne(adjally[n])) { taketime(adjally[n], getmovespeed(adjally[n])*2); // takes longer to climb diff --git a/lf.h b/lf.h index 38452f6..ef2303d 100644 --- a/lf.h +++ b/lf.h @@ -281,6 +281,7 @@ int stone(lifeform_t *lf); void stopeating(lifeform_t *lf); void stopresting(lifeform_t *lf); void stoprunning(lifeform_t *lf); +void stopsprinting(lifeform_t *lf); int testammo(lifeform_t *lf, object_t *o); int takeoff(lifeform_t *lf, object_t *o); void taketime(lifeform_t *lf, long howlong); diff --git a/map.c b/map.c index 296076c..f5e6f51 100644 --- a/map.c +++ b/map.c @@ -1213,7 +1213,9 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) { if (rnd(1,100) <= getvaultchance(map)) { vault_t *v; v = getvaulttype(map); - if (!createvault(map, i, v, &roomw[i],&roomh[i])) { + if (createvault(map, i, v, &roomw[i],&roomh[i])) { + // failed + } else { // success roomvault[i] = v; } @@ -1309,7 +1311,9 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) { while (!done) { c = getrandomroomcell(map, i); // if nothing there - if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) { + //if (c && isempty(c) && !countobs(c->obpile, B_TRUE)) { + if (c && cellwalkable(NULL, c, NULL)) { + int obchance; int nadded = 0; @@ -1330,6 +1334,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir) { } if (ntries >= numobs) { + done = B_TRUE; break; } } @@ -1654,6 +1659,11 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth) { int w,h,x,y; int minx,miny,maxx,maxy; flag_t *f; + + // default + if (retw) *retw = -1; + if (reth) *reth = -1; + if (!v) { return B_TRUE; } @@ -1670,8 +1680,6 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth) { // get width/height from vault w = v->w; h = v->h; - if (retw) *retw = w; - if (reth) *reth = h; // find vault position if (calcroompos(map, w, h, &minx, &miny)) { dblog("** couldn't make vault room!\n"); @@ -1698,6 +1706,9 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth) { } } + if (retw) *retw = w; + if (reth) *reth = h; + // add other stuff to the vault addvaultcontents(map, v, minx, miny, maxx, maxy); @@ -1706,19 +1717,19 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth) { autodoors(map, roomid, minx, miny, maxx, maxy); } - linkdoors(map, roomid, minx, miny, maxx,maxy); + linkexits(map, roomid, minx, miny, maxx,maxy); return B_FALSE; } -// make sure doors in a given room link up to the rest of the map. -void linkdoors(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) { +// make sure exits/doors in a given room link up to the rest of the map. +void linkexits(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) { int x,y,i; cell_t *poss[MAXCANDIDATES],*c; int nposs = 0; int db = B_FALSE; - if (db) dblog("linkdoors for roomid %d", roomid); + if (db) dblog("linkexits for roomid %d", roomid); // find all doors // TODO: ...or "exits" for (y = miny; y <= maxy; y++) { @@ -1726,14 +1737,14 @@ void linkdoors(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) { c = getcellat(m, x, y); if (!c) continue; - if (hasobwithflag(c->obpile, F_DOOR)) { - if (db) dblog("found door at %d,%d",x,y); + if (hasobwithflag(c->obpile, F_DOOR) || hasflagval(m->flags, F_ROOMEXIT, roomid, x, y, NULL)) { + if (db) dblog("found door/exit at %d,%d",x,y); poss[nposs++] = c; } } } - if (db) dblog("%d doors found.",nposs); + if (db) dblog("%d doors/exits found.",nposs); // for each door, make sure it links to at least one cell which isn't // part of this room @@ -1794,12 +1805,12 @@ void linkdoors(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) { c = getcellindir(poss[i], whichway); while (c && !cellwalkable(NULL, c, NULL)) { setcelltype(c, getemptycelltype(c->map->habitat)); - c = getcellindir(poss[i], whichway); + c = getcellindir(c, whichway); } } } // end if ncorridors = 0 } // end for each door - if (db) dblog("linkdoors complete."); + if (db) dblog("linkexits complete."); } // room w/h are returned in *w and *h if given. @@ -2459,7 +2470,7 @@ cell_t *getrandomcell(map_t *map) { return cell; } -cell_t *getrandomcelloftype(map_t *map, int id) { +cell_t *getrandomcelloftype(map_t *map, enum CELLTYPE id) { cell_t *cell; cell = getrandomcell(map); while (cell->type->id != id) { @@ -2491,7 +2502,10 @@ cell_t *getrandomroomcell(map_t *map, int roomid) { for (x = 0; x < map->w; x++) { c = getcellat(map, x, y); // is this cell in the correct room and not a wall? - if (c && isempty(c)) { + // using c->type->solid in case we have a room + // filled with boulders + //if (c && cellwalkable(NULL, c, NULL)) { + if (c && !c->type->solid) { int ok = B_FALSE; if (c->roomid == roomid) { ok = B_TRUE; diff --git a/map.h b/map.h index c1fc103..d9827ee 100644 --- a/map.h +++ b/map.h @@ -53,7 +53,7 @@ int getthingchance(int habitat); cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand); cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob); cell_t *getrandomcell(map_t *map); -cell_t *getrandomcelloftype(map_t *map, int id); +cell_t *getrandomcelloftype(map_t *map, enum CELLTYPE id); int getrandomdir(int dirtype); cell_t *getrandomroomcell(map_t *map, int roomid); void getroomcells(map_t *m, int roomid, cell_t **retcell, int *ncells); @@ -76,7 +76,7 @@ int isnewcellok(cell_t *cell, char *err); int isonmap(map_t *map, int x, int y); int isoutdoors(map_t *m); int iswallindir(cell_t *cell, int dir); -void linkdoors(map_t *m, int roomid, int minx, int miny, int maxx, int maxy); +void linkexits(map_t *m, int roomid, int minx, int miny, int maxx, int maxy); int linkstairs(object_t *o); void makedoor(cell_t *cell); void makelit(cell_t *c, enum LIGHTLEV how, int howlong); diff --git a/move.c b/move.c index 6843009..bb763cd 100644 --- a/move.c +++ b/move.c @@ -917,7 +917,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { didmsg = B_TRUE; } // stop sprinting - stoprunning(lf); + stopsprinting(lf); } } } @@ -1295,7 +1295,7 @@ int opendoor(lifeform_t *lf, object_t *o) { touch(lf, o); // stop sprinting - stoprunning(lf); + stopsprinting(lf); /* sf = lfhasflag(lf, F_SPRINTING); if (sf && sf->val[0]) { @@ -1455,7 +1455,7 @@ int closedoor(lifeform_t *lf, object_t *o) { if (lf) { // stop sprinting - stoprunning(lf); + stopsprinting(lf); if (isplayer(lf)) { msg("You close %s.", obname); diff --git a/objects.c b/objects.c index e32b26e..50aff20 100644 --- a/objects.c +++ b/objects.c @@ -427,7 +427,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { enum FLAG doorflag[5]; int ndoorflags = 0; - addedob[0] = NULL; // just in case we don't add any + // just in case we don't add any + addedob[0] = NULL; + nadded = 0; + nretobs = 0; localname = strdup(name); @@ -686,6 +689,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { if (!ot) { //if (gamestarted) msg("DB: No match for object name '%s'", p ); if (db) dblog("DB: No match for object name '%s'", p ); + nretobs = 0; return NULL; } } @@ -2046,6 +2050,10 @@ int canseeob(lifeform_t *lf, object_t *o) { } } } + + if (isblind(player) && hasflag(o->flags, F_NOFEEL)) { + return B_FALSE; + } return B_TRUE; } @@ -2939,9 +2947,9 @@ int getobvalue(object_t *o) { // do nothing price += (pow(getspelllevel(f->val[0]), 2) * 2); } else if (o->type->obclass->id == OC_POTION) { - price += (pow(getspelllevel(f->val[0]), 2) * 15); + price += (pow(getspelllevel(f->val[0]), 2) * 5); } else if (o->type->obclass->id == OC_WAND) { - price += (pow(getspelllevel(f->val[0]), 2) * 22); + price += (pow(getspelllevel(f->val[0]), 2) * 15); } } else if (f->id == F_MANUALOF) { price *= 124; @@ -4554,21 +4562,32 @@ int getthrowdam(object_t *o) { return (int)dam; } +// get either name of top object, or cell type if solid char *gettopobname(cell_t *c, char *retbuf) { char buf[BUFLEN]; - object_t *o; - o = gettopobject(c); - if (o) { - int nother; - getobname(o, buf, o->amt); - strcat(retbuf, buf); - // other obs here too? - nother = countnoncosmeticobs(c->obpile, B_TRUE) - 1; - if (nother >= 1) { + int nother; + if (c->type->solid) { + strcpy(retbuf, c->type->name); + nother = countnoncosmeticobs(c->obpile, B_TRUE); + if (nother) { sprintf(buf, " (+%d other thing%s)", nother, (nother == 1) ? "" : "s"); strcat(retbuf, buf); } return retbuf; + } else { + object_t *o; + o = gettopobject(c); + if (o) { + getobname(o, buf, o->amt); + strcat(retbuf, buf); + // other obs here too? + nother = countnoncosmeticobs(c->obpile, B_TRUE) - 1; + if (nother >= 1) { + sprintf(buf, " (+%d other thing%s)", nother, (nother == 1) ? "" : "s"); + strcat(retbuf, buf); + } + return retbuf; + } } return NULL; } @@ -5074,7 +5093,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_OBHP, 50, 50, NA, NULL); 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 technology.", '~', C_GREY); + addoc(OC_TECH, "Technology", "A strange piece of futuristic technology.", '[', C_GREY); addocnoun(lastobjectclass, "technology"); addocnoun(lastobjectclass, "tech"); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -5208,7 +5227,7 @@ void initobjects(void) { addot(OT_WATERSHALLOW, "shallow water", "Waist-deep water.", MT_WATER, 150, OC_TERRAIN); addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{"); + addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "~"); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DEEPWATER, DP_WAIST, NA, NA, NULL); addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice"); @@ -5220,7 +5239,7 @@ void initobjects(void) { addot(OT_WATERDEEP, "deep water", "Very deep water.", MT_WATER, 300, OC_TERRAIN); addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, C_BOLDBLUE, NA, NA, "{"); + addflag(lastot->flags, F_GLYPH, C_BOLDBLUE, NA, NA, "~"); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice"); addflag(lastot->flags, F_DTCREATEOB, DT_FIRE, 1, DT_COMPASS, "cloud of steam"); @@ -5246,9 +5265,16 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "."); addflag(lastot->flags, F_SECRET, 25, NA, NA, NULL); + addot(OT_TRAPTELEPORT, "teleportation trap", "A magical dispersal field.", MT_NOTHING, 0, OC_TRAP); + addflag(lastot->flags, F_TRAP, NA, B_TRUE, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_MAGENTA, NA, NA, "^"); + addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "."); + addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL); addot(OT_TRAPARROW, "arrow trap", "A pressure plate which causes arrows to shoot at you.", MT_NOTHING, 0, OC_TRAP); addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL); - addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -5257,7 +5283,6 @@ void initobjects(void) { addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL); addot(OT_TRAPARROWP, "poison arrow trap", "A pressure plate which causes poisoned arrows to shoot at you.", MT_NOTHING, 0, OC_TRAP); addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL); - addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -5266,7 +5291,6 @@ void initobjects(void) { addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL); addot(OT_TRAPGAS, "gas trap", "A pressure plate which releases poisonous gas.", MT_NOTHING, 0, OC_TRAP); addflag(lastot->flags, F_TRAP, 27, B_TRUE, NA, NULL); - addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -5275,7 +5299,6 @@ void initobjects(void) { addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL); addot(OT_TRAPFIRE, "fire trap", "A pressure plate which fires a pillar of flame.", MT_NOTHING, 0, OC_TRAP); addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); - addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 59, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -5284,7 +5307,6 @@ void initobjects(void) { addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL); addot(OT_TRAPMINE, "landmine trap", "A buried, pressure-sensitive explosive device.", MT_NOTHING, 0, OC_TRAP); addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); - addflag(lastot->flags, F_TRAP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 20, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); @@ -5846,6 +5868,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); + // l5 + addot(OT_S_CHAINLIGHTNING, "chain lightning", "Electricity arcs between all nearby enemies.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); /////////////////// // elemental - fire /////////////////// @@ -6080,13 +6108,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); - // l5 + // l6 addot(OT_S_LIGHTNINGSTORM, "lightning storm", "Blasts all visible enemies bolts of lightning from the sky.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); - // l6 addot(OT_S_SUMMONANIMALSLG, "summon large animals", "Summons 2-3 large animals.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); @@ -7153,7 +7180,7 @@ void initobjects(void) { addot(OT_ACIDSPLASH, "splash of acid", "A splash corrosive acid.", MT_ACID, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); + addflag(lastot->flags, F_GLYPH, NA, NA, NA, ","); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates"); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); @@ -7204,7 +7231,7 @@ void initobjects(void) { addot(OT_MUDPOOL, "pool of mud", "A large puddle of wet mud.", MT_WATER, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, ","); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "{"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -7231,7 +7258,7 @@ void initobjects(void) { addot(OT_PUDDLEWATERL, "large puddle of water", "A large pool of water.", MT_WATER, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, ","); + addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 85, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -7249,6 +7276,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); addot(OT_BLOODCSPLASH, "splash of cockatrice blood", "A small pool of cockatrice blood.", MT_BLOOD, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -7280,23 +7308,24 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LINKOB, OT_POT_BLOOD, NA, NA, NULL); addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL); - + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); addot(OT_BLOODPOOL, "pool of blood", "A large pool of blood.", MT_BLOOD, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, NA, NA, NA, ","); + addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SLIPPERY, 3, NA, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "blood stain"); addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "dries up"); addflag(lastot->flags, F_DIECONVERTTEXTPL, NA, NA, NA, "dry up"); - addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); + addflag(lastot->flags, F_OBHP, 45, 45, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DRINKABLE, B_TRUE, 0, NA, NULL); addflag(lastot->flags, F_LINKOB, OT_POT_BLOOD, NA, NA, NULL); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); addot(OT_WOODENBARREL, "wooden barrel", "A solid wooden barrel.", MT_WOOD, 20, OC_MISC); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL); @@ -7341,6 +7370,7 @@ void initobjects(void) { addot(OT_FOOTPRINT, "footprints", "Footprints which show the passage of some kind of creature.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_NO_A, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NO_PLURAL, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOGLYPH, NA, NA, NA, NULL); @@ -8003,7 +8033,7 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); - addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 1.5, OC_MISSILE); + addot(OT_JAVELIN, "javelin", "A long, sharp missile weapon.", MT_METAL, 6.5, OC_MISSILE); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_MISSILEDAM, 3, NA, NA, ""); @@ -12560,9 +12590,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, throwdam = getthrowdam(o); dam = (int)((float)throwdam * multiplier); takedamage(shield, dam, DT_PROJECTILE); - youhit = B_FALSE; - } } } @@ -12832,7 +12860,7 @@ void timeeffectsob(object_t *o) { if (haslos(player, location)) { getobname(sg, sgname, sg->amt); - canseeloc = B_FALSE; + canseeloc = B_TRUE; msg("The %s pulses %s!", noprefix(sgname), (o->blessed == B_CURSED) ? "white" : "black"); } @@ -13177,6 +13205,14 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) { losehp(lf, roll("1d4"), DT_BASH, NULL, "a falling rock trap"); } addob(lf->cell->obpile, "stone"); + } else if (oid == OT_TRAPTELEPORT) { + cell_t *newc; + // move somewhere else! + newc = getrandomcelloftype(lf->cell->map, getemptycelltype(lf->cell->map->habitat)); + if (newc) { + teleportto(lf, newc, B_TRUE); + } + } else if ((oid == OT_TRAPARROW) || (oid == OT_TRAPARROWP)) { int dir,bestdir = D_NONE; cell_t *src; diff --git a/spell.c b/spell.c index 3d4c3ed..49d1623 100644 --- a/spell.c +++ b/spell.c @@ -1766,6 +1766,92 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster)) { msg("A relaxing aroma surrounds you."); } + } else if (spellid == OT_S_CHAINLIGHTNING) { + cell_t *hitcell[MAXRETCELLS]; // all cells which have been hit in total + cell_t *arccell[MAXRETCELLS]; // cells hit this time + cell_t *arccell2[MAXRETCELLS]; // cells hit this time + int nhitcells = 0, narccells,narccells2; + int i; + int range; + int nsides = 6; + + range = getspellrange(spellid, power); + + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; + + // create a line of fire towards the target cell + animline(caster->cell, targcell, B_FALSE, '/', '\\', C_WHITE); + + if (cansee(player, caster)) { + msg("%s shoot%s a bolt of electricity!",castername, isplayer(caster) ? "" : "s"); + } + + if (targcell->lf) { + arccell[0] = targcell; + narccells = 1; + } else { + fizzle(caster); + } + + nhitcells = 0; + while (narccells) { + int stillseen = B_FALSE; + // everyone takes damage, and mark cells as hit + for (i = 0; i < narccells; i++) { + losehp(arccell[i]->lf, rolldie(2,nsides), DT_ELECTRIC, caster, "an electricity bolt"); + hitcell[nhitcells++] = arccell[i]; + + if (haslos(player, arccell[i])) { + stillseen = B_TRUE; + needredraw = B_TRUE; + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } + + // now range gets halved and damage lowered + range /= 2; + if (range <= 0) break; + if (--nsides <= 0) break; // ie. max of 5 arcs + + // now arc to other cells with lfs still within range + narccells2 = 0; + for (i = 0; i < narccells; i++) { + int x,y; + cell_t *c; + for (y = arccell[i]->y - range ; y <= arccell[i]->y + range; y++) { + for (x = arccell[i]->x - range ; x <= arccell[i]->x + range; x++) { + c = getcellat(targcell->map, x, y); + if (c && c->lf && (c->lf != caster) + && haslof(arccell[i], c, LOF_NEED, NULL)) { + int n,found = B_FALSE; + // if this cell hasn't been hit... + for (n = 0; n < nhitcells; n++) { + if (hitcell[n] == c) { + found = B_TRUE; + break; + } + } + + if (!found) { + // will arc to here + arccell2[narccells2++] = c; + animline(arccell[i], c, B_FALSE, '/', '\\', C_WHITE); + } + } + } + } + } + + // replace arccells + for (i = 0; i < narccells2; i++) { + arccell[i] = arccell2[i]; + } + narccells = narccells2; + + if (narccells && stillseen) { + msg("The electricity arcs!"); + } + } // end while narccells } else if (spellid == OT_S_CLOUDKILL) { int radius; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; @@ -5062,7 +5148,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (o = targcell->obpile->first ; o ; o = o->next) { flag_t *f; f = hasflag(o->flags, F_SECRET); - if (f) { + if (f && (f->val[0] != NA)) { char obname[BUFLEN]; getobname(o, obname, o->amt); msg("%s is magically revealed!", obname); @@ -5072,7 +5158,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } - // remove invisibility + // remove invisibility/hiding if (targcell->lf) { flag_t *f, *nextf; for (f = targcell->lf->flags->first ; f ; f = nextf) { @@ -5082,9 +5168,22 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ killflag(f); // player can see whoever just appeared, and the caster? if (cansee(player, targcell->lf) && cansee(player, caster)) { + char tname[BUFLEN]; seen = B_TRUE; + getlfname(targcell->lf, tname); + msg("%s becomes visible!", tname); } } + } else if ( (f->id == F_HIDING) && + !lfhasflagval(caster, F_SPOTTED, targcell->lf->id, NA, NA, NULL)) { + addflag(caster->flags, F_SPOTTED, targcell->lf->id, NA, NA, NULL); + // player can see whoever just appeared, and the caster? + if (cansee(player, targcell->lf) && cansee(player, caster)) { + char tname[BUFLEN]; + seen = B_TRUE; + getlfname(targcell->lf, tname); + msg("A hiding %s is revealed!", noprefix(tname)); + } } } } @@ -6574,6 +6673,9 @@ int getspellrange(enum OBTYPE spellid, int power) { case OT_S_LIGHTNINGBOLT: range = (power*3); break; + case OT_S_CHAINLIGHTNING: + range = (power*3); + break; default: break; }