diff --git a/attack.c b/attack.c index ee3174a..1816d07 100644 --- a/attack.c +++ b/attack.c @@ -432,8 +432,9 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } if (lfhasflagval(lf, F_INJURY, NA, BP_HANDS, DT_SLASH, NULL)) { - bleed(lf, B_FALSE); - losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); + if (!bleedfrom(lf, BP_HANDS, B_FALSE)) { + losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); + } } // god effects... @@ -1910,8 +1911,10 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) { if (victim) { if (lfhasflagval(victim, F_INJURY, NA, BP_BODY, DT_SLASH, NULL)) { - // extra damage - dam += rnd(1,2); + if (willbleedfrom(victim, BP_BODY)) { + // extra damage + dam += rnd(1,2); + } } } diff --git a/data/hiscores.db b/data/hiscores.db index ecacf0b..5c975bb 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 19c6790..248a5a3 100644 --- a/defs.h +++ b/defs.h @@ -50,7 +50,7 @@ #define B_DONTKILL (-1) #define B_APPENDYOU (-1) #define B_SPLATTER (-1) -#define B_FROMINJURY (-1) +#define B_FROMINJURY (-2) #define B_KEEPDIR (-2) @@ -257,6 +257,16 @@ enum RELATIVEDIR { #define MSGMORESTRING "^n--More--" #define SOLDOUTSTRING "--SOLD OUT--" +// COMMAND CHARACTERS +#define CH_TURN_W (8) // ctrl-h +#define CH_TURN_N (10) // ctrl-j +#define CH_TURN_S (11) // ctrl-k +#define CH_TURN_E (12) // ctrl-l +#define CH_TURN_NW (25) // ctrl-y +#define CH_TURN_NE (21) // ctrl-u +#define CH_TURN_SW (2) // ctrl-b +#define CH_TURN_SE (14) // ctrl-n + // SPECIAL NUMBERS/CONSTANTS #define DUMMYCELLTYPE 0xabcd #define UNLIMITED (-9876) @@ -1030,7 +1040,9 @@ enum OBTYPE { // scrolls OT_MAP, OT_GRAPHPAPER, + OT_SCR_AWARENESS, OT_SCR_NOTHING, + OT_SCR_CANINETRACKING, OT_SCR_CREATEMONSTER, OT_SCR_DETECTAURA, OT_SCR_DETECTLIFE, @@ -1079,16 +1091,19 @@ enum OBTYPE { OT_S_SMITEGOOD, OT_S_STENCH, // -- divination + OT_S_AWARENESS, + OT_S_CANINETRACKING, OT_S_DETECTAURA, OT_S_DETECTLIFE, OT_S_DETECTOBS, OT_S_DETECTMAGIC, + OT_S_IDENTIFY, OT_S_LOCATEOBJECT, OT_S_LORE, + OT_S_MAPPING, OT_S_REVEALHIDDEN, OT_S_SEEINVIS, - OT_S_IDENTIFY, - OT_S_MAPPING, + OT_S_SIXTHSENSE, // -- elemental - air OT_S_JOLT, OT_S_AIRBLAST, @@ -1205,6 +1220,7 @@ enum OBTYPE { OT_S_CREATEMONSTER, OT_S_SUMMONWEAPON, // -- translocation + OT_S_APPORTATION, OT_S_BLINK, OT_S_DISPERSAL, OT_S_GATE, @@ -1284,6 +1300,7 @@ enum OBTYPE { OT_BAGOFHOLDING, OT_BAGOFHOLDINGLARGE, OT_BAGOFHOLDINGHUGE, + OT_BANDAGE, OT_BLANKET, OT_BLINDFOLD, OT_BUGLAMP, @@ -1301,26 +1318,34 @@ enum OBTYPE { OT_SAFEBOX, OT_TORCH, OT_TOWEL, - // tech - OT_POCKETWATCH, - OT_C4, + // tech l0 OT_CREDITCARD, + OT_PAPERCLIP, + OT_SLEEPINGBAG, + // tech l1 + OT_POCKETWATCH, OT_DIGITALWATCH, + OT_INSECTICIDE, + OT_LANTERNLED, + OT_TENT, + // tech l2 + OT_C4, OT_FLASHBANG, OT_GRENADE, - OT_INFOVISOR, - OT_INSECTICIDE, - OT_JETPACK, - OT_LANTERNLED, - OT_LOCKHACKER, OT_MOTIONSCANNER, OT_NVGOGGLES, - OT_PAPERCLIP, + OT_STYPTIC, + // tech l3 + OT_INFOVISOR, + OT_LOCKHACKER, OT_PORTLADDER, - OT_SLEEPINGBAG, + // tech l4 + OT_JETPACK, + // tech l5 OT_TELEPAD, - OT_TENT, OT_XRAYGOGGLES, + // tech l6 + // none yet. // furniture OT_CANDELABRUM, OT_COFFIN, @@ -2235,6 +2260,7 @@ enum FLAG { F_ASLEEP, // is asleep. if v2 is set, means we are sleeping on // purpose and will wake up when at full hp/mp/etc. F_ATTACHEDTO, // you are attached to lf id v0, and will move with it + F_AWARENESS, // you can see 360 degrees around yourself F_BEINGSTONED,// turn to stone when v0 drops to zero. (drops 1/turn) F_BLIND, // cannot see anything F_CONFUSED, // move randomly about @@ -2465,25 +2491,28 @@ enum HUNGER { // injuries enum INJURY { IJ_NONE, + // bashing IJ_ANKLESWOLLEN, - IJ_ARTERYPIERCE, IJ_BLACKEYE, - IJ_CHESTBLEED, IJ_CONCUSSION, - IJ_EYELIDSCRAPED, - IJ_EYEDESTROYED, IJ_FINGERBROKEN, - IJ_FINGERMISSING, - IJ_HAMSTRUNG, - IJ_HANDBLEED, - IJ_LEGBLEED, IJ_LEGBROKEN, IJ_LEGBRUISE, IJ_NOSEBROKEN, IJ_RIBCRACKED, IJ_SHOULDERDISLOCATED, - IJ_TENDONCUT, IJ_WINDPIPECRUSHED, + // slashing + IJ_ARTERYPIERCE, + IJ_CHESTBLEED, + IJ_HAMSTRUNG, + IJ_HANDBLEED, + IJ_LEGBLEED, + IJ_TENDONCUT, + IJ_FINGERMISSING, + IJ_EYELIDSCRAPED, + IJ_EYEDESTROYED, + // }; diff --git a/flag.c b/flag.c index c1e1a8a..b293714 100644 --- a/flag.c +++ b/flag.c @@ -361,6 +361,7 @@ int flagcausesloscalc(enum FLAG fid) { case F_NIGHTVISRANGEMOD: case F_PRONE: case F_SEEINDARK: + case F_AWARENESS: case F_VISRANGE: case F_VISRANGEMOD: return B_TRUE; @@ -388,6 +389,7 @@ int flagcausesredraw(lifeform_t *lf, enum FLAG fid) { case F_SECRET: case F_SEEINDARK: case F_SEEINVIS: + case F_AWARENESS: case F_SPRINTING: case F_SLOWMOVE: case F_TIRED: diff --git a/io.c b/io.c index 5864fa6..db521f4 100644 --- a/io.c +++ b/io.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -1181,6 +1182,11 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("^%c%s begin%s to turn to stone!",isplayer(lf) ? 'B' : 'n', lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; + case F_AWARENESS: + if (isplayer(lf)) { + msg("You can suddenly see out the back of your head!"); + } + break; case F_BLIND: if (isplayer(lf)) { msg("^WYou cannot see!"); @@ -1748,6 +1754,11 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("The fragments of stone around %s%s body drop%s away.",lfname, getpossessive(lfname), isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; + case F_AWARENESS: + if (isplayer(lf)) { + msg("You can no longer see out the back of your head."); + } + break; case F_BLIND: msg("%s can see again.",lfname); donesomething = B_TRUE; @@ -2911,14 +2922,14 @@ void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... ) { int chartodir(char c) { switch (tolower(c)) { - case 'h': return DC_W; - case 'j': return DC_S; - case 'k': return DC_N; - case 'l': return DC_E; - case 'y': return DC_NW; - case 'u': return DC_NE; - case 'b': return DC_SW; - case 'n': return DC_SE; + case CH_TURN_W: case 'h': return DC_W; + case CH_TURN_N: case 'j': return DC_S; + case CH_TURN_S: case 'k': return DC_N; + case CH_TURN_E: case 'l': return DC_E; + case CH_TURN_NW: case 'y': return DC_NW; + case CH_TURN_NE: case 'u': return DC_NE; + case CH_TURN_SW: case 'b': return DC_SW; + case CH_TURN_SE: case 'n': return DC_SE; } return D_NONE; } @@ -3677,6 +3688,9 @@ void describeob(object_t *o) { case F_ATTRSET: mvwprintw(mainwin, y, 0, "%s modifies your %s.", buf, getattrname(f->val[1])); y++; break; + case F_AWARENESS: + mvwprintw(mainwin, y, 0, "%s grants you enhanced awareness.", buf); y++; + break; case F_BLIND: mvwprintw(mainwin, y, 0, "%s prevents you from seeing anything.", buf); y++; break; @@ -6232,6 +6246,7 @@ void initgfx(void) { noecho(); cbreak(); + //raw(); nodelay(mainwin, FALSE); getmaxyx(mainwin, SCREENH, SCREENW); @@ -6271,6 +6286,9 @@ void initgfx(void) { snprintf(prevmsg, BUFLEN, "!nolastmessage!"); msgmulti = 1; + + // handle sigstop (ctrl-y) + signal(SIGTSTP, handle_ctrl_y); } int drop(object_t *o, int count) { @@ -6743,7 +6761,6 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { int getkey(void) { int key_code=0; - key_code = getch(); // XXX NEW CODE: @@ -6779,6 +6796,10 @@ enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev) { return C_GREY; } +void handle_ctrl_y(int arg) { + ungetch(25); // put 'ctrl-y' char onto keyboard queue +} + void handleinput(void) { int ch; //char buf[BUFLEN]; @@ -6969,7 +6990,9 @@ void handleinput(void) { switch (tolower(ch)) { case 'h': case 'j': case 'k': case 'l': case 'y': case 'u': case 'b': case 'n': - break; + case CH_TURN_N: case CH_TURN_E: case CH_TURN_S: case CH_TURN_W: + case CH_TURN_NE: case CH_TURN_SE: case CH_TURN_SW: case CH_TURN_NW: + break; default: stoprunning(player); if (hasactivespell(player, OT_S_SLIDE)) stopspell(player, OT_S_SLIDE); @@ -7004,6 +7027,24 @@ void handleinput(void) { trymove(player, dir, B_TRUE, B_TRUE); } break; + // turn + case CH_TURN_N: + case CH_TURN_E: + case CH_TURN_S: + case CH_TURN_W: + case CH_TURN_NE: + case CH_TURN_SE: + case CH_TURN_SW: + case CH_TURN_NW: + dir = chartodir(ch); + if (dir != player->facing) { + if (getrelativedir(player, dir) != RD_FORWARDS) { + taketime(player, getturnspeed(player)); + } + setfacing(player, dir); + drawscreen(); + } + break; case 's': // slowwalk trysneak(player, D_NONE); break; @@ -9136,6 +9177,10 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } } + if (lfhasknownflag(lf, F_AWARENESS)) { + mvwprintw(mainwin, y, 0, "%s can see things which are behind %s.", you(lf), you(lf)); + y++; + } f = lfhasknownflag(lf, F_MAGICARMOUR); if (f && (f->known)) { diff --git a/io.h b/io.h index 6a46a49..ce33ee8 100644 --- a/io.h +++ b/io.h @@ -85,6 +85,7 @@ char getchoice(prompt_t *prompt); char getchoicestr(prompt_t *prompt, int useshortcuts, int showlallatstart); int getkey(void); enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev); +void handle_ctrl_y(int arg); void handleinput(void); void doheading(WINDOW *win, int *y, int x, char *what); void doheadingsmall(WINDOW *win, int y, int x, char *format, char *heading); diff --git a/lf.c b/lf.c index bdb8772..d596c7d 100644 --- a/lf.c +++ b/lf.c @@ -200,6 +200,14 @@ void bleed(lifeform_t *lf, int splatter) { } } +int bleedfrom(lifeform_t *lf, enum BODYPART bp, int splatter) { + if (willbleedfrom(lf, bp)) { + bleed(lf, splatter); + return B_FALSE; + } + return B_TRUE; +} + void breakgrabs(lifeform_t *lf, int fromme, int tome) { flag_t *f; lifeform_t *alf; @@ -6822,6 +6830,13 @@ int getthrowspeed(int str) { return speed; } +int getturnspeed(lifeform_t *lf) { + int speed; + speed = getmovespeed(lf) / 2; + limit(&speed, 1, NA); + return speed; +} + void getwantdistance(lifeform_t *lf, int *min, int *max, int attacking) { flag_t *f; @@ -8523,7 +8538,6 @@ void initjobs(void) { } } addflag(lastjob->flags, F_NOSCORE, B_TRUE, NA, NA, NULL); - addflag(lastjob->flags, F_ENHANCESMELL, 5, NA, NA, NULL); addjob(J_ADVENTURER, "Adventurer"); // stats @@ -9016,7 +9030,7 @@ void initrace(void) { flag_t *f; objecttype_t *ot; // race classes - addraceclass(RC_OTHER, "misc. creature", "miscellaneous creatures", SK_NONE); + addraceclass(RC_OTHER, "strange creature", "strange creatures", SK_NONE); addraceclass(RC_ANIMAL, "animal", "animals and insects", SK_LORE_NATURE); addraceclass(RC_AQUATIC, "aquatic creature", "aquatic creatures", SK_LORE_NATURE); addraceclass(RC_DEMON, "demon", "demons", SK_LORE_DEMONS); @@ -11949,6 +11963,7 @@ int isaquatic(lifeform_t *lf) { return B_FALSE; } +// returns B_FALSE, B_TRUE, or B_FROMINJURY int isbleeding(lifeform_t *lf) { float hppct; hppct = ((float)lf->hp / (float) lf->maxhp) * 100; @@ -11956,7 +11971,7 @@ int isbleeding(lifeform_t *lf) { if (hppct <= 40) return B_TRUE; if (lfhasflagval(lf, F_INJURY, NA, NA, DT_SLASH, NULL)) { - return B_TRUE; + return B_FROMINJURY; } return B_FALSE; } @@ -13165,6 +13180,15 @@ void autotarget(lifeform_t *lf) { } } +int issmellablelf(lifeform_t *lf) { + if (lf->race->raceclass->id != RC_UNDEAD) { + return B_TRUE; + } + + return B_FALSE; +} + + int isswimming(lifeform_t *lf) { if (!lf) return B_FALSE; if (gamemode != GM_GAMESTARTED) { @@ -14198,21 +14222,25 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha if (noisemaker) { enum SKILLLEVEL slev; char lfname[BUFLEN]; - char distbuf[BUFLEN]; + char distbuf[BUFLEN],distbufbad[BUFLEN]; char dirbuf[BUFLEN]; int dir; real_getlfnamea(noisemaker, lfname, B_FALSE); if (dist >= 20) { // 20+ - strcpy(distbuf, " far away"); + strcpy(distbuf, " very far away"); + strcpy(distbufbad, " far away"); } else if (dist >= 10) { // 10 - 19 - strcpy(distbuf, ""); + strcpy(distbuf, " far away"); } else if (dist >= 5) { // 5 - 9 strcpy(distbuf, " nearby"); + strcpy(distbufbad, " nearby"); } else if (dist >= 2) { // 2 - 4 strcpy(distbuf, " very nearby"); + strcpy(distbufbad, " nearby"); } else { // 1 strcpy(distbuf, " right beside you"); + strcpy(distbufbad, " nearby"); } dir = getdirtowards(l->cell, c, NULL, B_FALSE, DT_COMPASS); @@ -14244,6 +14272,9 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha } else if (slev >= PR_BEGINNER) { msg("You hear %s%s%c", textnopunc, distbuf, punc); rv = B_TRUE; + } else if (slev >= PR_NOVICE) { + msg("You hear %s%s%c", textnopunc, distbufbad, punc); + rv = B_TRUE; } else { assert(text); msg("You hear %s", text); @@ -14624,7 +14655,7 @@ void precalclos_new(lifeform_t *lf) { int numpixels; //int db = B_FALSE; enum SKILLLEVEL plev; - flag_t *missingeye,*enhancesmell; + flag_t *missingeye; f = hasflag(lf->flags, F_XRAYVIS); if (f) { @@ -14636,11 +14667,6 @@ void precalclos_new(lifeform_t *lf) { // right eye missing? missingeye = lfhasflagval(lf, F_INJURY, IJ_EYEDESTROYED, NA, NA, NULL); - // enhanced smell means we can "see" lifeforms and "smelly" objects in all - // directions. - enhancesmell = lfhasflag(lf, F_ENHANCESMELL); - - los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); blocker = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); nlos = 0; @@ -14656,7 +14682,7 @@ void precalclos_new(lifeform_t *lf) { nendcells = 0; if (MAXOF(maxvisrange, nightvisrange) == 0) { - } else if (lf->facing == D_ALL) { + } else if (lfhasflag(lf, F_AWARENESS) || (lf->facing == D_ALL)) { get_circular_fov_endpoints(lf, maxvisrange, endx, endy, &nendcells); } else { enum QUADRANT startq, endq,curq; @@ -14748,6 +14774,7 @@ void precalclos_new(lifeform_t *lf) { assert(nlos < (MAX_MAPW * MAX_MAPH)); // deal with enhanced smell - do a second sweep in all directions. + /* if (enhancesmell) { int n; get_circular_fov_endpoints(lf, enhancesmell->val[0], endx, endy, &nendcells); @@ -14771,6 +14798,7 @@ void precalclos_new(lifeform_t *lf) { } } } + */ // now fill in lifeform structure lf->los = malloc(sizeof(cell_t *) * nlos); @@ -15705,7 +15733,8 @@ void initskills(void) { addskilldesc(SK_FIRSTAID, PR_INEPT, "- Determines how long poison effects will last.", B_FALSE); addskilldesc(SK_FIRSTAID, PR_ADEPT, "^gYou can now recognise when poison is potentially fatal.", B_TRUE); addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds.", 200); - addskilldesc(SK_LISTEN, PR_BEGINNER, "^gYou now gauge the distance of sounds.", B_TRUE); + addskilldesc(SK_LISTEN, PR_NOVICE, "^gYou now gauge the distance of sounds.", B_TRUE); + addskilldesc(SK_LISTEN, PR_BEGINNER, "^gYou now more accurately gauge the distance of sounds.", B_TRUE); addskilldesc(SK_LISTEN, PR_ADEPT, "^gYou can now determine the direction sounds are coming from.", B_TRUE); addskilldesc(SK_LISTEN, PR_EXPERT, "^gYou can now identify monsters based on sound.", B_TRUE); addskilldesc(SK_LISTEN, PR_MASTER, "^gYou can now locate monsters based on sound.", B_TRUE); @@ -16573,8 +16602,9 @@ void startlfturn(lifeform_t *lf) { } if (lfhasflagval(lf, F_INJURY, IJ_ARTERYPIERCE, NA, NA, NULL)) { - bleed(lf, B_SPLATTER); - losehp(lf, rnd(1,8), DT_DIRECT, NULL, "blood loss"); + if (!bleedfrom(lf, BP_HANDS, B_SPLATTER)) { + losehp(lf, rnd(1,8), DT_DIRECT, NULL, "blood loss"); + } } // get more hungry @@ -16616,6 +16646,43 @@ void startlfturn(lifeform_t *lf) { } } + // sixth sense spell warnings + + f = hasactivespell(lf, OT_S_SIXTHSENSE); + if (f) { + cell_t *retcell[MAXCANDIDATES]; + int nretcells; + getradiuscells(lf->cell, 2, DT_COMPASS, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 0); + for (i = 0; i < nretcells; i++) { + if (retcell[i]->lf && !areallies(lf, retcell[i]->lf)) { + int dir,reldir; + dir = getdirtowards(lf->cell, retcell[i], NULL, B_FALSE, DT_ORTH); + reldir = getrelativedir(lf, dir); + if (reldir != RD_FORWARDS) { + if (isplayer(lf)) { + if (f->val[2] >= 5) { + char buf[BUFLEN]; + getlfname(retcell[i]->lf, buf); + warn("^WYour sixth sense warns you of %s %s you!", buf, + (reldir == RD_BACKWARDS) ? "behind" : "beside" ); + } else if (f->val[2] >= 3) { + warn("^WYour sixth sense warns you of %s %s %s you!", + needan(retcell[i]->lf->race->raceclass->name) ? "an" : "a", + retcell[i]->lf->race->raceclass->name, + (reldir == RD_BACKWARDS) ? "behind" : "beside" ); + } else { + warn("^WYour sixth sense warns you of something %s you!", + (reldir == RD_BACKWARDS) ? "behind" : "beside" ); + } + more(); + } + stopspell(lf, OT_S_SIXTHSENSE); + break; + } + } + } + } + if (hasactivespell(lf, OT_S_SUMMONWEAPON) && !hasobwithflagval(lf->pack, F_CREATEDBYSPELL, OT_S_SUMMONWEAPON, NA, NA, NULL)) { stopspell(lf, OT_S_SUMMONWEAPON); } @@ -18661,16 +18728,16 @@ int wear(lifeform_t *lf, object_t *o) { enum BODYPART bp; flag_t *retflag[MAXCANDIDATES]; int nretflags; + int showpos = B_FALSE; // this might impact your AR if (isplayer(lf)) { statdirty = B_TRUE; } - getobname(o, obname, 1); - // check for already equipped first! + // check if it is already equipped first! f = hasflag(o->flags, F_EQUIPPED); if (f) { if (isplayer(lf)) { @@ -18686,7 +18753,7 @@ int wear(lifeform_t *lf, object_t *o) { // metal objects and magshield? if (lfhasflag(lf, F_MAGSHIELD)) { if (isplayer(lf)) { - msg("^wYour %s evades your grasp!", noprefix(buf)); + msg("^wYour %s evades your grasp!", noprefix(obname)); } return B_TRUE; } @@ -18712,13 +18779,45 @@ int wear(lifeform_t *lf, object_t *o) { bp = possbp[0]; } else { // multiple possible locations int i; - // go in first possible place - bp = BP_NONE; - for (i = 0; i < nparts; i++) { - if (!hasobwithflagval(lf->pack, F_EQUIPPED, possbp[i], NA, NA, NULL)) { - bp = possbp[i]; - break; + + showpos = B_TRUE; + + // rings go in first possible place + if (o->type->obclass->id == OC_RING) { + bp = BP_NONE; + for (i = 0; i < nparts; i++) { + if (!hasobwithflagval(lf->pack, F_EQUIPPED, possbp[i], NA, NA, NULL)) { + bp = possbp[i]; + break; + } } + + if ((bp == BP_NONE) && isplayer(lf)) msg("You have no room to wear that."); + } else { + char ch = 'a'; + // ask where to put it + snprintf(buf, BUFLEN, "Where will you wear %s?",obname); + initprompt(&prompt, buf); + for (i = 0; i < nparts; i++) { + object_t *inway; + inway = getequippedob(lf->pack, possbp[i]); + if (inway) { + char inwayname[BUFLEN]; + getobname(inway, inwayname, inway->amt); + snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(possbp[i]), inwayname); + } else { + snprintf(buf, BUFLEN, "%s", getbodypartname(possbp[i])); + } + addchoice(&prompt, ch++, buf, NULL, &possbp[i]); + } + addchoice(&prompt, '-', "(cancel)", NULL, NULL); + ch = getchoice(&prompt); + + if (ch == '-') { + bp = BP_NONE; + + if (isplayer(lf)) msg("Cancelled."); + } else bp = *((enum BODYPART *)prompt.result); } if (bp == BP_NONE) { if (isplayer(lf)) { @@ -18859,7 +18958,11 @@ int wear(lifeform_t *lf, object_t *o) { if ((gamemode == GM_GAMESTARTED) && lf->created) { if (isplayer(lf)) { - msg("You are now wearing %s.", obname); + if (showpos) { + msg("You are now wearing %s (%s your %s).", obname, getbodypartequipname(bp), getbodypartname(bp)); + } else { + msg("You are now wearing %s.", obname); + } } else if (cansee(player, lf)) { getlfname(lf, buf); capitalise(buf); @@ -19192,6 +19295,17 @@ int weild(lifeform_t *lf, object_t *o) { return B_FALSE; } +int willbleedfrom(lifeform_t *lf, enum BODYPART bp) { + object_t *o; + o = getequippedob(lf->pack, bp); + if (o && (o->type->id == OT_BANDAGE)) { + // don't bleed. + return B_FALSE; + } + return B_TRUE; +} + + // will the lf flee after taking damage? int willflee(lifeform_t *lf) { enum ATTRBRACKET iqb; diff --git a/lf.h b/lf.h index b2207f6..503b768 100644 --- a/lf.h +++ b/lf.h @@ -22,6 +22,7 @@ void autoweild(lifeform_t *lf); int appearsrandomly(enum RACE rid); void awardxpfor(lifeform_t *killed, float pct); void bleed(lifeform_t *lf, int splatter); +int bleedfrom(lifeform_t *lf, enum BODYPART bp, int splatter); void breakgrabs(lifeform_t *lf, int fromme, int tome); long calcscore(lifeform_t *lf); int calcxp(lifeform_t *lf); @@ -203,6 +204,7 @@ char *getskilldesc(enum SKILL id ); char *getskillname(enum SKILL id ); char *getskilllevelname(enum SKILLLEVEL sl); int getthrowspeed(int str); +int getturnspeed(lifeform_t *lf); void getwantdistance(lifeform_t *lf, int *min, int *max, int attacking); object_t *getweapon(lifeform_t *lf); long getxpforlev(int level); @@ -267,6 +269,7 @@ int isprone(lifeform_t *lf); flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt); flag_t *isresting(lifeform_t *lf); object_t *isstuck(lifeform_t *lf); +int issmellablelf(lifeform_t *lf); int isswimming(lifeform_t *lf); int isundead(lifeform_t *lf); flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); @@ -358,5 +361,6 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose); int validateraces(void); int wear(lifeform_t *lf, object_t *o); int weild(lifeform_t *lf, object_t *o); +int willbleedfrom(lifeform_t *lf, enum BODYPART bp); int willflee(lifeform_t *lf); //int youhear(cell_t *c, char *text); diff --git a/map.c b/map.c index d0ee113..8405c4e 100644 --- a/map.c +++ b/map.c @@ -4532,19 +4532,13 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { int nretflags; int i; // handle scanner - f = lfhasflag(player, F_DETECTLIFE); - if (f) { - if (c->lf) { + if (c->lf) { + f = lfhasflag(player, F_DETECTLIFE); + if (f) { if (getcelldistorth(player->cell, c) <= f->val[0]) { *thing = c->lf; if (f->val[1] == B_TRUE) { - if (desc) { - real_getlfnamea(c->lf, desc, B_FALSE); - strcat(desc, " (detected)"); - } - if (glyph) { - *glyph = *(getlfglyph(c->lf)); - } + set_scanned_glyph(TT_MONSTER, c->lf, " (detected)", desc, glyph); } else { if (desc) { char *p; @@ -4560,7 +4554,22 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { return TT_MONSTER; } } + f = lfhasflag(player, F_ENHANCESMELL); + if (f && issmellablelf(c->lf)) { + if (getcelldistorth(player->cell, c) <= f->val[0]) { + set_scanned_glyph(TT_MONSTER, c->lf, " (smelled)", desc, glyph); + *thing = c->lf; + return TT_MONSTER; + } + } + if (lfhasflagval(player, F_CANHEARLF, c->lf->id, NA, NA, NULL)) { + // can hear them using master level listen skill? + set_scanned_glyph(TT_MONSTER, c->lf, " (heard)", desc, glyph); + *thing = c->lf; + return TT_MONSTER; + } } + f = lfhasflag(player, F_DETECTMETAL); if (f) { if (getcelldistorth(player->cell, c) <= f->val[0]) { @@ -4587,30 +4596,17 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { } } } - } + } // end if hasflag detectmetal - // can hear them using master level listen skill? - if (c->lf && lfhasflagval(player, F_CANHEARLF, c->lf->id, NA, NA, NULL)) { - if (glyph) { - *glyph = *(getlfglyph(c->lf)); - } - if (desc) { - real_getlfnamea(c->lf, desc, B_FALSE); - strcat(desc, " (heard)"); - } - - *thing = c->lf; - return TT_MONSTER; - } // get list of all detected ob ids. - getflags(player->flags, retflag, &nretflags, F_DETECTOBS, F_NONE); + getflags(player->flags, retflag, &nretflags, F_DETECTOBS, F_ENHANCESMELL, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; if (getcelldistorth(player->cell, c) <= f->val[0]) { object_t *o; for (o = c->obpile->first ; o ; o = o->next) { - if ((f->val[1] == NA) || (o->type->id == f->val[1])) { + if ((f->id == F_DETECTOBS) && ((f->val[1] == NA) || (o->type->id == f->val[1]))) { if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_DOOR)) { *thing = o; if (glyph) { @@ -4626,6 +4622,10 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { } return TT_OBJECT; } + } else if ((f->id == F_ENHANCESMELL) && issmellableob(o)) { + *thing = o; + set_scanned_glyph(TT_OBJECT, o, " (smelled)", desc, glyph); + return TT_OBJECT; } } } @@ -5089,6 +5089,28 @@ int remove_deadends(map_t *m, int howmuch) { return count; } +void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph) { + if (targettype == TT_MONSTER) { + if (desc) { + real_getlfnamea((lifeform_t *)what, desc, B_FALSE); + strcat(desc, descappend); + } + if (glyph) { + *glyph = *(getlfglyph((lifeform_t *) what)); + } + } else if (targettype == TT_OBJECT) { + object_t *o; + o = (object_t *)what; + if (desc) { + getobname(o, desc, o->amt); + strcat(desc, descappend); + } + if (glyph) { + *glyph = *(getglyph(o)); + } + } +} + void setcellknown(cell_t *cell, int forcelev) { enum SKILLLEVEL slev; diff --git a/map.h b/map.h index 4270272..37788b8 100644 --- a/map.h +++ b/map.h @@ -121,6 +121,7 @@ void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong); void mapentereffects(map_t *m); enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob); int remove_deadends(map_t *m, int howmuch); +void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph); void setcellknown(cell_t *cell, int forcelev); void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype); void setcelltype(cell_t *cell, enum CELLTYPE id); diff --git a/move.c b/move.c index 17f2fe3..568b89a 100644 --- a/move.c +++ b/move.c @@ -346,13 +346,26 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) { } enum RELATIVEDIR getrelativedir(lifeform_t *lf, int dir) { - int diff; - diff = abs(lf->facing - dir); - if (diff <= 1) { - return RD_FORWARDS; - } else if (diff == 2) { - return RD_SIDEWAYS; - } + int tempdir; + + // facing N, dir N == forwards + if (lf->facing == dir) return RD_FORWARDS; + + // facing N, dir NE == forwards + tempdir = lf->facing + 1; if (tempdir > DC_NW) tempdir -= MAXDIR_COMPASS; + if (tempdir == dir) return RD_FORWARDS; + // facing N, dir NW == forwards + tempdir = lf->facing - 1; if (tempdir < DC_N) tempdir += MAXDIR_COMPASS; + if (tempdir == dir) return RD_FORWARDS; + + // facing N, dir E == sideways + tempdir = lf->facing + 2; if (tempdir > DC_NW) tempdir -= MAXDIR_COMPASS; + if (tempdir == dir) return RD_SIDEWAYS; + // facing N, dir W == sideways + tempdir = lf->facing - 2; if (tempdir < DC_N) tempdir += MAXDIR_COMPASS; + if (tempdir == dir) return RD_SIDEWAYS; + + // anything else is backwards return RD_BACKWARDS; } @@ -897,8 +910,9 @@ int moveeffects(lifeform_t *lf) { if (isbleeding(lf)) { if (lfhasflagval(lf, F_INJURY, NA, BP_LEGS, DT_SLASH, NULL)) { - bleed(lf, B_FALSE); - losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); + if (!bleedfrom(lf, BP_LEGS, B_FALSE)) { + losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); + } } else { if (rnd(1,2) == 1) { bleed(lf, B_FALSE); @@ -2156,18 +2170,21 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { int moveok; int rndmove = B_FALSE; int howlong; + int reldir; flag_t *f; howlong = getmovespeed(lf); + reldir = getrelativedir(lf, dir); + + // if the given dir is behind us, just turn. if (onpurpose && !strafe) { - // if the given dir is behind us, just turn. - if (getrelativedir(lf, dir) != RD_FORWARDS) { - howlong /= 2; - limit(&howlong, 1, NA); - setfacing(lf, dir); - taketime(lf, howlong); - return B_FALSE; + if (reldir != RD_FORWARDS) { + if (!lfhasflag(lf, F_AWARENESS)) { + setfacing(lf, dir); + taketime(lf, getturnspeed(lf)); + return B_FALSE; + } } } @@ -2258,8 +2275,8 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { moveto(lf, cell, rndmove ? B_FALSE : onpurpose, dontclearmsg); if (onpurpose) { // strafing sideways/backwards takes longer - if (strafe) { - switch (getrelativedir(lf, dir)) { + if (strafe && !lfhasflag(lf, F_AWARENESS)) { + switch (reldir) { case RD_SIDEWAYS: howlong = pctof(125, howlong); break; case RD_BACKWARDS: howlong = pctof(150, howlong); break; case RD_FORWARDS: diff --git a/nexus.c b/nexus.c index 05d560a..c896fc3 100644 --- a/nexus.c +++ b/nexus.c @@ -250,13 +250,13 @@ int main(int argc, char **argv) { // extra choices for some jobs if (j->id == J_WIZARD) { skill_t *sk; - initprompt(&prompt, "Select your spell specialty:"); + initprompt(&prompt, "Select your primary spell specialty:"); addchoice(&prompt, 'a', getskillname(SK_SS_AIR), NULL, findskill(SK_SS_AIR)); addchoice(&prompt, 'c', getskillname(SK_SS_COLD), NULL, findskill(SK_SS_COLD)); addchoice(&prompt, 'f', getskillname(SK_SS_FIRE), NULL, findskill(SK_SS_FIRE)); getchoice(&prompt); sk = (skill_t *) prompt.result; - giveskill(player, sk->id); + giveskilllev(player, sk->id, PR_BEGINNER); switch (sk->id) { case SK_SS_AIR: addflag(player->flags, F_CANCAST, OT_S_MIST, NA, NA, NULL); @@ -270,6 +270,30 @@ int main(int argc, char **argv) { default: break; } + initprompt(&prompt, "Select your secondary spell school:"); + addchoice(&prompt, 'd', getskillname(SK_SS_DIVINATION), NULL, findskill(SK_SS_DIVINATION)); + addchoice(&prompt, 'm', getskillname(SK_SS_MODIFICATION), NULL, findskill(SK_SS_MODIFICATION)); + addchoice(&prompt, 's', getskillname(SK_SS_SUMMONING), NULL, findskill(SK_SS_SUMMONING)); + addchoice(&prompt, 't', getskillname(SK_SS_TRANSLOCATION), NULL, findskill(SK_SS_TRANSLOCATION)); + getchoice(&prompt); + sk = (skill_t *) prompt.result; + giveskilllev(player, sk->id, PR_NOVICE); + switch (sk->id) { + case SK_SS_DIVINATION: + addflag(player->flags, F_CANCAST, OT_S_SIXTHSENSE, NA, NA, NULL); + break; + case SK_SS_MODIFICATION: + addflag(player->flags, F_CANCAST, OT_S_HOLDPORTAL, NA, NA, NULL); + break; + case SK_SS_SUMMONING: + addflag(player->flags, F_CANCAST, OT_S_FLOATINGDISC, NA, NA, NULL); + break; + case SK_SS_TRANSLOCATION: + addflag(player->flags, F_CANCAST, OT_S_APPORTATION, NA, NA, NULL); + break; + default: + break; + } } diff --git a/objects.c b/objects.c index a1be911..b056fd4 100644 --- a/objects.c +++ b/objects.c @@ -6465,7 +6465,6 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_VILLAGE, 100, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "small puddle of water"); modflag(lastot->flags, F_HASHIDDENNAME, NA, NA, NA, "clear potion"); - addot(OT_POT_HEALING, "potion of healing", "Restores 10-20 health to whoever drinks it.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); @@ -6552,6 +6551,14 @@ void initobjects(void) { // scrolls + addot(OT_SCR_AWARENESS, "scroll of awareness", "Mimics the effects of a 'heightened awareness' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); + addflag(lastot->flags, F_LINKSPELL, OT_S_AWARENESS, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + + addot(OT_SCR_CANINETRACKING, "scroll of canine tracking", "Mimics the effects of a 'canine tracking' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); + addflag(lastot->flags, F_LINKSPELL, OT_S_CANINETRACKING, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addot(OT_SCR_REMOVECURSE, "scroll of remove curse", "Removes curses from all weilded equipment.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); @@ -6638,6 +6645,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); + addot(OT_SCR_TURNUNDEAD, "scroll of turn undead", "Instills fear in undead creatures.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_TURNUNDEAD, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_UNCOMMON, NULL); @@ -6797,30 +6805,45 @@ void initobjects(void) { // divination /////////////////// // l1 - addot(OT_S_DETECTLIFE, "detect life", "Senses the size of creatures near the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range."); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VI, exact creatures types are detected."); - addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); - // l2 addot(OT_S_LOCATEOBJECT, "locate object", "Locates any object within an area the caster has previously travelled.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addot(OT_S_SIXTHSENSE, "sixth sense", "Warns the caster of any creature attempting to sneak up behind them.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power III, the creature's species will be detected."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power V, the exact creature type will be detected."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); + // l2 + addot(OT_S_CANINETRACKING, "canine tracking", "Enhances the caster's sense of smell, allowing them to detect exact scents within a 3 cell radius.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Power determines the spell duration."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addot(OT_S_MAPPING, "sense surroundings", "Magically imbues the caster with a map of his/her surroundings.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range."); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addot(OT_S_DETECTLIFE, "detect life", "Senses the size of creatures within a 10-cell radius of the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range."); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power VIII, exact creatures types are detected."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); // l3 + addot(OT_S_AWARENESS, "heightened awareness", "This spell effectively gives the caster \"eyes in the back of their head\", expending their field of vision to a full 360 degrees.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addot(OT_S_DETECTOBS, "detect objects", "Senses objects near the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range and spell duration."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addot(OT_S_SEEINVIS, "see invisible", "Allows the caster to see invisible creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); - addot(OT_S_DETECTOBS, "detect objects", "Senses objects near the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the detection range and spell duration."); - addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINATION, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); // l4 addot(OT_S_DETECTAURA, "detect aura", "Senses holiness or evil near the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); @@ -7584,6 +7607,12 @@ void initobjects(void) { /////////////////// // translocation /////////////////// + // l1 + addot(OT_S_APPORTATION, "apportation", "Instantly transports a single visible object up to 10kg in weight to the caster's pack.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l2 addot(OT_S_BLINK, "blink", "Teleports the caster to a random location within view.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At Power VI you can choose where to blink to."); @@ -7879,6 +7908,12 @@ void initobjects(void) { addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); // tools + addot(OT_BANDAGE, "bandage", "A small medical bandage. When worn, it will counteract bleeding.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); + addot(OT_BLANKET, "wool blanket", "A warm wool blanket for those cold winter nights.", MT_CLOTH, 2, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); addflag(lastot->flags, F_HELPSREST, 10, NA, NA, NULL); @@ -8210,6 +8245,12 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 5, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); + addot(OT_STYPTIC, "styptic", "A medical compound designed to inhibit bleeding.", MT_METAL, 0.5, OC_TECH, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); + addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); // tech - l3 @@ -8259,8 +8300,6 @@ void initobjects(void) { // tech - l6 ??? - - // misc addot(OT_BONE, "bone", "A bone from an unknown creature.", MT_BONE, 0.1, OC_MISC, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, NULL); @@ -8908,10 +8947,10 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); - addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour. Designed to stop a bullet, but only once.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM); + addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour. Designed to stop a bullet, but ineffective against melee attacks.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); - addflag(lastot->flags, F_ARMOURRATING, 10, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); @@ -10471,6 +10510,13 @@ flag_t *isshield(object_t *o) { return hasflag(o->flags, F_SHIELD); } +int issmellableob(object_t *o) { + if (hasflag(o->flags, F_SMELLY)) { + return B_TRUE; + } + return B_FALSE; +} + int isthrownmissile(object_t *o) { if (hasflag(o->flags, F_THROWMISSILE)) { return B_TRUE; @@ -10900,6 +10946,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { object_t *o, *existob; int i,preburdened = B_FALSE; int db = B_FALSE; + int redrawaftermove = B_FALSE; flag_t *f; reason = E_OK; @@ -10932,6 +10979,16 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { preburdened = isburdened(dst->owner); } + // is the object moving FROM a cell that the player can see? + if (src->pile->where && haslos(player, src->pile->where)) { + if ((src->pile->where->lf) && !cansee(player, src->pile->where->lf)) { + redrawaftermove = B_TRUE; + } else { + redrawaftermove = B_TRUE; + } + } + + if (db) dblog("DB: moveob() - moving %d x %s",howmany, src->type->name); if (stackok) { existob = canstackob(dst, src); @@ -11016,7 +11073,11 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { } } - if (o && dst->where && !hasflag(o->flags, F_NOGLYPH) && haslos(player, dst->where)) { + if (redrawaftermove) { + needredraw = B_TRUE; + drawscreen(); + } else if (o && !hasflag(o->flags, F_NOGLYPH) && dst->where && haslos(player, dst->where)) { + // the object is moving to a cell that the player can see if ((dst->where->lf) && !cansee(player, dst->where->lf)) { // we can see the floor here // someone invisible there who we can't see @@ -11028,7 +11089,8 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { needredraw = B_TRUE; drawscreen(); } - } + } + // special effects when an object moves f = hasflag(o->flags, F_SHOPITEM); @@ -12305,6 +12367,41 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (!donesomething) { if (isplayer(lf)) msg("There is nothing to use your spanner on there!"); } + } else if (o->type->id == OT_STYPTIC) { + flag_t *retflag[MAXCANDIDATES]; + int i,nretflags = 0; + int donesomething = B_FALSE; + getflags(lf->flags, retflag, &nretflags, F_INJURY, F_NONE); + for (i = 0;i < nretflags; i++) { + switch (f->id) { + case IJ_ARTERYPIERCE: + case IJ_CHESTBLEED: + case IJ_HAMSTRUNG: + case IJ_HANDBLEED: + case IJ_LEGBLEED: + case IJ_EYELIDSCRAPED: + donesomething = B_TRUE; + killflag(f); + break; + default: break; + } + } + // fix bleeding too? + if (isbleeding(lf) == B_TRUE) { + donesomething = B_TRUE; + while (isbleeding(lf) == B_TRUE) { + gainhp(lf, 1); + } + } + + if (donesomething) { + if (isplayer(lf)) msg("^gThe styptic has stopped your wounds from bleeding."); + removeob(o, 1); + taketime(lf, getactspeed(lf)); + } else { + if (isplayer(lf)) msg("You are not bleeding right now."); + } + } else if (o->type->id == OT_TELEPAD) { map_t *m; cell_t *c,*dst = NULL; @@ -12887,7 +12984,6 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } break; case OT_POT_RUM: - // kill coffee flags killtransitoryflags(lf->flags, F_CAFFEINATED); if (lfhasflag(lf, F_CAFFEINATED)) { diff --git a/objects.h b/objects.h index f840b00..85b026c 100644 --- a/objects.h +++ b/objects.h @@ -180,6 +180,7 @@ int isreadable(object_t *o); int isrotting(object_t *o); flag_t *issecretdoor(object_t *o); flag_t *isshield(object_t *o); +int issmellableob(object_t *o); int isthrownmissile(object_t *o); int istried(object_t *o); int istriedot(objecttype_t *ot); diff --git a/spell.c b/spell.c index d0dfa28..920d9d1 100644 --- a/spell.c +++ b/spell.c @@ -2314,6 +2314,74 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { fizzle(caster); } + } else if (spellid == OT_S_APPORTATION) { + int failed = B_FALSE; + float maxweight; + + // if no target object... + if (!targob) { + // ask for a target cell (to take objects from) + if (!validatespellcell(caster, &targcell, TT_OBJECT, spellid, power, frompot)) return B_TRUE; + + if (targcell->obpile->first) { + // select object from cell... + targob = askobject(targcell->obpile, "Target which object", NULL, AO_NONE); + if (!targob) { + failed = B_TRUE; + } + } else { + failed = B_TRUE; + } + } + + if (!failed) { + char obname[BUFLEN]; + cell_t *obloc; + obloc = getoblocation(targob); + getobname(targob, obname, 1); + + targcell = caster->cell; + + // not liftable? + if (hasflag(targob->flags, F_NOPICKUP)) { + if (isplayer(caster)) { + nothinghappens(); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + return B_FALSE; + } + + // modify by power + maxweight = 10; + + if (getobweight(targob) > maxweight) { + if (haslos(player, obloc)) { + msg("%s fades out of view slightly, then reappears.",obname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + return B_FALSE; + } + + if (moveob(targob, caster->pack, 1)) { + if (isplayer(caster)) { + msg("%s appears in your pack!", obname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (haslos(player, obloc)) { + msg("%s vanishes!", obname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } else { + failed = B_TRUE; + } + } + + if (failed) { + fizzle(caster); + } + } else if (spellid == OT_S_AWARENESS) { + flag_t *f; + f = addtempflag(caster->flags, F_AWARENESS, B_TRUE, NA, NA, NULL, FROMSPELL); + f->obfrom = spellid; } else if (spellid == OT_S_BAFFLE) { if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = targcell->lf; @@ -2517,6 +2585,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (cansee(player, caster)) { needredraw = B_TRUE; } + } else if (spellid == OT_S_CANINETRACKING) { + int howlong; + howlong = getspellduration(20,30,blessed) + (power*10); + addtempflag(caster->flags, F_ENHANCESMELL, 4, NA, NA, NULL, howlong); } else if (spellid == OT_S_CONFISCATE) { char ch = 'a'; char obname[BUFLEN]; @@ -3484,7 +3556,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int howlong,radius; howlong = getspellduration(10,20,blessed) + (power*2); radius = power * 10; - addtempflag(target->flags, F_DETECTLIFE, 10, (power >= 5) ? B_TRUE : NA, NA, NULL, howlong); + addtempflag(target->flags, F_DETECTLIFE, 10, (power >= 8) ? B_TRUE : NA, NA, NULL, howlong); } else { // monsters can't use this } @@ -6646,6 +6718,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!shattercell(targcell, caster, buf)) { fizzle(caster); } + } else if (spellid == OT_S_SIXTHSENSE) { + if (isplayer(caster)) { + msg("You will now be warned of creatures behind you."); + } } else if (spellid == OT_S_SLEEP) { int howlong; if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE;