diff --git a/ai.c b/ai.c index eb339f1..c850022 100644 --- a/ai.c +++ b/ai.c @@ -934,10 +934,10 @@ int ai_handle_emergencies(lifeform_t *lf, enum ATTRBRACKET iqb) { if (lfhasflag(lf, F_RAGE)) return B_FALSE; + // if our cell is dangerous, move away! if (iqb >= AT_AVERAGE) { if (celldangerous(lf, lf->cell, B_TRUE, NULL)) { if (db) dblog("%s o O { there is something dangerous here, moving away } ", lf->race->name); - // if our cell is dangerous, move away! moveawayfromcell = B_TRUE; } } @@ -953,7 +953,7 @@ int ai_handle_emergencies(lifeform_t *lf, enum ATTRBRACKET iqb) { return B_TRUE; } } - + // flying monsters not flying? if (!isprone(lf)) { @@ -1211,14 +1211,26 @@ int ai_inventory_mgt(lifeform_t *lf, int *canattack) { object_t *curarm; bp = lf->race->bodypart[i].id; curarm = getarmour(lf, bp); + // is it red hot? + if (curarm && hasflag(curarm->flags, F_HOT) && !isimmuneto(lf->flags, DT_FIRE, B_FALSE)) { + if (db) dblog("%s o O { wearing a red-hot item. will try to remove it. } ", lf->race->name); + if (cantakeoff(lf, curarm)) { + if (!takeoff(lf, curarm)) { + return B_TRUE; + } + } else { + if (db) dblog("%s o O { cannot remove it. maybe cursed? } ", lf->race->name); + } + } // do we have a better one? for (o = lf->pack->first ; o ; o = o->next) { - if (canwear(lf, o, BP_NONE) && isbetterarmourthan(o, curarm)) { + if (!isdangerousob(o, lf, B_TRUE) && canwear(lf, o, BP_NONE) && isbetterarmourthan(o, curarm)) { // wear this armour instead if (!wear(lf, o)) return B_TRUE; } } } + // now check whetehr we have ANY weapon @@ -2622,7 +2634,6 @@ int lookforobs(lifeform_t *lf) { c = lf->los[i]; celldist = getcelldist(lf->cell, c); if ((c != lf->cell) && !c->lf && !lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) { - for (o = c->obpile->first ; o ; o = nexto) { nexto = o->next; if (aiwants_real(lf, o, &covets, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet) && @@ -2697,7 +2708,7 @@ int lookforobs(lifeform_t *lf) { } else if ((celldist == 1) && c->lf && (isunconscious(c->lf) || isasleep(c->lf)) && (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) > IQ_ANIMAL) && !isundead(lf) && !willeatlf(lf, c->lf)) { - // intelligent enemies will loot unconscious lfs to make sure they are not a threat. + // intelligent enemies will loot unconscious/sleeping lfs to make sure they are not a threat. // // in this case they'll loot more than normal. even if they wouldn't normally pick up // some of these objects, they'll assume they are good because the player was holding @@ -2722,9 +2733,9 @@ int lookforobs(lifeform_t *lf) { } } - // if we are in battle only go for it if we covet it + // if we are in battle with someone OTHER than this lf, then only go for it if we covet it if (getit) { - if (target && !covets) getit = B_FALSE; + if (target && (target != c->lf) && !covets) getit = B_FALSE; if (isdangerousob(o, lf, B_TRUE) || !aipickupok(lf, o)) getit = B_FALSE; } if (getit) { diff --git a/data.c b/data.c index a14aa9b..6f9c2e2 100644 --- a/data.c +++ b/data.c @@ -2019,7 +2019,7 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "3d6"); - addot(OT_MISTLETOE, "sprig of mistletoe", "A small cutting of mistletoe.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY); + addot(OT_MISTLETOE, "sprig of mistletoe", "A small cutting of mistletoe. Druids can sacrifice these cuttings to increase their magical reservces.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "leaf"); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, ""); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); @@ -3213,8 +3213,8 @@ void initobjects(void) { addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); - addot(OT_S_WEB, "web", "Slows down pursuers with a burst of sticky spider web.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); - addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how much webbing is created."); + addot(OT_S_WEB, "web", "Slows down pursuers with one or more bursts of sticky spider web.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how many webs are created."); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); @@ -7658,7 +7658,7 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gestures imperiously"); addflag(lastrace->flags, F_CASTCHANCE, 75, NA, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Purity"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Purity & Order"); addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_LIGHT, NA, NA, "pw:10;"); // may cast all life spells @@ -7717,7 +7717,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_ARMOUR, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SHIELDS, PR_MASTER, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, B_MALE, NA, NA, "Battle"); + addflag(lastrace->flags, F_GODOF, B_MALE, NA, NA, "Battle & Honour"); addflag(lastrace->flags, F_STAMREGEN, NA, NA, NA, "10"); // ie. basically infinite addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_WARCRY, NA, NA, NULL); @@ -7771,7 +7771,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_LORE_NATURE, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_ADEPT, NA, NULL); // ekrub hates dragons // god abilities - addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Creation"); + addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Creation & Nature"); // may cast all nature spells for (ot = objecttype ; ot ; ot = ot->next) { if ((ot->obclass->id == OC_SPELL) && (getspellschool(ot->id) == SS_NATURE)) { @@ -7822,7 +7822,7 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "waves his hand"); addflag(lastrace->flags, F_CASTCHANCE, 75, NA, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Revenge"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Revenge & Thievery"); addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANWILL, OT_S_CALLWIND, NA, NA, "pw:10;"); @@ -7862,7 +7862,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_MASTER, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Life"); + addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Life & Healing"); addflag(lastrace->flags, F_REGENERATES, 5, NA, NA, NULL); // may cast all life spells for (ot = objecttype ; ot ; ot = ot->next) { @@ -7964,7 +7964,7 @@ void initrace(void) { addflag(lastrace->flags, F_AUTOCREATEOB, 1, NA, NA, "large fire"); addflag(lastrace->flags, F_RETALIATE, 2, 4, DT_FIRE, "roaring flames"); addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, B_TRUE, NA, NULL); - addflag(lastrace->flags, F_GODOF, B_MALE, NA, NA, "Destruction"); + addflag(lastrace->flags, F_GODOF, B_MALE, NA, NA, "Destruction & Fire"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "starting fires"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "burning objects"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing with fire"); @@ -9086,6 +9086,7 @@ void initrace(void) { addrace(R_PEGASUS, "pegasus", 130, 'Q', C_GREY, MT_FLESH, RC_MAGIC, "A legendary white, winged horse."); setbodytype(lastrace, BT_QUADRAPED); addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_CANTALK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 57, NA, ""); addflag(lastrace->flags, F_RARITY, H_FOREST, 57, NA, NULL); addflag(lastrace->flags, F_RARITY, H_SWAMP, 57, NA, NULL); @@ -9372,6 +9373,7 @@ void initrace(void) { addrace(R_SPRITEFIRE, "fire sprite", 5, 'n', C_RED, MT_FIRE, RC_MAGIC, "A small magical creature surrounded by crackling flames."); setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_EXTRACORPSE, NA, NA, NA, "small fire"); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9987,7 +9989,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, SV_SHOUT, NA, "croaks^croaking"); - addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, SV_SHOUT, NA, "croaking^croaking"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, SV_SHOUT, NA, "croaks^croaking"); addflag(lastrace->flags, F_NOISETEXT, N_SPELLCAST, SV_SHOUT, NA, "gurgles loudly^a loud gurgling"); addflag(lastrace->flags, F_CANWILL, OT_A_JUMP, NA, NA, "stamcost:0;"); addflag(lastrace->flags, F_CANWILL, OT_S_FLOOD, 20, 20, "pw:6;"); @@ -10049,6 +10051,7 @@ void initrace(void) { setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_CANTALK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL); @@ -11379,6 +11382,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addrace(R_FIREBUG, "firebug", 2, 'x', C_RED, MT_FLESH, RC_INSECT, "Constantly burning insects which attack their victims with fire."); setbodytype(lastrace, BT_QUADRAPED); + addflag(lastrace->flags, F_EXTRACORPSE, NA, NA, NA, "small fire"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); @@ -11386,6 +11390,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4"); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TOUCHBURN, 3, NA, NULL); @@ -11692,6 +11697,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -11714,7 +11720,6 @@ void initrace(void) { addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); @@ -11744,6 +11749,7 @@ void initrace(void) { addflag(lastrace->flags, F_XRAYVIS, 3, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_INDUCEFEAR, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_INVISIBILITY, 40, 40, "pw:1;"); // special: ghosts gain canwill->possession if they are near diff --git a/data/hiscores.db b/data/hiscores.db index c144704..92a97cb 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 64b5f16..a04c50a 100644 --- a/defs.h +++ b/defs.h @@ -23,6 +23,9 @@ // Defaults #define DEF_AIFOLLOWTIME (50) // if target lf is out of view + +#define DEF_BURNTIMEMIN (3) +#define DEF_BURNTIMEMAX (6) // for this many turns, abandon chase //#define DEF_ANIMDELAY (1000000 / 50) // 1/100 of a second #define DEF_ANIMDELAY (1000000 / 25) // 1/50 of a second @@ -492,6 +495,7 @@ enum SAYPHRASE { SP_RECRUIT_DECLINE, SP_RECRUIT_DECLINE_CANTPAY, SP_RECRUIT_DECLINE_WONTPAY, + SP_ROBBED, SP_SORRY, SP_THANKS, SP_TRADEINFO_ACCEPT, @@ -2350,7 +2354,10 @@ enum FLAG { // v0 = enum RUSTINESS. // object mods/effects F_ONFIRE, // burning, also deals extra fire damage - // option text = xdx amount of damage. + // option text = xdx amount of extra damage to deal for + // weapons. + F_HOT, // object is very hot to the touch. + // v0 = amt of damage to deal if touched while gloveless F_ENCHANTED, // weapon also deals 'text' extra fire damage F_HEADLESS, // for corpses. can go on LFs too. F_MASTERWORK, // weps do higher damager, armour protects better @@ -2532,6 +2539,10 @@ enum FLAG { // text = killed by xxx F_WASROBBED, // your stuff was stolen while you were // unconscious. announce it when you wake up. + F_WOKENBY, // at the start of your next turn, you will wake up + // due to actions taken by lf id v0. + // if text is set, and it was the player waking up, + // then print this text. F_TURNED, // lf turned this turn. F_PRAYEDTO, // player has prayed to this god before. F_HPDRAIN, // lf loses v0 hit points eath turn. @@ -2629,6 +2640,8 @@ enum FLAG { F_CORPSETYPE, // text field specifies what corpse obtype to leave F_CORPSEFLAG, // add flag v0 to our corpse. // v1->v0, v2->v1, text->text + F_EXTRACORPSE, // text field specifies what additional corpse + // obtype to leave F_MYCORPSE, // text field contains obid of my corpse. // (for ghosts) F_NOCORPSE, // monster's body crumbles to dust after death @@ -2840,6 +2853,8 @@ enum FLAG { // for monsters F_MPMOD, // this race gains/loses v0 mp each level F_DOESNTMOVE, // this race doesn't move (but can still attack) + F_CANTALK, // this lf can talk, even if its raceclass normally + // wouldn't be able to. F_AQUATIC, // this race can attack normally in water and suffers no // movement penalties F_AVIAN, // this race is an avian @@ -3495,6 +3510,7 @@ typedef struct habitat_s { int randobpct; // % chance that 'something' is an ob rather than monster int randvaultpct; // % chance that a room will be a vault int maxvisrange; + enum OBTYPE upstairtype, downstairtype; enum CELLTYPE emptycelltype,solidcelltype; struct habitat_s *next, *prev; } habitat_t; diff --git a/doc/add_habitat.txt b/doc/add_habitat.txt index 0d2d144..dee8044 100644 --- a/doc/add_habitat.txt +++ b/doc/add_habitat.txt @@ -5,6 +5,9 @@ map.c: initmap: define via addhabitat() + finalisemap(): + define up/down stair types for this map + make a new function to create this kind of habitat diff --git a/god.c b/god.c index 487c34d..a404177 100644 --- a/god.c +++ b/god.c @@ -1287,7 +1287,7 @@ void pleasegod(enum RACE rid, int amt) { // announce if (hasflag(lf->flags, F_PRAYEDTO)) { - if (!isasleep(lf)) { + if (!isasleep(player)) { switch (rid) { case R_GODBATTLE: msg("You feel triumphant."); diff --git a/io.c b/io.c index 832294b..ed08017 100644 --- a/io.c +++ b/io.c @@ -2524,13 +2524,14 @@ int announceobflaggain(object_t *o, flag_t *f) { } - if (f->id == F_ONFIRE) { + if ((f->id == F_ONFIRE) || (f->id == F_HOT)) { // don't want "the flaming sword catches on fire" wantpremods = B_FALSE; } real_getobname(o, obname, o->amt, wantpremods, B_FALSE, B_TRUE, B_TRUE, B_FALSE); + if (o->pile->owner) { if (isplayer(o->pile->owner)) { snprintf(prefix, BUFLEN, "Your %s",noprefix(obname)); @@ -2553,6 +2554,14 @@ int announceobflaggain(object_t *o, flag_t *f) { donesomething = B_TRUE; if (o->birthtime != curtime) msg("%s start%s glowing!",prefix, OBS1(o)); break; + case F_HOT: + // you only know an object is hot if you notice the effects on the + // person wearing it. + if (hasflag(o->flags, F_EQUIPPED)) { + msg("%s glow%s red hot!", prefix, OBS1(o)); + } + break; + default: // no message break; } @@ -5702,6 +5711,11 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, "It is on fire.\n"); strncat(retbuf, buf, HUGEBUFLEN); } + f = hasflagknown(o->flags, F_HOT); + if (f) { + sprintf(buf, "It is extremely hot.\n"); + strncat(retbuf, buf, HUGEBUFLEN); + } if (obproduceslight(o)) { sprintf(buf, "It is producing light.\n"); @@ -6640,17 +6654,23 @@ char *makedesc_skill(enum SKILL skid, char *retbuf, enum SKILLLEVEL levhilite) { for (slev = PR_INEPT; slev <= PR_MASTER; slev++) { int found = B_FALSE; int hilitethis = B_FALSE; + int numdescs = 0; if ((levhilite != PR_INEPT) && (slev == levhilite)) { hilitethis = B_TRUE; } for (i = 0; i < sk->nskilldesc; i++) { if (sk->skilldesclev[i] == slev) { + numdescs++; if (slev == PR_INEPT) { // extra blank line after this one snprintf(buf, BUFLEN, "%s\n\n",sk->skilldesctext[i]); } else { char atxlevel[BUFLEN]; - snprintf(atxlevel, BUFLEN, "At %s level", getskilllevelname(sk->skilldesclev[i])); + if (numdescs == 1) { + snprintf(atxlevel, BUFLEN, "At %s level", getskilllevelname(sk->skilldesclev[i])); + } else { + snprintf(atxlevel, BUFLEN, " "); // same as last heading + } snprintf(buf, BUFLEN, "%s%-18s%s: %s\n", // right-align "at xx level" hilitethis ? "^w" : "", atxlevel, hilitethis ? "^n" : "", sk->skilldesctext[i]); @@ -12191,7 +12211,7 @@ void showlfstats(lifeform_t *lf, int showall) { centre(mainwin, C_WHITE, 0, "GODS"); y = 2; - snprintf(line, BUFLEN, "%-26s Prayed? %-22s %s","God","Piety", "Happiness"); + snprintf(line, BUFLEN, "%-30s Prayed? %-22s %s","God","Piety", "Happiness"); doheading(mainwin, &y, 0, line); @@ -12264,7 +12284,7 @@ void showlfstats(lifeform_t *lf, int showall) { strcat(pietybuf, "^n]"); } - snprintf(line, BUFLEN, "%s%s%-26s%-9s%s %s%s", + snprintf(line, BUFLEN, "%s%s%-30s%-9s%s %s%s", blocked ? "^B" : "", // whole line is red if this god is blocked blocked ? "" : prayedto ? "^g" : "^n", godname, diff --git a/lf.c b/lf.c index f3f6425..e9e7ea7 100644 --- a/lf.c +++ b/lf.c @@ -1488,16 +1488,18 @@ int cantakeoff(lifeform_t *lf, object_t *o) { } int cantalk(lifeform_t *lf) { - switch (lf->race->raceclass->id) { - case RC_DEMON: - case RC_DRAGON: - case RC_GOD: - case RC_HUMANOID: - // these ones can talk - break; - default: - return B_FALSE; - break; + if (!lfhasflag(lf, F_CANTALK)) { + switch (lf->race->raceclass->id) { + case RC_DEMON: + case RC_DRAGON: + case RC_GOD: + case RC_HUMANOID: + // these ones can talk + break; + default: + return B_FALSE; + break; + } } // too dumb? @@ -2775,6 +2777,13 @@ void die(lifeform_t *lf) { addobfast(corpsecell->obpile, OT_FIRESMALL); } } + + // some lfs have extra corpse objects + getflags(lf->flags, retflag, &nretflags, F_EXTRACORPSE, F_NONE); + for (i = 0; i < nretflags; i++) { + addob(corpsecell->obpile, retflag[i]->text); + } + } // splatter @@ -15250,6 +15259,12 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t case SP_RECRUIT_DECLINE_WONTPAY: rv = say(lf, "Perhaps another time, then.", volume); break; + case SP_ROBBED: + switch (rnd(0,1)) { + case 0: rv = say(lf, "Hey! Where are my things?", volume); break; + case 1: rv = say(lf, "I've been robbed!", volume); break; + } + break; case SP_SORRY: if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) >= AT_HIGH) { switch (rnd(0,1)) { @@ -16510,16 +16525,28 @@ void startlfturn(lifeform_t *lf) { } } + if (isasleep(lf) && ((f = lfhasflag(lf, F_WOKENBY)) != NULL)) { + lifeform_t *thief; + thief = findlf(lf->cell->map, f->val[0]); + if (isplayer(lf)) { + msg("%s", f->text); + } + if (thief) { + turntoface(lf, thief->cell); + } + killflagsofid(lf->flags, F_ASLEEP); + } - if (!isdead(lf) && !isunconscious(lf) && hasflag(lf->flags, F_WASROBBED)) { + + if (!isdead(lf) && !isunconscious(lf) && !isasleep(lf) && hasflag(lf->flags, F_WASROBBED)) { if (isplayer(lf)) { if (countobs(lf->pack, B_FALSE)) { - msg("Some of your items are missing!"); + msg("^wSome of your items are missing!^n"); more(); } else { - msg("All of your items are missing!"); + msg("^wAll of your items are missing!^n"); more(); } } else { - say(lf, "Hey! Where are my things?", SV_SHOUT); + sayphrase(lf, SP_ROBBED, SV_SHOUT, NA, NULL); } killflagsofid(lf->flags, F_WASROBBED); } @@ -17208,7 +17235,6 @@ void startlfturn(lifeform_t *lf) { } if (isdead(lf)) return; - // effects from cell objects? for (o = lf->cell->obpile->first ; o ; o = o->next) { f = hasflag(o->flags, F_WALKDAM); @@ -17286,6 +17312,29 @@ void startlfturn(lifeform_t *lf) { } if (isdead(lf)) return; + // effects from pack objects + for (o = lf->pack->first ; o ; o = o->next) { + // hot equipped objects? + if (isequipped(o) && !isweapon(o)) { + f = hasflag(o->flags, F_HOT); + if (f) { + f->known = B_TRUE; + if (isplayer(lf)) { + getobname(o, buf, 1); + msg("^BYour %s burns you!^n", noprefix(buf)); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + getobname(o, buf, 1); + msg("^B%s%s %s burns it!^n", lfname, getpossessive(lfname), noprefix(buf)); + } + losehp_real(lf, f->val[0], DT_HEAT, NULL, buf, B_TRUE, o, B_FALSE); + } + } + } + if (isdead(lf)) return; + + // effects for/on your own flags getflags(lf->flags, retflag, &nretflags, F_ATTACHEDTO, F_CANWILL, F_CHARMEDBY, F_CLIMBING, F_FEIGNFOOLEDBY,F_FLEEFROM, F_GRABBEDBY, F_GRABBING, F_HIDING, F_BOOSTSPELL, F_FEIGNINGDEATH, F_HPDRAIN, F_INJURY, @@ -17558,7 +17607,7 @@ 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!", getlfcol(op->owner, CC_BAD), obname, targname); + msg("^%cYou steal %s from %s!", getlfcol(op->owner, CC_BAD), obname, targname); } else if (cansee(player, lf)) { msg("^%c%s steals %s from %s!", getlfcol(op->owner, CC_BAD), lfname, obname, targname); } @@ -17834,7 +17883,9 @@ int takeoff(lifeform_t *lf, object_t *o) { } unequipeffects(lf, o); + return B_FALSE; + } void taketime(lifeform_t *lf, long howlong) { @@ -17979,6 +18030,7 @@ void timeeffectslf(lifeform_t *lf) { timeeffectsob(o); } + // holes in the floor/roof for (dir = D_UP; dir <= D_DOWN; dir++) { int donesomething = B_TRUE; @@ -18095,14 +18147,14 @@ int tradeknowledge(lifeform_t *lf) { } // return B_TRUE on failure. -int tryclimb(lifeform_t *lf, cell_t *where, char *towhat) { +int tryclimb(lifeform_t *lf, cell_t *where, char *towhat, int onpurpose) { // if you have a rope or there's an adjacent wall, you can try // to climb up int adjwalls; char lfname[BUFLEN]; // climbing without climb skill? - if (isplayer(lf) && + if (isplayer(lf) && onpurpose && !getskill(lf, SK_CLIMBING) && !lfhasflag(lf, F_SPIDERCLIMB) && !hasobwithflag(lf->pack, F_HELPSCLIMB)) { @@ -18152,7 +18204,12 @@ int tryclimb(lifeform_t *lf, cell_t *where, char *towhat) { } } else { // no rope or adjacent walls if (isplayer(lf)) { - msg("You can't reach the roof!"); + if (onpurpose) { + msg("You can't reach the roof!"); + } else { + // ie. you were fleeing. + msg("You try to climb upwards, but can't reach the roof!"); + } } return B_TRUE; } @@ -18165,9 +18222,12 @@ int tryclimb(lifeform_t *lf, cell_t *where, char *towhat) { // returns B_TRUE if the action which involved touching this should fail int touch(lifeform_t *lf, object_t *o) { flag_t *f; + flag_t *retflag[MAXCANDIDATES]; + int nretflags,i; char buf[BUFLEN]; char obname[BUFLEN]; char lfname[BUFLEN]; + object_t *gloves; if ((gamemode != GM_GAMESTARTED)) return B_FALSE; @@ -18218,7 +18278,7 @@ int touch(lifeform_t *lf, object_t *o) { snprintf(buf, BUFLEN, "touching %s",obname); losehp(lf, 2, DT_HOLY, NULL, buf); // drop the object if we're holding it - if (o->pile->owner == lf) { + if ((o->pile->owner == lf) && !isequipped(o)) { drop(o, ALL); } return B_TRUE; @@ -18238,11 +18298,11 @@ int touch(lifeform_t *lf, object_t *o) { } } + gloves = getequippedob(lf->pack, BP_HANDS); f = hasflag(o->flags, F_SHARP); if (f) { object_t *gloves; - gloves = getequippedob(lf->pack, BP_HANDS); if (!gloves) { if (isplayer(lf)) { msg("^bOw! You cut your finger on %s.", obname); @@ -18250,32 +18310,56 @@ int touch(lifeform_t *lf, object_t *o) { snprintf(buf, BUFLEN, "touching %s", obname); losehp(lf, rnd(1,2), DT_SLASH, NULL, buf); + // drop the object if we're holding it + if ((o->pile->owner == lf) && !isequipped(o)) { + drop(o, ALL); + } } } - // flaming objects? - if (hasflag(o->flags, F_ONFIRE)) { - // flaming weapons are ok - if (!isweapon(o)) { - object_t *gloves; + // flaming or red-hot objects? + getflags(o->flags, retflag, &nretflags, F_ONFIRE, F_HOT, F_NONE); // IMPORTANT - check ONFIRE first! + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + // flaming weapons are ok - only the blade is burning + if ((f->id == F_ONFIRE) && isweapon(o)) { + } else { // wearing gloves? they get damaged. - gloves = getequippedob(lf->pack, BP_HANDS); if (gloves) { - takedamage(gloves, 2, DT_FIRE); - if (!hasflag(gloves->flags, F_DEAD)) { - // if your gloves weren't destroyed the fire - // will go out. - killflagsofid(o->flags, F_ONFIRE); + if (f->id == F_ONFIRE) { + takedamage(gloves, 2, DT_FIRE); + if (hasflag(gloves->flags, F_DEAD)) { + gloves = NULL; + } else { + // if your gloves weren't destroyed the fire + // will go out. + killflagsofid(o->flags, F_ONFIRE); + } } } else { + enum DAMTYPE dt; + int dam = 3; // otherwise YOU get damaged. + f->known = B_TRUE; + getobname(o, obname, o->amt); // get name again after making flag known if (isplayer(lf)) { msg("^bOw! You burn your hands on %s.",obname); } else if (cansee(player, lf)) { msg("%s burns itself on %s.",lfname, obname); } snprintf(buf, BUFLEN, "touching %s",obname); - losehp(lf, 2, DT_FIRE, NULL, buf); + if (f->id == F_ONFIRE) { + dt = DT_FIRE; + dam = rnd(2,4); + } else if (f->id == F_HOT) { + dt = DT_HEAT; + dam = f->val[0]; + } + losehp(lf, dam, dt, NULL, buf); + // drop the object if we're holding it + if ((o->pile->owner == lf) && !isequipped(o)) { + drop(o, ALL); + } return B_TRUE; } @@ -18557,7 +18641,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { } else { char buf[BUFLEN]; snprintf(buf, BUFLEN, "the %s", noprefix(obname)); - if (tryclimb(lf, obcell, buf)) { + if (tryclimb(lf, obcell, buf, onpurpose)) { // failed return B_TRUE; } else { diff --git a/lf.h b/lf.h index db1bbfb..dc94b6d 100644 --- a/lf.h +++ b/lf.h @@ -424,7 +424,7 @@ void taketime(lifeform_t *lf, long howlong); int throwat(lifeform_t *thrower, object_t *o, cell_t *where); void timeeffectslf(lifeform_t *lf); int tradeknowledge(lifeform_t *lf); -int tryclimb(lifeform_t *lf, cell_t *where, char *towhat); +int tryclimb(lifeform_t *lf, cell_t *where, char *towhat, int onpurpose); int touch(lifeform_t *lf, object_t *o); void turntoface(lifeform_t *lf, cell_t *dstcell); void unequipeffects(lifeform_t *lf, object_t *o); diff --git a/map.c b/map.c index ac96e80..ac3c7ed 100644 --- a/map.c +++ b/map.c @@ -87,7 +87,7 @@ cell_t *addcell(map_t *m, int x, int y) { return cell; } -habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange) { +habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange, enum OBTYPE upstairtype, enum OBTYPE downstairtype) { habitat_t *a; // add to the end of the list if (firsthabitat == NULL) { @@ -113,6 +113,8 @@ habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum a->randobpct = obchance; a->randvaultpct = vaultchance; a->maxvisrange = maxvisrange; + a->upstairtype = upstairtype; + a->downstairtype = downstairtype; return a; } @@ -653,6 +655,19 @@ region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid, int regionoutline_t *ro,*poss[MAXCANDIDATES]; int nposs = 0; int id; + regiontype_t *rt; + + rt = findregiontype(rtype); + if (rt->majorbranch) { + // check for dupes + if (findregionbytype(rtype)) { + dblog("ERROR - trying to add duplicate region for a major branch (%s)", rt->name); + msg("ERROR - trying to add duplicate region for a major branch (%s)", rt->name); + more(); + raise(SIGINT); // debug + } + } + // is there already a region? if (lastregion) { id = lastregion->id + 1; @@ -928,6 +943,22 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in } +// change a wall into an empty cell, and add some rubble +void breakwall(cell_t *c) { + celltype_t *origtype; + int roomwall; + origtype = c->type; + roomwall = isroom(c); + setcelltype(c, c->habitat->emptycelltype); + if (origtype->solid && roomwall && onein(2)) { + switch (origtype->material->id) { + case MT_STONE: addob(c->obpile, "1-30 stones"); break; + case MT_GLASS: addob(c->obpile, "1-30 pieces of broken glass"); break; + default: break; + } + } +} + int cellhaslos(cell_t *c1, cell_t *dest) { int deltax, deltay; int numpixels; @@ -1758,10 +1789,12 @@ void calclight(map_t *map) { // did any lit values within player's los change? if (gamemode == GM_GAMESTARTED) { int dolos = B_FALSE; - for (i = 0; i < player->nlos; i++) { - if (player->los[i]->lastlit != player->los[i]->lit) { - dolos = B_TRUE; - break; + if (!isblind(player)) { + for (i = 0; i < player->nlos; i++) { + if (player->los[i]->lastlit != player->los[i]->lit) { + dolos = B_TRUE; + break; + } } } if (dolos) { @@ -2887,7 +2920,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex int i,x,y; enum HABITAT habitat; regionthing_t *thing[MAXOUTLINETHINGS]; - int nthings = 0,failed; + int nthings = 0,failed,nstairslinked = 0; int db = B_TRUE; //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging @@ -3344,6 +3377,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging // try to join up any unlinked staircases in this map. if (db) dblog(" joining unlinked stairs..."); + nstairslinked = 0; for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { cell_t *c; @@ -3359,6 +3393,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex dst = getstairdestination(o, NULL); dblog(" linked '%s' to map %s",o->type->name, dst->map->name); } + nstairslinked++; } else { if (db) { dblog(" FAILED to link stairs: '%s'",o->type->name); @@ -3368,6 +3403,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex } } } + if (db) dblog(" linked %d stairs.", nstairslinked); //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging @@ -4139,17 +4175,17 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { if (db) dblog(" Making path from vault to corner, initdir=%s", getdirname(startdir)); c = getcellindir(startcell, startdir); while (c != turncell) { - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); if (ncellsadded) (*ncellsadded)++; c = getcellindir(c, startdir); } // clear the corner cell - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); if (db) dblog(" Making path from corner to rest of map, turndir=%s", getdirname(turndir)); // now turn and clear up to the next room/empty cell c = getcellindir(c, turndir); while (c != endcell) { - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); if (ncellsadded) (*ncellsadded)++; c = getcellindir(c, turndir); } @@ -4228,17 +4264,17 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { if (db) dblog(" Making path from vault to first corner, initdir=%s", getdirname(startdir)); c = getcellindir(startcell, startdir); while (c != turncell) { - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); if (ncellsadded) (*ncellsadded)++; c = getcellindir(c, startdir); } // clear the corner cell - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); // now turn and clear up to the next turn if (db) dblog(" Making path from 1st corner to 2nd corner, turndir=%s", getdirname(turndir)); c = getcellindir(c, turndir); while (c != turncell2) { - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); if (ncellsadded) (*ncellsadded)++; c = getcellindir(c, turndir); } @@ -4247,7 +4283,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { if (db) dblog(" Making path from 2nd corner to rest of map, turndir=%s", getdirname(turndir2)); c = getcellindir(c, turndir2); while (c != endcell) { - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); if (ncellsadded) (*ncellsadded)++; c = getcellindir(c, turndir2); } @@ -4287,7 +4323,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { c = getcellindir(startcell, whichway); //while (c && !cellwalkable(NULL, c, NULL)) { while (c && c != directendcell[whichway]) { - setcelltype(c, c->habitat->emptycelltype); + breakwall(c); if (ncellsadded) (*ncellsadded)++; c = getcellindir(c, whichway); } @@ -4295,7 +4331,7 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { // now make sure the START cell is empty too! if (startcell->type->solid) { - setcelltype(startcell, startcell->habitat->emptycelltype); + breakwall(startcell); } return B_FALSE; @@ -4856,29 +4892,29 @@ void finalisemap(map_t *map, object_t *entryob) { char roomlightob[BUFLEN],corridorlightob[BUFLEN]; int roomlightchance = 0; int corridorlightfreq = 0; + int nupstairsneeded = 0,ndownstairsneeded = 0; cell_t *c; object_t *o,*nexto; // make sure this map has sufficient up/down staircases as defined by its // region type. // // first dungeon level is a special case. it has 1 up stairs, 3 down. - switch (map->habitat->id) { - case H_CAVE: - upstairtype = OT_TUNNELUP; - downstairtype = OT_TUNNELDOWN; - break; - case H_DUNGEON: - upstairtype = OT_STAIRSUP; - downstairtype = OT_STAIRSDOWN; - break; - default: - upstairtype = OT_NONE; - downstairtype = OT_NONE; - break; + + upstairtype = map->habitat->upstairtype; + downstairtype = map->habitat->downstairtype; + + nupstairsneeded = map->region->rtype->stairsperlev - countmapobs(map, upstairtype); + ndownstairsneeded = map->region->rtype->stairsperlev - countmapobs(map, downstairtype); + + if ( (nupstairsneeded && (upstairtype == OT_NONE)) || + (ndownstairsneeded && (downstairtype == OT_NONE)) ) { + dblog("ERROR - need up/down stairs, but no stairtype defined for habitat %s!", map->habitat->name); + msg("ERROR - need up/down stairs, but no stairtype defined for habitat %s!", map->habitat->name); more(); } // UP STAIRS if (upstairtype != OT_NONE) { + // SPECIAL CASE for first level: if ((map->habitat->id == H_DUNGEON) && (map->depth == 1)) { flag_t *f; // first dungeon level. just one exit stairs @@ -4909,9 +4945,7 @@ void finalisemap(map_t *map, object_t *entryob) { } } else { // up stairs on all other levels - int nneeded; - nneeded = map->region->rtype->stairsperlev - countmapobs(map, upstairtype); - for (i = 0; i < nneeded; i++) { + for (i = 0; i < nupstairsneeded; i++) { c = NULL; while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) { c = getrandomroomcell(map, ANYROOM); @@ -4936,9 +4970,7 @@ void finalisemap(map_t *map, object_t *entryob) { // DOWN STAIRS if ((downstairtype != OT_NONE) && (map->depth < map->region->rtype->maxdepth)) { - int nneeded; - nneeded = map->region->rtype->stairsperlev - countmapobs(map, downstairtype); - for (i = 0; i < nneeded; i++) { + for (i = 0; i < ndownstairsneeded; i++) { c = NULL; while (!c || !isempty(c) || countobs(c->obpile, B_TRUE)) { c = getrandomroomcell(map, ANYROOM); @@ -6028,16 +6060,16 @@ object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tfl void initmap(void) { // habitats - // thingchance, obchance, vaultchance, maxvisrange - addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 30, 6); - addhabitat(H_CAVE, "cave", CT_DIRT, CT_WALLDIRT, 5, 60, 10, 6); - addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0, MAXVISRANGE); - addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALLGLASS, 5, 0, 0, MAXVISRANGE); - addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0, 5); - addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0, MAXVISRANGE); - addhabitat(H_SEWER, "sewer", CT_CORRIDOR, CT_WALL, 5, 50, 0, MAXVISRANGE); - addhabitat(H_STOMACH, "stomach", CT_FLOORFLESH, CT_WALLFLESH, 5, 80, 0, MAXVISRANGE); - addhabitat(H_SWAMP, "swamp", CT_CORRIDOR, CT_WALL, 3, 50, 0, MAXVISRANGE); + // thingchance, obchance, vaultchance, maxvisrange, upstiartype, downstairtype + addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 30, 6, OT_STAIRSUP, OT_STAIRSDOWN); + addhabitat(H_CAVE, "cave", CT_DIRT, CT_WALLDIRT, 5, 60, 10, 6, OT_TUNNELUP, OT_TUNNELDOWN); + addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0, MAXVISRANGE, OT_NONE, OT_NONE); + addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALLGLASS, 5, 0, 0, MAXVISRANGE, OT_NONE, OT_NONE); + addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0, 5, OT_NONE, OT_NONE); + addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0, MAXVISRANGE, OT_NONE, OT_NONE); + addhabitat(H_SEWER, "sewer", CT_CORRIDOR, CT_WALL, 5, 50, 0, MAXVISRANGE, OT_NONE, OT_NONE); + addhabitat(H_STOMACH, "stomach", CT_FLOORFLESH, CT_WALLFLESH, 5, 80, 0, MAXVISRANGE, OT_NONE, OT_NONE); + addhabitat(H_SWAMP, "swamp", CT_CORRIDOR, CT_WALL, 3, 50, 0, MAXVISRANGE, OT_STAIRSUP, OT_STAIRSDOWN); // cell types - solid addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 50); diff --git a/map.h b/map.h index 119817d..4f7102d 100644 --- a/map.h +++ b/map.h @@ -1,7 +1,7 @@ #include "defs.h" cell_t *addcell(map_t *map, int x, int y); -habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange); +habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange, enum OBTYPE upstairtype, enum OBTYPE downstairtype); void addhomeobs(lifeform_t *lf); map_t *addmap(void); lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded); @@ -13,6 +13,7 @@ regionthing_t *addregionthing(regionoutline_t *ro, int depth, int x, int y, enum regiontype_t *addregiontype(enum REGIONTYPE id, char *name, int pluralname, enum HABITAT defaulthabitat, int maxdepth, int stairsperlev, int deeperdir, int major, int depthmod); void adjustcellglyphforlight(cell_t *c, glyph_t *col); int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, int doorpct, int dooropenchance); +void breakwall(cell_t *c); int cellhaslos(cell_t *c1, cell_t *dest); int cellisfixedvaultwall(cell_t *c); int cellokforreachability(cell_t *startcell, cell_t *c, int srcroomid, int dir, int wantfilled, int *insameroom); diff --git a/nexus.c b/nexus.c index 16f596b..7b43eb5 100644 --- a/nexus.c +++ b/nexus.c @@ -829,15 +829,15 @@ void donextturn(map_t *map) { // finished! p = f->text; p = readuntil(buf, p, ';'); - lfid = atoi(p); + lfid = atoi(buf); p = readuntil(buf, p, ';'); - obid = atol(p); + obid = atol(buf); p = readuntil(buf, p, ';'); - mapid = atoi(p); + mapid = atoi(buf); p = readuntil(buf, p, ';'); - x = atoi(p); + x = atoi(buf); p = readuntil(buf, p, ';'); - y = atoi(p); + y = atoi(buf); if (lfid >= 0) { targlf = findlf(NULL, lfid); diff --git a/objects.c b/objects.c index 63001c9..2f5aade 100644 --- a/objects.c +++ b/objects.c @@ -5198,6 +5198,10 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } } } + // other prefixes + if (hasflagknown(o->flags, F_HOT)) { + strcat(localbuf, "red-hot "); + } } // enchantments @@ -6550,14 +6554,14 @@ void ignite(object_t *o) { if (!hasflag(o->flags, F_DAMAGABLE)) { addflag(o->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); } - // on fire for 3 turns + // on fire for a while + howlong = rnd(DEF_BURNTIMEMIN,DEF_BURNTIMEMAX); addtempflag(o->flags, F_ONFIRE, B_TRUE, NA, NA, NULL, howlong); + } } } - - // returns the 'armourrating' flag flag_t *isarmour(object_t *o) { flag_t *f; @@ -6618,6 +6622,7 @@ int isunknownbadobject(object_t *o) { int isbetterarmourthan(object_t *a, object_t *b) { int arma, armb; flag_t *f; + if (!a) return B_FALSE; if (!b) return B_TRUE; @@ -6730,7 +6735,7 @@ int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown) { } if (!onlyifknown || (iqb >= IQ_ANIMAL)) { - if (hasflag(o->flags, F_ONFIRE)) { + if (hasflag(o->flags, F_ONFIRE) || hasflag(o->flags, F_HOT)) { if (!isimmuneto(lf->flags, DT_FIRE, B_FALSE)) { return B_TRUE; } @@ -6809,6 +6814,35 @@ int isflammable(object_t *o) { return B_FALSE; } +// returns amt of damage to do if touched while hot. +int isheatable(object_t *o) { + if (hasflag(o->flags, F_WET)) { + return 0; + } + switch (o->material->id) { + case MT_PAPER: + case MT_LEATHER: + case MT_CLOTH: + case MT_SILK: + case MT_PLANT: + return 2; + case MT_BONE: + case MT_STONE: + case MT_RUBBER: + case MT_WAX: + return 3; + case MT_GOLD: + case MT_SILVER: + case MT_PLASTIC: + case MT_METAL: + case MT_WIRE: + return 4; + default: + break; + } + return 0; +} + int isknown(object_t *o) { // if id'd, return the full name if (hasflag(o->flags, F_IDENTIFIED)) { @@ -7593,6 +7627,25 @@ int makeduller(object_t *o, int howmuch) { return rv; } + +void makehot(object_t *o, int howmuch, int howlong) { + flag_t *f; + int seen = B_FALSE; + f = addtempflag(o->flags, F_HOT, howmuch, NA, NA, NULL, howlong); + if (isequipped(o) && o->pile->owner) { + if (isplayer(o->pile->owner) || cansee(player, o->pile->owner)) { + seen = B_TRUE; + } + } + // you only know an object is hot if you notice the effects on the + // person wearing it. + if (seen) { + f->known = B_TRUE; + } else { + f->known = B_FALSE; + } +} + void makeknown(enum OBTYPE otid) { knowledge_t *k; object_t *o; @@ -7696,6 +7749,9 @@ void makewet(object_t *o, int amt) { strcpy(obnamefull, obname); } + killflagsofid(o->flags, F_ONFIRE); + killflagsofid(o->flags, F_HOT); + if (o->material->id == MT_METAL) { if (amt < R_RUSTY) amt = R_RUSTY; if (amt > R_TRUSTY) amt = R_TRUSTY; @@ -7795,7 +7851,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { touch_battle_spoils(src); // object being taken from an unconscious lf? - if (src->pile->owner && isunconscious(src->pile->owner)) { + if (src->pile->owner && (isunconscious(src->pile->owner) || isasleep(src->pile->owner))) { robbedlf = src->pile->owner; } @@ -7904,8 +7960,16 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { o->blessknown = B_TRUE; } - if (robbedlf && !lfhasflag(robbedlf, F_WASROBBED)) { - addflag(robbedlf->flags, F_WASROBBED, B_TRUE, NA, NA, NULL); + if (robbedlf) { + if (!lfhasflag(robbedlf, F_WASROBBED)) { + addflag(robbedlf->flags, F_WASROBBED, B_TRUE, NA, NA, NULL); + } + // if you were just asleep, you might be awoken. + if (!isunconscious(robbedlf) && dst->owner && !lfhasflag(robbedlf, F_WOKENBY)) { + if (!skillcheck(dst->owner, SC_STEALTH, 13, 0)) { //easy check since target is asleep! + addflag(robbedlf->flags, F_WOKENBY, dst->owner->id, NA, NA, "^WYou awaken to someone rummaging through your pack!^n"); + } + } } if (hasflag(o->flags, F_DOOR)) { @@ -10627,6 +10691,12 @@ int readsomething(lifeform_t *lf, object_t *o) { destregion = findregionbytype(destthing->value); destob = findmapobwithflagval(lf->cell->map, F_CLIMBABLE, NA, destregion->id, NA, NULL); + if (!destob) { + // doesn't exist for some reason?!?!? + dblog("Error - can't find entrance object for region!"); + msg("Error - can't find entrance object for region!"); more(); + return B_TRUE; + } destcell = getoblocation(destob); dist = getcelldist(lf->cell, destcell); getdisttext(lf->cell, destcell, distbuf, distbufbad, dirbuf); @@ -11557,6 +11627,7 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) { } } } + // actually take fire damage // fire damage falls through to owner if (o->pile->owner) { @@ -11608,6 +11679,16 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) { } } + // ie fire/heat + if (basedamagetype(damtype) == DT_FIRE) { + int heatamt; + heatamt = isheatable(o); + if (heatamt) { + makehot(o, heatamt, rnd(DEF_BURNTIMEMIN*4,DEF_BURNTIMEMAX*4)); + } + } + + // damage type creates other objects? f = hasflagval(o->flags, F_DTCREATEOB, damtype, NA, NA, NULL); @@ -12819,7 +12900,7 @@ void timeeffectsob(object_t *o) { // check each flag for this object... - getflags(o->flags, retflag, &nretflags, F_ACTIVATED, F_EDIBLE, F_MATCONVERT, F_OBHPDRAIN, F_ONFIRE, + getflags(o->flags, retflag, &nretflags, F_ACTIVATED, F_EDIBLE, F_MATCONVERT, F_HOT, F_OBHPDRAIN, F_ONFIRE, F_RECHARGE, F_REVIVETIMER, F_WALKDAM, F_WET, F_NONE); for (i = 0; i < nretflags; i++) { object_t *oo,*nextoo; @@ -13008,22 +13089,31 @@ void timeeffectsob(object_t *o) { //if (hasflag(o->flags, F_DEAD)) return; } - // is object on fire? - if (f->id == F_ONFIRE) { - int wasputout = B_FALSE; + // is object on fire or hot? + if ((f->id == F_ONFIRE) || (f->id == F_HOT)) { + int willputout = B_FALSE; // water puts out fire for (oo = o->pile->first ; oo ; oo = nextoo) { nextoo = oo->next; if ((oo != o) && (oo->material->id == MT_WATER)) { - extinguish(o); - wasputout = B_TRUE; + willputout = B_TRUE; break; } } - if (!wasputout) { - // if it hasn't been extinguished, fire burns - takedamage(o, 2, DT_FIRE); // TODO: don't hardcode - if (hasflag(o->flags, F_DEAD)) return; + if (willputout) { + if (f->id == F_ONFIRE) { + extinguish(o); + continue; + } else if (f->id == F_HOT) { + killflag(f); + continue; + } + } else { + // if it hasn't been extinguished, the object burns + if (f->id == F_ONFIRE) { + takedamage(o, 2, DT_FIRE); // TODO: don't hardcode + if (hasflag(o->flags, F_DEAD)) return; + } } } diff --git a/objects.h b/objects.h index fd7ba05..d60f5d8 100644 --- a/objects.h +++ b/objects.h @@ -190,6 +190,7 @@ flag_t *isequipped(object_t *o); int isequippedon(object_t *o, enum BODYPART bp); int isfirearm(object_t *o); int isflammable(object_t *o); +int isheatable(object_t *o); int isknown(object_t *o); int isknownot(objecttype_t *ot); int isheavyweapon(object_t *o); @@ -230,6 +231,7 @@ void killot(objecttype_t *ot); int knockbackob(object_t *o, int dir, int howfar, int power, lifeform_t *pusher); lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level); int makeduller(object_t *o, int howmuch); +void makehot(object_t *o, int howmuch, int howlong); void makeknown(enum OBTYPE otid); void maketried(enum OBTYPE otid, char *triedon); void makewet(object_t *o, int amt); diff --git a/spell.c b/spell.c index 16410e9..de9aefe 100644 --- a/spell.c +++ b/spell.c @@ -6636,13 +6636,18 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *dropob[MAXPILEOBS]; // affect equipped objects for (o = target->pack->first ; o ; o = nexto) { + int amt; nexto = o->next; - if (ismetal(o->material->id)) { + amt = isheatable(o); + + if (ismetal(o->material->id) && amt) { int dodam = B_FALSE; if (isequippedon(o, BP_WEAPON) || isequippedon(o, BP_SECWEAPON)) { nburn++; dodam++; - dropob[ndropobs++] = o; + if (!getequippedob(target->pack, BP_HANDS)) { + dropob[ndropobs++] = o; + } donesomething = B_TRUE; } else if (isequipped(o)) { nburn++; @@ -6651,30 +6656,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (dodam) { if (cansee(player, target)) { - char obname[BUFLEN]; - char lfname[BUFLEN]; - getobname(o, obname, o->amt); - getlfname(target, lfname); - msg("%s%s %s glow%s red hot!", lfname, getpossessive(lfname), - noprefix(obname), OBS1(o)); if (seenbyplayer) *seenbyplayer = B_TRUE; } - takedamage(o, rnd(6,12), DT_HEAT); + makehot(o, amt, rnd(3,6)); } } } - if (nburn && !isimmuneto(target->flags, DT_FIRE, B_FALSE)) { + if (ndropobs && !isimmuneto(target->flags, DT_FIRE, B_FALSE)) { int i; - losehp(target, rnd(nburn,4), DT_HEAT, caster, "red-hot metal"); - if (isplayer(target)) { - msg("^BThe red-hot metal burns you!"); - } else if (cansee(player, target)) { - char lfname[BUFLEN]; - getlfname(target, lfname); - msg("^BThe red-hot metal burns %s!", lfname); - } for (i = 0; i < ndropobs; i++) { + if (isplayer(target)) { + char obname[BUFLEN]; + getobname(dropob[i], obname, dropob[i]->amt); + msg("^BYour %s %s too hot to hold!", obname, (o->amt == 1) ? "is" : "are"); + } drop(dropob[i], dropob[i]->amt); } } @@ -6682,17 +6678,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { // affect objects on ground for (o = targcell->obpile->first ; o ; o = nexto) { + int amt; nexto = o->next; // damage metal items on the ground - if (ismetal(o->material->id)) { + amt = isheatable(o); + if (ismetal(o->material->id) && amt) { if (haslos(player, targcell)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + donesomething = B_TRUE; + } + makehot(o, amt, rnd(3,6)); + if (isplayer(caster)) { char obname[BUFLEN]; getobname(o, obname, o->amt); msg("%s glow%s red hot!", obname, OBS1(o)); - if (seenbyplayer) *seenbyplayer = B_TRUE; - donesomething = B_FALSE; } - takedamage(o, rnd(6,12), DT_HEAT); } } } @@ -6929,8 +6929,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } for (l = caster->cell->map->lf ; l ; l = l->next) { if (l != caster) { + /* if (isimmuneto(l->flags, DT_NECROTIC, B_FALSE) || spellresisted(l, caster, spellid, power, seenbyplayer, B_FALSE)) { + */ + if (spellresisted(l, caster, spellid, power, seenbyplayer, B_FALSE)) { if (isplayer(l)) { msg("Luckily, the evil doesn't seem to harm you."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -7301,7 +7304,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (newsize != SZ_ANY) { resizeobject(targob, newsize); - getobname(targob, obname, 1); + getobname(targob, newobname, 1); if (seen) msg("%s grows into %s!", obname, newobname); } else if (newoid == targob->id) { if (seen) msg("%s shudders for a moment.", obname); @@ -8360,7 +8363,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (o = op->first ; o ; o = nexto) { nexto = o->next; - if (getobunitweight(o) <= 5) { + if ((getobunitweight(o) <= 5) || + ((isweapon(o)) && (isequipped(o))) ) { poss[nposs++] = o; } } @@ -8480,7 +8484,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } - // fix dulled weapons + // fix rust and dulled weapons if (!iscursed(o)) { f = hasflag(o->flags, F_BONUS); if (f && (f->val[0] < 0)) { @@ -8488,6 +8492,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster) || cansee(player, caster)) msg("%s seems more effective!", fullobname); donesomething = B_TRUE; } + if (killflagsofid(o->flags, F_RUSTED)) { + if (isplayer(caster) || cansee(player, caster)) msg("%s is no longer rusted!", fullobname); + donesomething = B_TRUE; + } } if (donesomething) { @@ -9465,6 +9473,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (o = targcell->obpile->first ; o ; o = nexto) { nexto = o->next; // special cases + // this spell isn't powerful enough to burn or heat up other things if (isflammable(o) || (o->type->id == OT_CANDLE) || (o->type->id == OT_TORCH)) { takedamage(o, 1, DT_FIRE); donesomething = B_TRUE;