diff --git a/attack.c b/attack.c index 9d600e1..d43c6c1 100644 --- a/attack.c +++ b/attack.c @@ -266,7 +266,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } } } - // above average wisdom will prevent you from starting fires + // above average wisdom will prevent you from starting fires, or rusting your weapon if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_GTAVERAGE) { if (hasflag(c->type->material->flags, F_FLAMMABLE)) { if (getlorelevel(player, c->lf->race->raceclass->id) >= PR_BEGINNER) { @@ -280,6 +280,21 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } } } + if (c->lf->material->id == MT_WATER) { + object_t *priwep; + priwep = getweapon(lf); + if (priwep && willrust(priwep)) { + char victimname[BUFLEN],wepname[BUFLEN],buf[BUFLEN]; + getlfname(c->lf, victimname); + real_getobname(priwep, wepname, priwep->amt, B_NOPREMODS, + B_NOCONDITION, B_BLINDADJUST, + B_NOBLESSINGS, B_NOUSED, B_NOSHOWALL); + snprintf(buf, BUFLEN, "Attacking %s might rust your %s - proceed anyway?",victimname, wepname); + if (!warnabout(buf)) { + return B_TRUE; + } + } + } } if (lfhasflag(lf, F_HASNEWLEVEL)) { @@ -1265,12 +1280,41 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // we'll need to place the severed head object addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL); addflag(victim->flags, F_MUTILATED, B_TRUE, NA, NA, NULL); + if (damtypecausesbleed(damtype[i], wep)) { + bleed(victim, B_SPLATTER); + } } else if (strstr(buf, "bisect")) { if (victim->race->id != R_EARTHWYRM) { addflag(victim->flags, F_MUTILATED, B_TRUE, NA, NA, NULL); } + if (damtypecausesbleed(damtype[i], wep)) { + bleed(victim, B_SPLATTER); + } + } else { + if (damtypecausesbleed(damtype[i], wep)) { + int bloodamt = 0,n; + switch (getlfsize(victim)) { + case SZ_MINI: + if (onein(3)) bloodamt = 1; + break; + case SZ_TINY: bloodamt = rnd(0,1); break; + case SZ_SMALL: bloodamt = rnd(0,2); break; + case SZ_MEDIUM: bloodamt = rnd(1,3); break; + case SZ_HUMAN: bloodamt = rnd(3,5); break; + case SZ_LARGE: bloodamt = rnd(5,10); break; + case SZ_HUGE: bloodamt = rnd(10,15); break; + case SZ_ENORMOUS: + case SZ_MAX: + bloodamt = rnd(15,20); break; + default: bloodamt = 0; break; + } + for (n = 0; n < bloodamt; n++) { + bleed(victim, B_NOSPLATTER); + } + } } - if ((isplayer(lf) || cansee(player, victim)) && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { + //if ((isplayer(lf) || cansee(player, victim)) && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { + if (isplayer(lf) && cansee(player, victim) && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { if (!hasflag(victim->flags, F_PHANTASM)) { // don't also say "the xx dies" addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); @@ -2143,18 +2187,17 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, objec } } -int damtypecausesbleed(enum DAMTYPE dt) { +int damtypecausesbleed(enum DAMTYPE dt, object_t *fromob) { switch (dt) { case DT_PIERCE: case DT_SLASH: - case DT_BASH: case DT_BITE: case DT_CHOP: - case DT_PROJECTILE: case DT_EXPLOSIVE: - case DT_UNARMED: - case DT_FALL: return B_TRUE; + case DT_PROJECTILE: + if (fromob && hasflag(fromob->flags, F_MISSILEDAM)) return B_TRUE; + break; default: break; } diff --git a/attack.h b/attack.h index ecb31b7..411cf09 100644 --- a/attack.h +++ b/attack.h @@ -10,7 +10,7 @@ enum DAMTYPE basedamagetype(enum DAMTYPE dt); int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname); //void confereffects(flagpile_t *fp, lifeform_t *victim); void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, object_t *wep, int dam, enum DAMTYPE damtype); -int damtypecausesbleed(enum DAMTYPE dt); +int damtypecausesbleed(enum DAMTYPE dt, object_t *fromob); int damtypecausescriteffects(enum DAMTYPE dt); int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype); void getarrange(int arating, int *min, int *max); diff --git a/data.c b/data.c index dcf7de1..930372e 100644 --- a/data.c +++ b/data.c @@ -502,7 +502,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_COOKING, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_EVASION, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_UNARMED, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_UNARMED, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); @@ -1573,7 +1573,9 @@ void initobjects(void) { addflag(lastot->flags, F_DTCREATEOB, DT_FIRE, 0, DT_COMPASS, "cloud of steam"); addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, B_DONTKILL, NULL); addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_WATER, NA, NA, NULL); addflag(lastot->flags, F_GROWSTO, OT_WATERDEEP, VT_OB, NA, NULL); + addflag(lastot->flags, F_SHRINKSTO, OT_PUDDLEWATERL, VT_OB, NA, NULL); // blocks movement, but you can see and fire through them. addot(OT_GATEIRON, "iron gate", "A gate comprised of a series of vertical iron bars, raised slightly above the floor.", MT_METAL, 500, OC_DFEATURE, SZ_LARGE); @@ -5661,7 +5663,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_ACID, FALLTHRU, "2d4"); addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_ACID, NA, NA, NULL); addflag(lastot->flags, F_PURIFIESTO, OT_PUDDLEWATERL, NA, NA, NULL); addot(OT_ACIDPUDDLE, "puddle of acid", "A small puddle of corrosive acid.", MT_ACID, 0, OC_MISC, SZ_SMALL); @@ -5676,7 +5678,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_ACID, FALLTHRU, "1d4"); addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_ACID, NA, NA, NULL); addflag(lastot->flags, F_PURIFIESTO, OT_PUDDLEWATER, NA, NA, NULL); addot(OT_ACIDSPLASH, "splash of acid", "A splash corrosive acid.", MT_ACID, 0, OC_MISC, SZ_SMALL); @@ -5691,7 +5693,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_ACID, FALLTHRU, "1d2"); addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_LINKOB, OT_POT_ACID, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_ACID, NA, NA, NULL); addflag(lastot->flags, F_PURIFIESTO, OT_SPLASHWATER, NA, NA, NULL); addot(OT_SLIMEPOOL, "pool of slime", "A deep pool of foul-smelling slime.", MT_SLIME, 300, OC_TERRAIN, SZ_HUGE); @@ -5720,7 +5722,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_FLAMMABLE, 5, NA, NA, "medium fire"); addflag(lastot->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_LINKOB, OT_POT_OIL, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_OIL, NA, NA, NULL); addflag(lastot->flags, F_SLIPPERY, 13, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); @@ -5744,7 +5746,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "0d1+100"); - addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_WATER, 5, NA, NULL); addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL); addot(OT_MUDPOOL, "pool of mud", "A large puddle of wet mud.", MT_WATER, 60, OC_MISC, SZ_MEDIUM); @@ -5786,7 +5788,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_WATER, NA, NA, NULL); //addflag(lastot->flags, F_WALKDAM, DT_WATER, NA, NA, "0d1+1"); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+1"); addflag(lastot->flags, F_SLIPPERY, 1, NA, NA, NULL); @@ -5809,7 +5811,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_WATER, NA, NA, NULL); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+2"); addot(OT_BLOODSTAIN, "blood stain", "A dried stain of blood.", MT_BLOOD, 0, OC_MISC, SZ_TINY); @@ -5860,6 +5862,7 @@ void initobjects(void) { addflag(lastot->flags, F_COSMETIC, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PURIFIESTO, OT_SPLASHWATER, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_BLOOD, 5, NA, NULL); addot(OT_BLOODPOOL, "pool of blood", "A large pool of blood.", MT_BLOOD, 0, OC_MISC, SZ_MEDIUM); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -5879,6 +5882,7 @@ void initobjects(void) { addflag(lastot->flags, F_LINKOB, OT_POT_BLOOD, NA, NA, NULL); addflag(lastot->flags, F_NOFEEL, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PURIFIESTO, OT_PUDDLEWATERL, NA, NA, NULL); + addflag(lastot->flags, F_FILLPOT, OT_POT_BLOOD, NA, NA, NULL); addot(OT_SIGN, "sign", "A marker with something written on it.", MT_WOOD, 25, OC_MISC, SZ_MEDIUM); addflag(lastot->flags, F_GLYPH, C_BROWN, '|', NA, NULL); @@ -9934,6 +9938,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CASTCHANCE, 50, NA, NA, NULL); addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_LEVITATION, NA, NA, NULL); addrace(R_BOGGART, "bogle", 15, 'n', C_BROWN, MT_WOOD, RC_MAGIC, "An evil household fairy made of wood. They delight in sowing disease and misfortune."); setbodytype(lastrace, BT_HUMANOID); @@ -10588,6 +10593,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_ATTRMOD, A_STR, 5, "50"); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_FIRE, NA, "50"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_ELEMENTIMMUNE, NA, NA, NULL); addrace(R_GIANTFIREFC, "flame giant firemaster", 160, 'H', C_RED, MT_FLESH, RC_HUMANOID, "A subspecies of flame giant who have developed the ability to command the primal volcanic fires around them."); setbodytype(lastrace, BT_HUMANOID); @@ -10631,6 +10637,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 15, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_ATTRMOD, A_STR, 5, "50"); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_FIRE, NA, "50"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_ELEMENTIMMUNE, NA, NA, NULL); // TODO: storm giant @@ -11200,6 +11207,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_POISON, NA, NA, NULL); addrace(R_KOBOLD, "kobold", 18, 'k', C_BROWN, MT_FLESH, RC_HUMANOID, "An evil humanoid race with doglike features, kobolds are known for their cowardace and prefer to attack from a distance if at all possible."); @@ -11276,6 +11284,7 @@ void initrace(void) { addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 2, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_POISON, NA, NA, NULL); addrace(R_LEPRECHAUN, "leprechaun", 35, 'n', C_BOLDGREEN, MT_FLESH, RC_HUMANOID, "Leprechauns are tiny Irish humans, with a love for gold and practical jokes. Known for their supernatural luck."); setbodytype(lastrace, BT_HUMANOID); @@ -12205,6 +12214,7 @@ void initrace(void) { addrace(R_SANDMAN, "sandman", 10, 'y', C_BROWN, MT_DIRT, RC_OTHER, "A whirling tornado of sand, with a humanoid figure dimly visible within."); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "small dust cloud"); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "large dust cloud"); @@ -12472,6 +12482,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_FIRE, NA, "25"); addflag(lastrace->flags, F_WANTSOBFLAG, F_GEM, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_ELEMENTIMMUNE, NA, NA, NULL); addrace(R_SPRITEGRAVE, "grave sprite", 5, 'n', C_GREY, MT_FLESH, RC_MAGIC, "A small magical creature made from corpse dust."); setbodytype(lastrace, BT_HUMANOID); @@ -12550,6 +12561,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "25"); addflag(lastrace->flags, F_WANTSOBFLAG, F_GEM, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_ELEMENTIMMUNE, NA, NA, NULL); addrace(R_SPRITEWEED, "weed sprite", 5, 'n', C_ORANGE, MT_FLESH, RC_MAGIC, "The bright colour of weed sprites belies their evil nature."); setbodytype(lastrace, BT_HUMANOID); @@ -12872,7 +12884,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_WALK, 2, NA, "^gurgling"); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "gurgles loudly^a loud gurgle"); addflag(lastrace->flags, F_EATCONFER, F_MUTABLE, B_TRUE, NA, "100"); - + addflag(lastrace->flags, F_FILLPOT, OT_POT_FISHLUNG, NA, NA, NULL); addrace(R_PIRANHA, "piranha", 0.5, ';', C_GREEN, MT_FLESH, RC_AQUATIC, "A vicious, flesh-eating fish"); setbodytype(lastrace, BT_FISH); @@ -13072,6 +13084,7 @@ void initrace(void) { addflag(lastrace->flags, F_TR, 1, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); + addrace(R_FUNGUSRAGE, "ragefungus", 0.5, 'F', C_RED, MT_PLANT, RC_PLANT, "This deep red fungus protects itself by explelling rage-inducing pheremones, causing predators to attack each other instead of it."); addbodypart(lastrace, BP_BODY, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); @@ -13079,7 +13092,6 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL); - addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); addflag(lastrace->flags, F_HARMLESS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); @@ -13097,6 +13109,7 @@ void initrace(void) { addflag(lastrace->flags, F_TR, 1, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_BASH, NA, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_FURY, NA, NA, NULL); addrace(R_GLUON, "gluon", 1, 'F', C_YELLOW, MT_PLANT, RC_PLANT, "A walking plant-based monster whose body is covered with a thick glue-like secretion."); addbodypart(lastrace, BP_BODY, "stalk"); @@ -13326,6 +13339,7 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 6, NA, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_MAGIC, NA, NA, NULL); addrace(R_BATVAMPIRE, "vampire bat", 6, 'B', C_BLUE, MT_FLESH, RC_ANIMAL, "Bats which suck the blood of their victims."); setbodytype(lastrace, BT_BIRD); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); @@ -14196,6 +14210,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, B_TRUE, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "20"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_ELEMENTIMMUNE, NA, NA, NULL); addrace(R_ELEPHANT, "elephant", 4000, 'Q', C_GREY, MT_LEATHER, RC_ANIMAL, "A massive grey mammal with a long trunk and sharp tusks."); setbodytype(lastrace, BT_QUADRAPED); @@ -14507,6 +14522,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "scuttle"); addflag(lastrace->flags, F_POISONCORPSE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_POISON, NA, NA, NULL); addrace(R_ROC, "roc", 1, 'A', C_MAGENTA, MT_FLESH, RC_ANIMAL, "Rocs are unbelievably gargantuan birds or prey, large enough to carry a fully-grown elephant. They are generally peaceful, but deadly once provoked."); // 'A' for Avian setbodytype(lastrace, BT_BIRD); @@ -14578,6 +14594,7 @@ void initrace(void) { addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addrace(R_SNAIL, "mottled snail", 150, 'P', C_BROWN, MT_FLESH, RC_ANIMAL, "An enormous snail, protected by a hard, scaled shell and gifted with long, sharp fangs."); addbodypart(lastrace, BP_BODY, NULL); addbodypart(lastrace, BP_HEAD, NULL); @@ -14899,6 +14916,7 @@ void initrace(void) { addflag(lastrace->flags, F_FLEEONHPPCT, 25, NA, NA, ""); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_POISON, NA, "15"); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "creep"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_POISON, NA, NA, NULL); addrace(R_SPIDERREDBACK, "giant redback", 5, 'S', C_RED, MT_FLESH, RC_ANIMAL, "A version of a giant spider with a highly painful bite."); setbodytype(lastrace, BT_SPIDER); lastrace->baseid = R_SPIDER; @@ -14936,6 +14954,7 @@ void initrace(void) { addflag(lastrace->flags, F_FLEEONHPPCT, 25, NA, NA, ""); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_POISON, NA, "10"); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "creep"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_POISON, NA, NA, NULL); addrace(R_SPIDERTOMB, "tomb spider", 5, 'S', C_BLUE, MT_FLESH, RC_ANIMAL, "Tomb spiders are truly nightmarish beings. Their skin can absorb light itself, and they can boost their own life force by consuming the flesh of their victims."); setbodytype(lastrace, BT_SPIDER); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); @@ -15102,7 +15121,6 @@ void initrace(void) { addflag(lastrace->flags, F_CANINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); - addrace(R_WOLFWINTER, "winter wolf", 25, 'd', C_CYAN, MT_FLESH, RC_ANIMAL, "Wolves which have lived in close proximity to the undead sometimes mutate into these frosty beasts. While their claws have become less sharp, they instead deal unnatural cold damage."); setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); @@ -17160,6 +17178,7 @@ void initrace(void) { addflag(r->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(r->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL); addflag(r->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); + addflag(r->flags, F_FILLPOT, OT_POT_AMBROSIA, NA, NA, NULL); } else if (r->raceclass->id == RC_MAGIC) { addflag(r->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); @@ -17191,6 +17210,8 @@ void initrace(void) { addflag(r->flags, F_CORPSETYPE, NA, NA, NA, "unstable power core"); addflag(r->flags, F_MORALE, 30, NA, NA, NULL); addflag(r->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_BLOODOB, NA, NA, NA, "puddle of oil"); + if (!hasflagval(r->flags, F_NOISETEXT, N_WALK, NA, NA, NULL)) { addflag(r->flags, F_NOISETEXT, N_WALK, 2, NA, "^whirring"); } @@ -17587,11 +17608,11 @@ void initskills(void) { addskilldesc(sk->id, PR_INEPT, "At each skill level, more information about related creatures will be shown.", B_FALSE); addskilldesc(sk->id, PR_INEPT, "Each level also gives +1 damage and +2 accuracy against related creatures.", B_FALSE); - snprintf(buf, BUFLEN, "^gYou now know basic information about %s.^n", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou now have common knowledge about %s.^n", rc->pluralname); addskilldesc(sk->id, PR_NOVICE, buf, B_TRUE); - snprintf(buf, BUFLEN, "^gYou can now determine how much damage %s will deal.^n", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou now know about the powers/abilities of %s.^n", rc->pluralname); addskilldesc(sk->id, PR_BEGINNER, buf, B_TRUE); - snprintf(buf, BUFLEN, "^gYou can now determine how dangerous %s are.^n", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou have now comprehensively studied %s.^n", rc->pluralname); addskilldesc(sk->id, PR_ADEPT, buf, B_TRUE); snprintf(buf, BUFLEN, "^gYou can now anticipate how %s will react.^n", rc->pluralname); addskilldesc(sk->id, PR_SKILLED, buf, B_TRUE); diff --git a/data/hiscores.db b/data/hiscores.db index aa23ba8..9ef3758 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 620246b..929b233 100644 --- a/defs.h +++ b/defs.h @@ -91,6 +91,7 @@ #define B_ONPURPOSE (-1) #define B_NOTONPURPOSE (0) #define B_CHANGEDIR (-1) +#define B_NOCHANGEDIR (0) #define B_VIS (1) #define B_UNKNOWN (0) #define B_NOVIS (-1) @@ -102,11 +103,13 @@ #define B_DONTKILL (-1) #define B_APPENDYOU (-1) #define B_SPLATTER (-1) +#define B_NOSPLATTER (0) #define B_FROMINJURY (-2) #define B_KEEPDIR (-2) #define B_VERT (0) #define B_HORZ (1) + #define B_MELEEONLY (-1) @@ -427,6 +430,7 @@ enum SHOPACTION { #define AUTO (-7654) #define HEAVYWEPKG (5) #define HITDIESIDES (6) +#define B_NEWINJURY (-6654) // how quickly the game clock increments @@ -2439,6 +2443,8 @@ enum FLAG { F_ENCHANTABLE, // object can get +1/-1 ect F_FILLPOT, // can fill empty flasks with this object to create // a potion of obtype v0. + // if v1 != NA, then object count must be >= v1 to + // fill from this ob. F_GEM, // this object is a gem. F_GODGIFT, // this was a gift form god with race v0. F_GROWSTO, // used for spells. v0=new oid or celltype. @@ -3537,6 +3543,8 @@ enum FLAG { // v0 = timeleft (since 'lifetime' is used for FROMSPELL) F_INJURY, // v0 = enum injury, v1 = where (enum bp), v2 = damtype // text is desc, ie "rib is cracked" + // special: 'obfrom' is used to determine whether this + // is a new injury. F_INVISIBLE, // lifeform is invisible F_INVULNERABLE,// immune to most damage // this can apply to objects too! diff --git a/io.c b/io.c index 803cd2a..44591df 100644 --- a/io.c +++ b/io.c @@ -1425,7 +1425,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { } else if (f->val[1] == ST_MEDITATING) { msg("%s enter%s a trance.",lfname, isplayer(lf) ? "" : "s"); } else { - msg("%s lose%s consciousness.",lfname, isplayer(lf) ? "" : "s"); + msg("^%c%s lose%s consciousness.^n",getlfcol(lf, CC_BAD), lfname, isplayer(lf) ? "" : "s"); } } donesomething = B_TRUE; @@ -3073,6 +3073,8 @@ object_t *doaskobject(obpile_t *op, char *prompt, char *noobtext, int *count, in enum FLAG wantflag[MAXCANDIDATES]; va_list flags; int nwantflags; + flag_t *sellflag[MAXCANDIDATES]; + int nsellflags = 0; // construct list of valid obclasses va_start(flags, opts); @@ -3085,16 +3087,8 @@ object_t *doaskobject(obpile_t *op, char *prompt, char *noobtext, int *count, in va_end(flags); //dblog("nwantflags is %d",nwantflags); - // if selecting from a shop, we now override wantflags if (sellshop) { - flag_t *sellflag[MAXCANDIDATES]; - int nsellflags = 0; - nwantflags = 0; getflags(sellshop->flags, sellflag, &nsellflags, F_SHOPACCEPTSFLAG, F_NONE); - for (i = 0; i < nsellflags; i++) { - wantflag[nwantflags] = sellflag[i]->val[0]; - nwantflags++; - } } if (countobs(op, B_TRUE) <= 0) { @@ -3162,6 +3156,20 @@ object_t *doaskobject(obpile_t *op, char *prompt, char *noobtext, int *count, in } } + + // shop flags? + if (ok && nsellflags) { + int n; + // must match one of the sellflags + ok = B_FALSE; + for (n = 0; n < nsellflags; n++) { + if (obmatchessellflag(o, sellflag[n], sellaction)) { + ok = B_TRUE; + break; + } + } + } + if (ok) { // check for wanted flags for (n = 0; n < nwantflags; n++) { @@ -7076,7 +7084,9 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel // knowledge known by studying this creature a little. // eg: sleeping times, damage resist/vuln, silentmovement, morale // ADEPT: - // everything. + // nearly everything. except.... + // SKILLED: + // what their blood bottles to. doneflags = addflagpile(NULL, NULL); @@ -7085,11 +7095,13 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel if (showextra) { int a,n; int curidx,donesomething; - char bonheading[BUFLEN],penheading[BUFLEN]; + char bonheading[BUFLEN],penheading[BUFLEN],mischeading[BUFLEN]; + int donemischeading = B_FALSE; enum OBCLASS spellorabil[2]; sprintf(bonheading, "^%dStrengths^n:\n", C_WHITE); sprintf(penheading, "^%dWeaknesses^n:\n", C_WHITE); + sprintf(mischeading, "^%dOther^n:\n", C_WHITE); // stats snprintf(buf, HUGEBUFLEN, "HD: %-3d ", gettrrace(r)); strncat(retbuf, buf, HUGEBUFLEN); @@ -7181,6 +7193,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel strncat(retbuf, "@- ", HUGEBUFLEN); strcat(buf, "\n"); strncat(retbuf, buf, HUGEBUFLEN); + curidx++; } } } @@ -7202,6 +7215,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel strncat(retbuf, "@- ", HUGEBUFLEN); strcat(buf, "\n"); strncat(retbuf, buf, HUGEBUFLEN); + curidx++; } // auto bonuses from flags @@ -7432,8 +7446,46 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel if (curidx == 0) { strncat(retbuf, "^n@None known.\n", HUGEBUFLEN); } - } + ////////////////////////////////////////////// + // other + ////////////////////////////////////////////// + + // auto misc from flags + for (f = r->flags->first ; f ; f = f->next) { + char buf2[BUFLEN]; + strcpy(buf, ""); + switch (f->id) { + case F_FILLPOT: + if (lorelev >= PR_SKILLED) { + objecttype_t *ot; + ot = findot(f->val[0]); + if (ot) { + sprintf(buf2, "Its blood can be bottled to create %s %s.", + needan(ot->name) ? "an" : "a", + ot->name); + strcat(buf, buf2); + } + } + break; + default: + break; + } + if (strlen(buf)) { + if (!donemischeading) { + strncat(retbuf, mischeading, HUGEBUFLEN); + donemischeading = B_TRUE; + } + strncat(retbuf, "@- ", HUGEBUFLEN); + strcat(buf, "\n"); + strncat(retbuf, buf, HUGEBUFLEN); + curidx++; + } + } + if (donemischeading && (curidx == 0)) { + strncat(retbuf, "^n@None known.\n", HUGEBUFLEN); + } + } free(doneflags); return retbuf; @@ -11229,7 +11281,7 @@ void showlfarmour(lifeform_t *lf) { void showlfstats(lifeform_t *lf, int showall) { int y = 0, y2 = 0, x2 = 40; - int starty; + int startx,starty; int x; int arating, evasion; int acc; @@ -11821,6 +11873,7 @@ void showlfstats(lifeform_t *lf, int showall) { wattroff(mainwin, A_UNDERLINE); y++; starty = y; + startx = x; /* if (!isplayer(lf)) { @@ -12211,7 +12264,7 @@ void showlfstats(lifeform_t *lf, int showall) { wrapprint(mainwin, &y, &x, 0, "%s %s made out of %s. ",you(lf), is(lf), mt->name); } - if (y == starty) { + if ((y == starty) && (x == startx)) { wrapprint(mainwin, &y, &x, 0, "Nothing obvious."); } } else if (mode == 'a') { diff --git a/lf.c b/lf.c index 684b681..51ef24d 100644 --- a/lf.c +++ b/lf.c @@ -227,7 +227,12 @@ void bleed(lifeform_t *lf, int splatter) { object_t *o; o = addob(lf->cell->obpile, obname); + if (hasflag(lf->flags, F_FILLPOT)) { + // override object flags + killflagsofid(o->flags, F_FILLPOT); + } nfillpot = copyflag(o->flags, lf->flags, F_FILLPOT); + if (splatter) { addobsinradius(lf->cell, 1, DT_COMPASS, obname, B_TRUE, NULL); @@ -272,10 +277,7 @@ void breakgrabs(lifeform_t *lf, int fromme, int tome) { killflagsofid(grabee->flags, F_GRABBEDBY); killflagsofid(lf->flags, F_GRABBING); } - f = lfhasflag(lf, F_ATTACHEDTO); - if (f) { - killflag(f); - } + killflagsofid(lf->flags, F_ATTACHEDTO); } if (tome) { f = lfhasflag(lf, F_GRABBEDBY); @@ -3213,6 +3215,17 @@ void die(lifeform_t *lf) { pleasegodmaybe(R_GODDEATH, 1); } + // killing someone with an injury is considered merciful. + // (but only for injuries which you didn't just inflict!) + getflags(lf->flags, retflag, &nretflags, F_INJURY, F_NONE); + for (i = 0; i < nretflags; i++) { + if (retflag[i]->obfrom != B_NEWINJURY) { + pleasegodmaybe(R_GODMERCY, 5); + // only do this once. + break; + } + } + switch (lf->race->raceclass->id) { case RC_DRAGON: pleasegodmaybe(R_GODNATURE, 50); @@ -6890,6 +6903,49 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { } } + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { + // worshipping yumi increases wisdom based on piety + if ((attr == A_WIS) && godprayedto(R_GODMERCY)) { + enum PIETYLEV plev; + plev = getpietylev(R_GODMERCY, NULL, NULL); + switch (plev) { + case PL_ENRAGED: val -= 25; break; + case PL_FURIOUS: val -= 10; break; + case PL_ANGRY: val -= 5; break; + case PL_TOLERATED: break; + case PL_INDIFFERENT: val += 10; break; + case PL_PLEASED: val += 20 ; break; + case PL_DELIGHTED: val += 35 ; break; + case PL_ECSTATIC: val += 50 ; break; + default: break; + } + } else if ((attr == A_CON) && godprayedto(R_GODLIFE)) { + enum PIETYLEV plev; + plev = getpietylev(R_GODLIFE, NULL, NULL); + switch (plev) { + case PL_INDIFFERENT: val += 5; break; + case PL_PLEASED: val += 10 ; break; + case PL_DELIGHTED: val += 15 ; break; + case PL_ECSTATIC: val += 20 ; break; + default: break; + } + } else if ((attr == A_IQ) && godprayedto(R_GODMAGIC)) { + enum PIETYLEV plev; + plev = getpietylev(R_GODMAGIC, NULL, NULL); + switch (plev) { + case PL_ENRAGED: val -= 20; break; + case PL_FURIOUS: val -= 10; break; + case PL_ANGRY: val -= 5; break; + case PL_TOLERATED: break; + case PL_INDIFFERENT: val += 10; break; + case PL_PLEASED: val += 20 ; break; + case PL_DELIGHTED: val += 30 ; break; + case PL_ECSTATIC: val += 50 ; break; + default: break; + } + } + } + if (val < 0) val = 0; return val; @@ -10377,7 +10433,8 @@ void givejob(lifeform_t *lf, enum JOB jobid) { // also, they always use fists, even if the race has claws etc. f = lfhasflag(lf, F_HASATTACK); if (f) { - f->val[1] = 3; + f->val[0] = OT_FISTS; + f->val[1] = 5; } } else if (j->id == J_PIRATE) { flag_t *f; @@ -12109,7 +12166,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR case IJ_EARSRINGING: desc = strdup("ears are ringing^cannot hear sounds"); break; case IJ_TAILLACERATED: desc = strdup("tail is lacerated^chance of falling during movement"); break; case IJ_WINGDESTROYED: desc = strdup("wings are destroyed^cannot fly"); break; - case IJ_HANDSWOLLEN: desc = strdup("hand is swolled^rings cannot be put on/removed"); break; + case IJ_HANDSWOLLEN: desc = strdup("hand is swollen^rings cannot be put on/removed"); break; case IJ_FINGERBROKEN: desc = strdup("finger is broken^acc penalty"); break; case IJ_SHOULDERDISLOCATED: desc = strdup("shoulder is dislocated^acc penalty, cannot use heavy weapons"); break; case IJ_ARTERYPIERCE: desc = strdup("radial artery is pierced^constant bleeding"); break; // fatal - no description @@ -12123,7 +12180,9 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR if (desc) free(desc); return B_TRUE; } else { - addtempflag(lf->flags, F_INJURY, inj, where, damtype, desc, howlong); + flag_t *injflag; + injflag = addtempflag(lf->flags, F_INJURY, inj, where, damtype, desc, howlong); + injflag->obfrom = B_NEWINJURY; } if (desc) free(desc); @@ -12175,6 +12234,30 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR return B_FALSE; } +int lfcanbekod(lifeform_t *lf) { + if (isundead(lf)) return B_FALSE; + switch (getraceclass(lf)) { + case RC_ROBOT: + case RC_GOD: + case RC_SLIME: + case RC_PLANT: + case RC_OTHER: + case RC_UNDEAD: + return B_FALSE; + default: + break; + } + if (lfhasflag(lf, F_NONCORPOREAL)) { + return B_FALSE; + } + if (isdead(lf)) { + return B_FALSE; + } + // note: not checking whether they are already unconscious + // because merciful weapons CAN still KO them in this case. + return B_TRUE; +} + int lfcanbestoned(lifeform_t *lf) { switch (getlfmaterial(lf)) { case MT_GAS: @@ -15126,8 +15209,9 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml killflagsofid(lf->flags, F_HIDING); // methods of knocking unconscious - if (!isundead(lf)) { - // merciful weapons + if (!lfcanbekod(lf)) { + // merciful weapons - these will ALWAYS ko, even if + // they are already unconscious. if (!ko && fromob) { f = hasflag(fromob->flags, F_MERCIFUL); if (f && (amt >= lf->hp)) { @@ -15140,7 +15224,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // bashing damage sometimes ko's // damage when eating corpses also does this. - if (!ko) { + if (!ko && !isunconscious(lf)) { int threshold,kochance = 0; int damtypeok = B_FALSE; int playerinvolved = B_FALSE; @@ -15183,7 +15267,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } } - if (!ko) { + if (!ko && !isunconscious(lf)) { if (fromlf && lfhasflag(fromlf, F_STRIKETOKO)) { if (cansee(fromlf, lf)) { ko = B_TRUE; @@ -15207,9 +15291,9 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } */ - // occasionally drop blood - if (damtypecausesbleed(damtype) && onein(3)) { - bleed(lf, B_FALSE); + // drop blood + if (damtypecausesbleed(damtype, fromob)) { + bleed(lf, B_NOSPLATTER); } if (hasflag(lf->flags, F_DEBUG)) { @@ -15260,7 +15344,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } } - if (doeffects) { + if (doeffects || ko) { losehpeffects(lf, amt, damtype, fromlf, fromob, retaliate, ko, waskod, prelowhp); } @@ -15321,7 +15405,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml if (fromlf) { if (murder) { setkillverb(lf, "Murdered"); - } else if (amt >= lf->maxhp) { + } else if ((amt >= lf->maxhp) && !fromob) { setkillverb(lf, "Slaughtered"); } else { setkillverb(lf, "Slain"); @@ -18501,14 +18585,16 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { // certain other flags are rnadom //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging - getflags(lf->flags, retflag, &nretflags, F_RNDHOSTILE, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - if (f->id == F_RNDHOSTILE) { - if (pctchance(f->val[0])) { - addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + if (!frompolymorph) { + getflags(lf->flags, retflag, &nretflags, F_RNDHOSTILE, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->id == F_RNDHOSTILE) { + if (pctchance(f->val[0])) { + addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } + killflag(f); } - killflag(f); } } //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging @@ -20104,15 +20190,19 @@ void startlfturn(lifeform_t *lf) { if (lfhasflag(lf, F_DODGES)) { enum ERROR e; if (celldangerous(lf, lf->cell, B_TRUE, &e)) { + object_t *avoidob = NULL; cell_t *adj; + if ((e == E_AVOIDOB) && rdata) { + // remember this sine getdodgecell() will call + // calldangerous() again which will overwrite rdata. + avoidob = (object_t *)rdata; + } // autododge! adj = getdodgecell(lf); if (adj) { char fromx[BUFLEN]; if ((e == E_AVOIDOB) && rdata) { - object_t *o; - o = (object_t *)rdata; - getobname(o, fromx, o->amt); + getobname(avoidob, fromx, avoidob->amt); } else { sprintf(fromx, "danger"); } @@ -20629,9 +20719,12 @@ void startlfturn(lifeform_t *lf) { } } - // bleeding injuries can stain armour + // bleeding injuries can stain armour. also mark injuries as no longer new. if ((f->id == F_INJURY) && (f->val[2] == DT_SLASH)) { object_t *arm; + + if (f->obfrom == B_NEWINJURY) f->obfrom = B_FALSE; + arm = getequippedob(lf->pack, f->val[1]); if (arm && !hasobmod(arm, findobmod(OM_BLOODSTAINED)) && pctchance(5)) applyobmod(arm, findobmod(OM_BLOODSTAINED)); } @@ -20847,14 +20940,18 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { o = (object_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; } if (o) { + int amt = 1; //killflagsofid(o->flags, F_SHOPITEM); - o = moveob(o, lf->pack, 1); + if (o->type->id == OT_GOLD) { + amt = rnd(1,slev*33); + } + o = moveob(o, lf->pack, amt); if (o) { char obname[BUFLEN]; char lfname[BUFLEN]; char targname[BUFLEN]; getlfname(lf, lfname); - getobname(o, obname, 1); + getobname(o, obname, amt); if (op->owner) { getlfname(op->owner, targname); if (isplayer(lf)) { @@ -22386,6 +22483,18 @@ int validateraces(void) { goterror = B_TRUE; } } + if (f->id == F_FILLPOT) { + flag_t *f2; + if (!findot(f->val[0])) { + printf("ERROR in race '%s' - F_FILLPOT with bad object.\n", r->name); + goterror = B_TRUE; + } + f2 = hasflag(r->flags, F_BLOODOB); + if (f2 && !strlen(f2->text)) { + printf("ERROR in race '%s' - has F_FILLPOT but no bleed object.\n", r->name); + goterror = B_TRUE; + } + } if (f->id == F_HASATTACK) { if (!findot(f->val[0])) { printf("ERROR in race '%s' - F_HASATTACK with bad object.\n", r->name); diff --git a/lf.h b/lf.h index 8bac626..99f1abf 100644 --- a/lf.h +++ b/lf.h @@ -299,6 +299,7 @@ job_t *hasjob(lifeform_t *lf, enum JOB job); int hassubjob(lifeform_t *lf, enum SUBJOB id); void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch); int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJURY forcetype); +int lfcanbekod(lifeform_t *lf); int lfcanbestoned(lifeform_t *lf); flag_t *lfhasflag(lifeform_t *lf, enum FLAG fid); flag_t *lfhasflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int val2, char *text); diff --git a/move.c b/move.c index 13f1f44..71f8026 100644 --- a/move.c +++ b/move.c @@ -158,10 +158,10 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err flag_t *f; object_t *o; + rdata = NULL; // default if (error) { *error = E_OK; - rdata = NULL; } // never dangerous if there's someone there, since we'll @@ -1103,7 +1103,7 @@ int moveeffects(lifeform_t *lf, int moved) { } } else { if (rnd(1,2) == 1) { - bleed(lf, B_FALSE); + bleed(lf, B_NOSPLATTER); } } } @@ -2636,8 +2636,9 @@ void standup(lifeform_t *lf) { } } -void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int changedir, int onpurpose) { +void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int changedir1, int changedir2, int onpurpose) { cell_t *cell1,*cell2; + int tempfacing; cell1 = lf1->cell; cell2 = lf2->cell; @@ -2653,11 +2654,12 @@ void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int changedir, int onpurpose) lf2->cell = cell1; cell1->lf = lf2; - if (changedir) { - int tempfacing; - tempfacing = lf2->facing; - setfacing(lf2, lf1->facing); - setfacing(lf1, tempfacing); + tempfacing = lf1->facing; + if (changedir1) { + setfacing(lf1, lf2->facing); + } + if (changedir2) { + setfacing(lf2, tempfacing); } // remember that we just swapped, and this counts as a move @@ -3252,7 +3254,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { dontclearmsg = B_TRUE; } - swapplaces(lf, lfinway, B_FALSE, onpurpose); + swapplaces(lf, lfinway, B_NOCHANGEDIR, B_NOCHANGEDIR, onpurpose); //if (onpurpose) taketime(lf, getmovespeed(lf)); taketime(lf, getmovespeed(lf)); diff --git a/move.h b/move.h index e2c554f..f3e9fd0 100644 --- a/move.h +++ b/move.h @@ -31,7 +31,7 @@ int isorthogonal(int dir); int ispossiblemove(lifeform_t *lf, int dir); int rotatedir(int origdir, enum TURNDIR whichway, int amt); void standup(lifeform_t *lf); -void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int changedir, int onpurpose); +void swapplaces(lifeform_t *lf1, lifeform_t *lf2, int changedir1, int changedir2, int onpurpose); int teleportto(lifeform_t *lf, cell_t *c, int wantsmoke); void triggertrap(lifeform_t *lf, object_t *o, object_t *trapob, cell_t *where); int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe); diff --git a/nexus.c b/nexus.c index d2360c0..e71f974 100644 --- a/nexus.c +++ b/nexus.c @@ -122,7 +122,6 @@ extern race_t **raceposs; extern int *xpposs; int main(int argc, char **argv) { - int newworld = B_FALSE; object_t *o; char welcomemsg[BUFLEN]; int ch; @@ -285,7 +284,6 @@ int main(int argc, char **argv) { addflag(player->flags, F_CANWILL, OT_A_DEBUG, NA, NA, NULL); ///////// // make the initial level - newworld = B_TRUE; // create world map. wregion = findregionbytype(BH_WORLDMAP); @@ -427,35 +425,42 @@ int main(int argc, char **argv) { calclight(player->cell->map); // pre-calc line-of-sight for player //precalclos(player); - player->facing = D_ALL; + + if (!foundsavegame) { + player->facing = D_ALL; + } + setlosdirty(player); - // changes for anything within los/lof of player's starting pos: - // - don't want any mosnters starting here - // - don't want any impassable objects other than doors - // - don't want any locked doors - slev = getskill(player, SK_CARTOGRAPHY); - for (y = 0; y < player->cell->map->h; y++) { - for (x = 0; x < player->cell->map->w; x++) { - c = getcellat(player->cell->map, x, y); - if (c && (haslos(player, c) || haslof(player->cell, c, LOF_WALLSTOP, NULL))) { - object_t *o,*nexto; - if (c->lf && !isplayer(c->lf) && !ispetof(c->lf, player)) { - killlf(c->lf); - } - for (o = c->obpile->first ; o ; o = nexto) { - nexto = o->next; - if (hasflag(o->flags, F_IMPASSABLE) && !hasflag(o->flags, F_DOOR)) { - killob(o); - continue; - } else { - killflagsofid(o->flags, F_LOCKED); + if (!foundsavegame) { + // changes for anything within los/lof of player's starting pos: + // - don't want any mosnters starting here + // - don't want any impassable objects other than doors + // - don't want any locked doors + slev = getskill(player, SK_CARTOGRAPHY); + for (y = 0; y < player->cell->map->h; y++) { + for (x = 0; x < player->cell->map->w; x++) { + c = getcellat(player->cell->map, x, y); + if (c && (haslos(player, c) || haslof(player->cell, c, LOF_WALLSTOP, NULL))) { + object_t *o,*nexto; + if (c->lf && !isplayer(c->lf) && !ispetof(c->lf, player)) { + killlf(c->lf); + } + for (o = c->obpile->first ; o ; o = nexto) { + nexto = o->next; + if (hasflag(o->flags, F_IMPASSABLE) && !hasflag(o->flags, F_DOOR)) { + killob(o); + continue; + } else { + killflagsofid(o->flags, F_LOCKED); + } } } } } } + needredraw = B_TRUE; statdirty = B_TRUE; @@ -467,7 +472,7 @@ int main(int argc, char **argv) { // make player face the direction which gives them the most visibility // as we check, set all cells around us to start off known. - if (newworld) { + if (!foundsavegame) { int bestdir = D_NONE; int bestlos = -1; for (i = DC_N; i <= DC_NW; i++) { diff --git a/objects.c b/objects.c index 5b7fe13..23d68a2 100644 --- a/objects.c +++ b/objects.c @@ -804,7 +804,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum p += strlen("lit "); donesomething = B_TRUE; // different materials - } else if (((mat = strmatchesmaterial(p)) != NULL) && !strstr(p, "gold coin")) { + } else if (((mat = strmatchesmaterial(p)) != NULL) && !strstr(p, "gold coin") && !strstr(p, "leather armour")) { wantdiffmat = mat->id; p += strlen(mat->name); p++; // go past the space @@ -1566,7 +1566,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum } // fill in book types - if (o && (o->type->obclass->id == OC_BOOK)) { + if (o && (o->type->obclass->id == OC_BOOK) && (gamemode != GM_LOADING)) { hiddenname_t *hn,*selhn = NULL; int numhiddennames; int n,sel; @@ -1625,7 +1625,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum assert(addobfast(o->contents, oid)); } } - } else if ((o->type->id == OT_GRIMOIRE) && (gamemode != GM_LOADING)) { + } else if (o->type->id == OT_GRIMOIRE) { // 1 spell from each school int i; int nschools = -1; @@ -1742,6 +1742,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum n++; } } + killflagsofid(o->flags, F_HASHIDDENNAME); addflag(o->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, selhn->text); // don't call sethiddenname, because it acts on OBJECT TYPES not OBJECTS. // all books are unique @@ -6090,7 +6091,7 @@ objecttype_t *real_getrandomob(map_t *map, char *buf, int forcedepth, int forceh int amt; flag_t *f; int db = B_FALSE; - int partdb = B_TRUE; + int partdb = B_FALSE; char *pluralname; char brandname[BUFLEN]; char cursestr[BUFLEN]; @@ -7495,7 +7496,12 @@ int isplainob(object_t *o) { if (o->inscription) return B_FALSE; if (o->blessed != B_UNCURSED) return B_FALSE; if (isblessknown(o)) return B_FALSE; - if (isdamaged(o)) return B_FALSE; + if (isdamaged(o)) { + // splashes of liquid can combine even when 'damaged' + if (getmaterialstate(o->material->id) != MS_LIQUID) { + return B_FALSE; + } + } return B_TRUE; } @@ -8195,7 +8201,7 @@ void makewet(object_t *o, int amt) { killflagsofid(o->flags, F_ONFIRE); killflagsofid(o->flags, F_HOT); - if (o->material->id == MT_METAL) { + if (willrust(o)) { int rustchance = 25; f = hasflag(o->flags, F_RUSTED); if (f) rustchance += 25; @@ -9883,24 +9889,14 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { int donedip = B_FALSE; // anything here to fill with? for (oo = lf->cell->obpile->first ; (oo && !donedip); oo = nextoo) { + flag_t *fillflag; int dippable = B_FALSE; nextoo = oo->next; - switch (oo->type->id) { - case OT_BLOODSPLASH: - case OT_SPLASHWATER: - if (oo->amt >= 5) { - dippable = B_TRUE; - } - break; - case OT_BLOODPOOL: - case OT_PUDDLEWATER: - case OT_PUDDLEWATERL: - case OT_FOUNTAIN: - dippable = B_TRUE; - break; - default: - break; + fillflag = hasflag(oo->flags, F_FILLPOT); + if (fillflag && ((fillflag->val[1] == NA) || (oo->amt >= fillflag->val[1]))) { + dippable = B_TRUE; } + if (dippable) { char ch; char ques[BUFLEN]; @@ -9956,22 +9952,16 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { getobname(newob, newobname, newob->amt); msgnocap("%c - %s.",newob->letter, newobname); } - switch (oo->type->id) { - case OT_SPLASHWATER: - case OT_BLOODSPLASH: - removeob(oo, 5); - break; - case OT_PUDDLEWATER: + if (oo->type->id == OT_FOUNTAIN) { + if (fountain_will_dryup(oo)) { + removeob(oo, oo->amt); + } + } else { + if (fillflag->val[1] != NA) { + removeob(oo, fillflag->val[1]); + } else { removeob(oo, 1); - break; - case OT_FOUNTAIN: - if (fountain_will_dryup(oo)) { - removeob(oo, oo->amt); - } - break; - default: - break; - + } } } else { msg("That doesn't seem like a very good idea."); @@ -15160,6 +15150,15 @@ int cancrush(lifeform_t *lf, object_t *o) { return B_FALSE; } +int willrust(object_t *o) { + if (o->material->id == MT_METAL) { + if (!hasflag(o->flags, F_WATERPROOF)) { + return B_TRUE; + } + } + return B_FALSE; +} + int willshatter(enum MATERIAL mat) { switch (mat) { case MT_GLASS: diff --git a/objects.h b/objects.h index af048a6..878b578 100644 --- a/objects.h +++ b/objects.h @@ -296,6 +296,7 @@ int validatehiddennames(void); int validateobs(void); int wepdullable(object_t *o); int cancrush(lifeform_t *lf, object_t *o); +int willrust(object_t *o); int willshatter(enum MATERIAL mat); #endif diff --git a/spell.c b/spell.c index 1f80713..850e035 100644 --- a/spell.c +++ b/spell.c @@ -1351,7 +1351,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (c) { movelf(victim, c); } else { - swapplaces(victim, user, B_TRUE, B_FALSE); + swapplaces(victim, user, B_CHANGEDIR, B_CHANGEDIR, B_NOTONPURPOSE); swapped = B_TRUE; } @@ -6713,6 +6713,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (iscursed(o)) { setblessed(o, B_UNCURSED); } + killflagsofid(o->flags, F_RUSTED); } } else { // monsters can't id things! @@ -11712,12 +11713,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("You feel a wrenching sensation!"); if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (isplayer(target)) { - msg("You feel a wrenching sensation!"); + msg("You feel a wrenching sensation!"); more(); if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (cansee(player, caster)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } - swapplaces(caster, target, B_CHANGEDIR, B_ONPURPOSE); + swapplaces(caster, target, B_CHANGEDIR, B_NOCHANGEDIR, B_ONPURPOSE); } else if ((spellid == OT_S_SUMMONANIMALSSM) || (spellid == OT_S_SUMMONANIMALSMD) || (spellid == OT_S_SUMMONANIMALSLG) || diff --git a/text.c b/text.c index 9e44f4b..4731fc6 100644 --- a/text.c +++ b/text.c @@ -210,6 +210,15 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam } verb = getattackverb(lf, wep, damtype,dam,maxhp); + // when the player is being attacked, we want: + // "the xxx hits you. you die." + // rather than + // "the xxx kills you." + if (fatal && !isplayer(victim)) { + verb = getkillverb(victim, wep, damtype, dam, maxhp); + } else { + verb = getattackverb(lf, wep, damtype,dam,maxhp); + } strcpy(nodamstr, ""); if ((dam == 0) && (damtype != DT_TOUCH) && !lfhasflag(lf, F_PHANTASM)) { @@ -1076,11 +1085,13 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); - if (wep && hasflag(wep->flags, F_MERCIFUL)) { - return "knock out"; - } - if (wep && wep->pile->owner && lfhasflag(wep->pile->owner, F_STRIKETOKO)) { - return "knock out"; + if (!isunconscious(victim)) { + if (wep && hasflag(wep->flags, F_MERCIFUL)) { + return "knock out"; + } + if (wep && wep->pile->owner && lfhasflag(wep->pile->owner, F_STRIKETOKO)) { + return "knock out"; + } } if (victim->race->id == R_DANCINGWEAPON) { return "defeat";