diff --git a/ai.c b/ai.c index fb77623..25b2f64 100644 --- a/ai.c +++ b/ai.c @@ -235,9 +235,20 @@ cell_t *aigetlastknownpos(lifeform_t *lf, lifeform_t *target, int *lastx, int *l object_t *aigetrangedattack(lifeform_t *lf, enum RANGEATTACK *ra) { int db = B_FALSE; + enum ATTRBRACKET iqb; object_t *o; if (lfhasflag(lf, F_DEBUG)) db = B_TRUE; + iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); + if (iqb <= IQ_ANIMAL) { + // animal and lower intelligence won't use ranged + // attacks. + if (db) dblog(".oO { no ranged attack due to low iq. }"); + *ra = RA_NONE; + return NULL; + } + + o = getfirearm(lf); if (o && getammo(o)) { if (db) { @@ -591,6 +602,11 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // spell failed. we will keep going through aiturn. } else { // spell succesful + + if (spell == OT_A_STEAL) { + // run away for a few turns + fleefrom(lf, spelllf, rnd(3,7), B_TRUE); + } return B_FALSE; } } @@ -633,14 +649,10 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // if we got here, we're either at the correct distance or couldn't // move. if (attackok) { - enum ATTRBRACKET iqb; - iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); - // if not adjacent, check for guns, wands, throwing if ( (rangedattack != RA_NONE) && haslof(lf->cell, target->cell, LOF_NEED, NULL) && // and we have line of fire to them - (onein(2) || (getcelldist(lf->cell, target->cell) > 1) ) && // and we're not adjacent to target OR random - (iqb > IQ_ANIMAL) ) { // and we are smarter than an animal + (onein(2) || (getcelldist(lf->cell, target->cell) > 1) )) { // and we're not adjacent to target OR random if (rangedattack == RA_GUN) { setguntarget(lf, target); if (!shoot(lf)) { diff --git a/attack.c b/attack.c index 5562270..3467947 100644 --- a/attack.c +++ b/attack.c @@ -186,11 +186,19 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } }; } else { - // TODO: attack wall? - if (isplayer(lf) && !lfhasflag(lf, F_HURRICANESTRIKE)) { - msg("There is nothing there to attack!"); + // otehr attackable ob here? + o = hasobwithflag(c->obpile, F_ATTACKABLE); + + if (o) { + attacktype = AT_OB; + attacktarget = o; + } else { + // TODO: attack wall? + if (isplayer(lf) && !lfhasflag(lf, F_HURRICANESTRIKE)) { + msg("There is nothing there to attack!"); + } + return B_TRUE; } - return B_TRUE; } } @@ -562,7 +570,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) !lfhasflagval(victim, F_TARGETLF, lf->id, NA, NA, NULL) // victim isnt attacking us ) { addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL); - dam[0] *= (getskill(lf, SK_BACKSTAB)*2); + dam[0] *= (getskill(lf, SK_BACKSTAB)); firstisbackstab = B_TRUE; } // extra damage for being skilled? @@ -1131,7 +1139,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { if (isunarmed) { // touch effects touch(lf, o); - } else { + } else if (hasflag(o->flags, F_IMPASSABLE)) { // weapon gets damaged ? if (wep && (ndam > 0)) { if (wepdullable(wep)) { diff --git a/defs.h b/defs.h index d57fd15..502fe8a 100644 --- a/defs.h +++ b/defs.h @@ -11,10 +11,10 @@ #define WETTIME 10 // how long it takes for things to dry #define DRUNKTIME 10 // how long it takes for alcohol to wear off -/* -#define POISONDAMCHANCE 33 // chance of vomitting when poisoned -#define POISONDAM 2 // damage taken from vomiting when poisoned -*/ +// chances of things happening +#define ONEIN_FOUNTAINDRYUP 3 + +#define SHOPIDENTPRICE 50 // cost to identify a just-purchased item // ncurses colours #define C_NONE (-1) @@ -46,9 +46,11 @@ enum NOISECLASS { }; enum SAYPHRASE { + SP_BEG, SP_DRUNK, SP_PAYWARN, SP_PAYTHREAT, + SP_PAYTHANKS, SP_RECRUIT_ACCEPT, SP_RECRUIT_ASKPRICE, SP_RECRUIT_DECLINE, @@ -137,6 +139,7 @@ enum SKILLLEVEL { PR_EXPERT = 5, PR_MASTER = 6, }; +#define MAXSKILLLEVEL 7 // save/load @@ -258,6 +261,7 @@ enum SENSE { #define FROMBLESSING (-9866) #define FROMBRAND (-7865) #define FROMOBMOD (-7864) +#define FROMSKILL (-7863) #define FROMEXTERNAL_LOW (-7999) @@ -586,6 +590,7 @@ enum OBCLASS { OC_FLORA, OC_FOOD, OC_FURNITURE, + OC_GODSTONE, OC_MISC, OC_MISSILE, OC_MONEY, @@ -652,6 +657,7 @@ enum RACE { // human monsters R_HUMAN, R_BANDIT, + R_BEGGAR, R_DRUNK, R_TOWNGUARD, // monsters @@ -807,6 +813,7 @@ enum MATERIAL { MT_SILK = 24, MT_OIL = 25, MT_PLANT = 26, + MT_WIRE = 27, }; // Object Types @@ -850,6 +857,7 @@ enum OBTYPE { OT_ASHCONCEAL, OT_ASHSLEEP, OT_GEMOFSEEING, + OT_GODSTONEJ, // flora OT_FLOWER, OT_LEAF, @@ -1267,6 +1275,7 @@ enum OBTYPE { // armour - shields OT_BUCKLER, OT_SHIELD, + OT_SHIELDHIDE, OT_SHIELDLARGE, OT_SHIELDTOWER, // rings @@ -1531,6 +1540,7 @@ enum FLAG { F_NOGLYPH, // this object doesn't appear normally F_COSMETIC, // this object is mostly cosmetic, don't say 'you see xx' F_NOPICKUP, // cannot pick this up + F_ATTACKABLE, // can attack this with 'A' F_IMPASSABLE, // cannot walk past this if your size is between v0 and v1 // (inclusive) F_CRUSHABLE, // if you are bigger than size v0, walking on this crushes it @@ -1618,11 +1628,19 @@ enum FLAG { F_PICKLOCKS, // can pick locks? val0=% change, // val1=b_false, f_dieonfail, f_bluntonfail F_LOCKABLE,// this object can be locked - F_TRAP, // this object is a trap. v0 is sc_disarm difficulty. + F_CANBETRAPPED, // this object might start with a trap + // v0 = base pct chance + // v1 = extra pct chance every 5 levels + // v2 = max trap chance + F_TRAPPED, // this object HAS a trap. + // v0 is the trap object type + // v2 = TRUE means we've spotted this. + F_TRAP, // this object _IS_ a trap. v0 is sc_disarm/sc_spot difficulty. // (NA = impossible) // if v1 = true, trap will go off if you fail your 2nd disarm // check. // v2 = sc_dodge difficulty + F_OBJECTTRAP, // this trap can go onto an object (door, chest, etc) // doors F_DOOR, // this object is a door - ie. can open it // v0 and v1 are like F_IMPASSABLE @@ -1723,6 +1741,7 @@ enum FLAG { F_CHARGES, // generally the number of uses left,v0=min, v1=max F_DONTSHOWCHARGES, // don't show 'xx charges left' when id'd F_RECHARGEWHENOFF, // get power back when you turn it off + F_RECHARGE, // get v0 charges back each turn. F_REFILLWITH, // pour obj id val0 onto this to refill its charges // F_POWDER, // this item is a powder @@ -1739,7 +1758,6 @@ enum FLAG { F_NODIECONVERTTEXT, // don't anounce when this object changes // misc flags F_LINKOB, // val0 = linked object id - // for fountains: v2 = ifknown F_LINKRACE, // val0 = linked race id // scroll flags F_LINKSPELL, // val0 = spell this scroll will cast when read @@ -1866,6 +1884,9 @@ enum FLAG { F_STAYINHABITAT, // lf will not walk onto a cell of a different // habitat F_STAYINROOM, // lf will not walk out of roomid v0 + // if v0 is not set, we won't leave our current room. + // if v1 is set (not NA), then we are allowed to chase + // our targets out of the room. F_FALLDISTANCE, // how many floors this lf has fallen through. // ABILITY/SPELL FLAGS / ability flags / spell flags F_FAILEDINSPECT, // lf has failed an inspect check for item id v0 @@ -2178,6 +2199,7 @@ enum FLAG { // if a vault doesnt have this flag, it can go anywhere F_VAULTISSHOP, // this vault is a shop, so add f_shopitem to objects // here. + F_VAULTISSHRINE, // this vault is a godstone shrine F_VAULTSCATTER, // v0=thingtype, v1=pctchance // text=x1,y1,x2,y2,mincount-maxcount,thingname // if maxcount is PCT, mincount is a percentage @@ -2221,6 +2243,8 @@ enum HUNGER { #define B_FALSE (0) #define B_TRUE (-1) +#define B_MAYCHASE (-1) + #define B_NODOORS (0) #define B_DONTKILL (-1) @@ -2434,6 +2458,7 @@ enum HABITAT { typedef struct regiontype_s { enum REGIONTYPE id; enum HABITAT defaulthabitat; + char *name; int maxdepth; int stairsperlev; int deeperdir; @@ -2457,7 +2482,7 @@ typedef struct regionthing_s { char *what; } regionthing_t; -#define MAXOUTLINETHINGS 20 +#define MAXOUTLINETHINGS 60 typedef struct regionoutline_s { int id; regiontype_t *rtype; @@ -2736,6 +2761,10 @@ typedef struct skill_s { enum SKILL id; char *name; char *desc; + enum SKILLLEVEL skilldesclev[MAXSKILLLEVEL*2]; + char *skilldesctext[MAXSKILLLEVEL*2]; + int skilldescmsg[MAXSKILLLEVEL*2]; + int nskilldesc; int traintime; struct skill_s *next, *prev; } skill_t; diff --git a/doc/add_skill.txt b/doc/add_skill.txt index 68727c4..a9854ca 100644 --- a/doc/add_skill.txt +++ b/doc/add_skill.txt @@ -4,8 +4,10 @@ defs.h: lf.c: add addskill() + add addskilldesc() if it is a lore skill, update isloreskill() if it is a weapon skill, update isweaponskill() assign to jobs + diff --git a/flag.c b/flag.c index d121618..6104464 100644 --- a/flag.c +++ b/flag.c @@ -479,6 +479,7 @@ flag_t *hasflag_real(flagpile_t *fp, int id, int wantknown, flag_t *exception) { if (f == exception) valid = B_FALSE; if ((wantknown != NA) && (f->known != wantknown)) valid = B_FALSE; if (owner && (f->lifetime == FROMJOB) && !getjob(owner)) valid = B_FALSE; + //if (owner && (f->lifetime == FROMSKILL) && !getskill(owner, xxx)) valid = B_FALSE; if (valid) { foundflag = f; diff --git a/io.c b/io.c index 671e68b..1072b22 100644 --- a/io.c +++ b/io.c @@ -60,6 +60,8 @@ extern long curtime; char msgbuf[HUGEBUFLEN]; char lastmsgbuf[HUGEBUFLEN]; +char prevmsg[HUGEBUFLEN]; +int msgmulti = 1; extern lifeform_t *player; @@ -3253,6 +3255,7 @@ void describeob(object_t *o) { y++; } + // charges remaining if (o->type->obclass->id == OC_WAND) { if (isidentified(o)) { int charges; @@ -3264,6 +3267,17 @@ void describeob(object_t *o) { } y++; } + } else if (o->type->obclass->id == OC_GODSTONE) { + if (isidentified(o)) { + int charges,max; + getchargeinfo(o, &charges, &max); + if (charges == max) { + mvwprintw(mainwin, y, 0, "It is fully charged."); + } else { + mvwprintw(mainwin, y, 0, "It is depleted."); + } + y++; + } } f = hasflag(o->flags, F_PICKLOCKS); @@ -3283,93 +3297,94 @@ void describeob(object_t *o) { // skip line y++; - // immunities - strcpy(buf, ""); - f = hasflagval(o->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL); - if (f) { - sprintf(buf, "It is immune to %s", getdamname(DT_ALL)); - } else { - int first = B_TRUE; - for (i = 0; i < MAXDAMTYPE; i++) { - f = isimmuneto(o->flags, i); - if (f) { - char buf2[BUFLEN]; - if (first) { - sprintf(buf2, "It is immune to: %s", getdamname(i)); - first = B_FALSE; - } else { - sprintf(buf2, ", %s", getdamname(i)); - } - strcat(buf, buf2); - } - } - } - if (strlen(buf) > 0) { - strcat(buf, "."); - mvwprintw(mainwin, y, 0, buf); - y++; - } - - // resistances - strcpy(buf, ""); - f = hasflagval(o->flags, F_DTRESIST, DT_ALL, NA, NA, NULL); - if (f) { - sprintf(buf, "It is resistant to %s", getdamname(DT_ALL)); - } else { - int first = B_TRUE; - for (i = 0; i < MAXDAMTYPE; i++) { - f = isresistantto(o->flags, i); - if (f) { - char buf2[BUFLEN]; - if (first) { - sprintf(buf2, "It is resistant to: %s", getdamname(i)); - first = B_FALSE; - } else { - sprintf(buf2, ", %s", getdamname(i)); - } - strcat(buf, buf2); - } - } - } - if (strlen(buf) > 0) { - strcat(buf, "."); - mvwprintw(mainwin, y, 0, buf); - y++; - } - - // vulnerabilities - strcpy(buf, ""); - f = hasflagval(o->flags, F_DTVULN, DT_ALL, NA, NA, NULL); - if (f) { - sprintf(buf, "It is vulnerable to %s", getdamname(DT_ALL)); - } else { - int first = B_TRUE; - for (i = 0; i < MAXDAMTYPE; i++) { - f = isvulnto(o->flags, i); - if (f) { - char buf2[BUFLEN]; - if (first) { - sprintf(buf2, "It is vulnerable to: %s", getdamname(i)); - first = B_FALSE; - } else { - sprintf(buf2, ", %s", getdamname(i)); - } - strcat(buf, buf2); - } - } - } - if (strlen(buf) > 0) { - strcat(buf, "."); - mvwprintw(mainwin, y, 0, buf); - y++; - } - // been made invulnerable ? - if (hasflag(o->type->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) { - mvwprintw(mainwin, y, 0, "It has been rendered invulnerable to most damage."); + if (hasflagknown(o->type->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) { + mvwprintw(mainwin, y, 0, "It is invulnerable to most damage."); y++; + } else { + // immunities + strcpy(buf, ""); + f = hasflagval(o->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL); + if (f) { + sprintf(buf, "It is immune to %s", getdamname(DT_ALL)); + } else { + int first = B_TRUE; + for (i = 0; i < MAXDAMTYPE; i++) { + f = isimmuneto(o->flags, i); + if (f) { + char buf2[BUFLEN]; + if (first) { + sprintf(buf2, "It is immune to: %s", getdamname(i)); + first = B_FALSE; + } else { + sprintf(buf2, ", %s", getdamname(i)); + } + strcat(buf, buf2); + } + } + } + if (strlen(buf) > 0) { + strcat(buf, "."); + mvwprintw(mainwin, y, 0, buf); + y++; + } + + // resistances + strcpy(buf, ""); + f = hasflagval(o->flags, F_DTRESIST, DT_ALL, NA, NA, NULL); + if (f) { + sprintf(buf, "It is resistant to %s", getdamname(DT_ALL)); + } else { + int first = B_TRUE; + for (i = 0; i < MAXDAMTYPE; i++) { + f = isresistantto(o->flags, i); + if (f) { + char buf2[BUFLEN]; + if (first) { + sprintf(buf2, "It is resistant to: %s", getdamname(i)); + first = B_FALSE; + } else { + sprintf(buf2, ", %s", getdamname(i)); + } + strcat(buf, buf2); + } + } + } + if (strlen(buf) > 0) { + strcat(buf, "."); + mvwprintw(mainwin, y, 0, buf); + y++; + } + + // vulnerabilities + strcpy(buf, ""); + f = hasflagval(o->flags, F_DTVULN, DT_ALL, NA, NA, NULL); + if (f) { + sprintf(buf, "It is vulnerable to %s", getdamname(DT_ALL)); + } else { + int first = B_TRUE; + for (i = 0; i < MAXDAMTYPE; i++) { + f = isvulnto(o->flags, i); + if (f) { + char buf2[BUFLEN]; + if (first) { + sprintf(buf2, "It is vulnerable to: %s", getdamname(i)); + first = B_FALSE; + } else { + sprintf(buf2, ", %s", getdamname(i)); + } + strcat(buf, buf2); + } + } + } + if (strlen(buf) > 0) { + strcat(buf, "."); + mvwprintw(mainwin, y, 0, buf); + y++; + } } + for (f = o->flags->first ; f ; f = f->next) { if ((f->id == F_HITCONFER) && (f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) { mvwprintw(mainwin, y, 0, "It has been coated with poison."); @@ -3762,6 +3777,40 @@ void describeob(object_t *o) { restoregamewindows(); } +void describeskill(enum SKILL skid) { + skill_t *sk; + char buf[BUFLEN]; + int i; + cls(); + sk = findskill(skid); + if (!sk) return; + + // title + sprintf(buf, "Skill - %s",sk->name); + capitalise(buf); + mvwprintw(mainwin, 0, 0, buf); + + mvwprintw(mainwin, 2, 0,"%s\n\n", sk->desc); + + // descriptions + wmove(mainwin, 4, 0); + for (i = 0; i < sk->nskilldesc; i++) { + if (sk->skilldesclev[i] == PR_INEPT) { + sprintf(buf, "%s\n",sk->skilldesctext[i]); + } else { + sprintf(buf, "At %s level: %s\n",getskilllevelname(sk->skilldesclev[i]), sk->skilldesctext[i]); + } + textwithcol(mainwin, buf); + } + + wrefresh(mainwin); + + // wait for key + getch(); + real_clearmsg(B_TRUE); + restoregamewindows(); +} + void describespell(objecttype_t *ot) { char buf[BUFLEN]; flag_t *f; @@ -4047,9 +4096,25 @@ void docomms(lifeform_t *lf) { killflag(f); getobname(o, buf, o->amt); msg("You buy %s.", buf); + // get it identified? + if (!isknown(o) && (countmoney(player) >= SHOPIDENTPRICE)) { + char buf2[BUFLEN]; + char ch2; + sprintf(buf2, "Pay $%d to identify %s?",(int)SHOPIDENTPRICE, buf); + ch2 = askchar(buf2, "yn","n", B_TRUE); + if (ch2 == 'y') { + if (givemoney(player, lf, SHOPIDENTPRICE)) { + identify(o); + real_getobname(o, buf, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness + msgnocap("%c - %s",o->letter, buf); + } else { + msg("You can't afford to pay $%d.", SHOPIDENTPRICE); + } + } + } } } - say(lf, "Pleasure doing business with you!", SV_TALK); + sayphrase(lf, SP_PAYTHANKS, SV_TALK, NA, NULL); } break; case 'r': @@ -5757,6 +5822,9 @@ void initgfx(void) { // init message buffer strcpy(msgbuf, ""); strcpy(lastmsgbuf, "xxx"); + sprintf(prevmsg, "!nolastmessage!"); + msgmulti = 1; + } int drop(object_t *o, int count) { @@ -6782,8 +6850,15 @@ void msg_real(char *format, ... ) { vsprintf( buf, format, args ); va_end(args); - if (db) dblog("adding to msgbuf: [%s]",buf); + if (streq(buf, prevmsg) && !strchr(buf, '^')) { + msgmulti++; + sprintf(buf, "x%d",msgmulti); + } else { + strcpy(prevmsg, buf); + msgmulti = 1; + } + if (db) dblog("adding to msgbuf: [%s]",buf); assert(!strchr(buf, '#')); // ie. can the message buffer fit: @@ -7321,7 +7396,15 @@ void showlfarmour(lifeform_t *lf) { if (strlen(rhs)) strcat(rhs, " "); strcat(rhs, "(covered) "); } - if (!strlen(rhs)) { + if (strlen(rhs)) { + flag_t *f; + f = hasflag(o->flags, F_ARMOURRATING); + if (f) { + char numbuf[BUFLENSMALL]; + sprintf(numbuf, " [AR:%d]",f->val[0]); + strcat(rhs, numbuf); + } + } else { strcpy(rhs, "-"); } diff --git a/io.h b/io.h index 418e8f1..4a731d2 100644 --- a/io.h +++ b/io.h @@ -34,6 +34,7 @@ void clearretobs(void); void cls(void); int contains(enum OBCLASS *array, int nargs, enum OBCLASS want); void describeob(object_t *o); +void describeskill(enum SKILL skid); void describespell(objecttype_t *ot); void doattackcell(char dirch); void doclose(void); diff --git a/lf.c b/lf.c index 4b0e0e2..782491a 100644 --- a/lf.c +++ b/lf.c @@ -874,9 +874,12 @@ int cansee(lifeform_t *viewer, lifeform_t *viewee) { } } } + // viewee underwater and more than 1 cell away? + if ((getobdepth(o, viewee) >= DP_HEAD) && (dist > 1)) { + return B_FALSE; + } } - return B_TRUE; } @@ -918,6 +921,17 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { return B_FALSE; } + // other flags to check + for (f = o->flags->first ; f ; f = f->next) { + if (f->id == F_ATTREQ) { + // meetsattreq will set 'reason' for us. + if (!meetsattreq(lf, f, o)) { + return B_FALSE; + } + } + } + + if (where == BP_NONE) { // can we wear it ANYWHERE? enum BODYPART possbp[MAXBODYPARTS]; @@ -966,6 +980,7 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { } } + return B_TRUE; } @@ -1592,6 +1607,8 @@ void die(lifeform_t *lf) { if (hunger > 0) { modhunger(lf, -hunger); } + // put out fires + extinguishlf(lf); if (isplayer(lf)) { statdirty = B_TRUE; } @@ -2411,7 +2428,7 @@ int eat(lifeform_t *lf, object_t *o) { // stop eating if we are full if (!stopeating && !fullyeaten && (posthlev != hlev) && (posthlev <= H_FULL)) { - if (isplayer(lf)) { + if (isplayer(lf) && (posthlev != H_STUFFED)) { int ch; more(); ch = askchar("Stop eating?","yn","y", B_TRUE); @@ -2586,9 +2603,12 @@ void enhanceskills(lifeform_t *lf) { // any skills to get? if (skillstoenhance) { - char ques[BUFLEN]; + char ques[BUFLEN],ques2[BUFLEN]; + int done = B_FALSE; sprintf(ques, "Enhance which skill (%d left)?", lf->skillpoints); + sprintf(ques2, "Describe which skill (%d left)?", lf->skillpoints); initprompt(&prompt, ques); + addpromptq(&prompt, ques2); ch = 'a'; for (f = lf->flags->first ; f ; f = f->next) { @@ -2601,12 +2621,22 @@ void enhanceskills(lifeform_t *lf) { } addchoice(&prompt, '-', "None", "None", NULL); - getchoicestr(&prompt, B_FALSE, B_TRUE); - f = (flag_t *)prompt.result; - if (f) { - whichsk = f->val[0]; - giveskill(lf, whichsk); - lf->skillpoints--; + while (!done) { + getchoicestr(&prompt, B_FALSE, B_TRUE); + f = (flag_t *)prompt.result; + if (f) { + whichsk = f->val[0]; + + if (prompt.whichq == 0) { + giveskill(lf, whichsk); + lf->skillpoints--; + done = B_TRUE; + } else { // ie. describing a skill + describeskill(whichsk); + } + } else { + done = B_TRUE; + } } } else { msg("You have already mastered all your current skills."); @@ -2620,9 +2650,12 @@ void enhanceskills(lifeform_t *lf) { } else { if (skillstolearn) { - char ques[BUFLEN]; + int done = B_FALSE; + char ques[BUFLEN],ques2[BUFLEN]; sprintf(ques, "Learn which new skill (%d left)?", player->skillpoints); + sprintf(ques2, "Describe which skill (%d left)?", lf->skillpoints); initprompt(&prompt, ques); + addpromptq(&prompt, ques2); ch = 'a'; for (sk = firstskill ; sk ; sk = sk->next) { @@ -2633,11 +2666,20 @@ void enhanceskills(lifeform_t *lf) { } } addchoice(&prompt, '-', "None", "None", NULL); - getchoicestr(&prompt, B_FALSE, B_TRUE); - sk = (skill_t *)prompt.result; - if (sk) { - giveskill(player, sk->id); - player->skillpoints -= newskillcost; + while (!done) { + getchoicestr(&prompt, B_FALSE, B_TRUE); + sk = (skill_t *)prompt.result; + if (sk) { + if (prompt.whichq == 0) { + giveskill(player, sk->id); + player->skillpoints -= newskillcost; + done = B_TRUE; + } else { + describeskill(sk->id); + } + } else { + done = B_TRUE; + } } } else { msg("There is nothing more that you can learn."); @@ -2808,6 +2850,14 @@ void enhanceskills(lifeform_t *lf) { } } +void extinguishlf(lifeform_t *lf) { + object_t *o,*nexto; + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + extinguish(o); + } + killflagsofid(lf->flags, F_ONFIRE); +} // if the lf wearing something which shades their eyes? object_t *eyesshaded(lifeform_t *lf) { @@ -3156,27 +3206,29 @@ int flee(lifeform_t *lf) { } // start fleeing from 'enemy' -void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong) { +void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose) { flag_t *f; - // in recovery from fleeing? - // this is to prevent constant usage of war cry! - f = hasflagval(lf->flags, F_NOFLEEFROM, enemy->id, NA, NA, NULL); - if (f) { - if (f->lifetime > 0) { - f->lifetime -= 5; - if (f->lifetime <= 0) { - killflag(f); + if (!onpurpose) { + // in recovery from fleeing? + // this is to prevent constant usage of war cry! + f = hasflagval(lf->flags, F_NOFLEEFROM, enemy->id, NA, NA, NULL); + if (f) { + if (f->lifetime > 0) { + f->lifetime -= 5; + if (f->lifetime <= 0) { + killflag(f); + } } + if (isplayer(lf)) { + msg("You flinch."); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s flinches.",lfname); + } + return; } - if (isplayer(lf)) { - msg("You flinch."); - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s flinches.",lfname); - } - return; } // already fleeing? @@ -3680,6 +3732,13 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { if ((f->id == F_ATTRMOD) && (f->val[0] == attr)) { val += f->val[1]; } + if ((f->id == F_DRUNK) && (attr == A_DEX)) { + if (hasjob(lf, J_PIRATE)) { + val += f->val[0]; + } else { + val -= f->val[0]; + } + } } if (val < 0) val = 0; @@ -5578,6 +5637,8 @@ enum ATTRBRACKET getattrbracket(int attrval, enum ATTRIB whichatt, char *buf) { strcpy(buf, "hideous"); break; case A_CON: strcpy(buf, "frail"); break; + case A_DEX: + strcpy(buf, "uncoordinated"); break; case A_IQ: strcpy(buf, "vegetable"); break; case A_STR: @@ -6175,36 +6236,34 @@ int giveskill(lifeform_t *lf, enum SKILL id) { // special effects for gaining a skill. - // there aren't REALLY "from job", but mark them as such anyway, so that + // remember that these from from a SKILL, so that // they are invalidated if we get polymorphed. - - // NOTE: this WILL be a problem if i ever add code to allow change of jobs! if (id == SK_ATHLETICS) { newf = addflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } else if (id == SK_COOKING) { makeknown(OT_POT_WATER); } else if (id == SK_LORE_ARCANA) { newf = addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } else if (id == SK_METALWORK) { newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); if (!newf) { newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } } else if (id == SK_SEWING) { newf = hasflagval(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); if (!newf) { newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } } else if (id == SK_THIEVERY) { newf = addflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } else if (id == SK_TRAPS) { newf = addflag(lf->flags, F_CANWILL, OT_A_DISARM, NA, NA, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } statdirty = B_TRUE; // in case skill changes your stats @@ -6215,86 +6274,28 @@ int giveskill(lifeform_t *lf, enum SKILL id) { if (id == SK_ATHLETICS) { if (f->val[1] == PR_ADEPT) { newf = addflag(lf->flags, F_CANWILL, OT_A_TUMBLE, 2, 2, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } else if (f->val[1] == PR_EXPERT) { newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } } else if (id == SK_CARTOGRAPHY) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_NOVICE) { - msg("^gYou now make basic maps of your surroundings."); - } else if (f->val[1] == PR_BEGINNER) { - msg("^gYour map now shows the location of staircases."); - } else if (f->val[1] == PR_ADEPT) { - msg("^gYour map now shows the location of doors."); - } else if (f->val[1] == PR_SKILLED) { - //msg("You will no longer forget your surroundings."); - addflag(lf->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL); - } else if (f->val[1] == PR_EXPERT) { - msg("^gYour map will now show the location of objects."); - } + if (f->val[1] == PR_SKILLED) { + addflag(lf->flags, F_PHOTOMEM, B_TRUE, NA, NA, NULL); } if (f->val[1] == PR_MASTER) { newf = addflag(lf->flags, F_CANWILL, OT_S_MAPPING, 50, 50, "pw:1;"); - newf->lifetime = FROMJOB; + newf->lifetime = FROMSKILL; } } else if (id == SK_COOKING) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_NOVICE) { - msg("^gYou can now recognise rotting food."); - } else if (f->val[1] == PR_BEGINNER) { - msg("^gYou can now recognise all kinds of bad food."); - } else if (f->val[1] == PR_ADEPT) { - newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); - newf->lifetime = FROMJOB; - } - } - } else if (id == SK_FIRSTAID) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_ADEPT) { - msg("^gYou can now recgonise when poison is potentially fatal."); - statdirty = B_TRUE; - } - } - } else if (id == SK_LISTEN) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_BEGINNER) { - msg("^gYou can now gauge the distance of sounds."); - } else if (f->val[1] == PR_ADEPT) { - msg("^gYou can now determine the direction sounds are coming from."); - } else if (f->val[1] == PR_EXPERT) { - msg("^gYou can now identify monsters based on sound."); - } else if (f->val[1] == PR_MASTER) { - msg("^gYou can now locate monsters based on sound."); - } - } - } else if (id == SK_RANGED) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_MASTER) { - msg("^gYour no longer suffer ranged-based accuracy penalties when firing."); - } + if (f->val[1] == PR_ADEPT) { + newf = addflag(lf->flags, F_CANWILL, OT_A_COOK, NA, NA, NULL); + newf->lifetime = FROMSKILL; } } else if (id == SK_STEALTH) { if (f->val[1] == PR_BEGINNER) { newf = addflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); - newf->lifetime = FROMJOB; - } else if (f->val[1] == PR_EXPERT) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - msg("^gYou can now hide even when monsters are nearby."); - } - } - } else if (id == SK_SWIMMING) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_NOVICE) { - msg("^gYou can now swim."); - } else if ((f->val[1] >= PR_BEGINNER) && (f->val[1] <= PR_SKILLED)) { - msg("^gYou can now swim a bit faster."); - } else if (f->val[1] == PR_EXPERT) { - msg("^gYou can now attack awkwardly and cast spells while swimming."); - } else if (f->val[1] == PR_MASTER) { - msg("^gYou can now attack while swimming with no penalty."); - } + newf->lifetime = FROMSKILL; } } else if (id == SK_TECHUSAGE) { objecttype_t *ot; @@ -6321,57 +6322,9 @@ int giveskill(lifeform_t *lf, enum SKILL id) { } } } - } else if (id == SK_THIEVERY) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_BEGINNER) { - msg("^gYour accuracy penalty when stealing is reduced."); - } else if (f->val[1] == PR_ADEPT) { - msg("^gYou can now steal specific items."); - } else if (f->val[1] == PR_SKILLED) { - msg("^gYou can now steal heavy items."); - } else if (f->val[1] == PR_EXPERT) { - msg("^gYou can now steal multiple items."); - } else if (f->val[1] == PR_MASTER) { - msg("^gYou can now steal equipped items."); - } - } - } else if (id == SK_TRACKING) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_NOVICE) { - msg("^gYou can now see footprints."); - } else if (f->val[1] == PR_BEGINNER) { - msg("^gYou can now determine how recently footprints were made."); - } else if (f->val[1] == PR_ADEPT) { - msg("^gYou can now identify creatures from their footprints."); - } else if (f->val[1] == PR_SKILLED) { - msg("^gYou can now recognise the direction of footprints."); - } else if (f->val[1] == PR_EXPERT) { - msg("^gYou can now partially obscure your own footprints."); - } else if (f->val[1] == PR_MASTER) { - msg("^gYou can now move without leaving footprints."); - } - } } else if (id == SK_TWOWEAPON) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_NOVICE) { - msg("^gYou can now weild two weapons at once."); - } else if (f->val[1] == PR_ADEPT) { - msg("^gYou no longer suffer an accuracy penalty when weilding two weapons."); - } else if (f->val[1] == PR_SKILLED) { - msg("^gFollow-up attacks with your second weapon are now more accurate."); - } else if (f->val[1] == PR_EXPERT) { - addflag(lf->flags, F_CANWILL, OT_A_FLURRY, 3, 3, "pw:1;"); - } else if (f->val[1] == PR_MASTER) { - msg("^gYou can now deflect attacks with your second weapon."); - } - } - } else if (id == SK_UNARMED) { - if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { - if (f->val[1] == PR_SKILLED) { - if (hasbp(lf, BP_SECWEAPON)) { - msg("^gYou can now make melee attacks with your off-hand."); - } - } + if (f->val[1] == PR_EXPERT) { + addflag(lf->flags, F_CANWILL, OT_A_FLURRY, 3, 3, "pw:1;"); } } else if (id == SK_SS_ALLOMANCY) { // give all allomantic spells @@ -6383,30 +6336,18 @@ int giveskill(lifeform_t *lf, enum SKILL id) { addflag(lf->flags, F_CANCAST, OT_S_MINDSCAN, NA, NA, NULL); } */ - } else if (isloreskill(id) && (gamemode == GM_GAMESTARTED) && isplayer(lf)) { - raceclass_t *rc; - // find raceclass for this one - for (rc = firstraceclass ; rc ; rc = rc->next) { - if (rc->skill == id) { - break; - } - } + } - if (rc) { - // announce. - if (f->val[1] >= PR_MASTER) { - msg("^gYou now know everything there is to know about %s.", rc->pluralname); - } else if (f->val[1] >= PR_SKILLED) { - msg("^gYou can now anticipate how %s will react.", rc->pluralname); - } else if (f->val[1] >= PR_ADEPT) { - msg("^gYou can now determine how dangerous %s are.", rc->pluralname); - } else if (f->val[1] >= PR_BEGINNER) { - msg("^gYou can now determine how much damage %s will deal.", rc->pluralname); - } else if (f->val[1] >= PR_NOVICE) { - msg("^gYou now know basic information about %s.", rc->pluralname); + // announecments based on skill level + if ( (gamemode == GM_GAMESTARTED) && isplayer(lf)) { + int i; + for (i = 0; i < sk->nskilldesc; i++) { + if (sk->skilldesclev[i] == f->val[1]) { // does our proficiency need a description? + if (sk->skilldescmsg[i]) { + msg(sk->skilldesctext[i]); + } } } - } if ((gamemode == GM_GAMESTARTED) && statdirty) { @@ -6574,6 +6515,11 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { assert(strlen(text) > 0); if (rnd(1,100) <= val[0]) { o = addob(op, text); + if (!o) { + if (db) { + dblog("couldnt give startob: %s", text); + } + } } } else if (id == F_STARTOBRND) { if (rnd(1,100) <= val[0]) { @@ -7519,6 +7465,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_METALWORK, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); // abilities addjob(J_DRUID, "Druid"); @@ -7938,6 +7885,19 @@ void initrace(void) { addflag(lastrace->flags, F_NOJOBTEXT, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 15, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_STARTJOB, 50, J_ROGUE, NA, NULL); + addrace(R_BEGGAR, "beggar", 50, '@', C_BROWN, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_RARITY, H_VILLAGE, 80, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 70, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 1, 2, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTATT, A_DEX, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-2 gold coins"); + addflag(lastrace->flags, F_STARTOB, 25, OC_POTION, NA, "potion of rum"); + addflag(lastrace->flags, F_STARTSKILL, SK_THIEVERY, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_RANDOMTALKPCT, 30, NA, NA, NULL); + addflag(lastrace->flags, F_RANDOMTALK, SP_BEG, SV_WHISPER, SV_TALK, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addrace(R_DRUNK, "drunkard", 90, '@', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_RARITY, H_VILLAGE, 90, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL); @@ -8368,10 +8328,10 @@ void initrace(void) { addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); - //addflag(lastrace->flags, F_STARTJOB, 25, J_WIZARD, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTJOB, 25, J_ROGUE, NA, NULL); addrace(R_GOBLINWAR, "goblin warrior", 30, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); @@ -8631,6 +8591,8 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, 6, 3, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 12, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STAYINROOM, NA, NA, NA, NULL); // stay in our maze addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "5-7"); addflag(lastrace->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL); @@ -9371,6 +9333,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_BLINK, 2, 2, "pw:1;"); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addrace(R_DOGDEATH, "death hound", 40, 'd', C_MAGENTA, MT_FLESH, RC_ANIMAL); @@ -9770,7 +9733,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting - addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:1;range:4;"); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); @@ -9796,7 +9759,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting - addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:5;"); + addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:5;range:2;"); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); @@ -9822,7 +9785,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting - addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:7;"); + addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:7;range:3;"); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); @@ -10858,10 +10821,21 @@ skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime) { a->name = strdup(name); a->desc = strdup(desc); a->traintime = traintime; + a->nskilldesc = 0; return a; } +void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg) { + skill_t *sk; + sk = findskill(id); + assert(sk); + sk->skilldesclev[sk->nskilldesc] = lev; + sk->skilldesctext[sk->nskilldesc] = strdup(text); + sk->skilldescmsg[sk->nskilldesc] = wantmsg; + sk->nskilldesc++; +} + void addtrail(lifeform_t *lf, int dir) { object_t *footprint, *scent; flag_t *fpflag; @@ -11196,7 +11170,9 @@ int areallies(lifeform_t *lf1, lifeform_t *lf2) { } } else { if (lf1->race->baseid == lf2->race->baseid) { - return B_TRUE; + if (!isplayer(lf1) && !isplayer(lf2)) { + return B_TRUE; + } } } /* @@ -11262,6 +11238,10 @@ void autoskill(lifeform_t *lf) { enum SKILLLEVEL slev; int nweps = 0; + if (hasjob(lf, J_COMMANDO)) { + return; + } + if (isplayer(lf)) { slev = PR_NOVICE; } else { @@ -11847,6 +11827,9 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml takedamage(o, newdam, DT_COLD); } } + } else if (damtype == DT_WATER) { + // put out fires + extinguishlf(lf); } } @@ -12435,7 +12418,6 @@ void outfitlf(lifeform_t *lf) { //int db = B_FALSE; givestartskills(lf, lf->flags); givestartobs(lf, NULL, lf->flags); - autoskill(lf); // weild/wear stuff autoweild(lf); @@ -12598,11 +12580,11 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char // announce - announceflaggain won't be called // since this isn't a new flag. if (isplayer(lf)) { - msg("^bYou feel more sick."); + msg("^%cYou feel more sick.", getlfcol(lf, CC_VBAD)); } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%c%s looks even more sick.", getlfcol(lf, CC_BAD), lfname); + msg("^%c%s looks even more sick.", getlfcol(lf, CC_VBAD), lfname); } found = B_TRUE; @@ -12784,62 +12766,80 @@ int readytotrain(lifeform_t *lf) { int recruit(lifeform_t *lf) { int rv = B_FALSE; - if (!lfhasflag(lf, F_NOHIRE) && - (lfhasflag(lf, F_HIREPRICE) || skillcheck(player, A_CHA, 20 + ((gethitdice(player) - gethitdice(lf))*2), 0)) ) { + if (!lfhasflag(lf, F_NOHIRE)) { int dohire = B_FALSE; - int askingprice = 0; + int askingprice = -1; char lfname[BUFLEN]; char buf[BUFLEN]; flag_t *f; + getlfname(lf, lfname); // they will consider it - now negotiate a price f = lfhasflag(lf, F_HIREPRICE); if (f) { askingprice = f->val[0]; } else { - askingprice = rnd(gethitdice(lf)*50, gethitdice(lf)*100 ); - addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL); - } - - // modify by charisma - askingprice = pctof(100 + getstatmod(player, A_CHA), askingprice); - - sayphrase(lf, SP_RECRUIT_ASKPRICE, SV_TALK, askingprice, NULL); - more(); - - if (askingprice > countmoney(player)) { - } else { - char ch; - sprintf(buf, "Pay $%d to hire %s", askingprice, lfname); - ch = askchar(buf, "yn","n", B_TRUE); - if (ch == 'y') { - dohire = B_TRUE; - } - } - - 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); - } else { - if (askingprice > countmoney(player)) { - sayphrase(lf, SP_RECRUIT_DECLINE_CANTPAY, SV_TALK, askingprice, NULL); + int result; + int difficulty; + difficulty = 20 + ((gethitdice(player) - gethitdice(lf))*2); + if (real_skillcheck(player, A_CHA, difficulty, 0, &result)) { + // passed + askingprice = rnd(gethitdice(lf)*50, gethitdice(lf)*100 ); + addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL); } else { - sayphrase(lf, SP_RECRUIT_DECLINE_WONTPAY, SV_TALK, askingprice, NULL); + if (difficulty - result >= 10) { + // will never join + askingprice = -1; + } else { + // expensive + askingprice = rnd(gethitdice(lf)*100, gethitdice(lf)*200 ); + addflag(lf->flags, F_HIREPRICE, askingprice, NA, NA, NULL); + } } } - } else { - 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); + + 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 { + // modify by charisma + askingprice = pctof(100 + getstatmod(player, A_CHA), askingprice); + + sayphrase(lf, SP_RECRUIT_ASKPRICE, SV_TALK, askingprice, NULL); + more(); + + if (askingprice > countmoney(player)) { + } else { + char ch; + sprintf(buf, "Pay $%d to hire %s", askingprice, lfname); + ch = askchar(buf, "yn","n", B_TRUE); + if (ch == 'y') { + dohire = B_TRUE; + } + } + + 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); + } 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); + } + } } - } + } // end if !nohire return rv; } @@ -13080,6 +13080,14 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t int i,rv = B_FALSE; char buf[BUFLEN]; switch (what) { + case SP_BEG: + switch (rnd(1,3)) { + case 1: sprintf(buf, "Spare a coin, mister?"); break; + case 2: sprintf(buf, "Alms for the poor!"); break; + case 3: sprintf(buf, "Alms!"); break; + } + rv = say(lf, buf, volume); + break; case SP_DRUNK: // random blurred speech strcpy(buf, ""); @@ -13115,6 +13123,14 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t case 3: rv = say(lf, "I've been robbed!", volume); break; } break; + case SP_PAYTHANKS: + switch (rnd(1,3)) { + case 1: sprintf(buf, "Pleasure doing business with you!"); break; + case 2: sprintf(buf, "Thank you, come again!"); break; + case 3: sprintf(buf, "Another satisfied customer!"); break; + } + rv = say(lf, buf, volume); + break; case SP_RECRUIT_ACCEPT: if (text) { sprintf(buf, "I will join you - my name is %s.", text); @@ -13206,16 +13222,16 @@ int scare(lifeform_t *lf, lifeform_t *scarer, int howlong, int scarerbonus) { if (nfailures == 1) { // cower - fleefrom(lf, scarer, rnd(1,3)); + fleefrom(lf, scarer, rnd(1,3), B_FALSE); return B_TRUE; } else if (nfailures == 2) { // flee for given time - fleefrom(lf, scarer, howlong); + fleefrom(lf, scarer, howlong, B_FALSE); return B_TRUE; } else if (nfailures == 3) { object_t *wep; // drop weapon and flee for given time - fleefrom(lf, scarer, howlong); + fleefrom(lf, scarer, howlong, B_FALSE); wep = getweapon(lf); if (wep) { drop(wep, ALL); @@ -13474,38 +13490,177 @@ void setlastdam(lifeform_t *lf, char *buf) { } void initskills(void) { + skill_t *sk; addskill(SK_ARMOUR, "Armour", "Reduces evasion and stealth penalties from wearing armour.", 100); + addskilldesc(SK_ARMOUR, PR_INEPT, "- Reduces the noise you make when wearing metal armour.", B_FALSE); + addskilldesc(SK_ARMOUR, PR_NOVICE, "^gReduces armour evasion penalties by 10%.", B_FALSE); + addskilldesc(SK_ARMOUR, PR_BEGINNER, "^gReduces armour evasion penalties by 20%.", B_FALSE); + addskilldesc(SK_ARMOUR, PR_ADEPT, "^gReduces armour evasion penalties by 30%.", B_FALSE); + addskilldesc(SK_ARMOUR, PR_SKILLED, "^gReduces armour evasion penalties by 40%.", B_FALSE); + addskilldesc(SK_ARMOUR, PR_EXPERT, "^gReduces armour evasion penalties by 50%.", B_FALSE); + addskilldesc(SK_ARMOUR, PR_MASTER, "^gReduces armour evasion penalties by 60%.", B_FALSE); addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery.", 50); + addskilldesc(SK_ATHLETICS, PR_INEPT, "- Determines how far you can sprint before tiring.", B_FALSE); + addskilldesc(SK_ATHLETICS, PR_NOVICE, "^gYou gain the 'sprint' ability.", B_FALSE); + addskilldesc(SK_ATHLETICS, PR_ADEPT, "^gYou gain the 'tumble' ability.", B_FALSE); + addskilldesc(SK_ATHLETICS, PR_EXPERT, "^gYou gain the 'jump' ability.", B_FALSE); addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen.", 50); + addskilldesc(SK_BACKSTAB, PR_NOVICE, "^gYour unseen attacks inflict double damage.", B_FALSE); + addskilldesc(SK_BACKSTAB, PR_BEGINNER, "^gYour unseen attacks inflict triple damage.", B_FALSE); + addskilldesc(SK_BACKSTAB, PR_ADEPT, "^gYour unseen attacks inflict quadruple damage.", B_FALSE); + addskilldesc(SK_BACKSTAB, PR_SKILLED, "^gYour unseen attacks inflict 5x damage.", B_FALSE); + addskilldesc(SK_BACKSTAB, PR_EXPERT, "^gYour unseen attacks inflict 6x damage.", B_FALSE); + addskilldesc(SK_BACKSTAB, PR_MASTER, "^gYour unseen attacks inflict 7x damage.", B_FALSE); addskill(SK_CARTOGRAPHY, "Cartography", "Your ability to create and interpret maps.", 0); // untrainable + addskilldesc(SK_CARTOGRAPHY, PR_NOVICE, "^gYou now make basic maps of your surroundings.", B_TRUE); + addskilldesc(SK_CARTOGRAPHY, PR_BEGINNER, "^gYour map now shows the location of staircases.", B_TRUE); + addskilldesc(SK_CARTOGRAPHY, PR_ADEPT, "^gYour map now shows the location of doors.", B_TRUE); + addskilldesc(SK_CARTOGRAPHY, PR_SKILLED, "^gYou no longer forget your surroundings.", B_FALSE); + addskilldesc(SK_CARTOGRAPHY, PR_EXPERT, "^gYour map will now show the location of objects.", B_TRUE); + addskilldesc(SK_CARTOGRAPHY, PR_MASTER, "^gEvery 50 turns, you can map a small area around you.", B_FALSE); addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.", 0); // untrainable + addskilldesc(SK_CHANNELING, PR_NOVICE, "^gThe power level of wands and scrolls is increased by 1.", B_FALSE); + addskilldesc(SK_CHANNELING, PR_BEGINNER, "^gThe power level of wands and scrolls is increased by 2.", B_FALSE); + addskilldesc(SK_CHANNELING, PR_ADEPT, "^gThe power level of wands and scrolls is increased by 4.", B_FALSE); + addskilldesc(SK_CHANNELING, PR_SKILLED, "^gThe power level of wands and scrolls is increased by 6.", B_FALSE); + addskilldesc(SK_CHANNELING, PR_EXPERT, "^gThe power level of wands and scrolls is increased by 8.", B_FALSE); + addskilldesc(SK_CHANNELING, PR_MASTER, "^gThe power level of wands and scrolls is increased by 10.", B_FALSE); addskill(SK_CLIMBING, "Climbing", "Helps you to climb walls, mountains or other terrain.", 50); + addskilldesc(SK_CLIMBING, PR_INEPT, "- Increases you chances of successfully climbing by 10% per level.", B_FALSE); addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.", 50); + addskilldesc(SK_COOKING, PR_NOVICE, "^gYou now recognise water and rotting food.", B_TRUE); + addskilldesc(SK_COOKING, PR_BEGINNER, "^gYou can now recognise all kinds of bad food.", B_TRUE); + addskilldesc(SK_COOKING, PR_ADEPT, "^gYou can use the 'cook' ability to make jerky.", B_FALSE); + addskilldesc(SK_COOKING, PR_EXPERT, "^gYou can use the 'cook' ability to make stew.", B_FALSE); addskill(SK_EVASION, "Evasion", "Your ability to dodge blows or traps.", 50); + addskilldesc(SK_EVASION, PR_NOVICE, "^gIncreases your EV by 5%.", B_FALSE); + addskilldesc(SK_EVASION, PR_BEGINNER, "^gIncreases your EV by 10%.", B_FALSE); + addskilldesc(SK_EVASION, PR_ADEPT, "^gIncreases your EV by 15%.", B_FALSE); + addskilldesc(SK_EVASION, PR_SKILLED, "^gIncreases your EV by 20%.", B_FALSE); + addskilldesc(SK_EVASION, PR_EXPERT, "^gIncreases your EV by 25%.", B_FALSE); + addskilldesc(SK_EVASION, PR_MASTER, "^gIncreases your EV by 30%.", B_FALSE); addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison.", 0); // untrainable + addskilldesc(SK_FIRSTAID, PR_INEPT, "- Lets you recognise how healthy your opponents are.", B_FALSE); + addskilldesc(SK_FIRSTAID, PR_INEPT, "- Determines how fast you heal when resting. ", B_FALSE); + addskilldesc(SK_FIRSTAID, PR_INEPT, "- Determines how long poison effects will last.", B_FALSE); + addskilldesc(SK_FIRSTAID, PR_ADEPT, "^gYou can now recognise when poison is potentially fatal.", B_TRUE); addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds.", 100); + addskilldesc(SK_LISTEN, PR_BEGINNER, "^gYou now gauge the distance of sounds.", B_TRUE); + addskilldesc(SK_LISTEN, PR_ADEPT, "^gYou can now determine the direction sounds are coming from.", B_TRUE); + addskilldesc(SK_LISTEN, PR_EXPERT, "^gYou can now identify monsters based on sound.", B_TRUE); + addskilldesc(SK_LISTEN, PR_MASTER, "^gYou can now locate monsters based on sound.", B_TRUE); addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50); addskill(SK_METALWORK, "Metalwork", "Lets you repair metal objects.", 100); + addskilldesc(SK_METALWORK, PR_NOVICE, "^gYou can repair metal items up to 33% condition.", B_FALSE); + addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can repair metal items up to 50% condition", B_FALSE); + addskilldesc(SK_METALWORK, PR_ADEPT, "^gYou can repair metal items up to 60% condition", B_FALSE); + addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can repair metal items up to 70% condition", B_FALSE); + addskilldesc(SK_METALWORK, PR_EXPERT, "^gYou can repair metal items up to 85% condition", B_FALSE); + addskilldesc(SK_METALWORK, PR_MASTER, "^gYou can fully repair metal items.", B_FALSE); addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.", 50); + addskilldesc(SK_RANGED, PR_NOVICE, "^gYou suffer a -20% accuracy penalty when using ranged weapons.", B_FALSE); + addskilldesc(SK_RANGED, PR_BEGINNER, "^gYou suffer a -10% accuracy penalty when using ranged weapons.", B_FALSE); + addskilldesc(SK_RANGED, PR_ADEPT, "^gYou no longer suffer a accuracy penalty when using ranged weapons.", B_FALSE); + addskilldesc(SK_RANGED, PR_SKILLED, "^gYou gain a +10% accuracy bonus when using ranged weapons.", B_FALSE); + addskilldesc(SK_RANGED, PR_EXPERT, "^gYou gain a +20% accuracy bonus when using ranged weapons.", B_FALSE); + addskilldesc(SK_RANGED, PR_MASTER, "^gYou gain a +30% accuracy bonus when using ranged weapons.", B_FALSE); addskill(SK_SEWING, "Sewing", "Lets you repair cloth or leather objects.", 100); + addskilldesc(SK_SEWING, PR_NOVICE, "^gYou can repair cloth items up to 33% condition.", B_FALSE); + addskilldesc(SK_SEWING, PR_BEGINNER, "^gYou can repair cloth items up to 50% condition", B_FALSE); + addskilldesc(SK_SEWING, PR_ADEPT, "^gYou can repair cloth items up to 60% condition", B_FALSE); + addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can repair cloth items up to 70% condition", B_FALSE); + addskilldesc(SK_SEWING, PR_EXPERT, "^gYou can repair cloth items up to 85% condition", B_FALSE); + addskilldesc(SK_SEWING, PR_MASTER, "^gYou can fully repair cloth items.", B_FALSE); addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block projectiles.", 50); + addskilldesc(SK_SHIELDS, PR_INEPT, "- Without this skill, shield accuracy penalties are tripled.", B_FALSE); + addskilldesc(SK_SHIELDS, PR_NOVICE, "^gShield accuracy penalties are reduced by 5%.", B_FALSE); + addskilldesc(SK_SHIELDS, PR_BEGINNER, "^gShield accuracy penalties are reduced by 10%.", B_FALSE); + addskilldesc(SK_SHIELDS, PR_ADEPT, "^gShield accuracy penalties are reduced by 15%.", B_FALSE); + 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_SPELLCASTING, "Sorcery", "Determines your ability to cast spells from all schools.", 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); + addskilldesc(SK_SPEECH, PR_SKILLED, "^gShop item prices are reduced by 20%.", B_FALSE); + addskilldesc(SK_SPEECH, PR_EXPERT, "^gShop item prices are reduced by 25%.", B_FALSE); + addskilldesc(SK_SPEECH, PR_MASTER, "^gShop item prices are reduced by 30%.", B_FALSE); + addskill(SK_SPELLCASTING, "Sorcery", "Increases the power of spells from all schools except Allomancy, Nature and Psionics.", 50); addskill(SK_SPOTHIDDEN, "Searching", "Helps you to spot hidden traps or creatures.", 50); addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable? + addskilldesc(SK_STEALTH, PR_BEGINNER, "^gYou gain the 'hide' ability.", B_FALSE); + addskilldesc(SK_STEALTH, PR_EXPERT, "^gYou can now hide even when mosnters are nearby.", B_TRUE); addskill(SK_SWIMMING, "Swimming", "Allows you to safely swim through deep water.", 50); + addskilldesc(SK_SWIMMING, PR_NOVICE, "^gYou can now swim.", B_TRUE); + addskilldesc(SK_SWIMMING, PR_BEGINNER, "^gYou can now swim a bit faster.", B_TRUE); + addskilldesc(SK_SWIMMING, PR_ADEPT, "^gYou can now swim a bit faster.", B_TRUE); + addskilldesc(SK_SWIMMING, PR_SKILLED, "^gYou can now swim a bit faster.", B_TRUE); + addskilldesc(SK_SWIMMING, PR_EXPERT, "^gYou can now attack (awkwardly) and cast spells while swimming.", B_TRUE); + addskilldesc(SK_SWIMMING, PR_MASTER, "^gYou can now attack while swimming with no penalty.", B_TRUE); addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items.", 0); // untrain addskill(SK_THIEVERY, "Thievery", "Your ability to pick pockets and steal items.", 50); + addskilldesc(SK_THIEVERY, PR_NOVICE, "^gYou gain the 'steal' ability, usable on enemies or in shops.", B_FALSE); + addskilldesc(SK_THIEVERY, PR_BEGINNER, "^gYour accuracy penalty when stealing is reduced.", B_TRUE); + addskilldesc(SK_THIEVERY, PR_ADEPT, "^gYou can now choose which items to steal.", B_TRUE); + addskilldesc(SK_THIEVERY, PR_SKILLED, "gYou can now steal heavy items.", B_TRUE); + addskilldesc(SK_THIEVERY, PR_EXPERT, "gYou can now steal multiple items.", B_TRUE); + addskilldesc(SK_THIEVERY, PR_MASTER, "gYou can now steal equipped items.", B_TRUE); addskill(SK_THROWING, "Throwing", "Your accuracy when throwing objects at things.", 50); + addskilldesc(SK_RANGED, PR_NOVICE, "^gYou suffer a -20% accuracy penalty when throwing items.", B_FALSE); + addskilldesc(SK_RANGED, PR_BEGINNER, "^gYou suffer a -10% accuracy penalty when throwing items.", B_FALSE); + addskilldesc(SK_RANGED, PR_ADEPT, "^gYou no longer suffer a accuracy penalty when throwing items.", B_FALSE); + addskilldesc(SK_RANGED, PR_SKILLED, "^gYou gain a +10% accuracy bonus when throwing items.", B_FALSE); + addskilldesc(SK_RANGED, PR_EXPERT, "^gYou gain a +20% accuracy bonus when throwing items.", B_FALSE); + addskilldesc(SK_RANGED, PR_MASTER, "^gYou gain a +30% accuracy bonus when throwing items.", B_FALSE); addskill(SK_TRACKING, "Tracking", "Allows you to track enemies by their footprints.", 0); // untrain + addskilldesc(SK_TRACKING, PR_NOVICE, "^gYou can now see footprints.", B_TRUE); + addskilldesc(SK_TRACKING, PR_BEGINNER, "^gYou can now determine how recently footprints were made.", B_TRUE); + addskilldesc(SK_TRACKING, PR_ADEPT, "^gYou can now identify creatures from their footprints.", B_TRUE); + addskilldesc(SK_TRACKING, PR_SKILLED, "^gYou can now recognise the direction of footprints.", B_TRUE); + addskilldesc(SK_TRACKING, PR_EXPERT, "^gYou can now partially obscure your own footprints.", B_TRUE); + addskilldesc(SK_TRACKING, PR_MASTER, "^gYou can now move without leaving footprints.", B_TRUE); addskill(SK_TRAPS, "Traps", "Affects your ability to locate and disarm traps.", 25); + addskilldesc(SK_TRAPS, PR_NOVICE, "^gYou gain the 'disarm traps' ability.", B_FALSE); addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once.", 50); + addskilldesc(SK_TWOWEAPON, PR_NOVICE, "^gYou can now weild two weapons at once.", B_TRUE); + addskilldesc(SK_TWOWEAPON, PR_ADEPT, "gYou no longer suffer an accuracy penalty when weilding two weapons.", B_TRUE); + addskilldesc(SK_TWOWEAPON, PR_SKILLED, "^gFollow-up attacks with your second weapon are now more accurate.", B_TRUE); + addskilldesc(SK_TWOWEAPON, PR_EXPERT, "^gYou gain the 'flurry attack' ability.", B_FALSE); + addskilldesc(SK_TWOWEAPON, PR_MASTER, "^gYou can now deflect attacks with your second weapon.", B_TRUE); // knowledge addskill(SK_LORE_ARCANA, "Lore:Arcana", "Allows you a chance of recognising magical objects and creatures.", 0); + addskilldesc(SK_LORE_ARCANA, PR_NOVICE, "^gYou can attempt to identify objects with the 'inspect' ability.", B_FALSE); addskill(SK_LORE_DEMONS, "Lore:Demonology", "Determines your knowledge about demons.", 0); addskill(SK_LORE_HUMANOID, "Lore:Humanoid", "Determines your knowledge about humanoid (bipedal) creatures.", 0); addskill(SK_LORE_NATURE, "Lore:Nature", "Determines your knowledge of plants, animals and insects.", 0); addskill(SK_LORE_UNDEAD, "Lore:Undead", "Determines your knowledge of the undead.", 0); + + for (sk = firstskill ; sk ; sk = sk->next) { + if (isloreskill(sk->id)) { + raceclass_t *rc; + // find raceclass for this one + for (rc = firstraceclass ; rc ; rc = rc->next) { + if (rc->skill == sk->id) { + break; + } + } + if (rc) { + char buf[BUFLEN]; + sprintf(buf, "^gYou now know basic information about %s.", rc->pluralname); + addskilldesc(sk->id, PR_NOVICE, buf, B_TRUE); + sprintf(buf, "^gYou can now determine how much damage %s will deal.", rc->pluralname); + addskilldesc(sk->id, PR_BEGINNER, buf, B_TRUE); + sprintf(buf, "^gYou can now determine how dangerous %s are.", rc->pluralname); + addskilldesc(sk->id, PR_ADEPT, buf, B_TRUE); + sprintf(buf, "^gYou can now anticipate how %s will react.", rc->pluralname); + addskilldesc(sk->id, PR_SKILLED, buf, B_TRUE); + sprintf(buf, "^gYou now know everything there is to know about %s.", rc->pluralname); + addskilldesc(sk->id, PR_MASTER, buf, B_TRUE); + } + } + } + // weaponry addskill(SK_AXES, "Axes", "Helps you use chopping weapons like axes.", 50); addskill(SK_CLUBS, "Clubs", "Helps you use bashing weapons like maces or clubs.", 50); @@ -13514,22 +13669,115 @@ void initskills(void) { addskill(SK_SHORTBLADES, "Short Blades", "Helps you use daggers, short swords, etc.", 50); addskill(SK_STAVES, "Staves", "Helps you use quarterstaffs, staffs, etc.", 50); addskill(SK_UNARMED, "Unarmed Combat", "Helps you fight using your bare hands.", 50); + addskilldesc(SK_UNARMED, PR_SKILLED, "^gYou can now make melee attacks with your off-hand.", B_TRUE); // spell schools addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.", 50); + + addskilldesc(SK_SS_ALLOMANCY, PR_NOVICE, "You gain knowledge of all Allomancy spells.", B_FALSE); + addskilldesc(SK_SS_ALLOMANCY, PR_NOVICE, "Allows you to cast Allomancy spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_ALLOMANCY, PR_BEGINNER, "Allows you to cast Allomancy spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_ALLOMANCY, PR_ADEPT, "Allows you to cast Allomancy spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_ALLOMANCY, PR_SKILLED, "Allows you to cast Allomancy spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_ALLOMANCY, PR_EXPERT, "Allows you to cast Allomancy spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_ALLOMANCY, PR_MASTER, "Allows you to cast Allomancy spells up to level 9.", B_FALSE); addskill(SK_SS_AIR, "Air Magic", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_AIR, PR_NOVICE, "Allows you to cast Air Magic spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_AIR, PR_BEGINNER, "Allows you to cast Air Magic spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_AIR, PR_ADEPT, "Allows you to cast Air Magic spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_AIR, PR_SKILLED, "Allows you to cast Air Magic spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_AIR, PR_EXPERT, "Allows you to cast Air Magic spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_AIR, PR_MASTER, "Allows you to cast Air Magic spells up to level 9.", B_FALSE); addskill(SK_SS_DEATH, "Necromancy", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_DEATH, PR_NOVICE, "Allows you to cast Necromancy spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_DEATH, PR_BEGINNER, "Allows you to cast Necromancy spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_DEATH, PR_ADEPT, "Allows you to cast Necromancy spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_DEATH, PR_SKILLED, "Allows you to cast Necromancy spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_DEATH, PR_EXPERT, "Allows you to cast Necromancy spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_DEATH, PR_MASTER, "Allows you to cast Necromancy spells up to level 9.", B_FALSE); addskill(SK_SS_DIVINATION, "Divination", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_DIVINATION, PR_NOVICE, "Allows you to cast Divination spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_DIVINATION, PR_BEGINNER, "Allows you to cast Divination spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_DIVINATION, PR_ADEPT, "Allows you to cast Divination spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_DIVINATION, PR_SKILLED, "Allows you to cast Divination spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_DIVINATION, PR_EXPERT, "Allows you to cast Divination spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_DIVINATION, PR_MASTER, "Allows you to cast Divination spells up to level 9.", B_FALSE); addskill(SK_SS_ENCHANTMENT, "Enchantment", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_ENCHANTMENT, PR_NOVICE, "Allows you to cast Enchantment spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_ENCHANTMENT, PR_BEGINNER, "Allows you to cast Enchantment spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_ENCHANTMENT, PR_ADEPT, "Allows you to cast Enchantment spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_ENCHANTMENT, PR_SKILLED, "Allows you to cast Enchantment spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_ENCHANTMENT, PR_EXPERT, "Allows you to cast Enchantment spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_ENCHANTMENT, PR_MASTER, "Allows you to cast Enchantment spells up to level 9.", B_FALSE); addskill(SK_SS_FIRE, "Fire Magic", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_FIRE, PR_NOVICE, "Allows you to cast Fire Magic spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_FIRE, PR_BEGINNER, "Allows you to cast Fire Magic spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_FIRE, PR_ADEPT, "Allows you to cast Fire Magic spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_FIRE, PR_SKILLED, "Allows you to cast Fire Magic spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_FIRE, PR_EXPERT, "Allows you to cast Fire Magic spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_FIRE, PR_MASTER, "Allows you to cast Fire Magic spells up to level 9.", B_FALSE); addskill(SK_SS_COLD, "Cold Magic", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_COLD, PR_NOVICE, "Allows you to cast Cold Magic spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_COLD, PR_BEGINNER, "Allows you to cast Cold Magic spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_COLD, PR_ADEPT, "Allows you to cast Cold Magic spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_COLD, PR_SKILLED, "Allows you to cast Cold Magic spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_COLD, PR_EXPERT, "Allows you to cast Cold Magic spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_COLD, PR_MASTER, "Allows you to cast Cold Magic spells up to level 9.", B_FALSE); addskill(SK_SS_GRAVITY, "Gravitation Magic", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_GRAVITY, PR_NOVICE, "Allows you to cast Gravitation Magic spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_BEGINNER, "Allows you to cast Gravitation Magic spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_ADEPT, "Allows you to cast Gravitation Magic spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_SKILLED, "Allows you to cast Gravitation Magic spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_EXPERT, "Allows you to cast Gravitation Magic spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_GRAVITY, PR_MASTER, "Allows you to cast Gravitation Magic spells up to level 9.", B_FALSE); addskill(SK_SS_LIFE, "Life Magic", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_LIFE, PR_NOVICE, "Allows you to cast Life Magic spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_LIFE, PR_BEGINNER, "Allows you to cast Life Magic spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_LIFE, PR_ADEPT, "Allows you to cast Life Magic spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_LIFE, PR_SKILLED, "Allows you to cast Life Magic spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_LIFE, PR_EXPERT, "Allows you to cast Life Magic spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_LIFE, PR_MASTER, "Allows you to cast Life Magic spells up to level 9.", B_FALSE); addskill(SK_SS_MODIFICATION, "Modification", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_MODIFICATION, PR_NOVICE, "Allows you to cast Modification spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_MODIFICATION, PR_BEGINNER, "Allows you to cast Modification spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_MODIFICATION, PR_ADEPT, "Allows you to cast Modification spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_MODIFICATION, PR_SKILLED, "Allows you to cast Modification spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_MODIFICATION, PR_EXPERT, "Allows you to cast Modification spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_MODIFICATION, PR_MASTER, "Allows you to cast Modification spells up to level 9.", B_FALSE); addskill(SK_SS_MENTAL, "Psionics", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_MENTAL, PR_NOVICE, "Allows you to cast Psionic spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_MENTAL, PR_BEGINNER, "Allows you to cast Psionic spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_MENTAL, PR_ADEPT, "Allows you to cast Psionic spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_MENTAL, PR_SKILLED, "Allows you to cast Psionic spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_MENTAL, PR_EXPERT, "Allows you to cast Psionic spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_MENTAL, PR_MASTER, "Allows you to cast Psionic spells up to level 9.", B_FALSE); addskill(SK_SS_NATURE, "Nature Magic", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_NATURE, PR_NOVICE, "Allows you to cast Nature spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_NATURE, PR_BEGINNER, "Allows you to cast Nature spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_NATURE, PR_ADEPT, "Allows you to cast Nature spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_NATURE, PR_SKILLED, "Allows you to cast Nature spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_NATURE, PR_EXPERT, "Allows you to cast Nature spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_NATURE, PR_MASTER, "Allows you to cast Nature spells up to level 9.", B_FALSE); addskill(SK_SS_SUMMONING, "Summoning", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_SUMMONING, PR_NOVICE, "Allows you to cast Summoning spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_SUMMONING, PR_BEGINNER, "Allows you to cast Summoning spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_SUMMONING, PR_ADEPT, "Allows you to cast Summoning spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_SUMMONING, PR_SKILLED, "Allows you to cast Summoning spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_SUMMONING, PR_EXPERT, "Allows you to cast Summoning spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_SUMMONING, PR_MASTER, "Allows you to cast Summoning spells up to level 9.", B_FALSE); addskill(SK_SS_TRANSLOCATION, "Translocation", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_TRANSLOCATION, PR_NOVICE, "Allows you to cast Translocation spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_TRANSLOCATION, PR_BEGINNER, "Allows you to cast Translocation spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_TRANSLOCATION, PR_ADEPT, "Allows you to cast Translocation spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_TRANSLOCATION, PR_SKILLED, "Allows you to cast Translocation spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_TRANSLOCATION, PR_EXPERT, "Allows you to cast Translocation spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_TRANSLOCATION, PR_MASTER, "Allows you to cast Translocation spells up to level 9.", B_FALSE); addskill(SK_SS_WILD, "Wild Magic", "Boosts casting of spells from this school.", 50); + addskilldesc(SK_SS_WILD, PR_NOVICE, "Allows you to cast Wild Magic spells up to level 1.", B_FALSE); + addskilldesc(SK_SS_WILD, PR_BEGINNER, "Allows you to cast Wild Magic spells up to level 2.", B_FALSE); + addskilldesc(SK_SS_WILD, PR_ADEPT, "Allows you to cast Wild Magic spells up to level 4.", B_FALSE); + addskilldesc(SK_SS_WILD, PR_SKILLED, "Allows you to cast Wild Magic spells up to level 6.", B_FALSE); + addskilldesc(SK_SS_WILD, PR_EXPERT, "Allows you to cast Wild Magic spells up to level 8.", B_FALSE); + addskilldesc(SK_SS_WILD, PR_MASTER, "Allows you to cast Wild Magic spells up to level 9.", B_FALSE); } void interrupt(lifeform_t *lf) { @@ -14079,9 +14327,9 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { if (op->owner) { getlfname(op->owner, targname); if (isplayer(lf)) { - msg("You steal %s from %s!", obname, targname); + msg("You steal %s from %s!", getlfcol(op->owner, CC_BAD), obname, targname); } else if (cansee(player, lf)) { - msg("%s steals %s from %s!", lfname, obname, targname); + msg("^%c%s steals %s from %s!", getlfcol(op->owner, CC_BAD), lfname, obname, targname); } } else { if (isplayer(lf)) { @@ -14781,8 +15029,7 @@ void turneffectslf(lifeform_t *lf) { for (i = 0; i < lf->nlos; i++) { if (!lf->los[i]->lf) { object_t *o; - o = hasobwithflag(lf->los[i]->obpile, F_SECRET); - if (o) { + for (o = lf->los[i]->obpile->first; o ; o = o->next) { flag_t *f; int mod = 0; @@ -14806,6 +15053,35 @@ void turneffectslf(lifeform_t *lf) { practice(lf, SK_TRAPS, 1); } } + } + f = hasflag(o->flags, F_TRAPPED); + if (f && (f->val[2] != B_TRUE)) { + objecttype_t *ot; + flag_t *trapflag; + int diff; + + // find trap type + ot = findot(f->val[0]); + trapflag = hasflag(ot->flags, F_TRAP); + assert(trapflag); + diff = trapflag->val[0]; + + mod += getskill(lf, SK_TRAPS); + if (skillcheck(lf, SC_SEARCH, diff, mod)) { + char obname[BUFLEN]; + // reveal it + getobname(o, obname, o->amt); + msg("^wYou notice a trap on %s!",obname); + f->val[2] = B_TRUE; + needredraw = B_TRUE; + drawscreen(); + // train skills + practice(lf, SK_SPOTHIDDEN, 1); + if (hasflag(o->flags, F_TRAP)) { + practice(lf, SK_TRAPS, 1); + } + } + } } } @@ -15111,7 +15387,7 @@ void turneffectslf(lifeform_t *lf) { char targname[BUFLEN]; getlfname(lf, lfname); getlfname(targ, targname); - msg("db: %s no longer targetting %s.",lfname,targname); + //msg("db: %s no longer targetting %s.",lfname,targname); } killflag(f); continue; @@ -15970,7 +16246,6 @@ int rest(lifeform_t *lf, int onpurpose) { //if (isplayer(lf)) msg("hp given."); if (lf->hp < lf->maxhp) { // pass a skill check to regain hp - if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) { gainhp(lf, hpheal); } @@ -16190,6 +16465,24 @@ int wear(lifeform_t *lf, object_t *o) { case E_NOBP: if (isplayer(lf)) msg("You have no %s on which to wear that!", getbodypartname(bp)); break; + case E_LOWCHA: + msg("You are not attractive enough to wear this."); + break; + case E_LOWCON: + msg("You are not healthy enough to wear this."); + break; + case E_LOWDEX: + msg("You are not dextrous enough to wear this."); + break; + case E_LOWIQ: + msg("You are not smart enough to wear this."); + break; + case E_LOWSTR: + msg("You are not strong enough to wear this."); + break; + case E_LOWWIS: + msg("You are not wise enough to wear this."); + break; default: if (isplayer(lf)) { msg("You can't wear that!"); diff --git a/lf.h b/lf.h index 62ff009..e269f47 100644 --- a/lf.h +++ b/lf.h @@ -6,6 +6,7 @@ job_t *addjob(enum JOB id, char *name); race_t *addrace(enum RACE id, char *name, float weight, char glyph, int glyphcolour, enum MATERIAL mat, enum RACECLASS raceclass); raceclass_t *addraceclass(enum RACECLASS id, char *name, char *pluralname, enum SKILL skill); skill_t *addskill(enum SKILL id, char *name, char *desc, int traintime); +void addskilldesc(enum SKILL id, enum SKILLLEVEL lev, char *text, int wantmsg); void addtrail(lifeform_t *lf, int dir); void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype); void adjustspeedforwater(lifeform_t *lf, int *speed); @@ -60,6 +61,7 @@ void dumpxp(void); int eat(lifeform_t *lf, object_t *o); void enhancerandomskill(lifeform_t *lf); void enhanceskills(lifeform_t *lf); +void extinguishlf(lifeform_t *lf); object_t *eyesshaded(lifeform_t *lf); int fall(lifeform_t *lf, lifeform_t *fromlf, int announce); int fallasleep(lifeform_t *lf, int howlong); @@ -75,7 +77,7 @@ skill_t *findskill(enum SKILL id); skill_t *findskillbyname(char *name); enum SKILLLEVEL findskilllevbyname(char *name); int flee(lifeform_t *lf); -void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong); +void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose); int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong); void gainhp(lifeform_t *lf, int amt); void gainlevel(lifeform_t *lf); diff --git a/map.c b/map.c index 6b23c8a..77548ea 100644 --- a/map.c +++ b/map.c @@ -426,7 +426,7 @@ void getradiuscells(cell_t *centre, int radius, int dirtype, enum LOFTYPE needlo *ncells = 0; - if (!c) { + if (!centre) { return; } if (dirtype == DT_ORTH) { @@ -588,10 +588,16 @@ regionthing_t *addregionthing(regionoutline_t *ro, int depth, int x, int y, enum } ro->nthings++; + + if (ro->nthings >= MAXOUTLINETHINGS) { + dblog("error - too many outlinethings!"); + printf("error - too many outlinethings!\n"); + exit(1); + } return rt; } -regiontype_t *addregiontype(enum REGIONTYPE id, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major) { +regiontype_t *addregiontype(enum REGIONTYPE id, char *name, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major) { regiontype_t *a; // add to the end of the list @@ -611,6 +617,7 @@ regiontype_t *addregiontype(enum REGIONTYPE id, enum HABITAT defaulthabitat, int // props a->id = id; + a->name = strdup(name); a->defaulthabitat = defaulthabitat; a->maxdepth = maxdepth; a->stairsperlev = stairsperlev; @@ -2081,6 +2088,15 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex if (db) dblog(" checking region outline for things..."); for (i = 0; i < region->outline->nthings; i++) { int matched = B_FALSE; + if (db) { + dblog(" Checking outlinething #%d (thing:depth=%d,x=%d,y=%d thismap:depth=%d,x=%d,y=%d ).", i, + region->outline->thing[i].depth, + region->outline->thing[i].x, + region->outline->thing[i].y, + depth,x,y + ); + } + if ((region->rtype->id == RG_WORLDMAP) && (region->outline->thing[i].depth == NA)) { // match on x/y coords if ((region->outline->thing[i].x == x) && (region->outline->thing[i].y == y)) { @@ -2110,6 +2126,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex } else { if (db) dblog(" region has no outline."); } + if (db) dblog(" %d things remembered for later.",nthings); // build it... @@ -2764,6 +2781,40 @@ printf("dump of map '%s' (%d x %d):\n",map->name, map->w, map->h); } } +void dumpoutlines(void) { + region_t *r; + int i; + for (r = firstregion ; r ; r = r->next) { + dblog("region:%s",r->rtype->name); + if (r->outline) { + for (i = 0; i < r->outline->nthings; i++ ){ + regionthing_t *rt; + char loctext[BUFLEN]; + rt = &r->outline->thing[i]; + if (rt->depth == NA) { + sprintf(loctext, "%d,%d",rt->x, rt->y); + } else { + sprintf(loctext, "depth %d",rt->depth); + } + if (rt->whatkind == RT_REGIONLINK) { + regiontype_t *rtype; + rtype = findregiontype(rt->value); + dblog(" at %s: link to %s",loctext, rtype->name); + } else if (rt->whatkind == RT_HABITAT) { + habitat_t *h; + h = findhabitat(rt->value); + dblog(" at %s: %s",loctext, h->name); + } else if (rt->whatkind == RT_VAULT) { + vault_t *v; + v = findvault(rt->what); + dblog(" at %s: %s",loctext, v->id); + } + } + } + } +} + + // dirtype of DT_ORTH will give a square explosion // dirtype of DT_COMPASS will give a circular explosion void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce) { @@ -3594,7 +3645,7 @@ object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tfl void initmap(void) { - int vx,vy; + int vx[4],vy[4],i; // habitats // thingchance, obchance, vaultchance addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 10); @@ -3618,30 +3669,41 @@ void initmap(void) { addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -1); // region types - addregiontype(RG_WORLDMAP, H_FOREST, 10, 0, D_NONE, B_TRUE); - addregiontype(RG_FIRSTDUNGEON, H_DUNGEON, 30, 3, D_DOWN, B_TRUE); - addregiontype(RG_PIT, H_PIT, 1, 1, D_DOWN, B_FALSE); + addregiontype(RG_WORLDMAP, "World map", H_FOREST, 10, 0, D_NONE, B_TRUE); + addregiontype(RG_FIRSTDUNGEON, "First Dungeon", H_DUNGEON, 20, 3, D_DOWN, B_TRUE); + addregiontype(RG_PIT, "Pit", H_PIT, 1, 1, D_DOWN, B_FALSE); + // region definitions (outlines) addregionoutline(RG_WORLDMAP); // link to first dungeon addregionthing(lastregionoutline, NA, 0, 0, RT_REGIONLINK, RG_FIRSTDUNGEON, "staircase going down"); - // the village - /* - vx = 0; vy = 0; - while ((vx == 0) && (vy == 0)) { - vx = rnd(-2,2); - vy = rnd(-2,2); + // four villages + for (i = 0; i < 4; i++) { + vx[i] = 0; vy[i] = 0; + while ((vx[i] == 0) && (vy[i] == 0)) { + int n, distfromcentre; + distfromcentre = 2 + (i*2); + vx[i] = rnd(-distfromcentre,distfromcentre); + vy[i] = rnd(-distfromcentre,distfromcentre); + // check for other villages in this map... + for (n = 0; n < i; n++) { + if ((vx[n] == vx[i]) && (vy[n] == vy[i])) { + vx[i] = 0; vy[i] = 0; // invalidate! + break; + } + } + } + addregionthing(lastregionoutline, NA, vx[i], vy[i], RT_HABITAT, H_VILLAGE, NULL); + addregionthing(lastregionoutline, NA, vx[i], vy[i], RT_VAULT, NA, "food_shop"); + addregionthing(lastregionoutline, NA, vx[i], vy[i], RT_VAULT, NA, "pub"); + addregionthing(lastregionoutline, NA, vx[i], vy[i], RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL); + addregionthing(lastregionoutline, NA, vx[i], vy[i], RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL); + addregionthing(lastregionoutline, NA, vx[i], vy[i], RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL); } - */ - vx = 0; vy = -1; - addregionthing(lastregionoutline, NA, vx, vy, RT_HABITAT, H_VILLAGE, NULL); - addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "food_shop"); - addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "pub"); - addregionthing(lastregionoutline, NA, vx, vy, RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL); - addregionthing(lastregionoutline, NA, vx, vy, RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL); - addregionthing(lastregionoutline, NA, vx, vy, RT_RNDVAULTWITHFLAG, F_VAULTISSHOP, NULL); + //vx = 0; vy = -1; addregionoutline(RG_FIRSTDUNGEON); - addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair"); + addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair"); + addregionthing(lastregionoutline, 20, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISSHRINE, NULL); // godstone on last floor } int isadjacent(cell_t *src, cell_t *dst) { @@ -4063,6 +4125,7 @@ void makedoor(cell_t *cell, int openchance) { // at dungeon lev 50, chance is 5 in 6 chance = rolldie(1,6) - (m->depth / 10); + if (chance <= 1) { addflag(o->flags, F_LOCKED, B_TRUE, getdoorlockdiff(m->depth), NA, NULL); } @@ -4154,7 +4217,7 @@ void mapentereffects(map_t *m) { lifeform_t *lf; killlf(c->lf); lf = addmonster(c, R_HUMAN, B_TRUE, 1, B_FALSE, NULL); - addflag(lf->flags, F_STAYINROOM, c->roomid, NA, NA, NULL); + addflag(lf->flags, F_STAYINROOM, c->roomid, B_MAYCHASE, NA, NULL); } } } diff --git a/map.h b/map.h index 6500b87..7967eef 100644 --- a/map.h +++ b/map.h @@ -10,7 +10,7 @@ int addrandomthing(cell_t *c, int obchance, int *nadded); region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid); regionoutline_t *addregionoutline(enum REGIONTYPE rtype); regionthing_t *addregionthing(regionoutline_t *ro, int depth, int x, int y, enum REGIONTHING whatkind, int value, char *what); -regiontype_t *addregiontype(enum REGIONTYPE id, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major); +regiontype_t *addregiontype(enum REGIONTYPE id, char *name, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major); int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int doorpct, int dooropenchance); int cellhaslos(cell_t *c1, cell_t *dest); void clearcell(cell_t *c); diff --git a/move.c b/move.c index e45a622..0708924 100644 --- a/move.c +++ b/move.c @@ -119,6 +119,11 @@ int canswapwith(lifeform_t *lf, lifeform_t *lf2) { if (celldangerous(lf2, lf->cell, B_FALSE, NULL)) { return B_FALSE; } + + // cannot swap with sleeping lfs + if (lfhasflag(lf2, F_ASLEEP)) { + return B_FALSE; + } // allies can always swap if (areallies(lf, lf2)) { @@ -682,6 +687,8 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc if (lfhasflag(lf, F_LEVITATING)) { howfar *= 2; } + + breakallgrabs(lf); for (i = 0; i < howfar; i++) { if (moveclear(lf, dir, &reason)) { @@ -690,6 +697,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc } trymove(lf, dir, B_FALSE); } + if (reason != E_OK) { char buf[BUFLEN]; char thing[BUFLEN]; @@ -1045,6 +1053,9 @@ int movelf(lifeform_t *lf, cell_t *newcell) { msg("%s starts swimming.", lfname); didmsg = B_TRUE; } + // put out fires + extinguishlf(lf); + // stop sprinting stopsprinting(lf); } @@ -1052,7 +1063,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } f = hasflag(o->flags, F_SHARP); - if (f && hasbp(lf, BP_FEET)) { + if (f && hasbp(lf, BP_FEET) && !lfhasflag(lf, F_SNEAK)) { object_t *boots; // has boots on? boots = getequippedob(lf->pack, BP_FEET); @@ -1072,7 +1083,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } f = hasflag(o->flags, F_CRUSHABLE); - if (f) { + if (f && !lfhasflag(lf, F_SNEAK)) { enum LFSIZE crushsize; crushsize = f->val[0]; @@ -1128,9 +1139,11 @@ int movelf(lifeform_t *lf, cell_t *newcell) { // or rooms with pillars. would be better to fix // haslos() code to handle looking along walls // instead. - // if you walked into a new fully lit room, reveal it + // if you walked into a new fully lit room, which + // ISNT a vault, reveal it. + // - if (getskill(lf, SK_CARTOGRAPHY) >= PR_NOVICE) { + if ((getskill(lf, SK_CARTOGRAPHY) >= PR_NOVICE) && (!lf->cell->vault)) { if ((postroom > 0) && (postroom != preroom)) { cell_t *c[MAX_MAPW*MAX_MAPH]; int ncells; @@ -1454,6 +1467,21 @@ int opendoor(lifeform_t *lf, object_t *o) { return B_TRUE; } else { if (lf) { + // has known trap? + if (isplayer(lf)) { + if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { + if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { + char ch; + sprintf(buf,"Really open %s?", obname); + ch = askchar(buf,"yn","n", B_TRUE); + if (ch != 'y') { + msg("Cancelled."); + return B_TRUE; + } + } + } + } + taketime(lf, getactspeed(lf)); touch(lf, o); @@ -1467,6 +1495,12 @@ int opendoor(lifeform_t *lf, object_t *o) { */ } + // trapped? + if (lf && hasflag(o->flags, F_TRAPPED)) { + if (doobtraps(o, lf)) { + return B_TRUE; + } + } // locked? if (hasflag(o->flags, F_LOCKED)) { if (lf && isplayer(lf)) { @@ -1502,12 +1536,10 @@ int opendoor(lifeform_t *lf, object_t *o) { // open it addflag(o->flags, F_OPEN, B_TRUE, NA, NA, NULL); - f = hasflag(o->flags, F_IMPASSABLE); - if (f) killflag(f); - f = hasflag(o->flags, F_BLOCKSVIEW); - if (f) killflag(f); - f = hasflag(o->flags, F_SECRET); - if (f) killflag(f); + killflagsofid(o->flags, F_IMPASSABLE); + killflagsofid(o->flags, F_BLOCKSVIEW); + killflagsofid(o->flags, F_SECRET); + killflagsofid(o->flags, F_TRAPPED); if (lf) { if (isplayer(lf)) { @@ -2291,7 +2323,10 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { killflagsofid(lf->flags, F_GRABBEDBY); killflagsofid(grabbedby->flags, F_GRABBING); // move - don't clear the 'you break free from' msg - moveto(lf, cell, B_TRUE, B_TRUE); + // NOW is the move possible? + if (moveclear(lf, dir, &errcode)) { + moveto(lf, cell, B_TRUE, B_TRUE); + } } else { if (isplayer(lf)) { msg("You cannot get away from %s!",gbname); @@ -2453,16 +2488,31 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { return B_FALSE; } - // shopkeepers will only leave their shops if they have a target + // some lfs will only leave their rooms if they have a target + // ie. shopkeepers f = lfhasflag(lf, F_STAYINROOM); if (f) { int roomid; roomid = f->val[0]; - // if moving out of my room.. - if ((lf->cell->roomid == roomid) && (lf->cell->roomid != cell->roomid)) { - if (!aihastarget(lf)) { - if (error) *error = E_WONT; - return B_FALSE; + if (roomid == NA) { + // don't move out of ANY room. + if ((lf->cell->roomid != cell->roomid)) { + if ((f->val[1] != NA) && aihastarget(lf)) { + // exception! + } else { + if (error) *error = E_WONT; + return B_FALSE; + } + } + } else { + // don't move out of the given room. + if ((lf->cell->roomid == roomid) && (lf->cell->roomid != cell->roomid)) { + if ((f->val[1] != NA) && aihastarget(lf)) { + // exception! + } else { + if (error) *error = E_WONT; + return B_FALSE; + } } } } diff --git a/nexus.c b/nexus.c index 6ec02ec..88c3cca 100644 --- a/nexus.c +++ b/nexus.c @@ -843,7 +843,6 @@ int init(void) { // random numbers srand(time(NULL)); - gamemode = GM_INIT; playerglyph.ch = '@'; diff --git a/objects.c b/objects.c index 0f83ab9..9ec6a58 100644 --- a/objects.c +++ b/objects.c @@ -73,6 +73,7 @@ enum OBCLASS sortorder[] = { OC_TOOLS, OC_BOOK, OC_FURNITURE, + OC_GODSTONE, OC_ROCK, OC_FLORA, OC_DFEATURE, @@ -244,11 +245,14 @@ brand_t *addbrand(enum BRAND id, char *suffix, enum BODYPART bp) { object_t *addemptyob(obpile_t *where, object_t *o) { char buf[BUFLEN]; object_t *empty; + // determine what kind of empty container to drop if (strstr(o->type->name, "vial")) { strcpy(buf, "empty vial"); - } else { + } else if (strstr(o->type->name, "potion")) { strcpy(buf, "empty flask"); + } else { + return NULL; } empty = addob(where, buf); @@ -434,6 +438,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes enum FLAG doorflag[5]; int ndoorflags = 0; char *signtext = NULL; + int trapchance = 0; // just in case we don't add any addedob[0] = NULL; @@ -613,6 +618,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes dorandombrand = B_TRUE; p += strlen("branded "); donesomething = B_TRUE; + } else if (strstarts(p, "trapped ")) { + trapchance = 100; + p += strlen("trapped "); + donesomething = B_TRUE; } } @@ -1418,27 +1427,28 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes wantbrand = getrandombrandfor(ot); } - // check for specific brands. eg. "xxx of pyromania" - // NOTE: this will override any random brands from "branded" - for (br = firstbrand ; br ; br = br->next) { - if (strstr(name, br->suffix)) { - // does this brand apply to this objecttype? - if (brandappliesto(br, o->type)) { - wantbrand = br; - break; - } - } - } - - if (wantbrand) { - if (brandappliesto(wantbrand, o->type)) { - copyflags(o->flags, wantbrand->flags, FROMBRAND); - addflag(o->flags, F_HASBRAND, wantbrand->id, NA, NA, NULL); - } - } - } + // check for specific brands. eg. "xxx of pyromania" + // NOTE: this will override any random brands from "branded" + for (br = firstbrand ; br ; br = br->next) { + if (strstr(name, br->suffix)) { + // does this brand apply to this objecttype? + if (brandappliesto(br, o->type)) { + wantbrand = br; + break; + } + } + } + + if (wantbrand) { + if (brandappliesto(wantbrand, o->type)) { + copyflags(o->flags, wantbrand->flags, FROMBRAND); + addflag(o->flags, F_HASBRAND, wantbrand->id, NA, NA, NULL); + } + } + + if (where->owner) { // new owner gains "hold confer" flags conferred by this object giveobflags(where->owner, o, F_HOLDCONFER); @@ -1476,10 +1486,33 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } */ - // containers - if (hasflag(o->flags, F_CONTAINER)) { - if (getoblocation(o)) { - givestartobs(NULL, o, o->flags); + // ie. don't do these things when just creating objects + // for validation purposes + if (obloc) { + // containers + if (hasflag(o->flags, F_CONTAINER)) { + if (getoblocation(o)) { + givestartobs(NULL, o, o->flags); + } + } + + // trapped? l1=10%, l5=20%, l10=30%, l15=40%, l20+=60% + if (!trapchance) { + f = hasflag(o->flags, F_CANBETRAPPED); + if (f) { + trapchance = f->val[0] + (f->val[1] * (obloc->map->depth/5)); + limit(&trapchance, f->val[0], f->val[2]); + } + } + + if (trapchance) { + if (pctchance(trapchance)) { + enum OBTYPE traptype; + // get a random trap + // + traptype = getrandomtrapforob(); + addflag(o->flags, F_TRAPPED, traptype, NA, NA, NULL); + } } } @@ -2441,6 +2474,25 @@ void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype) { } } +int doobtraps(object_t *o, lifeform_t *lf) { + flag_t *f; + f = hasflag(o->flags, F_TRAPPED); + if (f) { + enum OBTYPE trapid; + + // announce... + if (isplayer(lf)) { + msg("^wA trap goes off!"); + } + + trapid = f->val[0]; + trapeffects(NULL, trapid, lf); + killflag(f); // now the trap gets removed + return B_TRUE; + } + return B_FALSE; +} + void dumpobrarity(void) { enum RARITY rr; objecttype_t *ot; @@ -2888,6 +2940,19 @@ char *genhiddenname(enum OBCLASS id) { return NULL; } +// returns -1 if object doesn't have the flag +int getchargeinfo(object_t *o, int *cur, int *max) { + flag_t *f; + int amt = -1; + f = hasflag(o->flags, F_CHARGES); + if (f) { + amt = f->val[0]; + if (cur) *cur = amt; + if (max) *max = f->val[1]; + } + return amt; +} + // returns -1 if object doesn't have the flag int getcharges(object_t *o) { flag_t *f; @@ -3012,7 +3077,10 @@ int getobspellpower(object_t *o, lifeform_t *lf) { if (power == NA) power = 1; if (lf) { // increase based on your magic item usage skill - power += (getskill(lf, SK_CHANNELING)*2); + enum SKILLLEVEL slev; + slev = getskill(lf, SK_CHANNELING); + power += slev; + if (slev >= PR_ADEPT) power += (slev - 2); } // blessed objects are more powerful if (isblessed(o)) power += 4; @@ -3373,6 +3441,18 @@ objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity return NULL; } +enum OBTYPE getrandomtrapforob(void) { + objecttype_t *ot; + enum OBTYPE poss[MAXCANDIDATES]; + int nposs = 0; + for (ot = objecttype ; ot ;ot = ot->next) { + if ((ot->obclass->id == OC_TRAP) && hasflag(ot->flags, F_OBJECTTRAP)) { + poss[nposs++] = ot->id; + } + } + return poss[rnd(0,nposs-1)]; +} + char *getdamname(enum DAMTYPE damtype) { switch (damtype) { case DT_ALL: return "all damage"; @@ -3467,6 +3547,27 @@ char *gethiddenname(object_t *o) { return o->type->name; } +char *gethiddennameot(enum OBTYPE otid) { + knowledge_t *k; + objecttype_t *ot; + ot = findot(otid); + for (k = knowledge; k ; k = k->next) { + if (k->id == ot->id) { + // it DOES have a hidden name. + // does the player know about it? + if (k->known == B_KNOWN) { + // if so, return real name + return ot->name; + } else { + // otherwise return hidden one + return k->hiddenname; + } + + } + } + return ot->name; +} + int getobattackdelay(object_t *o) { int delay = 100; // ie. 100% flag_t *f; @@ -3505,6 +3606,7 @@ int getmaterialvalue(enum MATERIAL mat) { case MT_GAS: case MT_ACID: return 0; + case MT_WIRE: case MT_FOOD: case MT_PLANT: case MT_ICE: @@ -3786,10 +3888,18 @@ char *getobextrainfo(object_t *o, char *buf) { if (f && f->known) { if (!hasflag(o->flags, F_DONTSHOWCHARGES)) { char chargestr[BUFLEN]; - if (f->val[0] > 0) { - sprintf(chargestr, " (%d charges left)",f->val[0]); + if (o->type->obclass->id == OC_GODSTONE) { + if (f->val[0] == f->val[1]) { + sprintf(chargestr, " (charged)"); + } else { + sprintf(chargestr, " (depleted)"); + } } else { - sprintf(chargestr, " (empty)"); + if (f->val[0] > 0) { + sprintf(chargestr, " (%d charges left)",f->val[0]); + } else { + sprintf(chargestr, " (empty)"); + } } strcat(buf, chargestr); } @@ -3956,7 +4066,11 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan if (isactivated(o) && hasflag(o->flags, F_ACTIVATEPREFIX)) { f = hasflag(o->flags, F_ACTIVATEPREFIX); sprintf(basename, "%s ", f->text); + } else if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { + // known trap? + strcpy(basename, "trapped "); } + if (showall) { strcat(basename,o->type->name); } else { @@ -4040,23 +4154,54 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan sprintf(basename, "%s corpse",corpserace->name); } } - } else if ((o->type->id == OT_FOUNTAIN) && hasflagval(o->flags, F_LINKOB, NA, NA, B_TRUE, NULL)) { + } else if (o->type->id == OT_FOUNTAIN) { objecttype_t *ot; - // ie. if fountain type is known + // find out what kind of fountain this is f = hasflag(o->flags, F_LINKOB); - ot = findot(f->val[0]); - if (ot) { - char *srcp; - srcp = ot->name; - // skip first word from potion name. - // ie. we're left with " of xxx" - while (*srcp != ' ') { - srcp++; + if (f) { + ot = findot(f->val[0]); + if (ot) { + char *srcp; + // get potion name (or hidden name if we don't recognise it) + srcp = gethiddennameot(ot->id); + + // if this is "potion of xxx" + if (strstarts(srcp, "potion ")) { + // skip first word from potion name. + // ie. we're left with " of xxx" + while (*srcp != ' ') { + srcp++; + } + srcp++; // go past the space + // now copy the rest into buf + strcpy(buf, srcp); + if (streq(buf, "of water")) { + strcpy(basename, "water fountain"); + } else { + sprintf(basename, "fountain %s",buf); + } + } else { + char *dstp; + // ie. "orange potion" + // get rid of "potion" onwards + dstp = buf; + while (!streq(srcp, "potion")) { + *dstp = *srcp; + srcp++; + dstp++; + } + *dstp = '\0'; + // buf should now be something like "orange " + sprintf(basename, "%sfountain",buf); + } + } else { + // should never happen + strcpy(basename, "??strange fountain??"); } - srcp++; // go past the space - // now copy the rest into buf - strcpy(buf, srcp); - sprintf(basename, "fountain %s",buf); + } else { // end if f + // should never happen in gameplay, but might be triggered + // during object creation. + strcpy(basename, "??strange fountain2??"); } } else if (o->type->id == OT_STATUE) { f = hasflag(o->flags, F_CORPSEOF); @@ -4331,7 +4476,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan strcpy(prefix, ""); } } else { - if (hasflag(o->flags, F_UNIQUE)) { // TODO: && o->identified + if (hasflag(o->flags, F_UNIQUE) && isknown(o)) { strcpy(prefix, "The "); } else { if (needan(localbuf)) { @@ -5103,7 +5248,7 @@ void identify(object_t *o) { } void ignite(object_t *o) { - flag_t *f,*ff; + flag_t *ff; char convertto[BUFLEN]; int howlong = 3; // default @@ -5114,8 +5259,7 @@ void ignite(object_t *o) { strcpy(convertto, ff->text); } - f = hasflag(o->flags, F_ONFIRE); - if (!f) { + if (!hasflag(o->flags, F_ONFIRE)) { if (strlen(convertto)) { cell_t *where; object_t *newob; @@ -5342,6 +5486,20 @@ void initobjects(void) { addmaterial(MT_MAGIC, "magical energy", 0); addmaterial(MT_FIRE, "fire", 0); addmaterial(MT_GAS, "gas", 0.5); + addmaterial(MT_WIRE, "wire", 1); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_PROJECTILE, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_HOLY, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_MELT, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_ELECTRIC, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_DECAY, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_UNARMED, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_LIGHT, NA, NA, NULL); + addflag(lastmaterial->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); addmaterial(MT_PLANT, "plant matter", 1); addflag(lastmaterial->flags, F_FLAMMABLE, PERMENANT, NA, NA, NULL); addflag(lastmaterial->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); @@ -5480,6 +5638,14 @@ void initobjects(void) { addocnoun(lastobjectclass, "food"); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addoc(OC_GODSTONE, "Godstones", "Ancient artifacts, created by the elder gods.", '*', C_BOLDMAGENTA); + addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL); + addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pulsating purple stone"); + addflag(lastobjectclass->flags, F_UNIQUE, NA, NA, NA, NULL); + addflag(lastobjectclass->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL); + addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addoc(OC_CORPSE, "Corpses", "Dead flesh which was once living.", '%', C_GREY); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); @@ -5521,6 +5687,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBETRAPPED, 10, 5, 60, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_BASH, NA, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL); @@ -5534,6 +5701,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBETRAPPED, 10, 10, 60, NULL); addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); addflag(lastot->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL); addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL); @@ -5716,7 +5884,7 @@ void initobjects(void) { addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL); // traps - addot(OT_TRAPTRIP, "tripwire", "A thin wire at ankle height.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); + 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, "^"); @@ -5724,6 +5892,10 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "."); addflag(lastot->flags, F_SECRET, 25, NA, NA, NULL); + 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); @@ -5743,6 +5915,7 @@ void initobjects(void) { 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_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); @@ -5773,6 +5946,7 @@ void initobjects(void) { 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); addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); @@ -5783,6 +5957,7 @@ void initobjects(void) { 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_TRAPMINE, "landmine trap", "A buried, pressure-sensitive explosive device.", MT_NOTHING, 0, OC_TRAP, SZ_SMALL); addflag(lastot->flags, F_TRAP, 30, B_TRUE, NA, NULL); @@ -5794,6 +5969,7 @@ void initobjects(void) { 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); // money etc @@ -5852,6 +6028,12 @@ void initobjects(void) { addflag(lastot->flags, F_HOLDCONFER, F_DETECTMAGIC, B_TRUE, NA, NULL); addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + // godstones + addot(OT_GODSTONEJ, "Godstone of Justice", "An ancient artifact representing the power of justice.", MT_STONE, 3, OC_GODSTONE, SZ_SMALL); + addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL); + addflag(lastot->flags, F_CHARGES, 100, 100, NA, NULL); + addflag(lastot->flags, F_RECHARGE, 1, NA, NA, NULL); + addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); // flora addot(OT_FLOWER, "flower", "A colourful woodland flower.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, ""); @@ -6087,15 +6269,15 @@ void initobjects(void) { // scrolls addot(OT_SCR_REMOVECURSE, "scroll of remove curse", "Removes curses from all weilded equipment.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addot(OT_SCR_IDENTIFY, "scroll of identify", "Completely identifies any one item.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_IDENTIFY, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addot(OT_SCR_MENDING, "scroll of mending", "Repairs damage to objects.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_MENDING, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 98, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 98, RR_COMMON, NULL); addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL); addot(OT_SCR_NOTHING, "scroll of nothing", "Looks like a magic scroll, but doesn't do anything.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); @@ -6103,57 +6285,57 @@ void initobjects(void) { addot(OT_GRAPHPAPER, "piece of graph paper", "Paper containing a set of grid-lines, intended for mapping.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_HOLDCONFER, F_PHOTOMEM, NA, IFKNOWN, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_MAP, "map", "A visual representation of the area.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addot(OT_SCR_CREATEMONSTER, "scroll of create monster", "Summons a (probably hostile) monster to a nearby location.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_CREATEMONSTER, 4, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); addot(OT_SCR_DETECTAURA, "scroll of detect aura", "Senses holiness or evil near the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTAURA, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_SCR_DETECTLIFE, "scroll of detect life", "Senses life near the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTLIFE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_SCR_DETECTOBS, "scroll of detect objects", "Senses objects near the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTOBS, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_SCR_DETECTMAGIC, "scroll of detect magic", "Allows the reader to detect magical enchantments.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_DETECTMAGIC, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addot(OT_SCR_FLAMEPILLAR, "scroll of flame pillar", "Creates a tall pillar of flame.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_FLAMEPILLAR, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_SCR_FLAMEBURST, "scroll of flame burst", "Creates a radial blast of fire out from the caster, dealing 2d6 damage. Range is based on spell power.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_FLAMEBURST, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addot(OT_SCR_ENCHANT, "scroll of enchantment", "Magically enhances a weapon or piece of armour.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_ENCHANT, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addot(OT_SCR_FREEZEOB, "scroll of freezing touch", "Permenantly changes the next object touched into solid ice.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_FREEZEOB, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_RARE, NULL); addot(OT_SCR_KNOCK, "scroll of knock", "Magically opens a barrier.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_KNOCK, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_COMMON, NULL); addot(OT_SCR_LIGHT, "scroll of light", "Creates a permenant light source centred on the caster.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_LIGHT, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); addot(OT_SCR_MAPPING, "scroll of sense surroundings", "Magically imbues the caster with a map of his/her surroundings.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); @@ -7060,9 +7242,9 @@ void initobjects(void) { // books addot(OT_MANUAL, "manual", "Teaches you one level of its subject matter.", MT_PAPER, 1.5, OC_BOOK, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 48, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addot(OT_SPELLBOOK, "spellbook", "Teaches you the spell contained within.", MT_PAPER, 1.5, OC_BOOK, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); // wands addot(OT_WAND_KNOCK, "wand of opening", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL); @@ -7254,6 +7436,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 15, 15, 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_CANBETRAPPED, 20, 25, 66, NULL); addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); @@ -7280,12 +7463,14 @@ void initobjects(void) { // tech - l0 addot(OT_CREDITCARD, "credit card", "A rectangular plastic card.", MT_PLASTIC, 0.01, OC_TECH, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 2, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addot(OT_PAPERCLIP, "paperclip", "A thin, looped wire for holding paper together.", MT_METAL, 0.01, OC_TECH, SZ_TINY); + addot(OT_PAPERCLIP, "paperclip", "A thin, looped wire for holding paper together.", MT_WIRE, 0.01, OC_TECH, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); @@ -7301,17 +7486,17 @@ void initobjects(void) { // tech - l1 addot(OT_POCKETWATCH, "pocket watch", "A portable timekeeping device made to be carried in a pocket.", MT_METAL, 0.1, OC_TECH, SZ_TINY); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_DIGITALWATCH, "digital watch", "An electronic timekeeping device which shows the time as a number.", MT_METAL, 0.1, OC_TECH, SZ_TINY); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_INSECTICIDE, "can of insecticide", "A spraycan containing poisonous chemicals.", MT_METAL, 0.5, OC_TECH, SZ_TINY); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, RR_UNCOMMON, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, NA, NA, "Where will you spray?"); @@ -7320,7 +7505,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_LANTERNLED, "LED lantern", "A low-powered but efficient lantern which will last almost forever.", MT_METAL, 0.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_UNCOMMON, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL); @@ -7328,15 +7513,15 @@ void initobjects(void) { addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_TENT, "tent", "A easy to use, portable shelter made of fabric.", MT_CLOTH, 10, OC_TECH, SZ_HUMAN); - addflag(lastot->flags, F_RARITY, H_ALL, 60, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); addflag(lastot->flags, F_HELPSREST, 15, 1, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); // tech - l2 addot(OT_FLASHBANG, "flashbang", "A stun grenade which temporarily blinds all within sight.", MT_METAL, 1, OC_TECH, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -7352,7 +7537,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_GRENADE, "grenade", "An explosive weapon which explodes a short time after activation.", MT_METAL, 1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -7368,7 +7553,7 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_C4, "block of c4", "A highly explosive plastic which explodes a medium time after activation.", MT_PLASTIC, 1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 76, RR_UNCOMMON, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -7382,7 +7567,7 @@ void initobjects(void) { addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_MOTIONSCANNER, "motion scanner", "Small scanning device which detects nearby lifeforms.", MT_METAL, 1.5, OC_TECH, SZ_TINY); - addflag(lastot->flags, F_RARITY, H_ALL, 60, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL); 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); @@ -7391,26 +7576,26 @@ void initobjects(void) { // tech - l3 addot(OT_INFOVISOR, "infovisor", "Sleek looking metal visor which displays info directly into the retina.", MT_METAL, 0.2, OC_TECH, SZ_SMALL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_RARE, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_EXTRAINFO, B_TRUE, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ENHANCESEARCH, 10, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_LOCKHACKER, "lock hacker", "A sophisticated machine to manipulate physical locks.", MT_METAL, 3, OC_TECH, SZ_TINY); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 78, RR_UNCOMMON, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_PORTLADDER, "portable ladder", "A lightweight two metre ladder which automatically folds down to pocket size.", MT_METAL, 2, OC_TECH, SZ_TINY); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, RR_UNCOMMON, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_ADEPT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); // tech - l4 addot(OT_JETPACK, "jet pack", "A portable ion-thruster which allows the wearer to fly.", MT_METAL, 10, OC_TECH, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 68, RR_RARE, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RNDCHARGES, 10, 30, NA, NULL); @@ -7422,14 +7607,14 @@ void initobjects(void) { // tech - l5 addot(OT_TELEPAD, "teleport beacon", "A metal cone which will teleport the user to the nearest similar cone.", MT_METAL, 3, OC_TECH, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 68, RR_UNCOMMON, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_EXPERT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_XRAYGOGGLES, "pair of xray goggles", "Bulky looking goggles which allow you to see through walls.", MT_METAL, 0.3, OC_TECH, SZ_TINY); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_XRAYVIS, 2, NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, RR_RARE, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_EXPERT, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); @@ -7451,6 +7636,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 6, 6, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBETRAPPED, 20, 20, 66, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STARTOBRND, 90, NA, NA, NULL); addflag(lastot->flags, F_STARTOBRND, 80, NA, NA, NULL); @@ -8022,167 +8208,188 @@ 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, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 1, 1, 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, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 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, 75, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 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, 72, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 67, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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); + addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour, designed to stop a bullet.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_ALL, 25, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 75, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 60, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 1, 1, 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, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 4, 4, 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, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 4, 4, 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, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, 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, 6, 6, NA, NULL); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_WATERPROOF, B_TRUE, NA, NA, NULL); 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, 85, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_WAIST, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 1, 1, 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, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 2, 2, 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, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 5, 5, 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, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 8, 8, 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, 75, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 85, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 60, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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); - addflag(lastot->flags, F_OBHP, 8, 8, NA, NULL); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); 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, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 5, 5, 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, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 5, 5, 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, 83, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 2, 2, 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, 85, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 5, 5, 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, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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); addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); + 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, 75, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 1, 1, 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, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 1, 1, 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, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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); @@ -8190,34 +8397,32 @@ 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, 75, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 15, 15, 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, 75, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 10, 10, 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, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 20, 20, 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, 85, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_SCARY, 4, NA, NA, NULL); - - // armour - eyes - addot(OT_SUNGLASSES, "sunglasses", "Tinted eyewear to protect against sunlight.", MT_PLASTIC, 0.01, OC_ARMOUR, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + 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_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); @@ -8225,12 +8430,12 @@ 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, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 25, NA, NULL); + 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); @@ -8240,28 +8445,36 @@ void initobjects(void) { // 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, 83, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 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_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, 76, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 78, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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, 65, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 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); @@ -8448,7 +8661,7 @@ void initobjects(void) { addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, ""); - addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); + addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); @@ -9245,8 +9458,11 @@ int isknownot(objecttype_t *ot) { // you know whether it is cursed or not int isidentified(object_t *o) { flag_t *f; + // blessed status not known? if (!isblessknown(o)) return B_FALSE; + // unknown object type? if (!isknown(o)) return B_FALSE; + // unknown flags? for (f = o->flags->first ; f ; f = f->next) { if (!f->known) return B_FALSE; } @@ -9343,6 +9559,7 @@ int ismetal(enum MATERIAL mat) { int metal = B_FALSE; switch (mat) { case MT_METAL: + case MT_WIRE: case MT_GOLD: metal = B_TRUE; break; @@ -10134,6 +10351,8 @@ void obdie(object_t *o) { // announce the change real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); + strcpy(desc, ""); + f2 = NULL; if (o->amt > 1) { f2 = hasflag(o->flags, F_DIECONVERTTEXTPL); @@ -10144,7 +10363,10 @@ void obdie(object_t *o) { if (f2) { sprintf(desc, "%s", f2->text); } else if (oblastdamtype(o) == DT_DECAY) { - sprintf(desc, "%s completed rotted away", (o->amt == 1) ? "has" : "have"); + // don't announce devay death while traning + if (!lfhasflag(player, F_TRAINING)) { + sprintf(desc, "%s completed rotted away", (o->amt == 1) ? "has" : "have"); + } } else { sprintf(desc, "%s destroyed", (o->amt == 1) ? "is" : "are"); } @@ -10152,24 +10374,27 @@ void obdie(object_t *o) { assert(0 == 1); } - if (o->pile->owner) { - if (isplayer(o->pile->owner)) { - msg("Your %s %s!",noprefix(obname), desc); - } else if (cansee(player, o->pile->owner)) { + + if (strlen(desc)) { + if (o->pile->owner) { + if (isplayer(o->pile->owner)) { + msg("Your %s %s!",noprefix(obname), desc); + } else if (cansee(player, o->pile->owner)) { + // don't announce decay death unless we are holding it + if (oblastdamtype(o) != DT_DECAY) { + char monname[BUFLEN]; + getlfname(o->pile->owner, monname); + msg("%s's %s %s!",monname, noprefix(obname), desc); + } + } + } else if (haslos(player, o->pile->where)) { // don't announce decay death unless we are holding it if (oblastdamtype(o) != DT_DECAY) { - char monname[BUFLEN]; - getlfname(o->pile->owner, monname); - msg("%s's %s %s!",monname, noprefix(obname), desc); + capitalise(obname); + msg("%s %s.",obname, desc); } - } - } else if (haslos(player, o->pile->where)) { - // don't announce decay death unless we are holding it - if (oblastdamtype(o) != DT_DECAY) { - capitalise(obname); - msg("%s %s.",obname, desc); - } - } + } + } // end if desc != "" } // change into something else @@ -10186,26 +10411,31 @@ void obdie(object_t *o) { real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE); if (!hasflag(o->flags, F_NOOBDIETEXT)) { // announce the death + strcpy(desc, ""); f = hasflag(o->flags, F_OBDIETEXT); if (f) { sprintf(desc, "%s", f->text); } else if (oblastdamtype(o) == DT_DECAY) { - sprintf(desc, "%s completely rotted away", (o->amt == 1) ? "has" : "have" ); + if (!lfhasflag(player, F_TRAINING)) { + sprintf(desc, "%s completely rotted away", (o->amt == 1) ? "has" : "have" ); + } } else { sprintf(desc, "%s destroyed", (o->amt == 1) ? "is" : "are"); } - if (o->pile->owner) { - if (isplayer(o->pile->owner)) { - msg("Your %s %s!",noprefix(obname), desc); - } else if (cansee(player, o->pile->owner)) { - char monname[BUFLEN]; - getlfname(o->pile->owner, monname); - msg("%s's %s %s!",monname, noprefix(obname), desc); - } - } else if (haslos(player, o->pile->where)) { - msg("%s %s.",obname, desc); - } + if (strlen(desc)) { + if (o->pile->owner) { + if (isplayer(o->pile->owner)) { + msg("Your %s %s!",noprefix(obname), desc); + } else if (cansee(player, o->pile->owner)) { + char monname[BUFLEN]; + getlfname(o->pile->owner, monname); + msg("%s's %s %s!",monname, noprefix(obname), desc); + } + } else if (haslos(player, o->pile->where)) { + msg("%s %s.",obname, desc); + } + } } // explodes? @@ -10521,6 +10751,21 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { return B_TRUE; } + // has known trap? + if (isplayer(lf)) { + if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { + if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_AVERAGE) { + char ch; + sprintf(buf,"Really operate %s?", obname); + ch = askchar(buf,"yn","n", B_TRUE); + if (ch != 'y') { + msg("Cancelled."); + return B_TRUE; + } + } + } + } + // objects with charges... if (hasflag(o->flags, F_OPERUSECHARGE)) { // operating toggles on/off int chargesleft; @@ -10621,6 +10866,11 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { // mark obejct as tried maketried(o->type->id); + // trapped? + if (doobtraps(o, lf)) { + return B_TRUE; + } + /* if (lf->controller != C_PLAYER) { @@ -10635,7 +10885,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (hasflag(o->flags, F_CONTAINER) && (o->type->id != OT_VENDINGMACHINE)) { // loot it if (isplayer(lf)) { // only player can loot. char ch; - sprintf(buf, "Looting a %s. Will you:",obname); + sprintf(buf, "Looting %s. Will you:",obname); initprompt(&prompt, buf); if (countobs(lf->pack, B_FALSE)) { sprintf(buf, "Put items in %s",obname); @@ -10704,6 +10954,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (f) { enum OBTYPE spelltocast; int power; + enum SKILLLEVEL chanlev; spelltocast = f->val[0]; power = f->val[1]; @@ -10711,7 +10962,11 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (power == NA) power = 1; if (isblessed(o)) power += 4; - power += (getskill(lf, SK_CHANNELING)*2); + + // increase based on your magic item usage skill + chanlev = getskill(lf, SK_CHANNELING); + power += chanlev; + if (chanlev >= PR_ADEPT) power += (chanlev - 2); // certain wands always used the blessed version of spells // certain wands have different effects when cursed @@ -10825,7 +11080,44 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } } } - // FROM HERE ON ARE INDIVIDUAL ones + // FROM HERE ON ARE INDIVIDUAL ONES + } else if (o->type->id == OT_GODSTONEJ) { + f = hasflag(o->flags, F_CHARGES); + if (f && (f->val[0] == f->val[1])) { + int x,y; + // announce + if (isplayer(lf)){ + msg("Your %s unleashes a blast of power!", noprefix(obname)); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s%s %s unleashes a blast of power!", lfname, getpossessive(lfname), noprefix(obname)); + } + noise(lf->cell, NULL, NC_OTHER, 10, "an ear-splitting crack", NULL); + // everyone in lof drops to same hp as user + 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) && haslof(lf->cell, c, LOF_NEED, NULL)) { + c->lf->hp = lf->hp; + if (isplayer(c->lf)) { + msg("You are blasted with the power of justice!"); + } else if (cansee(player, c->lf)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("%s is blasted with the power of justice!", lfname); + } + } + } + } + f->val[0] = 0; // use up all charges + } else { + if (isplayer(lf)) { + nothinghappens(); + } + } + taketime(lf, getactspeed(lf)); } else if (o->type->id == OT_INSECTICIDE) { int seen = B_FALSE; // if above half charges, big spray @@ -10884,6 +11176,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { case OT_BLOODPOOL: case OT_PUDDLEWATER: case OT_PUDDLEWATERL: + case OT_FOUNTAIN: dippable = B_TRUE; break; default: @@ -10893,22 +11186,34 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { char ch; char ques[BUFLEN]; char liquidname[BUFLEN]; + int autoid = B_FALSE; object_t *newob; getobname(oo, liquidname, 1); sprintf(ques, "Fill your %s from %s?", noprefix(obname), liquidname); ch = askchar(ques, "yn", "y", B_TRUE); if (ch == 'y') { char newobname[BUFLEN]; - switch (oo->material->id) { - case MT_BLOOD: - strcpy(newobname, "potion of blood"); - break; - case MT_WATER: - strcpy(newobname, "potion of water"); - break; - default: - strcpy(newobname, ""); - break; + if (oo->type->id == OT_FOUNTAIN) { + objecttype_t *ot; + // same type as fountain + f = hasflag(oo->flags, F_LINKOB); + ot = findot(f->val[0]); + strcpy(newobname, ot->name); + // if you knew what the fountain was, you'll + // know what the potion object is. + if (f->val[2] == B_TRUE) autoid = B_TRUE; + } else { + switch (oo->material->id) { + case MT_BLOOD: + strcpy(newobname, "potion of blood"); + break; + case MT_WATER: + strcpy(newobname, "potion of water"); + break; + default: + strcpy(newobname, ""); + break; + } } if (strlen(newobname)) { // kill the empty flask @@ -10916,12 +11221,13 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { // give the new potion newob = addob(lf->pack, newobname); if (newob) { + if (autoid) makeknown(newob->type->id); // overwrite newobname getobname(newob, newobname, newob->amt); msgnocap("%c - %s.",newob->letter, newobname); } // kill the ground object? - switch (oo->id) { + switch (oo->type->id) { case OT_SPLASHWATER: case OT_BLOODSPLASH: removeob(oo, 5); @@ -10929,6 +11235,20 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { case OT_PUDDLEWATER: removeob(oo, 1); break; + case OT_FOUNTAIN: + if (onein(ONEIN_FOUNTAINDRYUP)) { + cell_t *loc; + loc = getoblocation(oo); + if (haslos(player, loc)) { + char fname[BUFLEN]; + getobname(oo, fname, oo->amt); + msg("%s dries up.", obname); + } + removeob(oo, oo->amt); + } + break; + default: + break; } } else { msg("That doesn't seem like a very good idea."); @@ -11458,6 +11778,7 @@ void quaff(lifeform_t *lf, object_t *o) { int seen; int killobwhendone = B_TRUE; flag_t *drinkflag; + enum OBTYPE fountainobid = OT_NONE; getobname(o, obname, 1); @@ -11494,7 +11815,6 @@ void quaff(lifeform_t *lf, object_t *o) { // figure out whether to id the object willid = B_FALSE; if (playercansee) { - enum OBTYPE obid; if (o->type->id == OT_FOUNTAIN) { flag_t *f; // ie if not already identified... @@ -11502,16 +11822,16 @@ void quaff(lifeform_t *lf, object_t *o) { if (f->val[2] == B_TRUE) { // already identified willid = B_FALSE; - obid = OT_NONE; + fountainobid = OT_NONE; } else { // then identify based on potion effects... - obid = f->val[0]; + fountainobid = f->val[0]; } } else { - obid = o->type->id; + fountainobid = o->type->id; } - switch (obid) { + switch (fountainobid) { case OT_NONE: willid = B_FALSE; break; @@ -11531,9 +11851,8 @@ void quaff(lifeform_t *lf, object_t *o) { if (willid) { if (o->type->id == OT_FOUNTAIN) { - flag_t *f; - f = hasflag(o->flags, F_LINKOB); - f->val[2] = B_TRUE; + // id the linked potion + makeknown(fountainobid); // refresh fountain name getobname(o, obname, 1); if (isplayer(lf)) { @@ -11573,12 +11892,12 @@ void quaff(lifeform_t *lf, object_t *o) { } // fountains sometimes dry up - if ((o->type->id == OT_FOUNTAIN) && onein(4)) { + if ((o->type->id == OT_FOUNTAIN) && onein(ONEIN_FOUNTAINDRYUP)) { cell_t *loc; // dry up (ie. remove DONTKILL property) drinkflag->val[2] = NA; loc = getoblocation(o); - if (haslos(lf, loc)) { + if (haslos(player, loc)) { msg("%s dries up.", obname); } } @@ -13011,13 +13330,48 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno // reduce damage a tiny bit howmuch--; - } - if (isflammable(o)) { + } else if (isflammable(o) && !hasflag(o->flags, F_ONFIRE)) { ignite(o); if (isdeadob(o)) { return howmuch; } - } + } + // actually take fire damage + // fire damage falls through to owner + if (o->pile->owner) { + flag_t *f; + lifeform_t *owner; + int lfdam = 0; + owner = o->pile->owner; + f = hasflag(o->flags, F_EQUIPPED); + if (f && (f->val[0] != BP_WEAPON) && (f->val[0] != BP_SECWEAPON)) { + // ob equipped? 1.5x damage. + lfdam = pctof(150,howmuch); + } else { + // otherwise normal. + lfdam = howmuch; + } + if (lfdam) { + // announce + getobname(o, obname, o->amt); + if (isplayer(owner)) { + msg("Your %s burn%s you!", noprefix(obname), (o->amt == 1) ? "s" : ""); + } 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" : ""); + } + + // 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); + if (isdead(owner)) { + return howmuch; + } + } + } + } else if (damtype == DT_COLD) { // cold will shatter glass if (o->material->id == MT_GLASS) { @@ -14100,6 +14454,21 @@ void timeeffectsob(object_t *o) { } } + if (f->id == F_RECHARGE) { + flag_t *f2; + f2 = hasflag(o->flags, F_CHARGES); + if (f2 && (f2->val[0] < f2->val[1])) { + f2->val[0] += f->val[0]; + if (f2->val[0] == f2->val[1]) { + if (isplayer(o->pile->owner)) { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + msg("Your %s is now fully charged.", noprefix(obname)); + } + } + } + } + // damaging objects here will damage other objects if (f->id == F_WALKDAM) { // everything here takes damage @@ -14223,7 +14592,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) { ct = SC_DODGE; break; } - avoided = skillcheck(lf, ct, f->val[2], 0); + avoided = skillcheck(lf, ct, f->val[2], lfhasflag(lf, F_SNEAK) ? 5 : 0); } } } @@ -14289,7 +14658,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, lifeform_t *lf) { } else if (oid == OT_TRAPGAS) { // can't be dodged dospelleffects(NULL, OT_S_CLOUDKILL, 3, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); - removeob(trapob, trapob->amt); + if (trapob) removeob(trapob, trapob->amt); } else if (oid == OT_TRAPMINE) { // can't be dodged explodecells(lf->cell, roll("2d6"), B_FALSE, trapob, 1, DT_ORTH, B_TRUE); diff --git a/objects.h b/objects.h index 1abf267..6fa2590 100644 --- a/objects.h +++ b/objects.h @@ -40,7 +40,7 @@ int countobs(obpile_t *op, int onlyifknown); int countnoncosmeticobs(obpile_t *op, int onlyifknown); int curseob(object_t *o); void damageallobs(object_t *srcob, obpile_t *op, int howmuch, int damtype); -void dumprandomobs(int amt); +int doobtraps(object_t *o, lifeform_t *lf); void dumpobrarity(void); void explodeob(object_t *o, flag_t *f, int bigness); void extinguish(object_t *o); @@ -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); +int getchargeinfo(object_t *o, int *cur, int *max); int getcharges(object_t *o); int geteffecttime(int min, int max, enum BLESSTYPE isblessed); objecttype_t *getlinkspell(object_t *o); @@ -76,6 +77,7 @@ object_t *getrandomammo(lifeform_t *lf); objecttype_t *getrandomammofor(object_t *o); brand_t *getrandombrandfor(objecttype_t *ot); objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity); +enum OBTYPE getrandomtrapforob(void); char *getdamname(enum DAMTYPE damtype); char *getdamnamenoun(enum DAMTYPE damtype); char *getfillingname(int nutrition); @@ -229,6 +231,7 @@ void turnoff(lifeform_t *lf, object_t *o); void turnon(lifeform_t *lf, object_t *o); int uncurseob(object_t *o, int *seen); int usecharge(object_t *o); +int usefountaincharge(object_t *o, flag_t *drinkflag); int validateobs(void); int wepdullable(object_t *o); int willshatter(enum MATERIAL mat); diff --git a/save.c b/save.c index b0a0d12..3c8f5d5 100644 --- a/save.c +++ b/save.c @@ -29,6 +29,7 @@ extern enum GAMEMODE gamemode; int loadall(void) { DIR *dir; struct dirent *ent; + int db = B_FALSE; gamemode = GM_LOADING; @@ -41,7 +42,7 @@ int loadall(void) { // load region outlines first. if (loadregions()) { // this isn't an error - just means no savegames - dblog("No region data found."); + if (db) dblog("No region data found."); return B_FALSE; } diff --git a/spell.c b/spell.c index d8165c6..2c2dff0 100644 --- a/spell.c +++ b/spell.c @@ -338,9 +338,15 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // trap there? for (o = targcell->obpile->first ; o ; o = o->next) { if (hasflag(o->flags, F_TRAP) && !hasflag(o->flags, F_SECRET)) { + // ie. a known trapped cell trapob = o; trapflag = hasflag(trapob->flags, F_TRAP); break; + } else if (hasflagval(o->flags, F_TRAPPED, NA, NA, B_TRUE, NULL)) { + // ie. a known trapped object + trapob = o; + trapflag = hasflag(trapob->flags, F_TRAPPED); + break; } } if (!trapob) { @@ -348,8 +354,6 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef return B_TRUE; } - getobname(trapob, buf, 1); - if (isplayer(user) || cansee(player, user)) { needredraw = B_TRUE; } @@ -357,32 +361,60 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // taketime taketime(user, getactspeed(user)); - // move player there... - movelf(user, targcell); + // if this was a cell trap, move player there. + if (trapflag->id == F_TRAP) { + movelf(user, targcell); + } // try to disarm it if (skillcheck(user, SC_DISARM, trapflag->val[0], 0)) { + if (trapflag->id == F_TRAP) { + // ie. trapped cell + getobname(trapob, buf, 1); + removeob(trapob, trapob->amt); + } else { + // ie. trapped object + killflag(trapflag); + getobname(trapob, buf, 1); // get name AFTER killing the flag! + } if (isplayer(user)) { msg("You disarm %s.",buf); } else if (cansee(player, user)) { msg("%s disarms %s.",username, buf); } - removeob(trapob, trapob->amt); if (isplayer(user) && hasjob(user, J_ROGUE)) { gainxp(user, trapflag->val[0]); } practice(user, SK_TRAPS, 1); } else { + int trapgoesoff = B_FALSE; // failed. another check to see if it goes off - if ((trapflag->val[1] == B_TRUE) && !skillcheck(user, SC_DISARM, trapflag->val[0], 0)) { + if (trapflag->id == F_TRAP) { + getobname(trapob, buf, 1); + if ((trapflag->val[1] == B_TRUE) && !skillcheck(user, SC_DISARM, trapflag->val[0], 0)) { + trapgoesoff = B_TRUE; + } + } else { + strcpy(buf, "the trap"); + if (!skillcheck(user, SC_DISARM, trapflag->val[0], 0)) { + trapgoesoff = B_TRUE; + } + } + if (trapgoesoff) { if (isplayer(user)) { msg("Oops - you trigger %s!",buf); } else if (cansee(player, user)) { msg("%s triggers %s!",username, buf); } - trapeffects(trapob, trapob->type->id, user); + + if (trapflag->id == F_TRAP) { + trapeffects(trapob, trapob->type->id, user); + } else { + trapeffects(NULL, trapflag->val[0], user); + } } else { + getobname(trapob, buf, 1); if (isplayer(user)) { msg("You fail to disarm %s.",buf); } else if (cansee(player, user)) { @@ -602,6 +634,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int dodged = B_FALSE; cell_t *origcell; int maxrange = 2; + object_t *o; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You can't jump while swimming!"); @@ -707,6 +740,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } + // splash? + for (o = targcell->obpile->first ; o ; o = o->next) { + if ((o->material->id == MT_WATER) && (o->type->id != OT_PUDDLEWATER)) { + addobburst(targcell, 1, DT_COMPASS, "small puddle of water", NULL, LOF_NEED); + break; + } + } + if (victim) { if (dodged) { if (cansee(player, user)) { @@ -1188,6 +1229,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } + // rolling around will put out fires + extinguishlf(user); + } else if (abilid == OT_A_POLYREVERT) { flag_t *f; if (!target) target = user; @@ -4840,6 +4884,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ min = caster->cell->map->depth - (power*2); max = caster->cell->map->depth + (power*2); + limit(&min, 1, caster->cell->map->region->rtype->maxdepth); + limit(&max, 1, caster->cell->map->region->rtype->maxdepth); if (min < 1) min = 1; // ask which level @@ -5106,7 +5152,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster) || cansee(player, caster)) { if (lfhasflag(player, F_SEEINDARK)) { - msg("The light burns your eyes!"); + msg("The light burns your vision-enhanced eyes!"); // blind for 5-10 turns addtempflag(player->flags, F_BLIND, B_TRUE, NA, NA, NULL, rnd(5,10)); }