From 07844bb69e5a6cd8983967d8d5f8655193f30ab3 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Tue, 26 Jul 2011 02:01:05 +0000 Subject: [PATCH] * [+] operate a candlabrum on the ground confers permenant light producing! * [+] bug - water appearing in walls. - [+] make armour less common in forests - [+] too many --more--s when enhancing stats. use drawmsg() rather than more(). - [+] when i go up/down stairs, i keep ending up BESIDE them?? * [+] "you hear footstepszzzzzzzzzzzzzzzzzzzzzzz" (random junk) - [+] when i start training with a spell active, it gets interrupted. try again, interrupted again! works 3rd time. - [+] replace lockpicking with "locksmithing" - [+] replace 'body control' with 'slow metabolism' - [+] pit traps broken - fixed now. - [+] doheading issue in @M still. * [+] how did zombie get 28 hp? bug in rollhitdice. - [+] blind a skeleton with light. it gets blind, starts fleeing. but because it can't SEE you, it stops fleeing instantly! * [+] getflags(flagpile_t *fp, ... ) - [+] stun spell - [+] only say "x2" etc if msgbuf we are going to draw still contains the original text. - [+] when you level up, your psionic skill determines your chance of learning a new psionic spell? - [+] when you teleport/use stairs, get all allies in SIGHT, not adjacent. * [+] more traps! * [+] prisoners in cells - [+] recruitment: instead of outright refusing to join, just up the price. * [+] make spellbook contents depend on map difficulty - [+] cloak of shadows - give invisibility when in darkness * [+] limited wish: - [+] casting WISH reduces max hp by 50%! - [+] monster ai code: if inventory full (or close), put non-eqiupped stuff into containers * [+] infinite loop in firedam to lf - [+] pot of xp isn't working for monsters. they get no more hp!! - [+] summonmosnter should jsut relocate existing uniques - [+] 'planeshift' spell for gods - "unsummon"s them. * [+] diety - greedgod * [+] more village contents --- ai.c | 56 ++++- attack.c | 28 +-- defs.h | 29 ++- doc/colours.txt | 5 + doc/godnames | 1 + flag.c | 31 +++ flag.h | 1 + io.c | 84 +++++++- lf.c | 471 +++++++++++++++++++++++++++++----------- lf.h | 6 +- map.c | 8 +- move.c | 20 +- nexus.c | 14 +- objects.c | 546 ++++++++++++++++++++++++++++++++++------------- objects.h | 1 + spell.c | 438 ++++++++++++++++++++++++++++++++++--- spell.h | 2 +- vaults/jimbo.vlt | 1 + 18 files changed, 1401 insertions(+), 341 deletions(-) create mode 100644 doc/colours.txt create mode 100644 doc/godnames diff --git a/ai.c b/ai.c index 25b2f64..07027dd 100644 --- a/ai.c +++ b/ai.c @@ -603,7 +603,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { } else { // spell succesful - if (spell == OT_A_STEAL) { + if ((spell == OT_A_STEAL) && !lfhasflag(lf, F_NOFLEE)) { // run away for a few turns fleefrom(lf, spelllf, rnd(3,7), B_TRUE); } @@ -800,7 +800,7 @@ int aipickup(lifeform_t *lf, object_t *o) { if (isedible(o)) { return eat(lf, o); } else { - return pickup(lf, o, o->amt, B_TRUE); + return pickup(lf, o, o->amt, B_TRUE, B_TRUE); } return B_FALSE; } @@ -918,6 +918,53 @@ void aiturn(lifeform_t *lf) { // use items, talk,etc /////////////////////////////////////////////// + if ((lf->race->id == R_PRISONER) && master && isplayer(master) && cansee(lf, master)) { + if (isoutdoors(lf->cell->map) && pctchance(20)) { + object_t *o; + say(lf, "Thanks for getting me out!", SV_TALK); + o = addob(master->pack, "manual"); + if (o) { + char obname[BUFLEN]; + say(lf, "Here, let me teach you something as a reward.", SV_TALK); + getobname(o, obname, o->amt); + msgnocap("%c - %s", o->letter, obname); + } + killflagsofid(lf->flags, F_PETOF); + } + } + + // too many objects? + i = countobs(lf->pack, B_FALSE); + if (i >= (MAXPILEOBS - 5)) { + object_t *container; + // get largest container with space + container = getbestcontainer(lf->pack); + if (container) { + object_t *o; + // find object which will fit + for (o = lf->pack->first ; o ; o = o->next) { + if ((o != container) && !isequipped(o) && obfits(o, container->contents)) { + // put it in. + moveob(o, container->contents, ALL); + if (cansee(player, lf)) { + char obname[BUFLEN]; + char lfname[BUFLEN]; + char containername[BUFLEN]; + // announce + getobname(o, obname, o->amt); + getobname(container, containername, 1); + getlfname(lf, lfname); + msg("%s puts %s into %s.", lfname, obname, containername); + } + // timetime + taketime(lf, getactspeed(lf)); + return; + } + } + + } + } + // talking f = lfhasflag(lf, F_RANDOMTALKPCT); if (f) { @@ -1572,6 +1619,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) { specificcheckok = B_FALSE; } + if ((ot->id == OT_A_STEAL) || (ot->id == OT_S_CONFISCATE)) { + if (!countobs(victim->pack, B_FALSE)) { + specificcheckok = B_FALSE; + } + } if ((ot->id == OT_A_SWOOP) || (ot->id == OT_A_CHARGE)) { flag_t *willflag; flag_t *srflag; diff --git a/attack.c b/attack.c index 3467947..39bd730 100644 --- a/attack.c +++ b/attack.c @@ -84,8 +84,10 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty actualdam *= multiplier; } - // actually apply the damage to the armour - damtaken = takedamage(armour,actualdam, damtype); + if (actualdam > 0) { + // actually apply the damage to the armour + damtaken = takedamage(armour,actualdam, damtype); + } } return damtaken; } @@ -351,15 +353,15 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } else if (attacktype == AT_OB) { if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break; } - } - attacksdone++; + attacksdone++; - // stop attacking if they somehow got out of range - // (eg. dodging) - if (attacktype == AT_LF) { - if (getcelldist(lf->cell, ((lifeform_t *)attacktarget)->cell) > 1) { - attacksdone = maxattacks; - break; + // stop attacking if they somehow got out of range + // (eg. dodging) + if (attacktype == AT_LF) { + if (getcelldist(lf->cell, ((lifeform_t *)attacktarget)->cell) > 1) { + attacksdone = maxattacks; + break; + } } } } @@ -789,7 +791,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } else if (lfhasflag(lf, F_QUIVERINGPALM)) { // victim explodes! - losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE); + losehp_real(victim, victim->hp, DT_EXPLOSIVE, lf, "a quivering palm strike", B_FALSE, NULL); } else { char attackername2[BUFLEN]; real_getlfname(lf, attackername2, B_FALSE); @@ -805,7 +807,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) strcpy(buf, attackername2); } - losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE); + losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE, NULL); // victim's armour loses hp if (reduceamt) { @@ -850,7 +852,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) char lfname[BUFLEN]; dam = rolldie(f->val[0], f->val[1]) + f->val[2]; real_getlfname(lf, lfname, B_FALSE); - losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE); + losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE, NULL); if (isplayer(victim) || cansee(player, victim)) { msg("^%c%s bites %s!", isplayer(victim) ? 'b' : 'n', lfname, victimname); } diff --git a/defs.h b/defs.h index 502fe8a..c64ed2b 100644 --- a/defs.h +++ b/defs.h @@ -47,6 +47,8 @@ enum NOISECLASS { enum SAYPHRASE { SP_BEG, + SP_BEGATTACK, + SP_BEGTHANKS, SP_DRUNK, SP_PAYWARN, SP_PAYTHREAT, @@ -641,6 +643,7 @@ enum RACECLASS { RC_ANIMAL, RC_AQUATIC, RC_DEMON, + RC_GOD, RC_HUMANOID, RC_INSECT, RC_SLIME, @@ -659,7 +662,10 @@ enum RACE { R_BANDIT, R_BEGGAR, R_DRUNK, + R_PRISONER, R_TOWNGUARD, + // gods + R_GODGREED, // monsters R_BEHOLDER, R_BUGBEAR, @@ -841,14 +847,20 @@ enum OBTYPE { // terrain OT_WATERDEEP, // traps + OT_TRAPALARM, OT_TRAPARROW, OT_TRAPARROWP, + OT_TRAPEBLAST, OT_TRAPFIRE, OT_TRAPGAS, OT_TRAPMINE, + OT_TRAPNEEDLEP, + OT_TRAPPIT, OT_TRAPROCK, + OT_TRAPSUMMON, OT_TRAPTELEPORT, OT_TRAPTRIP, + OT_TRAPWIND, // rocks / plants OT_GOLD, OT_STONE, @@ -1012,15 +1024,18 @@ enum OBTYPE { OT_S_HEALING, OT_S_HEALINGMIN, OT_S_HEALINGMAJ, + OT_S_SPEAKDEAD, OT_S_TURNUNDEAD, // -- mental / psionic - OT_S_BODYCONTROL, + OT_S_CHARM, + OT_S_HUNGER, OT_S_MINDSCAN, - OT_S_SLEEP, - OT_S_TELEKINESIS, + OT_S_LOWERMETAB, OT_S_PACIFY, OT_S_PSYARMOUR, - OT_S_CHARM, + OT_S_SLEEP, + OT_S_STUN, + OT_S_TELEKINESIS, // -- modification OT_S_DARKNESS, OT_S_ENCHANT, @@ -1076,6 +1091,7 @@ enum OBTYPE { OT_S_BLINK, OT_S_DISPERSAL, OT_S_GATE, + OT_S_PLANESHIFT, OT_S_SUCK, OT_S_TELEPORT, OT_S_TWIDDLE, @@ -1090,7 +1106,9 @@ enum OBTYPE { OT_S_CREATEVAULT, OT_S_GIFT, OT_S_WISH, + OT_S_WISHLIMITED, OT_A_BLINDALL, + OT_S_CONFISCATE, OT_A_DEBUG, OT_A_ENHANCE, OT_A_LEARN, @@ -1153,6 +1171,7 @@ enum OBTYPE { OT_PICKAXE, OT_ROPE, OT_SACK, + OT_SACKHUGE, OT_SAFEBOX, OT_TORCH, OT_TOWEL, @@ -1559,6 +1578,7 @@ enum FLAG { F_NOBLESS, // can't be blessed or cursed F_NOQUALITY, // can't be masterwork / shoddy F_CORPSEOF, // this is a corpse of montype val0. + // text is how it died. F_DTCONVERT, // damtype val0 converts this to f->text F_DTCREATEOB, // damtype val0 creates object f->text here // v1 = radius to burst in @@ -1977,6 +1997,7 @@ enum FLAG { F_HITDICE, // val0: # d4 to roll for maxhp per level. val1: +xx F_MPDICE, // val0: # d4 to roll for maxmp per level. val1: +xx F_JOB, // val0 = player's class/job + F_GODOF, // text = what this lf is the god of. use capitals. F_NAME, // text = lf's name F_XPMOD, // add/subtract this much from calculated xpval F_BLOODOB, // text = type of object to drop for blood diff --git a/doc/colours.txt b/doc/colours.txt new file mode 100644 index 0000000..d270a1c --- /dev/null +++ b/doc/colours.txt @@ -0,0 +1,5 @@ +^B very bad +^b bad +^w warning +^g good +^G very good diff --git a/doc/godnames b/doc/godnames new file mode 100644 index 0000000..d1272a1 --- /dev/null +++ b/doc/godnames @@ -0,0 +1 @@ +Avamon God of greed (neutral) diff --git a/flag.c b/flag.c index 6104464..aa10fe7 100644 --- a/flag.c +++ b/flag.c @@ -10,6 +10,9 @@ #include "spell.h" #include "text.h" +flag_t *retflag[MAXCANDIDATES]; +int nretflags; + extern enum GAMEMODE gamemode; extern int needredraw; extern int statdirty; @@ -1016,6 +1019,34 @@ void timeeffectsflag(flag_t *f, int howlong) { } } +// populates retflag & nretflags with matching flags +int getflags(flagpile_t *fp, ... ) { + va_list flags; + enum FLAG wantflag[MAXCANDIDATES]; + int nwantflags,i; + flag_t *f; + + va_start(flags, fp); + nwantflags = 0; + wantflag[nwantflags] = va_arg(flags, enum FLAG); + while (wantflag[nwantflags] != F_NONE) { + nwantflags++; + wantflag[nwantflags] = va_arg(flags, enum FLAG); + } + va_end(flags); + + // now populate retflag[] with matches flags + nretflags = 0; + for (i = 0; i < nwantflags; i++) { + f = hasflag(fp, wantflag[i]); + while (f && (f->id == wantflag[i])) { + retflag[nretflags++] = f; + f = f->next; + } + } + return nretflags; +} + int modcounter(flagpile_t *fp, int amt) { flag_t *f; f = hasflag(fp, F_COUNTER); diff --git a/flag.h b/flag.h index 2ee6296..762ce6d 100644 --- a/flag.h +++ b/flag.h @@ -14,6 +14,7 @@ int countflags(flagpile_t *fp); int flagcausesredraw(lifeform_t *lf, enum FLAG fid); int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid); int flagstacks(enum FLAG fid); +int getflags(flagpile_t *fp, ... ); int modcounter(flagpile_t *fp, int amt); flag_t *hasflag(flagpile_t *fp, int id); flag_t *hasflagknown(flagpile_t *fp, int id); diff --git a/io.c b/io.c index 1072b22..ae359b7 100644 --- a/io.c +++ b/io.c @@ -1174,7 +1174,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { objecttype_t *ot; ot = findot(f->val[0]); if (ot) { - msg("^gYou have learned the spell '%s'.", ot->name); + enum SPELLSCHOOL school; + school = getspellschoolknown(lf, ot->id); + msg("^gYou have learned the %s '%s'.", + (school = SS_MENTAL) ? "psionic power" : "spell", ot->name); donesomething = B_TRUE; } } @@ -1392,7 +1395,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { lf2 = findlf(NULL, f->val[0]); if (lf2) { getlfname(lf2, buf); - msg("^w%s %s %s!",buf, isplayer(lf2) ? "grab" : "grabs", lfname); + msg("^%c%s %s %s!",getlfcol(lf, CC_VBAD), buf, isplayer(lf2) ? "grab" : "grabs", lfname); donesomething = B_TRUE; } break; @@ -3956,6 +3959,7 @@ void doclose(void) { void docomms(lifeform_t *lf) { cell_t *where; + int i; char buf[BUFLEN]; char lfname[BUFLEN]; char ch; @@ -4008,7 +4012,15 @@ void docomms(lifeform_t *lf) { addchoice(&prompt, '>', "Keep your distance.", NULL, NULL); } } else if (ishirable(lf) ) { - addchoice(&prompt, 'j', "Join me on my quest!", NULL, NULL); + if (lf->race->id == R_PRISONER) { + addchoice(&prompt, 'j', "Join me, and I will help you escape.", NULL, NULL); + } else { + addchoice(&prompt, 'j', "Join me on my quest!", NULL, NULL); + } + } + + if ((lf->race->id == R_BEGGAR) && countmoney(player)) { + addchoice(&prompt, 'd', "(donate a gold coin)", NULL, NULL); } f = lfhasflag(lf, F_OWNSSHOP); @@ -4060,6 +4072,57 @@ void docomms(lifeform_t *lf) { aigoto(lf, c, MR_OTHER, NULL, AI_FOLLOWTIME); } break; + case 'd': // donate to beggar + givemoney(player, lf, 1); // we already checked that we had enough. + if (countmoney(lf) == 1) { + i = rnd(1,100); + if (i <= 5) { // attack you + sayphrase(lf, SP_BEGATTACK, SV_SHOUT, NA, NULL); + fightback(lf, player); + } else if (i <= 10) { // limited wish + // change to a god. + setrace(lf, R_GODGREED, B_TRUE); + // behold! i am me! + say(lf, "Behold mortal! It is I, Avamon!", SV_SHOUT); + say(lf, "For your selfless act, I grant you a wish.", SV_TALK); + // grant a wish. + castspell(lf, OT_S_WISHLIMITED, player, NULL, NULL); + say(lf, "Until next time, mortal!", SV_TALK); + unsummon(lf, B_TRUE); + } else if (i <= 20) { // identify + object_t *poss[MAXPILEOBS],*o; + int nposs = 0; + sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); + // get random unknown item from player's pack + for (o = player->pack->first ; o ; o = o->next){ + if (!isknown(o)) { + poss[nposs++] = o; + } + } + if (nposs) { + char oldobname[BUFLEN]; + char newobname[BUFLEN]; + o = poss[rnd(0,nposs-1)]; + + getobname(o, oldobname, o->amt); + makeknown(o->type->id); + getobname(o, newobname, o->amt); + msg("%s points at your pack.", lfname); + msg("Hey I recognise %s %s.", + (o->amt == 1) ? "that" : "those", + oldobname); + msg("%s %s.", + (o->amt == 1) ? "It's" : "They're", + newobname); + } + } else { // nothing + sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); + } + } else { + // they already had some money + sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL); + } + break; case 'g': sprintf(buf, "Tell %s to go where?",lfname); sprintf(buf2, "%s->Goto->",lfname); @@ -5025,7 +5088,7 @@ int dopickup(obpile_t *op, int forceask) { } for (i = 0; i < nretobs; i++) { - pickup(player, retobs[i],retobscount[i], B_TRUE); + pickup(player, retobs[i],retobscount[i], B_TRUE, B_TRUE); } /* @@ -5724,12 +5787,14 @@ void drawlevelfor(lifeform_t *lf) { } void doheading(WINDOW *win, int *y, int x, char *what) { - int len; + int len,i; char *buf; len = strlen(what) + 1; buf = malloc(len * sizeof(char)); - memset(buf, '-', (size_t)(len-1)); - buf[len] = '\0'; + for (i = 0; i < len; i++) { + buf[i] = '-'; + } + buf[i] = '\0'; setcol(win, C_WHITE); mvwprintw(win, *y, x, what); (*y)++; mvwprintw(win, *y, x, buf); (*y)++; @@ -6850,7 +6915,10 @@ void msg_real(char *format, ... ) { vsprintf( buf, format, args ); va_end(args); - if (streq(buf, prevmsg) && !strchr(buf, '^')) { + assert(buf[0] != '\0'); + + // ie repeat of previous message, doesn't have colours, prev msg still on screen + if (streq(buf, prevmsg) && !strchr(buf, '^') && strstr(msgbuf, prevmsg)) { msgmulti++; sprintf(buf, "x%d",msgmulti); } else { diff --git a/lf.c b/lf.c index 782491a..fa59c91 100644 --- a/lf.c +++ b/lf.c @@ -27,6 +27,9 @@ extern skill_t *firstskill, *lastskill; extern objecttype_t *objecttype; extern lifeform_t *player; +extern flag_t *retflag[]; +extern int nretflags; + extern glyph_t playerglyph; extern glyph_t tempglyph; @@ -821,6 +824,7 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) { flag_t *f; int xray = 0; int dist; + int tremordist; if (gamemode < GM_GAMESTARTED) { return B_TRUE; @@ -836,6 +840,16 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) { xray = 0; } dist = getcelldist(viewer->cell, viewee->cell); + f = lfhasflag(viewer, F_TREMORSENSE); + if (f) { + if (f->val[0] > 0) { + tremordist = f->val[0]; + } else { + tremordist = dist; + } + } else { + tremordist = -1; + } // viewer asleep? if (lfhasflag(viewer, F_ASLEEP)) { @@ -852,11 +866,21 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) { // viewee is invisible? if (lfhasflag(viewee, F_INVISIBLE)) { - if (!lfhasflag(viewer, F_SEEINVIS)) { + if (!lfhasflag(viewer, F_SEEINVIS) && (tremordist < dist)) { return B_FALSE; } } + // cloak of shadows? + o = getequippedob(viewee->pack, BP_SHOULDERS); + if (o && hasflagval(o->flags, F_HASBRAND, BR_SHADOWS, NA, NA, NULL)) { + if (!islit(viewee->cell)) { + if (!lfhasflag(viewer, F_SEEINVIS) && (tremordist < dist)) { + return B_FALSE; + } + } + } + // viewee hiding? if (lfhasflag(viewee, F_HIDING) && (viewee != viewer)) { if (!lfhasflagval(viewer, F_SPOTTED, viewee->id, NA, NA, NULL)) { @@ -1780,6 +1804,13 @@ void die(lifeform_t *lf) { addflag(corpse->flags, f->val[0], f->val[1], f->val[2], NA, f->text); } } + + // remember what killed us. + f = hasflag(corpse->flags, F_CORPSEOF); + if (f) { + free(f->text); + f->text = strdup(lf->lastdam); + } } @@ -2486,6 +2517,7 @@ void enhanceskills(lifeform_t *lf) { char ch = 'a'; int newskillcost = 1; float hpratio,mpratio; + enum SKILLLEVEL slev; lf->level = lf->newlevel; @@ -2547,7 +2579,7 @@ void enhanceskills(lifeform_t *lf) { drawstatus(); wrefresh(statwin); // wait for player to acknowledge 'you feel stronger' etc - more(); + drawmsg(); // TODO: this use to be more() } f = lfhasflag(lf, F_STATGAINREADY); } @@ -2842,6 +2874,27 @@ void enhanceskills(lifeform_t *lf) { } } + // psionics sometimes lets you learn spells + slev = getskill(lf, SK_SS_MENTAL); + if (pctchance(slev*10)) { + // construct list of castable mental spells + makespellchoicelist(&prompt, lf, "Learn which new psionic power:","Describe which psionic power:", SS_MENTAL, B_TRUE, B_FALSE, player->maxmp); + if (prompt.nchoices > 0) { + objecttype_t *ot; + msg("You have developed a new psionic power!"); more(); + getchoicestr(&prompt, B_TRUE, B_TRUE); + ot = prompt.result; + if (ot) { + if (prompt.whichq == 0) { // learn the spell + addflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL); + } else { + describespell(ot); + } + } + } + + } + killflagsofid(lf->flags, F_HASNEWLEVEL); // ready for another level? @@ -3029,6 +3082,17 @@ lifeform_t *findlf(map_t *m, int lfid) { return NULL; } +lifeform_t *findlfunique(enum RACE rid) { + lifeform_t *lf; + map_t *thismap; + for (thismap = firstmap ; thismap ; thismap = thismap->next) { + for (lf = thismap->lf ; lf ; lf = lf->next) { + if (lf->race->id == rid) return lf; + } + } + return NULL; +} + race_t *findrace(enum RACE id) { race_t *r; for (r = firstrace; r ; r = r->next) { @@ -3151,8 +3215,10 @@ int flee(lifeform_t *lf) { // a certain time period (ie. f->lifetime == PERMENANT), we can now stop fleeing. if (f->lifetime == PERMENANT) { killflag(f); + } else { + // if the flag is temporary, wait for it to time out normally + fleefrom = thisone; } - // if the flag is temporary, wait for it to time out normally } } } @@ -3161,6 +3227,9 @@ int flee(lifeform_t *lf) { // found someone who we are fleeing from? if (fleefrom) { object_t *stairs; + + breakallgrabs(lf); + // ways of fleeing other than movement? if (!isplayer(lf)) { enum OBTYPE spell; @@ -3478,23 +3547,38 @@ int getactspeed(lifeform_t *lf) { } // include allies or enemies which will follow you up/down stairs etc +// ie. allies within LOS +// ie. adjacent enemies void getadjallies(lifeform_t *lf, object_t *stairob, lifeform_t **adjally, int *nadjallies) { - int d; - for (d = DC_N; d <= DC_NW; d++) { - cell_t *c; - c = getcellindir(lf->cell, d); - if (c && c->lf) { - if (areallies(lf, c->lf) || areenemies(lf, c->lf)) { + int x,y; + for (y = 0; y < lf->cell->map->h; y++) { + for (x = 0; x < lf->cell->map->w; x++) { + cell_t *c; + c = getcellat(lf->cell->map, x, y); + if (c && c->lf && (c->lf != lf)) { if (!isimmobile(c->lf) && cansee(c->lf, lf)) { - int ok = B_TRUE; - // if this was a pit, only flying things will follow - if (stairob && hasflag(stairob->flags, F_PIT)) { - if (!lfhasflag(c->lf, F_FLYING)) { - ok = B_FALSE; + int ok = B_FALSE; + if (areallies(lf, c->lf) && haslof(c->lf->cell, lf->cell, LOF_WALLSTOP, NULL)) { + // ally with a clear path to you + ok = B_TRUE; + } else if (areenemies(lf, c->lf) && (getcelldist(c, lf->cell) == 1)) { + // adjacent enemy + ok = B_TRUE; + } + + if (ok) { + // if this was a pit, only flying things will follow + if (stairob && hasflag(stairob->flags, F_PIT)) { + if (!lfhasflag(c->lf, F_FLYING)) { + ok = B_FALSE; + } + } + + if (ok) { // still ok? + adjally[*nadjallies] = c->lf; + (*nadjallies)++; } } - adjally[*nadjallies] = c->lf; - (*nadjallies)++; } } } @@ -4352,6 +4436,8 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { // get weapon if (wep) { acc = getobaccuracy(wep, lf); + } else { + acc = 100; // fists } // dual weilding? @@ -7493,6 +7579,8 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_FIRSTAID, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_RANGED, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); // abilities @@ -7547,7 +7635,7 @@ void initjobs(void) { addflag(lastjob->flags, F_LEVFLAG, 2, F_MPDICE, 1, NULL); addflag(lastjob->flags, F_LEVSPELL, 2, OT_S_CALMANIMALS, NA, NULL); // 2: body control - low metabolism - addflag(lastjob->flags, F_LEVSPELL, 3, OT_S_BODYCONTROL, NA, NULL); + addflag(lastjob->flags, F_LEVSPELL, 3, OT_S_LOWERMETAB, NA, NULL); // 4: self-healing (mp), immune to haste/slow (innate) addflag(lastjob->flags, F_LEVFLAG, 4, F_DISEASEIMMUNE, B_TRUE, NULL); addflag(lastjob->flags, F_LEVABIL, 5, OT_A_HEAVYBLOW, 3, NULL); @@ -7795,6 +7883,7 @@ void initrace(void) { 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); + addraceclass(RC_GOD, "god", "dieties", SK_NONE); addraceclass(RC_HUMANOID, "humanoid", "humanoid creatures", SK_LORE_HUMANOID); addraceclass(RC_INSECT, "insect", "insects and animals", SK_LORE_NATURE); addraceclass(RC_MAGIC, "magical creature", "magical creatures", SK_LORE_ARCANA); @@ -7856,6 +7945,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTJOB, 75, J_RANDOM, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); // human monsters... addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); @@ -7917,6 +8007,22 @@ void initrace(void) { f = addflag(lastrace->flags, F_DRUNK, 5, NA, NA, NULL); addcondition(f, FC_NOCONDITION, 30); addaltval(f, F_DRUNK, 3, NA, NA, NULL); + + addrace(R_PRISONER, "prisoner", 60, '@', C_GREY, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-2 stones"); + addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HIREPRICE, 0, NA, NA, NULL); + addrace(R_TOWNGUARD, "town guard", 100, '@', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "12-18"); @@ -7943,6 +8049,38 @@ void initrace(void) { addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + // gods + addrace(R_GODGREED, "Avamon", 300, '@', C_BOLDMAGENTA, MT_FLESH, RC_GOD); + addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "20"); + addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "10"); + addflag(lastrace->flags, F_STARTATT, A_WIS, NA, NA, "9"); + addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "10"); + addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "8"); + addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "6"); + addflag(lastrace->flags, F_DONTSTARTASLEEP, NA, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed ring of hunger"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 huge sacks"); + //addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_RARITY, NA, NA, NULL); // ie. everything + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "waves his hand"); + // god abilities + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Greed"); + addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_OBESE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_CALLWIND, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_CONFISCATE, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_WISHLIMITED, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_HUNGER, NA, NA, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); + // monsters addrace(R_BEHOLDER, "beholder", 5, 'e', C_MAGENTA, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VHIGH, NA, NULL); @@ -9315,7 +9453,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NUMAPPEAR, 2, 8, NA, ""); + addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); @@ -9981,13 +10119,14 @@ void initrace(void) { // undead addrace(R_ZOMBIE, "zombie", 50, 'Z', C_BLUE, MT_FLESH, RC_UNDEAD); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "6"); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); - addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, 2, 4, 1, NULL); + addflag(lastrace->flags, F_HITDICE, 2, 4, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); @@ -10421,9 +10560,15 @@ int isingunrange(lifeform_t *lf, cell_t *where) { return B_FALSE; } +int isgod(lifeform_t *lf) { + if (lf->race->raceclass->id == RC_GOD) return B_TRUE; + if (hasjob(lf, J_GOD)) return B_TRUE; + return B_FALSE; +} + // can you try to recruit this lf? int ishirable(lifeform_t *lf) { - if (!isplayer(lf) && ispeaceful(lf) && lfhasflag(lf, F_JOB)) { + if (!isplayer(lf) && ispeaceful(lf)) { if (lfhasflag(lf, F_HIRABLE)) { return B_TRUE; } @@ -11151,8 +11296,10 @@ void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) { msg("^b%s %ss you!", buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp)); } else if (cansee(player, lf)) { char lfname[BUFLEN]; + char buf2[BUFLEN]; getlfname(lf, lfname); - msg("^c%s %ss %s!", getlfcol(lf, CC_BAD), buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname); + sprintf(buf2, "^%c%s %ss %s!", getlfcol(lf, CC_BAD), buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname); + msg("%s", buf2); } } } @@ -11607,10 +11754,10 @@ void loseconcentration(lifeform_t *lf) { // lose hp, and adjust damage based on resistances int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc) { - return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE); + return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE, NULL); } -int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam) { +int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob) { char buf[BUFLEN]; char buf2[BUFLEN]; char lfname[BUFLEN]; @@ -11800,7 +11947,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } // elemental effects on held objects - if (damtype == DT_FIRE) { + if ((damtype == DT_FIRE) && !fromob) { object_t *o, *nexto; // fire: dam*10 chance of burning each object which is vulnerable to fire for (o = lf->pack->first ; o ; o = nexto) { @@ -11813,7 +11960,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml takedamage(o, newdam, DT_FIRE); } } - } else if (damtype == DT_COLD) { + } else if ((damtype == DT_COLD) && !fromob) { object_t *o, *nexto; // cold: dam*10 chance of shattering potions, or damaging other things. for (o = lf->pack->first ; o ; o = nexto) { @@ -12254,7 +12401,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha // something, its ->cell will be null here! dist = getcelldist(l->cell, c); - if ((l != noisemaker) && (l->cell)) { + if (l != noisemaker) { int difficulty; int lbonus; //if (canhear(l, c) && haslos(l, c)) { @@ -12265,14 +12412,15 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha // you always hear it, as long as you're in range difficulty = 0; } else { - difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); + //difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); + difficulty = (int) ( ((float)getcelldist(l->cell, c) / ((float)gethearingrange(l) + volume)) * 20); } // listen bonus is the sound volume + lbonus = volume; if (lfhasflag(l, F_ASLEEP)) { - lbonus = 0; - } else { - lbonus = volume; + lbonus -= 5; + limit(&lbonus, 0, NA); } // skillcheck to hear this @@ -12294,9 +12442,11 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha char punc; int dist; - punc = text[strlen(text)-1]; - strncpy(textnopunc, text, strlen(text)-1); - textnopunc[strlen(text)] = '\0'; + //punc = text[strlen(text)-1]; + //strncpy(textnopunc, text, strlen(text)-1); + strcpy(textnopunc, text); + punc = textnopunc[strlen(textnopunc)-1]; + textnopunc[strlen(textnopunc)-1] = '\0'; dist = getcelldist(l->cell, c); @@ -12357,15 +12507,17 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha rv = B_TRUE; } // only hear one thing per turn. - addflag(l->flags, F_DONELISTEN, B_TRUE, NA, NA, NULL); - practice(l, SK_LISTEN, 1); + if (isplayer(l)) { + addflag(l->flags, F_DONELISTEN, B_TRUE, NA, NA, NULL); + practice(l, SK_LISTEN, 1); + } } } // wake up a little f = lfhasflag(l, F_ASLEEP); if (f) { if (f->lifetime > 0) { // ie. temporary - timeeffectsflag(f, rnd(1,10)); + timeeffectsflag(f, volume + rnd(1,3)); } else if (f->lifetime == PERMENANT) { if (f->val[2] == NA) { // ie asleep rather than 'resting' // wake up! @@ -12403,8 +12555,6 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha isplayer(l) ? "" : "s", isplayer(l) ? "your" : "its"); } - } else { - break; } } } @@ -12432,7 +12582,7 @@ void petify(lifeform_t *lf, lifeform_t *owner) { } -int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) { +int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int wantannounce) { char obname[BUFLEN]; object_t *o; //flag_t *f; @@ -12511,14 +12661,16 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) { // try to move whatever was selected o = moveob(what, lf->pack, howmany); if (o) { // if pickup was successful... - if (isplayer(lf)) { - // refresh obname to copd with stacking - getobname(o, obname, o->amt); - msgnocap("%c - %s",o->letter, obname); - } else if (cansee(player, lf)) { - char buf[BUFLEN]; - getlfname(lf, buf); - msg("%s picks up %s.",buf, obname); + if (wantannounce) { + if (isplayer(lf)) { + // refresh obname to copd with stacking + getobname(o, obname, o->amt); + msgnocap("%c - %s",o->letter, obname); + } else if (cansee(player, lf)) { + char buf[BUFLEN]; + getlfname(lf, buf); + msg("%s picks up %s.",buf, obname); + } } /* taketime(lf, (SPEED_PICKUP * howmany)); @@ -12677,25 +12829,26 @@ void practice(lifeform_t *lf, enum SKILL skid, int amt) { void precalclos(lifeform_t *lf) { int x,y; cell_t *c; + cell_t **los; int maxvisrange; - cell_t *los[MAX_MAPW * MAX_MAPH]; - int nlos; + int oldnlos = -1,nlos = 0; int i; + + los = malloc( sizeof(cell_t *) * (MAX_MAPW * MAX_MAPH)); // free existing structures if (lf->los) { - free(lf->los); + oldnlos = lf->nlos; + free(lf->los); lf->los = NULL; } - nlos = 0; - maxvisrange = getvisrange(lf); for (y = lf->cell->y - maxvisrange; y <= lf->cell->y + maxvisrange ; y++) { for (x = lf->cell->x - maxvisrange; x <= lf->cell->x + maxvisrange ; x++) { c = getcellat(lf->cell->map, x, y); // - if ((c != lf->cell) && haslos(lf, c)) { + if (c && (c != lf->cell) && haslos(lf, c)) { los[nlos] = c; nlos++; } @@ -12708,6 +12861,7 @@ void precalclos(lifeform_t *lf) { lf->los[i] = los[i]; } lf->nlos = nlos; + free(los); } int push(lifeform_t *lf, object_t *o, int dir) { @@ -12766,7 +12920,11 @@ int readytotrain(lifeform_t *lf) { int recruit(lifeform_t *lf) { int rv = B_FALSE; - if (!lfhasflag(lf, F_NOHIRE)) { + if (lfhasflag(lf, F_NOHIRE)) { + // refusing to join at all. + sayphrase(lf, SP_RECRUIT_DECLINE, SV_TALK, NA, NULL); + rv = B_TRUE; + } else { int dohire = B_FALSE; int askingprice = -1; char lfname[BUFLEN]; @@ -12788,8 +12946,9 @@ int recruit(lifeform_t *lf) { addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL); } else { if (difficulty - result >= 10) { - // will never join - askingprice = -1; + // very expensive + askingprice = rnd(gethitdice(lf)*250, gethitdice(lf)*300 ); + addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL); } else { // expensive askingprice = rnd(gethitdice(lf)*100, gethitdice(lf)*200 ); @@ -12798,14 +12957,7 @@ int recruit(lifeform_t *lf) { } } - if (askingprice == -1) { - // refusing to join at all. - sayphrase(lf, SP_RECRUIT_DECLINE, SV_TALK, NA, NULL); - rv = B_TRUE; - if (!lfhasflag(lf, F_NOHIRE)) { - addflag(lf->flags, F_NOHIRE, B_TRUE, NA, NA, NULL); - } - } else { + if (askingprice != 0) { // modify by charisma askingprice = pctof(100 + getstatmod(player, A_CHA), askingprice); @@ -12821,22 +12973,25 @@ int recruit(lifeform_t *lf) { dohire = B_TRUE; } } + } else { + dohire = B_TRUE; + } - if (dohire) { - char *p = NULL; - petify(lf, player); + if (dohire) { + char *p = NULL; + petify(lf, player); - // give them a name - if (getjob(lf)) { - p = assignnpcname(lf); - } - sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p); + // give them a name + //if (getjob(lf)) { + if (lf->race->raceclass->id == RC_HUMANOID) { + p = assignnpcname(lf); + } + sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p); + } else { + if (askingprice > countmoney(player)) { + sayphrase(lf, SP_RECRUIT_DECLINE_CANTPAY, SV_TALK, askingprice, NULL); } else { - if (askingprice > countmoney(player)) { - sayphrase(lf, SP_RECRUIT_DECLINE_CANTPAY, SV_TALK, askingprice, NULL); - } else { - sayphrase(lf, SP_RECRUIT_DECLINE_WONTPAY, SV_TALK, askingprice, NULL); - } + sayphrase(lf, SP_RECRUIT_DECLINE_WONTPAY, SV_TALK, askingprice, NULL); } } } // end if !nohire @@ -12923,6 +13078,11 @@ int startresting(lifeform_t *lf, int willtrain) { // stop hiding killflagsofid(lf->flags, F_HIDING); + // stop all spells + stopallspells(lf); + + killflagsofid(lf->flags, F_INTERRUPTED); + if (willtrain) { addflag(lf->flags, F_TRAINING, B_TRUE, NA, traincounter, NULL); } else { @@ -13088,6 +13248,22 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t } rv = say(lf, buf, volume); break; + case SP_BEGATTACK: + switch (rnd(1,3)) { + case 1: sprintf(buf, "Now give me the everything else!"); break; + case 2: sprintf(buf, "Rich fool!"); break; + case 3: sprintf(buf, "Is that all?"); break; + } + rv = say(lf, buf, volume); + break; + case SP_BEGTHANKS: + switch (rnd(1,3)) { + case 1: sprintf(buf, "A thousand thanks, good sir!"); break; + case 2: sprintf(buf, "Oh thank you!"); break; + case 3: sprintf(buf, "My family shall eat tonight!"); break; + } + rv = say(lf, buf, volume); + break; case SP_DRUNK: // random blurred speech strcpy(buf, ""); @@ -13132,10 +13308,18 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t rv = say(lf, buf, volume); break; case SP_RECRUIT_ACCEPT: - if (text) { - sprintf(buf, "I will join you - my name is %s.", text); + if (lf->race->id == R_PRISONER) { + if (text) { + sprintf(buf, "Thank you! My name is %s.", text); + } else { + sprintf(buf, "Thank you!"); + } } else { - sprintf(buf, "I will join you."); + if (text) { + sprintf(buf, "I will join you - my name is %s.", text); + } else { + sprintf(buf, "I will join you."); + } } rv = say(lf, buf, volume); break; @@ -13180,6 +13364,7 @@ int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus) { // immune to fear? if (lfhasflag(lf, F_UNDEAD)) return B_FALSE; + if (isgod(lf)) return B_FALSE; if (lfhasflag(lf, F_ASLEEP)) { return B_FALSE; @@ -13342,7 +13527,12 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { msg("^wYou transform into %s %s!", isvowel(newrace->name[0]) ? "an" : "a", newrace->name); } else if (cansee(player, lf)) { getlfname(lf, buf); - msg("^w%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name); + f = lfhasflag(lf, F_GODOF); + if (f) { + msg("^w%s transforms into %s, the God of %s!", buf, newrace->name, f->text); + } else { + msg("^w%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name); + } } } } @@ -13579,7 +13769,7 @@ void initskills(void) { addskilldesc(SK_SHIELDS, PR_SKILLED, "^gShield accuracy penalties are reduced by 20%.", B_FALSE); addskilldesc(SK_SHIELDS, PR_EXPERT, "^gShield accuracy penalties are reduced by 25%.", B_FALSE); addskilldesc(SK_SHIELDS, PR_MASTER, "^gShield accuracy penalties are reduced by 30%.", B_FALSE); - addskill(SK_SPEECH, "Speech", "Your skill at haggling prices, or swaying others through speech.", 50); + addskill(SK_SPEECH, "Negotiation", "Your skill at haggling prices, or swaying others through speech.", 50); addskilldesc(SK_SPEECH, PR_NOVICE, "^gShop item prices are reduced by 5%.", B_FALSE); addskilldesc(SK_SPEECH, PR_BEGINNER, "^gShop item prices are reduced by 10%.", B_FALSE); addskilldesc(SK_SPEECH, PR_ADEPT, "^gShop item prices are reduced by 15%.", B_FALSE); @@ -14285,7 +14475,6 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { char buf[BUFLEN]; sprintf(buf, "Steal what (%d of %d)?", i+1, nsteals); initprompt(&prompt, buf); - addchoice(&prompt, '-', "Nothing", NULL, NULL); for (o = op->first ; o ; o = o->next) { int ok = B_TRUE; if ((slev < PR_SKILLED) && (getobunitweight(o) >= 3)) { @@ -14307,7 +14496,8 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { } } if (prompt.nchoices > 1) { - if (slev >= PR_ADEPT) { + if (isplayer(lf) && (slev >= PR_ADEPT)) { + addchoice(&prompt, '-', "Nothing", NULL, NULL); // pick what you want getchoice(&prompt); o = (object_t *)prompt.result; @@ -14448,32 +14638,51 @@ void stopsprinting(lifeform_t *lf) { // very much like addmonster(), but announce that it appears // and make it worth zero xp. +// +// for unique monsters, they move from their current position. lifeform_t *summonmonster(lifeform_t *caster, cell_t *c, enum RACE rid, int randomjobsok, job_t *forcejob, int lifetime, int wantfriendly) { lifeform_t *newlf = NULL; char buf[BUFLEN]; - newlf = addmonster(c, rid, randomjobsok, 1, B_FALSE, NULL); - if (newlf) { - // assign job if required - if (forcejob) { - givejob(newlf, forcejob->id); + race_t *r; + r = findrace(rid); + + if (r && hasflag(r->flags, F_UNIQUE)) { + // does it already exist? + newlf = findlfunique(rid); + + // if so, move it here, then exit. + if (newlf) { + teleportto(newlf, c, B_FALSE); } - if (haslos(player, c)) { - //char *newbuf; - getlfnamea(newlf, buf); - capitalise(buf); - msg("%s appears!", buf); + } + + if (!newlf) { + newlf = addmonster(c, rid, randomjobsok, 1, B_FALSE, NULL); + if (newlf) { + // assign job if required + if (forcejob) { + givejob(newlf, forcejob->id); + } + if (haslos(player, c)) { + //char *newbuf; + getlfnamea(newlf, buf); + capitalise(buf); + msg("%s appears!", buf); + } + // summoned + if (caster) { + addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); + if (wantfriendly) { + addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL); + if (areallies(player, caster)) { + makefriendly(newlf, PERMENANT); + } + } + } + // not worth any xp + killflagsofid(newlf->flags, F_XPVAL); + addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); } - // summoned - addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); - if (wantfriendly) { - addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL); - if (areallies(player, caster)) { - makefriendly(newlf, PERMENANT); - } - } - // not worth any xp - killflagsofid(newlf->flags, F_XPVAL); - addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); } return newlf; } @@ -14625,10 +14834,9 @@ void timeeffectslf(lifeform_t *lf) { } } - f = lfhasflag(lf, F_INTERRUPTED); - if (f) { + if (lfhasflag(lf, F_INTERRUPTED)) { interrupt(lf); - killflag(f); + killflagsofid(lf->flags, F_INTERRUPTED); } if (isdead(lf)) { @@ -14756,7 +14964,7 @@ void turneffectslf(lifeform_t *lf) { map_t *map; enum ERROR error; object_t *o; - flag_t *f, *nextf; + flag_t *f; flag_t *asp; char buf[BUFLEN]; lifeform_t *l; @@ -14849,7 +15057,9 @@ void turneffectslf(lifeform_t *lf) { } // MP regeneration - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_MPREGEN, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_MPREGEN) { gainmp(lf, f->val[0]); } @@ -15055,7 +15265,7 @@ void turneffectslf(lifeform_t *lf) { } } f = hasflag(o->flags, F_TRAPPED); - if (f && (f->val[2] != B_TRUE)) { + if (f && (f->val[2] != B_TRUE) && !hasflag(o->flags, F_SECRET)) { objecttype_t *ot; flag_t *trapflag; int diff; @@ -15237,7 +15447,9 @@ void turneffectslf(lifeform_t *lf) { // for flags which can occur multiple times - for (f = o->flags->first ; f ; f = f->next) { + getflags(o->flags, F_DEEPWATER, F_WALKDAMBP, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if ((f->id == F_DEEPWATER) && !isairborne(lf)) { checkfordrowning(lf, o); if (isdead(lf)) return; @@ -15282,8 +15494,10 @@ void turneffectslf(lifeform_t *lf) { if (isdead(lf)) return; - for (f = lf->flags->first ; f ; f = nextf) { - nextf = f->next; + getflags(lf->flags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_FLEEFROM, F_GRABBEDBY, F_GRABBING, F_BOOSTSPELL, F_FEIGNINGDEATH, + F_NOFLEEFROM, F_PETOF, F_SPOTTED, F_STABBEDBY, F_TARGETCELL, F_TARGETLF, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; // remove impossible flags if ((f->id == F_BOOSTSPELL) && (f->val[0] == OT_S_PASSWALL)) { if (!lfhasflag(lf, F_NONCORPOREAL)) { @@ -15515,11 +15729,17 @@ void unsummon(lifeform_t *lf, int vanishobs) { if (cansee(player, lf)) { char lfname[BUFLEN]; + int doyour = B_FALSE; + + if (creator && (creator == player)) { + if (!hasflag(lf->flags, F_UNIQUE)) { + doyour = B_TRUE; + } + } + getlfname(lf, lfname); - msg("%s%s vanishes.", - (creator && (creator == player)) ? "Your " : "", - (creator && (creator == player)) ? noprefix(lfname) : lfname - ); + msg("%s%s vanishes.", doyour ? "Your " : "", + doyour ? noprefix(lfname) : lfname); } if (vanishobs) { @@ -15983,9 +16203,18 @@ int validateraces(void) { addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); } else if (r->raceclass->id == RC_DEMON) { - addflag(lastrace->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); + } else if (r->raceclass->id == RC_GOD) { + addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); + addflag(r->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(r->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); + addflag(r->flags, F_FLEEONHPPCT, 20, NA, NA, NULL); + addflag(r->flags, F_RESISTMAG, 15, NA, NA, NULL); + addflag(r->flags, F_MORALE, 40, NA, NA, NULL); } else if (r->raceclass->id == RC_MAGIC) { - addflag(lastrace->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_PLANT) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DTRESIST, DT_BASH, NA, NA, NULL); diff --git a/lf.h b/lf.h index e269f47..e63688f 100644 --- a/lf.h +++ b/lf.h @@ -69,6 +69,7 @@ void fightback(lifeform_t *lf, lifeform_t *attacker); job_t *findjob(enum JOB jobid); job_t *findjobbyname(char *name); lifeform_t *findlf(map_t *m, int lfid); +lifeform_t *findlfunique(enum RACE rid); race_t *findrace(enum RACE id); race_t *findracebyname(char *name); raceclass_t *findraceclass(enum RACECLASS id); @@ -223,6 +224,7 @@ int isfleeing(lifeform_t *lf); int isfreebp(lifeform_t *lf, enum BODYPART bp); int isfriendly(lifeform_t *lf); int isgenius(lifeform_t *lf); +int isgod(lifeform_t *lf); int ishirable(lifeform_t *lf); int isimmobile(lifeform_t *lf); flag_t *isimmuneto(flagpile_t *fp, enum DAMTYPE dt); @@ -253,7 +255,7 @@ int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo); int loadfirearmfast(lifeform_t *lf); void loseconcentration(lifeform_t *lf); int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc); -int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam); +int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam, object_t *fromob); void losemp(lifeform_t *lf, int amt); void makefriendly(lifeform_t *lf, int howlong); int makenauseated(lifeform_t *lf, int amt, int howlong); @@ -269,7 +271,7 @@ int needstorest(lifeform_t *lf, char *validchars); int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext); void outfitlf(lifeform_t *lf); void petify(lifeform_t *lf, lifeform_t *owner); -int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground); +int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int antannounce); void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat); int poisoncausesvomit(enum POISONTYPE ptype); int poisonthreatenslife(lifeform_t *lf, flag_t *f); diff --git a/map.c b/map.c index 77548ea..6d8c4b5 100644 --- a/map.c +++ b/map.c @@ -1105,7 +1105,7 @@ flag_t *getmapcoords(map_t *m, int *x, int *y) { int getmapdifficulty(map_t *m) { int diff = 1; if (m) { - if (m->region == RG_WORLDMAP) { + if (isoutdoors(m)) { int x,y; // depth is distance from 0,0 getmapcoords(m, &x, &y); @@ -2541,14 +2541,14 @@ int linkexits(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) { int bestdist = 999; if (db) dblog(" Need to link."); // link it. starting from the door, count the number of cells in - // each direction until we hit an empty (walkable) cell not of this room. + // 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++) { dist[d] = 0; c = getcellindir(poss[i], d); while (c) { dist[d]++; - if (c->roomid == roomid) { + if (isroom(c)) { // mark dir as invalid dist[d] = 999; break; @@ -3915,7 +3915,7 @@ int isonmap(map_t *map, int x, int y) { } int isoutdoors(map_t *m) { - if (m->region == RG_WORLDMAP) { + if (m->region->rtype->id == RG_WORLDMAP) { return B_TRUE; } return B_FALSE; diff --git a/move.c b/move.c index 0708924..8cbc34d 100644 --- a/move.c +++ b/move.c @@ -1467,8 +1467,8 @@ int opendoor(lifeform_t *lf, object_t *o) { return B_TRUE; } else { if (lf) { - // has known trap? if (isplayer(lf)) { + // has known trap? if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { char ch; @@ -1480,6 +1480,24 @@ int opendoor(lifeform_t *lf, object_t *o) { } } } + // hear water behind it? + if (getskill(lf, SK_LISTEN)) { + int dir; + cell_t *pastdoorcell; + dir = getdirtowards(doorcell, lf->cell, NULL, B_FALSE, DT_ORTH); + pastdoorcell = getcellindir(doorcell, dir); + if (pastdoorcell && getcellwaterdepth(pastdoorcell, NULL)) { + if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { + char ch; + sprintf(buf,"Your hear running water behind %s. Really open it?", obname); + ch = askchar(buf,"yn","n", B_TRUE); + if (ch != 'y') { + msg("Cancelled."); + return B_TRUE; + } + } + } + } } taketime(lf, getactspeed(lf)); diff --git a/nexus.c b/nexus.c index 88c3cca..10a3f87 100644 --- a/nexus.c +++ b/nexus.c @@ -1183,15 +1183,14 @@ int rollhitdice(lifeform_t *lf) { } if (db) dblog("rollhitdice() for %s - rolling %dd4 + %d",lf->race->name,ndice,plus); - mod = getstatmod(lf, A_CON); - if (mod > 0) mod *= 2; + mod = 100 + getstatmod(lf, A_CON); if (db) dblog("rollhitdice() - mod is +%0.0f%%",mod); if (ndice == 0) { int thisroll; // just the bonus thisroll = plus; - thisroll = thisroll + (int)((float)thisroll * (mod/100)); + if (thisroll < 1) thisroll = 1; roll += thisroll; @@ -1206,8 +1205,8 @@ int rollhitdice(lifeform_t *lf) { } } if (db) dblog("TOTAL: %d",roll); - roll = roll + (int)((float)roll * (mod/100)); - // must be at least 1!! + // modify for fitness/con + roll = pctof(mod, roll); limit(&roll, 1, NA); if (db) dblog(" -> modified to: %d",roll); return roll; @@ -1227,12 +1226,11 @@ int rollmpdice(lifeform_t *lf) { } else { return 0; } - mod = getstatmod(lf, A_IQ); - if (mod > 0) mod *= 2; + mod = 100 + getstatmod(lf, A_IQ); roll = rolldie(ndice, 4) + plus; - roll = roll + (int)((float)roll * (mod/100)); + roll = pctof(mod, roll); return roll; } diff --git a/objects.c b/objects.c index 9ec6a58..cf70d64 100644 --- a/objects.c +++ b/objects.c @@ -25,6 +25,10 @@ extern obmod_t *firstobmod,*lastobmod; extern material_t *material,*lastmaterial; extern skill_t *firstskill, *lastskill; +extern flag_t *retflag[]; +extern int nretflags; + + extern object_t *retobs[MAXPILEOBS+1]; extern int retobscount[MAXPILEOBS+1]; extern int nretobs; @@ -875,7 +879,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes // inherit flags from objecttype copyflags(o->flags, ot->flags, NA); // don't want certain objecttype only flags... - killflagsofid(o->flags, F_RARITY); + //killflagsofid(o->flags, F_RARITY); // random flags... f = hasflag(o->flags, F_RNDCHARGES); @@ -1009,10 +1013,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes int numhiddennames; int n,sel; if (bookcontents == -1) { + int maxlev; + maxlev = getmapdifficulty(obloc->map) / 3; + limit(&maxlev, 1, 9); if (o->type->id == OT_SPELLBOOK) { - bookcontents = getrandomspell(); + bookcontents = getrandomspell(maxlev); while (!schoolappearsinbooks(getspellschool(bookcontents))) { - bookcontents = getrandomspell(); + bookcontents = getrandomspell(maxlev); } } else { // ie. manual bookcontents = getrandomskill(); @@ -2940,6 +2947,46 @@ char *genhiddenname(enum OBCLASS id) { return NULL; } +// returns largest posisble container with free space +object_t *getbestcontainer(obpile_t *op) { + object_t *o,*poss[MAXPILEOBS],*poss2[MAXPILEOBS]; + int nposs = 0,nposs2 = 0,i; + enum LFSIZE bestsize = SZ_MIN; + + // find best container size + for (o = op->first ; o ; o = o->next) { + if (hasflag(o->flags, F_CONTAINER)) { + enum LFSIZE thissize; + poss[nposs] = o; + nposs++; + thissize = getobsize(o); + if (thissize > bestsize) bestsize = thissize; + } + } + if (!nposs) { + return NULL; + } + // now find all containers of this size + for (i = 0; i < nposs; i++) { + int valid = B_TRUE; + if (getobsize(poss[i]) != bestsize) { + valid = B_FALSE; + } + if (countobs(poss[i]->contents, B_FALSE) >= MAXPILEOBS) { + // no space + valid = B_FALSE; + } + if (valid) { + poss2[nposs2++] = poss[i]; + } + } + + if (!nposs2) { + return NULL; + } + return poss2[rnd(0,nposs2-1)]; +} + // returns -1 if object doesn't have the flag int getchargeinfo(object_t *o, int *cur, int *max) { flag_t *f; @@ -5883,40 +5930,7 @@ void initobjects(void) { addflag(lastot->flags, F_DEEPWATER, DP_MAX, NA, NA, NULL); addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL); - // traps - addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_WIRE, 0.1, OC_TRAP, SZ_SMALL); - addflag(lastot->flags, F_TRAP, 10, B_FALSE, 20, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); - addflag(lastot->flags, F_GLYPH, C_GREY, 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, 25, NA, NA, NULL); - addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); - - addot(OT_TRAPROCK, "falling rock trap", "A pressure plate which causes heavy rocks to drop from the ceiling.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); - addflag(lastot->flags, F_TRAP, 20, B_TRUE, 22, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); - addflag(lastot->flags, F_GLYPH, C_GREY, 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, 25, NA, NA, NULL); - addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); - - addot(OT_TRAPTELEPORT, "teleportation trap", "A magical dispersal field.", MT_NOTHING, 0, OC_TRAP, SZ_LARGE); - 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); - addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL); - + // traps - cell only addot(OT_TRAPARROW, "arrow trap", "A pressure plate which causes arrows to shoot at you.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); addflag(lastot->flags, F_TRAP, 25, B_TRUE, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, NA, NULL); @@ -5937,20 +5951,97 @@ void initobjects(void) { addflag(lastot->flags, F_SECRET, 30, NA, NA, NULL); addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); - addot(OT_TRAPGAS, "gas trap", "A pressure plate which releases poisonous gas.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); - addflag(lastot->flags, F_TRAP, 27, B_TRUE, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 69, NA, NULL); + addot(OT_TRAPPIT, "pit trap", "A pressure plate which causes the floor to drop away.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_TRAP, 20, B_TRUE, 22, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); + addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + + addot(OT_TRAPROCK, "falling rock trap", "A pressure plate which causes heavy rocks to drop from the ceiling.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_TRAP, 20, B_TRUE, 22, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_GREY, 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, 25, NA, NA, NULL); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); + + addot(OT_TRAPSUMMON, "summoning trap", "A magical trap which causes a monster to appear.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_BOLDGREEN, 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); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); + + addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_WIRE, 0.1, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_TRAP, 10, B_FALSE, 20, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_GREY, 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, 25, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); + + + // traps - object only + addot(OT_TRAPNEEDLEP, "poison needle trap", "A springed needle coated with poison.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TRAP, 23, B_TRUE, 25, NULL); + addflag(lastot->flags, F_GLYPH, C_GREY, NA, NA, "^"); + addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addot(OT_TRAPWIND, "wind trap", "A magical trap which assails the target with a blast of air.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TRAP, 20, B_TRUE, 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); + + // traps - either cell on object + addot(OT_TRAPALARM, "alarm trap", "A trap which sounds a loud siren.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_TRAP, 18, B_TRUE, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, 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); addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL); - addot(OT_TRAPFIRE, "fire trap", "A pressure plate which fires a pillar of flame.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addot(OT_TRAPEBLAST, "energy blast trap", "A magical trap which blasts its victim with energy.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, 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); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); + + addot(OT_TRAPFIRE, "fire trap", "A trap which fires a pillar of flame.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 59, NA, NULL); + addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_GLYPH, C_GREY, 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); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); + + addot(OT_TRAPGAS, "gas trap", "A trap which releases poisonous gas.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + addflag(lastot->flags, F_TRAP, 27, B_TRUE, 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); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); @@ -5963,12 +6054,23 @@ void initobjects(void) { addflag(lastot->flags, F_TRAP, 30, B_TRUE, 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_OBJECTTRAP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GLYPH, C_GREY, 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); addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); + + addot(OT_TRAPTELEPORT, "teleportation trap", "A magical dispersal field.", MT_NOTHING, 0, OC_TRAP, SZ_LARGE); + 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); + addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBJECTTRAP, B_TRUE, NA, NA, NULL); @@ -6093,8 +6195,8 @@ void initobjects(void) { addot(OT_BERRY, "berry", "Juicy, brightly coloured berries.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 8, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 15, NA, ""); addot(OT_NUT, "peanut", "A species in the legume family.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); @@ -6105,8 +6207,8 @@ void initobjects(void) { addot(OT_BANANA, "banana", "Ba-na-na-na-na-na na-na na-na-na.", MT_FOOD, 0.3, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addot(OT_BANANASKIN, "banana skin", "A slippery banana skin.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); @@ -6117,8 +6219,8 @@ void initobjects(void) { addot(OT_APPLE, "apple", "A crunchy apple.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 85, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addot(OT_MUSHROOM, "mushroom", "A large brown mushroom.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); @@ -6127,39 +6229,39 @@ void initobjects(void) { addot(OT_BREADSTALE, "loaf of stale bread", "A small loaf of old, stale bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 80, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); addot(OT_CHEESE, "chunk of cheese", "A chunk of hard cheese.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 85, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addot(OT_STEW, "stew", "Some kind of meat soaked in water.", MT_FOOD, 1.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addot(OT_ROASTMEAT, "chunk of roast meat", "A chunk of flame-roasted flesh.", MT_FLESH, 1, OC_FOOD, SZ_TINY); // weight normally comes from corpse type addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_BREADFRESH, "loaf of fresh bread", "A freshly-baked loaf of bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); addot(OT_CLOVER, "four leafed clover", "A rare 4-leafed clover.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_RARE, NULL); addflag(lastot->flags, F_HOLDCONFER, F_EXTRALUCK, 1, NA, NULL); addot(OT_CARROT, "carrot", "A stout orange carrot. Rumour has it that carrots are good for your eyesight.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_ORANGE, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); - addflag(lastot->flags, F_RARITY, H_FOREST, 85, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addot(OT_CHOCOLATE, "block of chocolate", "An entire block of chocolate.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 110, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 40, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); // corpses addot(OT_CORPSE, "corpse", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); @@ -6359,7 +6461,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_UNCOMMON, NULL); addot(OT_SCR_WISH, "scroll of wishing", "Grants the caster any item of their choice (with some limitations).", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); - addflag(lastot->flags, F_LINKSPELL, OT_S_WISH, NA, NA, NULL); + addflag(lastot->flags, F_LINKSPELL, OT_S_WISHLIMITED, NA, NA, NULL); // spells - actually defined as object types @@ -6895,6 +6997,7 @@ void initobjects(void) { addot(OT_S_FLIGHT, "fly", "Allows the caster to fly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_GRAVITY, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addot(OT_S_HASTE, "haste", "Increases the speed of the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); @@ -6903,7 +7006,7 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// - // life + // life / clearic spells /////////////////// // l1 addot(OT_S_HEALINGMIN, "minor healing", "Restores 1-8 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); @@ -6915,6 +7018,11 @@ void initobjects(void) { addot(OT_S_TURNUNDEAD, "turn undead", "Instills fear in undead creatures. Power depends on caster's skill.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); + // l2 + addot(OT_S_SPEAKDEAD, "speak with dead", "Temporarily allow a corpse to answer questions about its former life.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); // l3 addot(OT_S_HEALING, "healing", "Restores 10-20 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); @@ -6930,23 +7038,28 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_STUN, "stun", "Stuns the target, preventing them from taking action for a few seconds.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, 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_BODYCONTROL, "body control", "Slow your body's functions, decreasing your rate of hunger but also your speed. At power level V your speed is no longer affected.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_LOWERMETAB, "lower metabolism", "Slow your body's functions, decreasing your rate of hunger but also your speed. At power level V your speed is no longer affected.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); - addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); - addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); - addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_TELEKINESIS, "telekinesis", "Mentally move or manipulate nearby objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); + addot(OT_S_HUNGER, "hunger", "Causes the target to become revenously hungry.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l3 addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); @@ -6961,11 +7074,11 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l4 - addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); + addot(OT_S_SLEEP, "sleep", "Puts the target creature to sleep.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_HEALINGMAJ, "major healing", "Restores 20-30 health to the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); @@ -6973,6 +7086,13 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + // l5 + addot(OT_S_CHARM, "charm", "Causes another lifeform to temporary become friendly.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // modification /////////////////// @@ -7101,7 +7221,13 @@ void initobjects(void) { addot(OT_S_GATE, "gate", "Creates a portal to a different dungeon level.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + // l9 + addot(OT_S_PLANESHIFT, "planeshift", "Instantly transports the caster to a different plane of existence.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 9, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); /////////////////// // wild @@ -7153,9 +7279,17 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_LEVELUP, "levelup", "Bestow the given xp level.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); - addot(OT_S_WISH, "wish", "Grants the caster any item of their choice (with some limitations).", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_WISH, "wish", "Grants the caster any item of their choice. Beware - casting this powerful spell will reduce the caster's hit points by 50%.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLLEVEL, 9, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); + addot(OT_S_WISHLIMITED, "limited wish", "Grants the caster a wish of their choice. Beware - casting this powerful spell will reduce the caster's hit points by 25%.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLLEVEL, 7, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); + addot(OT_S_CONFISCATE, "confiscate", "Takes any object from the target.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 9, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_GIFT, "gift", "Grants the target any item of their choice (with some limitations).", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLLEVEL, 9, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_DIVINE, NA, NA, NULL); @@ -7428,6 +7562,22 @@ void initobjects(void) { addflag(lastot->flags, F_STARTOBRND, 30, NA, NA, NULL); addflag(lastot->flags, F_STARTOBRND, 10, NA, NA, NULL); + addot(OT_SACKHUGE, "huge sack", "An enormous cloth sack.", MT_CLOTH, 1, OC_TOOLS, SZ_LARGE); + addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "("); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 100, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); + addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); + addot(OT_SAFEBOX, "safebox", "A small metal container for safely storing valuables.", MT_METAL, 2, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 77, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GLYPH, C_YELLOW, NA, NA, "("); @@ -7571,6 +7721,15 @@ void initobjects(void) { addflag(lastot->flags, F_HOLDCONFER, F_DETECTLIFE, 10, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addot(OT_NVGOGGLES, "nightvis goggles", "Special goggles which allow the wear to see in the dark.", MT_METAL, 1.5, OC_TECH, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, 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_GOESON, BP_EYES, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); + 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); // tech - l3 @@ -8208,48 +8367,49 @@ void initobjects(void) { // armour - body addot(OT_COTTONSHIRT, "cotton shirt", "A comfortable white cotton shirt.", MT_CLOTH, 0.7, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addot(OT_ARMOURLEATHER, "leather armour", "Body armour created from soft leather.", MT_LEATHER, 10, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 3, NA, NULL); addot(OT_ARMOURRING, "suit of ring mail", "Body armour formed by a series of metallic rings sewn to a leather foundation.", MT_METAL, 15, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 20, 20, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 7, NA, NULL); addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addot(OT_ARMOURSCALE, "suit of scale armour", "Body armour consisting of many small scales attached to leather.", MT_METAL, 20, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 10, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 30, 30, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addflag(lastot->flags, F_OBHP, 35, 35, NA, NULL); addot(OT_ARMOURCHAIN, "suit of chainmail", "Heavy body armour consisting of tightly meshed metal rings.", MT_METAL, 25, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 15, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 40, 40, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); addflag(lastot->flags, F_OBHP, 45, 45, NA, NULL); addot(OT_ARMOURSPLINT, "suit of splint mail", "Heavy armour, consisting of strips of metal attached to a leather backing.", MT_METAL, 35, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 20, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 50, 50, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 11, NA, NULL); addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); addot(OT_ARMOURPLATE, "suit of plate mail", "Heavy armour with embedded metal plates.", MT_METAL, 40, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 90, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_RARE, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 25, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 60, 60, NULL); @@ -8257,37 +8417,39 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour, designed to stop a bullet.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); + 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_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addot(OT_OVERALLS, "pair of overalls", "Well-made, brightly coloured workman overalls.", MT_CLOTH, 1, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addot(OT_SILKSHIRT, "silk shirt", "A lightweight, comfortable white silk shirt.", MT_SILK, 0.5, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addot(OT_ROBE, "robe", "A plain robe.", MT_CLOTH, 4, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addot(OT_VELVETROBE, "velvet robe", "A luxurious velvet robe.", MT_CLOTH, 4, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 90, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); // armour - shoulders addot(OT_CLOAK, "cloak", "A standard leather cloak.", MT_LEATHER, 4, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_SHOULDERS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); @@ -8295,43 +8457,47 @@ void initobjects(void) { addflag(lastot->flags, F_HELPSREST, 5, NA, NA, NULL); // armour - waist addot(OT_BELTLEATHER, "leather belt", "A plain leather belt.", MT_LEATHER, 0.2, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_WAIST, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); // armour - legs addot(OT_CLOTHTROUSERS, "pair of cloth trousers", "A rough pair of cloth trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addot(OT_RIDINGTROUSERS, "pair of riding trousers", "A fitted pair of leather trousers.", MT_LEATHER, 2, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addot(OT_COMBATPANTS, "pair of combat pants", "An armoured pair of camoflauged trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); // armour - feet addot(OT_SANDALS, "pair of sandals", "Comfortable pair of open leather sandals.", MT_LEATHER, 1, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); addot(OT_SHOESLEATHER, "pair of leather shoes", "Cheap and rather uncomfortable leather shoes.", MT_LEATHER, 2, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); addot(OT_BOOTSRUBBER, "pair of rubber boots", "A waterproof (but somewhat cumbersome) pair of rubber boots.", MT_RUBBER, 6, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 0, 5, NULL); @@ -8339,33 +8505,35 @@ void initobjects(void) { addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_ELECTRIC, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addot(OT_BOOTSSPIKED, "pair of spiked boots", "A plain pair of leather boots with spikes on the bottom.", MT_LEATHER, 3, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_STABILITY, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); addot(OT_BOOTSLEATHER, "pair of leather boots", "A stout pair of leather boots.", MT_LEATHER, 4, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); // armour - gloves addot(OT_GLOVESCLOTH, "pair of cloth gloves", "A pair of soft cloth gloves.", MT_CLOTH, 0.15, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addot(OT_GLOVESLEATHER, "pair of leather gloves", "A pair of coarse leather gloves.", MT_LEATHER, 0.25, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); addot(OT_GAUNTLETS, "pair of gauntlets", "A durable pair of metal gauntlets.", MT_METAL, 2, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 5, NULL); @@ -8373,23 +8541,25 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); // armour - head addot(OT_SUNHAT, "sun hat", "Wide-brimmed hat made for working in the sun.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addot(OT_PIRATEHAT, "tricorne", "A three cornered hat with a skull and crossbones emblem.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL); addot(OT_CAP, "cap", "Close-fitting headwear with a short shade visor at the front.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addot(OT_GASMASK, "gas mask", "A full face mask which protects the wearer from toxic gasses.", MT_METAL, 3.5, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL); @@ -8397,24 +8567,25 @@ void initobjects(void) { addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_POISONGAS, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -5, NA, NULL); addot(OT_HELM, "helmet", "A plain metal helmet.", MT_METAL, 2, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addot(OT_HELMFOOTBALL, "football helmet", "A metal helmet with a grill in front of the face.", MT_METAL, 1, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL); addot(OT_GOLDCROWN, "golden crown", "A heavy gold crown, encrusted with jewels.", MT_GOLD, 5, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 25, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 25, RR_RARE, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addot(OT_HELMBONE, "bone helmet", "Scary-looking helmet made from the bones of an animal (?).", MT_BONE, 1, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); @@ -8422,7 +8593,8 @@ void initobjects(void) { // armour - eyes addot(OT_SUNGLASSES, "pair of sunglasses", "Tinted eyewear to protect against sunlight.", MT_PLASTIC, 0.01, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); @@ -8430,22 +8602,16 @@ void initobjects(void) { addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addot(OT_EYEPATCH, "eyepatch", "A small patch of black material which covers one eye. Scary looking.", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL); - addot(OT_NVGOGGLES, "nightvis goggles", "Special goggles which allow the wear to see in the dark.", MT_METAL, 1.5, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL); - addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); - addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - 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); // armour - shields addot(OT_BUCKLER, "buckler", "A small, unobtrusive wooden shield.", MT_WOOD, 3.00, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); @@ -8453,28 +8619,28 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); // similar to a buckler, but repairable, lighter, and less durable addot(OT_SHIELDHIDE, "hide shield", "A small shield constructed out of animal skin.", MT_LEATHER, 2.00, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_OBHP, 18, 18, NA, NULL); addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL); addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addot(OT_SHIELDLARGE, "large shield", "A large (if somewhat cumbersome) shield.", MT_METAL, 6.00, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 8, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 20, NA, NULL); addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR, SZ_HUMAN); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 12, NA, NA, NULL); @@ -12103,8 +12269,15 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } if (isplayer(lf)) { msg("You feel more experienced!"); + gainxp(lf, getxpforlev(lf->level+1) - lf->xp); + } else { + if (cansee(player, lf)) { + msg("%s looks more experienced!", lfname); + } + gainlevel(lf); + enhanceskills(lf); } - gainxp(lf, getxpforlev(lf->level+1) - lf->xp); + break; case OT_POT_GASEOUSFORM: dospelleffects(lf, OT_S_GASEOUSFORM, (potblessed) ? 5 : 1, lf, NULL, lf->cell, potblessed, seen, B_TRUE); @@ -12393,15 +12566,10 @@ int readsomething(lifeform_t *lf, object_t *o) { if (o->type->obclass->id == OC_BOOK) { // is this a spellbook? if (linkspell) { - // if so, only id if we are able to read it - // even if we id though, can only actually LEARN + // if so, always id it. + // note though that we can only actually LEARN // the spell if we are skilled in that school. - if (getspellpower(lf, linkspell->id) > 0) { - - willid = B_TRUE; - } else { - willid = B_FALSE; - } + willid = B_TRUE; } else { // ie. a manual willid = B_TRUE; @@ -12755,7 +12923,7 @@ int readsomething(lifeform_t *lf, object_t *o) { } } } else { - if (isplayer(lf)) msg("You cannot comprehend this book."); + if (isplayer(lf)) msg("You cannot comprehend the contents of this book."); } } else { // manuals @@ -13359,13 +13527,12 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno } else if (cansee(player, owner)) { char lfname[BUFLEN]; getlfname(owner, lfname); - msg("%s%s %s burn%s it!", lfname, getpossessive(lfname), - noprefix(obname), (o->amt == 1) ? "s" : ""); + msg("%s is burnt by %s!", lfname, obname); } // now use the REAL name - real_getobname(o, obname, o->amt, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); - losehp(owner, howmuch , damtype, NULL, obname); + real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_TRUE); + losehp_real(owner, howmuch , damtype, NULL, obname, B_TRUE, o); if (isdead(owner)) { return howmuch; } @@ -14055,16 +14222,14 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, wepeffects(o->flags, target->cell, hasflag(o->flags, F_DAM), dam); - if (firearm) { - practice(thrower, SK_RANGED, 1); - } - missiledam += ((speed*2)+1); - if (firearm) { - practice(thrower, SK_THROWING, 1); - } else { - practice(thrower, SK_RANGED, 1); + if (thrower) { + if (firearm) { + practice(thrower, SK_THROWING, 1); + } else { + practice(thrower, SK_RANGED, 1); + } } } } else { // ie. if !youhit @@ -14120,11 +14285,12 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } void timeeffectsob(object_t *o) { - flag_t *f, *nextf; + flag_t *f; cell_t *location; lifeform_t *owner; object_t *sg; char obname[BUFLEN],ownername[BUFLEN]; + int i; if (hasflag(o->flags, F_DEAD)) return; @@ -14169,8 +14335,9 @@ void timeeffectsob(object_t *o) { int nearundead = B_FALSE; // are we glowing? - for (f = o->flags->first ; f ; f = nextf) { - nextf = f->next; + getflags(o->flags, F_PRODUCESLIGHT, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if ((f->id == F_PRODUCESLIGHT) && (f->lifetime == FROMBLESSING)) { glowflag = f; break; @@ -14340,9 +14507,10 @@ void timeeffectsob(object_t *o) { // check each flag for this object... - for (f = o->flags->first ; f ; f = nextf) { + getflags(o->flags, F_ACTIVATED, F_EDIBLE, F_MATCONVERT, F_OBHPDRAIN, F_ONFIRE, F_RECHARGE, F_WALKDAM, F_WET, F_NONE); + for (i = 0; i < nretflags; i++) { object_t *oo,*nextoo; - nextf = f->next; + f = retflag[i]; // CHECKS FOR CURRENT OBJECT if (f->id == F_ACTIVATED) { @@ -14597,7 +14765,25 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) { } } - if (oid == OT_TRAPROCK) { + if (oid == OT_TRAPWIND) { + // can't be dodged + dospelleffects(NULL, OT_S_GUSTOFWIND, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards + } else if (oid == OT_TRAPNEEDLEP) { + if (isplayer(lf)) { + msg("A needle shoots out %s", avoided ? "at you, but misses." : "and hits you!"); + } else if (cansee(player, lf)) { + if (avoided) { + msg("A needle shoots out at %s, but misses.",lfname); + } else { + msg("A needle shoots out and hits %s!",lfname); + } + } + if (!avoided) { + poison(lf, rnd(10,20), P_VENOM, 1, "a needle trap"); + } + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards + } else if (oid == OT_TRAPROCK) { if (haslos(player, lf->cell)) { msg("A heavy rock drops onto %s%s", lfname, avoided ? ", but misses." : "!"); @@ -14613,7 +14799,30 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) { if (newc) { teleportto(lf, newc, B_TRUE); } + } else if (oid == OT_TRAPWIND) { + // can't be dodged + dospelleffects(NULL, OT_S_GUSTOFWIND, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards + } else if (oid == OT_TRAPPIT) { + cell_t *escapeto = NULL; + addob(lf->cell->obpile, "hole in the ground"); + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards + if (avoided) { + escapeto = getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND); + if (!escapeto) avoided = B_FALSE; + } + + if (avoided) { + if (isplayer(lf)) { + msg("You leap away from the pit!"); + } else if (cansee(player, lf)) { + msg("%s leaps away from a pit!", lfname); + } + movelf(lf, escapeto); + } + } else if (oid == OT_TRAPALARM) { + noise(lf->cell, NULL, NC_OTHER, 10, "a blaring siren!", NULL); } else if ((oid == OT_TRAPARROW) || (oid == OT_TRAPARROWP)) { int dir,bestdir = D_NONE; cell_t *src; @@ -14652,17 +14861,34 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) { msg("failed."); } } + } else if (oid == OT_TRAPEBLAST) { + if (haslos(player, lf->cell)) { + msg("A blast of energy comes out of nowhere!"); + } + // can't be dodged + dospelleffects(NULL, OT_S_ENERGYBLAST, 1, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards } else if (oid == OT_TRAPFIRE) { // can't be dodged dospelleffects(NULL, OT_S_FLAMEPILLAR, 3, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards } else if (oid == OT_TRAPGAS) { // can't be dodged dospelleffects(NULL, OT_S_CLOUDKILL, 3, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); - if (trapob) removeob(trapob, trapob->amt); + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards } else if (oid == OT_TRAPMINE) { // can't be dodged explodecells(lf->cell, roll("2d6"), B_FALSE, trapob, 1, DT_ORTH, B_TRUE); - if (trapob) removeob(trapob, trapob->amt); + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards + } else if (oid == OT_TRAPSUMMON) { + cell_t *c; + // can't be dodged + c = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); + if (c) { + summonmonster(NULL, c, R_NONE, B_TRUE, NULL, PERMENANT, B_FALSE); + } + if (trapob) removeob(trapob, trapob->amt); // trap dies afterwards + } else if (oid == OT_TRAPTRIP) { if (avoided) { if (isplayer(lf)) { @@ -14734,13 +14960,22 @@ void turnoff(lifeform_t *lf, object_t *o) { void turnon(lifeform_t *lf, object_t *o) { char obname[BUFLEN]; flag_t *f; + int held = B_FALSE; + + if (lf && (o->pile->owner == lf)) { + held = B_TRUE; + } f = hasflag(o->flags, F_ACTIVATED); if (f) { // already on if (lf && isplayer(lf)) { - msg("Your %s is already activated!\n", noprefix(obname)); + if (held) { + msg("Your %s is already activated!\n", noprefix(obname)); + } else { + msg("%s is already activated!\n", obname); + } } return; } @@ -14758,7 +14993,8 @@ void turnon(lifeform_t *lf, object_t *o) { getobname(o, obname, 1); if (lf) { if (isplayer(lf)) { - msg("You activate your %s.",noprefix(obname)); + msg("You activate%s %s.", held ? " your" : "", + held ? noprefix(obname) : obname); } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); @@ -14777,7 +15013,13 @@ void turnon(lifeform_t *lf, object_t *o) { // announce new ob addflag(newob->flags, F_ACTIVATED, B_TRUE, NA, NA, NULL); getobname(newob, newobname, 1); - msgnocap("%c - %s [activated].",newob->letter, newobname); + if (lf && isplayer(lf)) { + if (held) { + msgnocap("%c - %s [activated].",newob->letter, newobname); + } else { + msgnocap("You activate %s.",newob->letter, newobname); + } + } } else { if (isplayer(lf)) { msg("You don't have room for an activated %s!",noprefix(obname)); @@ -14787,7 +15029,7 @@ void turnon(lifeform_t *lf, object_t *o) { addflag(o->flags, F_ACTIVATED, B_TRUE, NA, NA, NULL); } - if (lf) { + if (held) { giveobflags(lf, o, F_ACTIVATECONFER); } } diff --git a/objects.h b/objects.h index 6fa2590..d7c97b5 100644 --- a/objects.h +++ b/objects.h @@ -54,6 +54,7 @@ objecttype_t *findot(enum OBTYPE id); objecttype_t *findotn(char *name); // find objecttype by name void fragments(cell_t *centre, char *what, int speed, int howfar); void genhiddennames(void); +object_t *getbestcontainer(obpile_t *op); int getchargeinfo(object_t *o, int *cur, int *max); int getcharges(object_t *o); int geteffecttime(int min, int max, enum BLESSTYPE isblessed); diff --git a/spell.c b/spell.c index 2c2dff0..a9ee24f 100644 --- a/spell.c +++ b/spell.c @@ -19,6 +19,7 @@ extern lifeform_t *player; extern skill_t *firstskill, *lastskill; extern race_t *firstrace, *lastrace; +extern knowledge_t *knowledge; extern int needredraw; @@ -1814,15 +1815,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int d; float totweight = 0; int powerinc = 0; + object_t *o; for (d = DC_N; d <= DC_NW; d++) { c = getcellindir(caster->cell, d); if (c) { - object_t *o; for (o = c->obpile->first ; o ; o = o->next){ if (o->type->obclass->id == OC_FLORA) totweight += getobweight(o); } } } + for (o = caster->cell->obpile->first ; o ; o = o->next){ + if (o->type->obclass->id == OC_FLORA) totweight += getobweight(o); + } + for (o = caster->pack->first ; o ; o = o->next){ + if (o->type->obclass->id == OC_FLORA) totweight += getobweight(o); + } powerinc = totweight / 50; if (powerinc > 0) { power += powerinc; @@ -2150,7 +2157,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } teleportto(caster, targcell, B_TRUE); } - } else if (spellid == OT_S_BODYCONTROL) { + } else if (spellid == OT_S_LOWERMETAB) { flag_t *f; // ie. 2 - 4 f = addtempflag(caster->flags, F_SLOWMETAB, 2+(power/4), NA, NA, NULL, FROMSPELL); @@ -2213,6 +2220,62 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (cansee(player, caster)) { needredraw = B_TRUE; } + } else if (spellid == OT_S_CONFISCATE) { + object_t *o; + char ch = 'a'; + char obname[BUFLEN]; + // ask for a target cell + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; + + target = targcell->lf; + if (!target) { + fizzle(caster); + return B_FALSE; + } + // take an object + initprompt(&prompt, "Confiscate which object?"); + addchoice(&prompt, '-', "(Cancel)", NULL, NULL); + for (o = target->pack->first ; o ; o = o->next) { + getobname(o, obname, o->amt); + addchoice(&prompt, ch, obname, NULL, o); + if (ch == 'z') { + ch = 'A'; + } else { + ch++; + } + } + if (isplayer(caster)) { + // select one + getchoice(&prompt); + o = (object_t *)prompt.result; + } else { + // random one + o = (object_t *) prompt.choice[rnd(0,prompt.nchoices-1)].data; + } + if (o) { + if (isplayer(target)) { + getobname(o, obname, o->amt); + msg("^%cYour %s vanish%s!", getlfcol(target, CC_VBAD), noprefix(obname), (o->amt == 1) ? "es" : ""); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (isplayer(caster)) { + char targname[BUFLEN]; + getlfname(target, targname); + getobname(o, obname, o->amt); + msg("%s%s %s appear%s in your pack!", targname, getpossessive(targname), + noprefix(obname), (o->amt == 1) ? "es" : ""); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (cansee(player, target)) { + char targname[BUFLEN]; + getlfname(target, targname); + getobname(o, obname, o->amt); + msg("^%c%s%s %s vanish%s!", getlfcol(target, CC_VBAD), targname, getpossessive(targname), noprefix(obname), + (o->amt == 1) ? "es" : ""); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + moveob(o, caster->pack, ALL); + } else { + fizzle(caster); + } } else if (spellid == OT_S_CALLLIGHTNING) { int failed = B_FALSE; // ask for a target cell @@ -3311,30 +3374,32 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int range; int x,y; // announce - if (isplayer(caster) || cansee(player, caster)) { - msg("%s emit%s a radial blast of energy!",castername,isplayer(caster) ? "" : "s"); - if (seenbyplayer) *seenbyplayer = B_TRUE; + if (caster) { + if (!targcell) targcell = caster->cell; + if (isplayer(caster) || cansee(player, caster)) { + msg("%s emit%s a radial blast of energy!",castername,isplayer(caster) ? "" : "s"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } } - range = 2 + (power / 4); - animradial(caster->cell, range, '}', C_CYAN); + animradial(targcell, range, '}', C_CYAN); - for (y = caster->cell->y - range ; y <= caster->cell->y + range; y++) { - for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { - targcell = getcellat(caster->cell->map, x,y); - if (targcell && (getcelldist(caster->cell, targcell) <= range)) { - if (targcell->lf && (targcell->lf != caster) && haslof(caster->cell, targcell, B_FALSE, NULL)) { + for (y = targcell->y - range ; y <= targcell->y + range; y++) { + for (x = targcell->x - range ; x <= targcell->x + range; x++) { + cell_t *c; + c = getcellat(targcell->map, x,y); + if (c && (getcelldist(targcell, c) <= range)) { + if (c->lf && (c->lf != caster) && haslof(targcell, c, B_FALSE, NULL)) { // automatic hit - if (isplayer(targcell->lf)) { + if (isplayer(c->lf)) { msg("A blast of energy hits you!"); - } - /* - if (haslos(caster, targcell)) { + } else if (cansee(player, c->lf)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); msg("A blast of energy hits %s.",lfname); } - */ - losehp(targcell->lf, rnd(2,6), DT_MAGIC, caster, "an energy blast"); + losehp(c->lf, rnd(2,6), DT_MAGIC, caster, "an energy blast"); } } } @@ -4154,6 +4219,29 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("%s glows for a moment.",buf); if (seenbyplayer) *seenbyplayer = B_TRUE; } + } else if (spellid == OT_S_HUNGER) { + if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; + + target = targcell->lf; + if (!target) { + fizzle(caster); + return B_FALSE; + } + if (isplayer(target)) { + // make more hungry + modhunger(target, HUNGERCONST); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else { + if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("%s looks ravenously hungry!", lfname); + if (!lfhasflagval(target, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL)) { + addflag(target->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); + } + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } } else if (spellid == OT_S_ICEEDGE) { object_t *wep; enum DAMTYPE dt; @@ -4533,6 +4621,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // 5 is the same as AT_VHIGH strength // 10 = gun speed fireat(caster, targob, 1, targcell, 8 + (power / 2) , NULL); + } else if (spellid == OT_S_PLANESHIFT) { + if (isplayer(caster)) { + msg("^B__not yet implemented__"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else { + if (cansee(player, caster)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + // for now, just disappear. + unsummon(caster, B_TRUE); + } } else if (spellid == OT_S_PARALYZE) { int howlong; int saved = B_FALSE; @@ -5442,15 +5541,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int i; char targname[BUFLEN]; - if (isoutdoors(caster->cell->map)) { - power += 5; - limit(&power, NA, 10); - } if (!validatespellcell(caster, &targcell, TT_MONSTER|TT_OBJECT, spellid, power, frompot)) return B_TRUE; target = targcell->lf; + if (isoutdoors(targcell->map)) { + power += 5; + limit(&power, NA, 10); + } + if (target) { getlfname(target, targname); // objects held by target @@ -6000,7 +6100,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } howlong = getspellduration(5,10,blessed) + (power/2); - fallasleep(target, F_ASLEEP); + fallasleep(target, howlong); if (isplayer(target) || haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -6121,6 +6221,53 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } } + } else if (spellid == OT_S_SPEAKDEAD) { + object_t *corpse = NULL; + + if (!isplayer(caster)) { + return B_FALSE; + } + + corpse = hasobwithflag(caster->cell->obpile, F_CORPSEOF); + if (corpse) { + char buf[BUFLEN],corpsename[BUFLEN]; + char ch; + getobname(corpse, corpsename, 1); + sprintf(buf, "What will you ask %s?", corpsename); + initprompt(&prompt, buf); + addchoice(&prompt, 'a', "How did you die?", NULL, NULL); + addchoice(&prompt, '-', "(nothing)", NULL, NULL); + + ch = getchoice(&prompt); + if (ch == 'a') { + flag_t *f; + char *p; + + sprintf(buf, "%s whispers:", corpsename); + msg(buf); + + f = hasflag(corpse->flags, F_CORPSEOF); + if (f && strlen(f->text)) { + char killer[BUFLEN]; + char weapon[BUFLEN]; + p = readuntil(killer, f->text, '^'); + if (strstr(p, "weilding")) { + p = readuntil(weapon, p, '^'); + } else { + strcpy(weapon, ""); + } + sprintf(buf, "\"I was killed by %s", killer); + if (strlen(weapon)) { + strcat(buf, ", "); + strcat(buf, weapon); + } + strcat(buf, ".\""); + msg(buf); + } else { + msg("\"I do not know what killed me.\""); + } + } + } } else if (spellid == OT_S_STENCH) { int howlong; if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, spellid, power, frompot)) return B_TRUE; @@ -6271,6 +6418,36 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { fizzle(caster); } + } else if (spellid == OT_S_STUN) { + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; + target = targcell->lf; + + if (lfhasflag(target, F_ASLEEP) || !ischarmable(target)) { + fizzle(caster); + return B_TRUE; + } + + if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (isplayer(target)) { + msg("You shrug off a mental attack."); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (haslos(player, target->cell)) { + getlfname(target, buf); + msg("%s shrugs off %s mental attack.", buf, isplayer(caster) ? "your" : "a"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + return B_FALSE; + } else { + if (isplayer(target)) { + msg("You are stunned!"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (haslos(player, target->cell)) { + getlfname(target, buf); + msg("%s is stunned!", buf); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + taketime(target, getactspeed(target)*2); + } } else if (spellid == OT_S_SUCK) { if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; @@ -7028,6 +7205,203 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = addtempflag(caster->flags, F_WINDSHIELD, power, NA, NA, NULL, FROMSPELL); f->obfrom = spellid; + } else if (spellid == OT_S_WISHLIMITED) { + object_t *o; + char obname[BUFLEN]; + char ch; + if (!target) target = caster; + initprompt(&prompt, "For what do you wish?"); + addchoice(&prompt, 'a', "Wealth", NULL, NULL); + addchoice(&prompt, 'b', "Power", NULL, NULL); + addchoice(&prompt, 'c', "Protection", NULL, NULL); + addchoice(&prompt, 'd', "Fame", NULL, NULL); + addchoice(&prompt, 'e', "Knowledge", NULL, NULL); + addchoice(&prompt, 'f', "Magic", NULL, NULL); + if (isplayer(target)) { + ch = getchoice(&prompt); + } else { + ch = 'e'; + // ie. don't select 'knowledge' + while (ch == 'e') { + ch = rnd('a', 'f'); + } + } + if (ch == 'a') { // wealth (gold, bad: goldtouch) + sprintf(buf, "1000-2000 gold coins"); + } else if (ch == 'b') { // power (weapons, bad: battery) + skill_t *sk,*poss[MAXSKILLS]; + int nposs = 0; + // get a list of all valid weapon skills + for (sk = firstskill ; sk ; sk = sk->next) { + if (isweaponskill(sk->id) && getskill(target, sk->id)) { + poss[nposs++] = sk; + } + } + if (nposs) { + int nweps = 0; + objecttype_t *ot; + // pick a random one + sk = poss[rnd(0,nposs-1)]; + // find all associated weapons + for (ot = objecttype ; ot ; ot = ot->next) { + if (hasflagval(ot->flags, F_USESSKILL, sk->id, NA, NA, NULL)) { + nweps++; + } + } + if (nweps) { + int sel,n = 0; + sel = rnd(0,nweps-1); + for (ot = objecttype ; ot ; ot = ot->next) { + if (hasflagval(ot->flags, F_USESSKILL, sk->id, NA, NA, NULL)) { + if (n == sel) break; + n++; + } + } + sprintf(buf, "excellent branded %s", ot->name); + } else { + sprintf(buf, "stick"); + } + } else { + sprintf(buf, "stick"); + } + } else if (ch == 'c') { // protection. bad: turn to stone + enum BODYPART bp,poss[MAXBODYPARTS]; + int nposs = 0; + // get a list of all valid body parts + for (bp = 0; bp <= MAXBODYPARTS; bp++) { + if (!lfhasflagval(target, F_NOBODYPART, bp, NA, NA, NULL)) { + poss[nposs++] = bp; + } + } + if (nposs) { + int narms = 0; + objecttype_t *ot; + // pick a random body part + bp = poss[rnd(0,nposs-1)]; + // find all associated armour + for (ot = objecttype ; ot ; ot = ot->next) { + if ((ot->obclass->id == OC_ARMOUR) && hasflagval(ot->flags, F_GOESON, bp, NA, NA, NULL)) { + narms++; + } + } + if (narms) { + int sel,n = 0; + sel = rnd(0,narms-1); + for (ot = objecttype ; ot ; ot = ot->next) { + if ((ot->obclass->id == OC_ARMOUR) && hasflagval(ot->flags, F_GOESON, bp, NA, NA, NULL)) { + if (n == sel) break; + n++; + } + } + sprintf(buf, "excellent branded %s", ot->name); + } else { + sprintf(buf, "sun hat"); + } + } else { + sprintf(buf, "sun hat"); + } + } else if (ch == 'd') { // fame (allies bad: useless allies) + lifeform_t *lf; + cell_t *c; + job_t *j; + char *p,lfname[BUFLEN]; + // summon a human + c = getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND); + j = getrandomjob(B_TRUE); + lf = addlf(c, R_HUMAN, target->level); + givejob(lf, j->id); + getlfnamea(lf, lfname); + if (cansee(player, lf)) { + msg("%s appears!", lfname); + } + petify(lf, target); + + if (isplayer(target)) { + p = assignnpcname(lf); + sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p); + } + + strcpy(buf, ""); + } else if (ch == 'e') { // knowledge (makeknown everything you have plus 5-10 others. bad: insanity) + // only possible for the player! + strcpy(buf, ""); + if (isplayer(target)) { + knowledge_t *k; + msg("^GKnowledge floods into your mind!"); + for (o = target->pack->first ; o ; o = o->next) { + if (!isidentified(o)) { + identify(o); + getobname(o, obname, o->amt); + msgnocap("%c - %s.", o->letter, obname); + } + } + // now identify everything that you have tried, + // and 10% chance of identifying others + for (k = knowledge; k ; k = k->next) { + if ((k->known == B_TRIED) || pctchance(10)) { + makeknown(k->id); + } + } + } + } else if (ch == 'f') { // magic (spellbooks) + objecttype_t *ot,*poss[MAXCANDIDATES]; + int nposs = 0; + // find all castable spells (spellpower > 0) + for (ot = objecttype ; ot ; ot = ot->next) { + if ((ot->obclass->id == OC_SPELL) && getspellpower(target, ot->id)) { + poss[nposs++] = ot; + } + } + if (!nposs) { + // give knowledge of a random spell school plus sorcery + enum SPELLSCHOOL school; + skill_t *poss2[MAXSKILLS],*sk; + int nposs2 = 0; + giveskill(target, SK_SPELLCASTING); + for (school = SS_AIR; school < SS_LAST; school++) { + sk = findskill(getschoolskill(school)); + poss2[nposs2++] = sk; + } + sk = poss2[rnd(0,nposs2-1)]; + giveskill(target, sk->id); + + // ... then try to find castable spells again + for (ot = objecttype ; ot ; ot = ot->next) { + if ((ot->obclass->id == OC_SPELL) && getspellpower(target, ot->id)) { + poss[nposs++] = ot; + } + } + } + + if (nposs) { + // pick a random spell from this list + ot = poss[rnd(0,nposs-1)]; + sprintf(buf, "spellbook of %s",ot->name); + } else { + strcpy(buf, ""); + } + } + + if (strlen(buf)) { + // give the object + o = addob(target->pack, buf); + getobname(o, obname, o->amt); + msgnocap("%c - %s.", o->letter, obname); + } + + // now age the caster + if (!isgod(caster)) { + caster->maxhp -= pctof(25,caster->maxhp); + limit(&caster->hp, NA, caster->maxhp); + if (isplayer(caster)) { + msg("^BYour body ages unnaturally!"); + statdirty = B_TRUE; + } + } + + if (isplayer(target)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + } } else if ((spellid == OT_S_WISH) || (spellid == OT_S_GIFT)) { object_t *o; if (isplayer(caster)) { @@ -7091,6 +7465,16 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // couldn't make it appear - ob doesn't exist msg("The air in front of %s seems to ripple for a while.", lfname); } + + // now age the caster + if (!isgod(caster)) { + caster->maxhp -= pctof(50,caster->maxhp); + limit(&caster->hp, NA, caster->maxhp); + if (isplayer(caster)) { + msg("^BYour body ages unnaturally!"); + statdirty = B_TRUE; + } + } } else { // monsters can't wish } @@ -7127,7 +7511,9 @@ void fizzle(lifeform_t *caster) { } } -enum OBTYPE getrandomspell(void) { + +// maxlev <= 0 means 'any lev' +enum OBTYPE getrandomspell(int maxlev) { int wantlev; objecttype_t *ot,*poss[MAXCANDIDATES]; int nposs = 0; @@ -7136,6 +7522,7 @@ enum OBTYPE getrandomspell(void) { while (rnd(1,2) == 1) { wantlev++; } + limit(&wantlev, 1, maxlev); // get list of all spells of this level for (ot = objecttype ; ot ; ot = ot->next) { @@ -7343,6 +7730,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { if (db) { dblog("-->power = %d (from canwill)", power); } + // note that this power _can_ override max spell power return power; } } @@ -7740,7 +8128,7 @@ void pullobto(object_t *o, lifeform_t *lf) { if (isplayer(lf) || haslos(player, lf->cell)) { msg("%s %s %s.", lfname, isplayer(lf) ? "catch" : "catches", obname); } - pickup(lf, o, o->amt, B_FALSE); + pickup(lf, o, o->amt, B_FALSE, B_FALSE); } } diff --git a/spell.h b/spell.h index 651ae0c..6e9ebc0 100644 --- a/spell.h +++ b/spell.h @@ -8,7 +8,7 @@ objecttype_t *findspelln(char *buf); void fizzle(lifeform_t *caster); //int getiqreq(enum OBTYPE oid); int getmpcost(lifeform_t *lf, enum OBTYPE oid); -enum OBTYPE getrandomspell(void); +enum OBTYPE getrandomspell(int maxlev); enum SKILL getschoolskill(enum SPELLSCHOOL ss); char *getspellcosttext(lifeform_t *lf, enum OBTYPE spellid, int power, char *buf); int getspellduration(int min,int max,int blessed); diff --git a/vaults/jimbo.vlt b/vaults/jimbo.vlt index ecd9dd2..1b6f964 100644 --- a/vaults/jimbo.vlt +++ b/vaults/jimbo.vlt @@ -15,6 +15,7 @@ #:cell:rock wall |:ob:locked iron gate ,:ob:1-4 bones:50 +,:mon:prisoner:50 +:ob:wooden door /:ob:wooden table -:ob:wooden footstool