diff --git a/attack.c b/attack.c index ea8c3f0..34fd82e 100644 --- a/attack.c +++ b/attack.c @@ -107,20 +107,17 @@ void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int * int db = B_FALSE; int newdam = 0; - // armour can't stop armour-piercing weapons - if (hasflag(wep->flags, F_ARMOURPIERCE)) { - reduceamt = 0; - } // figure out reduced damage value if (dam) { int ar; - newdam = *dam; ar = getarmourrating(lf, NULL, NULL, NULL); + // if you did at least one damage... if ((*dam >= 1) && (reduceamt >= 0)) { int lowerlimit = 0,divideby; + // reduce it. newdam -= reduceamt; @@ -132,6 +129,8 @@ void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int * divideby = ar/2; if (divideby <= 0) divideby = 1; lowerlimit = (*dam / divideby); + + limit(&lowerlimit, 1, NA); limit(&newdam, lowerlimit, NA); // don't reduce too far. } @@ -944,7 +943,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } //if (!isplayer(lf) && !isplayer(victim)) { - noise(lf->cell, lf, NC_FIGHTING, 3, "fighting.", NULL); + noise(lf->cell, lf, NC_FIGHTING, SV_SHOUT, "fighting.", NULL); //} if (fatal) { if (strstr(buf, "behead")) { @@ -993,7 +992,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // don't adjust damage - we've already done that if (wep && !isunarmed) { char wepname[BUFLEN]; - getobname(wep, wepname, 1); + real_getobname(wep, wepname, 1, B_TRUE, B_FALSE, B_FALSE, B_TRUE, B_FALSE); /* snprintf(buf, BUFLEN, "%s^%s %s",attackername2, (lf == victim) ? "using" : "weilding", @@ -1637,8 +1636,9 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d int ar,min,max; //int pctrange; object_t *o; + flag_t *pierce = NULL; - if (hasflag(wep->flags, F_ARMOURPIERCE)) { + if (hasflag(wep->flags, F_ARMOURIGNORE)) { reduceamt = 0; } @@ -1663,6 +1663,13 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d } } + // and if weapon is armour piercing, you always take at least its + // armourpiercing valut. + pierce = hasflag(wep->flags, F_ARMOURPIERCE); + if (pierce) { + reduceamt -= pierce->val[0]; + } + if (reduceamt < 0) reduceamt = 0; return reduceamt; } @@ -2054,7 +2061,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) } if (!canreach(lf, victim, &reachpenalty)) { - acc -= (15*reachpenalty); + acc -= (10*reachpenalty); } // modify for defender's evasion diff --git a/data.c b/data.c index 4ca3cf0..7987887 100644 --- a/data.c +++ b/data.c @@ -963,8 +963,8 @@ void initobjects(void) { addflag_real(lastbrand->flags, F_FLAMESTRIKE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_REVENGE, "of revenge", BP_WEAPON, B_UNCURSED, 0); addflag_real(lastbrand->flags, F_REVENGE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); - addbrand(BR_SHARPNESS, "of sharpness", BP_WEAPON, B_UNCURSED, 0); - addflag_real(lastbrand->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); + addbrand(BR_SHARPNESS, "of penetration", BP_WEAPON, B_UNCURSED, 0); + addflag_real(lastbrand->flags, F_ARMOURIGNORE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_LIFESUCK, "of lifesucking", BP_WEAPON, B_UNCURSED, 0); addflag_real(lastbrand->flags, F_VAMPIRIC, NA, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); @@ -1162,6 +1162,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_OPERUSECHARGE, B_TRUE, NA, NA, NULL); + addflag(lastobjectclass->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_RNDCHARGES, 1, 8, NA, NULL); addoc(OC_POTION, "Potions", "A strange concoction contained within a small flask.", '!', C_GREY, RR_COMMON); @@ -1847,6 +1848,7 @@ void initobjects(void) { addflag(lastot->flags, F_CHARGES, 100, 100, NA, NULL); addflag(lastot->flags, F_RECHARGE, 1, NA, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); // flora addot(OT_FLOWER, "flower", "A colourful woodland flower.", MT_PLANT, 0.01, OC_FLORA, SZ_TINY); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_FREQUENT, ""); @@ -2137,7 +2139,7 @@ void initobjects(void) { addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_BADOBJECT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); - addot(OT_POT_ACID, "flask of battery acid", "Causes massive internal burning if ingested.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addot(OT_POT_ACID, "flask of acid", "Causes massive internal burning if ingested.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid"); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); @@ -2309,6 +2311,11 @@ void initobjects(void) { addflag(lastot->flags, F_VALUE, 400, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 50, RR_RARE, NULL); + addot(OT_SCR_REPLENISHMENT, "scroll of replenishment", "Restores a random amount of charges to a wand.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_LINKSPELL, OT_S_REPLENISH, NA, NA, NULL); + + addot(OT_SCR_TELEPORT, "scroll of teleportation", "Causes the caster to teleport to a random location within the same level.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_LINKSPELL, OT_S_TELEPORT, 4, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); @@ -2435,7 +2442,7 @@ void initobjects(void) { addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); - addot(OT_S_DRAINLIFE, "necrotic beam", "Draws life force from the victim in order to heal the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_DRAINLIFE, "necrobeam", "Draws life force from the victim in order to heal the caster.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The amount of life force drained is ^b1d6+power^n."); addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -3572,6 +3579,18 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ANYWHERE, NA, NA, NULL); + // l4 + addot(OT_S_NULLIFY, "nullify", "Permenantly removes the target's ability to use one or more spells/abilities.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the amount of spells nullified."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER|TT_DOOR, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addot(OT_S_REPLENISH, "replenish", "Restores a some amount of power to a wand.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the amount of charges restored."); + addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); // l6 addot(OT_S_DETONATE, "detonate", "Causes a given area to explode with massive force.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the size of the explosion."); @@ -3795,6 +3814,10 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, RR_UNCOMMON, NULL); addflag(lastot->flags, F_LINKSPELL, OT_S_LIGHT, 3, NA, NULL); addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, TR_NEEDLOF, NA, NULL); + addot(OT_WAND_NULLIFY, "wand of nullification", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, RR_RARE, NULL); + addflag(lastot->flags, F_LINKSPELL, OT_S_NULLIFY, NA, NA, NULL); + addflag(lastot->flags, F_OPERNEEDTARGET, TT_MONSTER, TR_NEEDLOF, NA, NULL); addot(OT_WAND_REVEALHIDDEN, "wand of reveal hidden", "A limited-use magical wand which casts the imbued spell.", MT_METAL, 0.5, OC_WAND, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, RR_UNCOMMON, NULL); addflag(lastot->flags, F_LINKSPELL, OT_S_REVEALHIDDEN, NA, NA, NULL); @@ -3915,6 +3938,7 @@ void initobjects(void) { addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers"); addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out"); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_FRIDGE, "refrigerator", "An insulated household appliance, made for storing food.", MT_METAL, 120, OC_TOOLS, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); @@ -3958,6 +3982,7 @@ void initobjects(void) { addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers"); addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out"); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_LANTERNOIL, "oil lantern", "An oil-powered lantern which produces a lot of light.", MT_METAL, 1, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 55, NA, NULL); @@ -3971,6 +3996,7 @@ void initobjects(void) { addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers"); addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out"); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_LOCKPICK, "lockpick", "An angled piece of metal, used to open locks.", MT_METAL, 0.05, OC_TOOLS, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -4124,6 +4150,7 @@ void initobjects(void) { addflag(lastot->flags, F_LIGHTSOURCE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers"); addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out"); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_TOWEL, "towel", "An large absorbent cloth used for drawing off moisture.", MT_CLOTH, 1.5, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 73, NA, NULL); @@ -4137,6 +4164,7 @@ void initobjects(void) { addflag(lastot->flags, F_STACKABLE, B_FALSE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_PICKLOCKS, 2, NA, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_PAPERCLIP, "paperclip", "A thin, looped wire for holding paper together.", MT_WIRE, 0.01, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); addflag(lastot->flags, F_VALUE, 5, NA, NA, NULL); @@ -4163,6 +4191,7 @@ void initobjects(void) { addflag(lastot->flags, F_RNDCHARGES, 5, 10, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_POCKETWATCH, "pocket watch", "A portable timekeeping device made to be carried in a pocket.", MT_METAL, 0.1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 90, NA, NULL); addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); @@ -4185,6 +4214,7 @@ void initobjects(void) { addflag(lastot->flags, F_RNDCHARGES, 1, 5, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_LANTERNLED, "LED lantern", "A low-powered but efficient lantern which will last almost forever.", MT_METAL, 0.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, NULL); @@ -4197,8 +4227,15 @@ void initobjects(void) { addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); // tech - l2 + addot(OT_BATTERY, "induction battery", "A power storage and provision device which automatically feeds power to nearby devices as needed.", MT_METAL, 1, OC_TECH, SZ_HUMAN); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 75, NA, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); + addflag(lastot->flags, F_RNDCHARGES, 10, 30, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_TENT, "tent", "A easy to use, portable shelter made of fabric.", MT_CLOTH, 10, OC_TECH, SZ_HUMAN); - addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL); addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); addflag(lastot->flags, F_HELPSREST, 15, 1, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); @@ -4342,6 +4379,7 @@ void initobjects(void) { addflag(lastot->flags, F_ACTIVATECONFER, F_PRODUCESLIGHT, 2, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_SKILLED, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); // tech - l5 addot(OT_TELEPAD, "teleport beacon", "A metal cone which will teleport the user to the nearest similar cone.", MT_METAL, 3, OC_TECH, SZ_MEDIUM); @@ -5610,8 +5648,9 @@ void initobjects(void) { addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); addot(OT_RING_MIRACLES, "ring of miracles", "Grants a limited number of miracles to the wearer.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); - addflag(lastot->flags, F_CHARGES, 1, 3, NA, NULL); + addflag(lastot->flags, F_CHARGES, 1, 3, NA, NULL); // always starts with just 1 charge addflag(lastot->flags, F_VALUE, 400, NA, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); addot(OT_RING_MPBOOST, "ring of arcane power", "Increases the power of the wearer's spells.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); @@ -5764,7 +5803,7 @@ void initobjects(void) { // monster weapons addot(OT_ACIDATTACK, "acidattack", "acid attack object", MT_WATER, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_ACID, 2, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 60, NA, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); @@ -5781,7 +5820,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addot(OT_TOUCHPARALYZE, "paralyzing touch", "paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); - addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, ""); + addflag(lastot->flags, F_ARMOURPIERCE, 90, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_TOUCH, 1, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 22, "2-4"); @@ -5790,7 +5829,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addot(OT_TOUCHPARALYZE2, "strong paralyzing touch", "strong paralyzing touch object", MT_BONE, 0, OC_WEAPON, SZ_TINY); - addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, ""); + addflag(lastot->flags, F_ARMOURPIERCE, 90, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_TOUCH, 1, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_HITCONFER, F_PARALYZED, SC_CON, 30, "5-10"); @@ -5814,7 +5853,7 @@ void initobjects(void) { addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_MISSILEDAM, 1, NA, NA, ""); - addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, ""); + addflag(lastot->flags, F_ARMOURPIERCE, 10, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); @@ -5916,6 +5955,7 @@ void initobjects(void) { // axes addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 4, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 6, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_BASH, 4, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); @@ -5924,14 +5964,17 @@ void initobjects(void) { addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 8, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 11, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_BASH, 5, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 4, NA, NA, ""); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, 10, NULL); addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 10, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 10, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 18, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_BASH, 6, NA, NULL); addflag(lastot->flags, F_NEEDSSPACE, B_TRUE, NA, NA, NULL); @@ -5941,6 +5984,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 15, 15, NULL); addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2.5, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 4, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 7, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_MISSILEDAM, 5, NA, NA, NULL); @@ -5950,6 +5994,7 @@ void initobjects(void) { addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); addot(OT_HATCHET, "hatchet", "Similar to a handaxe but weighted at the head. A fast one-handed axe, ideal for throwing.", MT_METAL, 4, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 6, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 8, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); @@ -5958,6 +6003,7 @@ void initobjects(void) { addflag(lastot->flags, F_CRITCHANCE, 6, NA, NA, NULL); addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 7, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 8, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 12, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_BASH, 5, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); @@ -6085,6 +6131,7 @@ void initobjects(void) { // long blades addot(OT_BASTARDSWORD, "bastard sword", "Very large, heavy sword.", MT_METAL, 8, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 2, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_SLASH, 12, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_PIERCE, 12, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); @@ -6095,6 +6142,7 @@ void initobjects(void) { addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL); addot(OT_FALCHION, "falchion", "A single-edged heavy sword made for chopping.", MT_METAL, 6.5, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 61, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 4, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 11, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); @@ -6103,6 +6151,7 @@ void initobjects(void) { addot(OT_GREATSWORD, "greatsword", "A massive two-handed sword.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 55, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 2, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_SLASH, 15, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_PIERCE, 15, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); @@ -6168,6 +6217,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 71, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_TRIPLF, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 4, NA, NA, ""); addflag(lastot->flags, F_DAM, DT_CHOP, 13, NA, NULL); addflag(lastot->flags, F_ALTDAM, DT_SLASH, 10, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); @@ -6399,15 +6449,17 @@ void initobjects(void) { addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 10, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 9, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 4, NA, NA, ""); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 12, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 7, NA, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 125, NA, NA, NULL); - addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM); + addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace. Its weight makes it good for penetrating armour.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 12, NA, NULL); + addflag(lastot->flags, F_ARMOURPIERCE, 6, NA, NA, ""); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); @@ -7895,6 +7947,34 @@ void initrace(void) { addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 0, NA, NA, NULL); + addrace(R_GREMLIN, "gremlin", 20, 'g', C_GREEN, MT_FLESH, RC_HUMANOID, "Small mischievous imps known for their love of sabotage."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4"); + addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, NULL); + addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); + addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_TECH, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 50, OC_TECH, NA, "wand of wonder"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "chuckles^a chuckle"); + addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); + addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_GASEOUSFORM, NA, NA, "pw:3;"); + // gremlins also cause tech to fail around them. + addrace(R_HOBGOBLIN, "hobgoblin", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID, "A larger, stronger, smarter and more menacing form of a goblin."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -8487,7 +8567,7 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_ACIDATTACK, 11, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_ACIDATTACK, 8, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 5, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slurping"); addflag(lastrace->flags, F_DTIMMUNE, DT_ACID, B_TRUE, NA, NULL); @@ -8576,6 +8656,7 @@ void initrace(void) { addrace(R_SPRITEICE, "ice sprite", 5, 'n', C_WHITE, MT_ICE, RC_MAGIC, "A small magical creature made from freezing ice."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "sheet of ice"); + addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "small puddle of water"); 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); @@ -8590,8 +8671,8 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_SPELLSPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_S_FROSTBITE, NA, NA, "pw:1;"); - addflag(lastrace->flags, F_CANWILL, OT_S_FREEZEOB, NA, NA, "pw:1;"); - addflag(lastrace->flags, F_CANWILL, OT_S_ICICLE, NA, NA, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_FREEZEOB, 10, 10, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_ICICLE, 3, 3, "pw:1;"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gestures"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); @@ -9450,6 +9531,56 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addrace(R_SLUG, "dragon slug", 150, 'P', C_GREY, MT_FLESH, RC_ANIMAL, "While dragon slugs lack the protective shell of their snail cousings, their rubbery flesh is extremely resilient. Their acid-based attacks also make them much more dangerous."); + addbodypart(lastrace, BP_BODY, NULL); + addbodypart(lastrace, BP_HEAD, NULL); + addbodypart(lastrace, BP_EYES, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, ""); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, ""); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_FREQUENT, NULL); + addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "7d4+1"); + addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_ACIDATTACK, 11, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^slurping"); + addflag(lastrace->flags, F_DTIMMUNE, DT_ACID, B_TRUE, NA, NULL); + addflag(lastrace->flags, F_AUTOCREATEOB, 0, NA, NA, "puddle of acid"); + addflag(lastrace->flags, F_DIESPLATTER, 3, NA, NA, "splash of acid"); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); + addflag(lastrace->flags, F_VULNTOSALT, B_TRUE, NA, NA, NULL); + 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, "dragon 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); + addbodypart(lastrace, BP_EYES, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, ""); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, ""); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_FREQUENT, NULL); + addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+1"); + addflag(lastrace->flags, F_ARMOURRATING, 18, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); + addflag(lastrace->flags, F_VULNTOSALT, B_TRUE, NA, NA, NULL); + 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_SNAKE, "brown snake", 3, 's', C_BROWN, MT_FLESH, RC_ANIMAL, "Common venomous snakes."); setbodytype(lastrace, BT_SNAKE); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); @@ -9523,7 +9654,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addrace(R_SNAKECOBRABLACK, "black cobra", 3, 's', C_BLUE, MT_FLESH, RC_ANIMAL, "Black cobras can spit globs of venom at their prey."); setbodytype(lastrace, BT_SNAKE); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9548,7 +9679,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addrace(R_SNAKECOBRAGOLDEN, "golden cobra", 3, 's', C_YELLOW, MT_FLESH, RC_ANIMAL, "Golden cobras spit a blindness-inducing venom at their enemies."); setbodytype(lastrace, BT_SNAKE); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9604,6 +9735,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSMELL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_COLDBLOOD, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9779,7 +9911,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_SWALLOW, 5, 5, NULL); addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "opens its mouth wide.."); - addflag(lastrace->flags, F_NOISETEXT, N_WALK, SV_ROAR, NA, "^slithering"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, SV_CAR, NA, "^slithering"); addflag(lastrace->flags, F_FLEEONHPPCT, 20, NA, NA, ""); addflag(lastrace->flags, F_MORALE, 50, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); @@ -10590,6 +10722,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBWEPSK, 50, SK_AXES, NA, NULL); addflag(lastrace->flags, F_STARTOB, 25, NA, NA, "buckler"); addflag(lastrace->flags, F_DTVULN, DT_BASH, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_FALL, NA, NA, "2d3"); addflag(lastrace->flags, F_DTRESIST, DT_PIERCE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); @@ -10864,9 +10997,11 @@ void initrace(void) { addflag(r->flags, F_FLAMMABLE, PERMENANT, NA, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_SLIME) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_UNDEAD) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index d0b980d..e66f7d1 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 3174b35..1375ed5 100644 --- a/defs.h +++ b/defs.h @@ -472,8 +472,9 @@ enum SPEECHVOL { SV_WHISPER = 1, SV_TALK = 2, SV_SHOUT = 3, - SV_ROAR = 4, - SV_BELLOW = 5, + SV_CAR = 4, + SV_TRUCK = 5, + SV_PLANE = 6, }; enum SKILL { @@ -877,6 +878,7 @@ enum RACE { R_GOBLINWAR, R_GOBLINSHOOTER, R_GOBLINHEXER, + R_GREMLIN, R_HOBGOBLIN, R_HOBGOBLINWAR, R_KOBOLD, @@ -944,6 +946,8 @@ enum RACE { R_NEWT, R_PORCUPINE, R_RAT, + R_SLUG, + R_SNAIL, R_SNAKE, R_SNAKECARPET, R_SNAKECOBRABLACK, @@ -1235,6 +1239,7 @@ enum OBTYPE { OT_SCR_ENCHANT, OT_SCR_FREEZEOB, OT_SCR_REMOVECURSE, + OT_SCR_REPLENISHMENT, OT_SCR_TELEPORT, OT_SCR_TURNUNDEAD, OT_SCR_WISH, @@ -1430,6 +1435,8 @@ enum OBTYPE { OT_S_ENERGYBOLT, OT_S_ENERGYBLAST, OT_S_FLASH, + OT_S_NULLIFY, + OT_S_REPLENISH, // -- divine powers OT_S_CREATEVAULT, OT_S_GIFT, @@ -1501,6 +1508,7 @@ enum OBTYPE { OT_WAND_INVIS, OT_WAND_KNOCK, OT_WAND_LIGHT, + OT_WAND_NULLIFY, OT_WAND_POLYMORPH, OT_WAND_REVEALHIDDEN, OT_WAND_SLOW, @@ -1544,6 +1552,7 @@ enum OBTYPE { OT_LANTERNLED, OT_SOLDERINGIRON, // tech l2 + OT_BATTERY, OT_C4, OT_FLASHBANG, OT_GRENADE, @@ -1834,7 +1843,6 @@ enum OBTYPE { OT_PUSHE, OT_PUSHS, OT_PUSHW, -oooo }; #define MAXBUILDINGTYPES (10) @@ -2122,6 +2130,7 @@ enum FLAG { F_RNDCHARGES, // ob starts with between val0 and val1 charges // this will cause F_CHARGES to be filled in F_CHARGES, // generally the number of uses left,v0=min, v1=max + F_REPLENISHABLE, // the 'replenish' spell works on this object F_DONTSHOWCHARGES, // don't show 'xx charges left' when id'd F_RECHARGEWHENOFF, // get power back when you turn it off F_RECHARGE, // get v0 charges back each turn. @@ -2280,7 +2289,9 @@ enum FLAG { // v1->v0, v2->v1 is added to this object after it hits. F_ACCURACY, // 100 - val0 = modify to tohit% (ie. higher is better) F_UNARMEDWEP, // this is not a real weapon, ie. claws, teeth etc - F_ARMOURPIERCE, // goes through armour + F_ARMOURIGNORE, // armour has no effect + F_ARMOURPIERCE, // goes through armour. armour can't reduce the + // damage dealt to less than v0. F_TWOHANDED, // weapon uses two hands to weild F_NEEDSSPACE, // weapon needs space to swing - 75% chance of hitting // a wall if used with < 3 empty cells around you @@ -2319,7 +2330,7 @@ enum FLAG { F_LINKGOD, // val0 = linked god race id // scroll flags F_LINKSPELL, // val0 = spell this scroll will cast when read - // v1 = spell power + // v1 = spell power (optional) // book flags F_MANUALOF, // val0 = skill this book trains F_LINKSCHOOL, // val0 = spellschool this book has spells from diff --git a/doc/glyphs.txt b/doc/glyphs.txt index ecc5ab0..0ee6b46 100644 --- a/doc/glyphs.txt +++ b/doc/glyphs.txt @@ -16,11 +16,12 @@ e = eye E = elemental ? f = feline/cat F = flora (flowers, plants, etc) -g = goblin +g = goblin / gremlin G = large goblin h = humanoid H = large humanoid i = insect +P = gastroPod j = jelly/ooze/leech k = kobold m = mutant diff --git a/god.c b/god.c index f2955dc..24d0190 100644 --- a/god.c +++ b/god.c @@ -958,7 +958,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { first = B_FALSE; } killflagsofid(o->flags, F_LOCKED); - noise(c, NULL, NC_OTHER, 2, "the click of a lock.", NULL); + noise(c, NULL, NC_OTHER, SV_TALK, "the click of a lock.", NULL); } } } diff --git a/io.c b/io.c index 52fb158..57a3275 100644 --- a/io.c +++ b/io.c @@ -5118,25 +5118,41 @@ char *makedesc_ob(object_t *o, char *retbuf) { if (f) { char sizetext[BUFLEN]; switch (f->val[0]) { - case SZ_MEDIUM: + case SZ_MINI: + snprintf(sizetext, BUFLEN, "miniature"); + break; + case SZ_TINY: + snprintf(sizetext, BUFLEN, "tiny"); + break; + case SZ_SMALL: snprintf(sizetext, BUFLEN, "small"); break; - case SZ_LARGE: - snprintf(sizetext, BUFLEN, "very large"); + case SZ_MEDIUM: + snprintf(sizetext, BUFLEN, "medium"); break; case SZ_HUMAN: - default: snprintf(sizetext, BUFLEN, "human"); break; + case SZ_LARGE: + snprintf(sizetext, BUFLEN, "large"); + break; + case SZ_HUGE: + snprintf(sizetext, BUFLEN, "huge"); + break; + case SZ_ENORMOUS: + snprintf(sizetext, BUFLEN, "enormous"); + break; + default: + snprintf(sizetext, BUFLEN, "irregular"); // should never happen + break; } snprintf(buf, BUFLEN, "%sIt will only fit %s sized creatures.^n\n", (f->val[0] != getlfsize(player)) ? "^B" : "^n", sizetext); strncat(retbuf, buf, HUGEBUFLEN); } - // charges remaining - if (o->type->obclass->id == OC_WAND) { + if ((o->type->obclass->id == OC_WAND) || (o->type->id == OT_BATTERY)) { if (isidentified(o)) { int charges; charges = getcharges(o); @@ -5360,9 +5376,14 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, "It is ineffective in confined spaces due to its length.\n"); strncat(retbuf, buf, HUGEBUFLEN); } + f = hasflag(o->flags, F_ARMOURIGNORE); + if (f && f->known) { + sprintf(buf, "Armour will not reduce %s damage at all.\n",OB1(o,"its","their")); + strncat(retbuf, buf, HUGEBUFLEN); + } f = hasflag(o->flags, F_ARMOURPIERCE); if (f && f->known) { - sprintf(buf, "Armour will not reduce %s damage.\n",OB1(o,"its","their")); + sprintf(buf, "Armour will not reduce %s damage below %d.\n",OB1(o,"its","their"), f->val[0]); strncat(retbuf, buf, HUGEBUFLEN); } f = hasflag(o->flags, F_BALANCE); diff --git a/lf.c b/lf.c index ecb3363..44e7d6b 100644 --- a/lf.c +++ b/lf.c @@ -1002,10 +1002,10 @@ int canreach(lifeform_t *lf, lifeform_t *victim, int *reachpenalty) { if (!isairborne(lf)) { switch (isairborne(victim)) { case F_FLYING: - sizetoreach = SZ_HUGE; + sizetoreach = SZ_HUMAN; break; case F_LEVITATING: - sizetoreach = SZ_HUMAN; + sizetoreach = SZ_MEDIUM; break; default: sizetoreach = SZ_ANY; break; } @@ -2256,7 +2256,7 @@ void die(lifeform_t *lf) { if ((lf->race->id == R_VAMPIRE) && !hasflag(lf->flags, F_ORIGRACE)) { // if are asleep or killed by running water/sunlight, we will die normally if (lfhasflag(lf, F_ASLEEP) || (lf->lastdamtype == DT_DIRECT)) { - noise(lf->cell, lf, NC_OTHER, 4, "a horrified scream!", "screams in horror!"); + noise(lf->cell, lf, NC_OTHER, SV_CAR, "a horrified scream!", "screams in horror!"); } else if (findobinmap(lf->cell->map, OT_COFFIN)) { // coffin around? // restore 1 hp lf->hp = 1; @@ -3833,7 +3833,6 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) { getlfname(lf,lfname); - if (announce) { if (isplayer(lf) || cansee(player, lf)) { if (fromlf) { @@ -3849,6 +3848,11 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) { addflag(lf->flags, F_PRONE, B_TRUE, NA, NA, NULL); loseconcentration(lf); + if (isvulnto(lf->flags, DT_FALL, B_FALSE)) { + // 0 will be repplaced with the dtvuln flag + losehp(lf, 0, DT_FALL, fromlf, "a bad fall"); + } + return B_FALSE; } @@ -13313,7 +13317,7 @@ void precalclos_new(lifeform_t *lf) { //int db = B_FALSE; enum SKILLLEVEL plev = PR_INEPT; flag_t *missingeye; - long visdiameter; + //long visdiameter; long allocamt; @@ -13345,8 +13349,10 @@ void precalclos_new(lifeform_t *lf) { } // ie. you can see both ways, plus your own cell - visdiameter = (MAXVISRANGE+1)*2; - allocamt = visdiameter * visdiameter; + //visdiameter = (MAXVISRANGE+1)*2; + //allocamt = visdiameter * visdiameter; + allocamt = MAX_MAPW * MAX_MAPH; + los = malloc( sizeof(cell_t *) * allocamt); losdark = malloc( sizeof(cell_t *) * allocamt); blocker = malloc( sizeof(cell_t *) * allocamt); @@ -13437,13 +13443,23 @@ void precalclos_new(lifeform_t *lf) { nlos++; assert (nlos < allocamt); } else { - // if cell WASNT lit, add it to an array of dark "visible" cells - // (lf->darklos) - // that way we can check for these to determine whether we need to recalc our los - // when light changes. - losdark[nlosdark] = c; - nlosdark++; - assert (nlos < allocamt); + int idx,found=B_FALSE; + for (idx=0;idxdarklos) + // that way we can check for these to determine whether we need to recalc our los + // when light changes. + losdark[nlosdark] = c; + nlosdark++; + assert (nlosdark < allocamt); + } } } } else { // ie. if !c @@ -18444,7 +18460,7 @@ int weild(lifeform_t *lf, object_t *o) { // make certain flags known if (isplayer(lf)) { - f = hasflag(o->flags, F_ARMOURPIERCE); + f = hasflag(o->flags, F_ARMOURIGNORE); if (f) { msg("^gYour %s seems unnaturally sharp!",noprefix(buf)); f->known = B_TRUE; diff --git a/map.c b/map.c index 3b074f0..0ac40b8 100644 --- a/map.c +++ b/map.c @@ -4330,7 +4330,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int } if (!haslos(player, c)) { - noise(c, NULL, NC_OTHER, (range > 0) ? 6 : 5, "an explosion!", NULL); + noise(c, NULL, NC_OTHER, (range > 0) ? SV_PLANE : SV_TRUCK, "an explosion!", NULL); } for (y = c->y - range ; y <= c->y + range ; y++) { @@ -6202,7 +6202,7 @@ int shattercell(cell_t *c, lifeform_t *fromlf, char *damstring) { seen = B_TRUE; } else { // very loud - noise(c, NULL, NC_OTHER, 7, "shattering glass.", NULL); + noise(c, NULL, NC_OTHER, SV_CAR, "shattering glass.", NULL); } if (target) { diff --git a/move.c b/move.c index e4eec51..fe52fdf 100644 --- a/move.c +++ b/move.c @@ -1437,7 +1437,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (alarm && areenemies(lf, l) && haslof(lf->cell, l->cell, LOF_WALLSTOP, NULL) ) { // in range of alarm? range is 3 * spell power cells. if (getcelldist(lf->cell, l->cell) <= (alarm->val[2]*3)) { - // alarm goes off + // incredibly loud alarm goes off noise(l->cell, NULL, NC_OTHER, 50, "a blaring siren!", NULL); killflag(alarm); } @@ -1464,7 +1464,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { shk = findshopkeeper(lf->cell->map, preshop); if (shk && getowing(lf, preshop, NULL)) { // call the guards - sayphrase(shk, SP_PAYTHREAT, SV_ROAR, NA, NULL); + sayphrase(shk, SP_PAYTHREAT, SV_CAR, NA, NULL); didmsg = B_TRUE; fightback(shk, lf); // shopkeeper attacks callguards(shk, lf); // guards come running @@ -1758,6 +1758,7 @@ int opendoor(lifeform_t *lf, object_t *o) { } return B_TRUE; } else { + int wasjammed = B_FALSE; if (lf) { if (!canopendoors(lf)) { if (isplayer(lf)) { @@ -1811,7 +1812,7 @@ int opendoor(lifeform_t *lf, object_t *o) { // stop sprinting stopsprinting(lf); - } + } // end if lf // trapped? if (lf && hasflag(o->flags, F_TRAPPED)) { @@ -1831,24 +1832,26 @@ int opendoor(lifeform_t *lf, object_t *o) { attackcell(lf, doorcell, B_TRUE); return B_FALSE; } else { - noise(doorcell, NULL, NC_OTHER, 2, "a door handle rattling.", NULL); + noise(doorcell, NULL, NC_OTHER, SV_TALK, "a door handle rattling.", NULL); } } taketime(lf, getactspeed(lf)); touch(lf, o); } return B_TRUE; - } else { + } else {// ie. door not locked, but it might be jammed int openit = B_TRUE; f = hasflag(o->flags, F_JAMMED); if (f && lf) { + wasjammed = B_TRUE; + openit = B_FALSE; if (isplayer(lf) && (f->val[1] != B_TRUE)) { // not known yet msg("The %s is jammed.", noprefix(obname)); openit = B_FALSE; f->val[1] = B_TRUE; } else { // known - try to force it - int amt; + int amt = 0; amt = getattr(lf, A_STR) - 10; if (amt < 0) amt = 0; @@ -1874,18 +1877,20 @@ int opendoor(lifeform_t *lf, object_t *o) { } else { char noisebuf[BUFLEN]; sprintf(noisebuf, "%s jiggling against its hinges.", obname); - noise(doorcell, NULL, NC_OTHER, 3, noisebuf, NULL); + noise(doorcell, NULL, NC_OTHER, SV_SHOUT, noisebuf, NULL); } } } // loosen a bit if (amt) { f->val[0] -= amt; - if (f->val[0] <= 0) { - killflag(f); - } } - openit = B_FALSE; // don't open the door + if (f->val[0] <= 0) { + killflag(f); + openit = B_TRUE; + } else { + openit = B_FALSE; // don't open the door + } } // end if jammedknown } // end if jammed if (openit) { @@ -1899,20 +1904,40 @@ int opendoor(lifeform_t *lf, object_t *o) { killflagsofid(o->flags, F_TRAPPED); if (lf) { - if (isplayer(lf)) { - msg("You force %s open!",obname); - } else { - if (cansee(player, lf) && isadjacent(lf->cell, doorcell)) { - getlfname(lf, buf); - capitalise(buf); - msg("%s forces %s open!",buf, obname); - } else if (haslos(player, doorcell)) { - capitalise(obname); - msg("%s bursts open!",obname); + if (wasjammed) { + if (isplayer(lf)) { + msg("You force %s open!",obname); } else { - char noisebuf[BUFLEN]; - sprintf(noisebuf, "%s bursting open!", obname); - noise(doorcell, NULL, NC_OTHER, 4, noisebuf, NULL); + //if (cansee(player, lf) && isadjacent(lf->cell, doorcell)) { + if (cansee(player, lf)) { + getlfname(lf, buf); + capitalise(buf); + msg("%s forces %s open!",buf, obname); + } else if (haslos(player, doorcell)) { + capitalise(obname); + msg("%s bursts open!",obname); + } else { + char noisebuf[BUFLEN]; + sprintf(noisebuf, "%s bursting open!", obname); + noise(doorcell, NULL, NC_OTHER, SV_CAR, noisebuf, NULL); + } + } + } else { + if (isplayer(lf)) { + msg("You open %s.",obname); + } else { + if (cansee(player, lf)) { + getlfname(lf, buf); + capitalise(buf); + msg("%s opens %s.",buf, obname); + } else if (haslos(player, doorcell)) { + capitalise(obname); + msg("%s opens.",obname); + } else { + char noisebuf[BUFLEN]; + sprintf(noisebuf, "%s opening.", obname); + noise(doorcell, NULL, NC_OTHER, SV_TALK, noisebuf, NULL); + } } } @@ -1929,12 +1954,12 @@ int opendoor(lifeform_t *lf, object_t *o) { // checking if we have LOS to the lifeform making // sound, but in this case it's the door making // the sound, not the lf. - noise(where, NULL, NC_OTHER, 2, "a door opening.", NULL); + noise(where, NULL, NC_OTHER, SV_TALK, "a door opening.", NULL); } } } return B_FALSE; - } + } // end if door locked } return B_FALSE; @@ -1988,7 +2013,7 @@ int closedoor(lifeform_t *lf, object_t *o) { // any solid object other than the door? for (oo = cell->obpile->first ; oo ; oo = oo->next) { - if ((oo != o) && (getmaterialstate(oo->material->id) == MS_SOLID)) { + if ((oo != o) && (getmaterialstate(oo->material->id) == MS_SOLID) && (getobsize(o) >= SZ_SMALL)) { if (lf && isplayer(lf)) { char inwayname[BUFLEN]; getobname(oo, inwayname, oo->amt); diff --git a/objects.c b/objects.c index 285ad5b..4626f9f 100644 --- a/objects.c +++ b/objects.c @@ -629,6 +629,14 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes p += strlen("cursed "); donesomething = B_TRUE; // armour flags + } else if (strstarts(p, "gargantuan ")) { + wantarmsize = SZ_ENORMOUS; + p += strlen("gargantuan "); + donesomething = B_TRUE; + } else if (strstarts(p, "titan-sized ")) { + wantarmsize = SZ_HUGE; + p += strlen("titan-sized "); + donesomething = B_TRUE; } else if (strstarts(p, "giant-sized ")) { wantarmsize = SZ_LARGE; p += strlen("giant-sized "); @@ -637,6 +645,18 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes wantarmsize = SZ_MEDIUM; p += strlen("half-sized "); donesomething = B_TRUE; + } else if (strstarts(p, "baby-sized ")) { + wantarmsize = SZ_SMALL; + p += strlen("baby-sized "); + donesomething = B_TRUE; + } else if (strstarts(p, "tiny-sized ")) { + wantarmsize = SZ_TINY; + p += strlen("tiny-sized "); + donesomething = B_TRUE; + } else if (strstarts(p, "minisicule ")) { + wantarmsize = SZ_MINI; + p += strlen("minisicule "); + donesomething = B_TRUE; // door flags } else if (strstarts(p, "locked ")) { doorflag[ndoorflags++] = F_LOCKED; // for doors @@ -1082,11 +1102,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes amt = rnd(f->val[0], f->val[1]); chargeflag = hasflag(o->flags, F_CHARGES); if (chargeflag) { - chargeflag->val[0] = amt; - chargeflag->val[1] = amt; + chargeflag->val[0] = amt; // randomly selected amt + chargeflag->val[1] = f->val[1]; // highest possible amt chargeflag->known = B_FALSE; } else { - chargeflag = addflag_real(o->flags, F_CHARGES, amt, amt, NA, NULL, PERMENANT, B_UNKNOWN, -1); + chargeflag = addflag_real(o->flags, F_CHARGES, amt, f->val[1], NA, NULL, PERMENANT, B_UNKNOWN, -1); } } @@ -1262,6 +1282,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes if (wantarmsize == SZ_ANY) { // if giving to a lifeform being created, match their size if (where->owner) { + // note: this COULD result in weird sizings other than + // medium, human or large. this is okay - other code + // will understand it. just when randomly making armour, + // only megium/human/large will appear. wantarmsize = getlfsize(where->owner); } else { // random size @@ -4767,12 +4791,27 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan char sizetext[BUFLEN]; // prepend size switch (f->val[0]) { + case SZ_MINI: + strcpy(sizetext, "miniscule"); + break; + case SZ_TINY: + strcpy(sizetext, "tiny "); + break; + case SZ_SMALL: + strcpy(sizetext, "baby-sized"); + break; case SZ_MEDIUM: strcpy(sizetext, "half-sized"); break; case SZ_LARGE: strcpy(sizetext, "giant-sized"); break; + case SZ_HUGE: + strcpy(sizetext, "titan-sized"); + break; + case SZ_ENORMOUS: + strcpy(sizetext, "gargantuan"); + break; default: strcpy(sizetext, ""); break; @@ -8050,24 +8089,6 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } } - // objects with charges... - if (hasflag(o->flags, F_OPERUSECHARGE)) { // operating toggles on/off - int chargesleft; - chargesleft = getcharges(o); - if (chargesleft > 0) { - chargesleft = usecharge(o); - // TODO: notify if getting low - } else { - if (isplayer(lf)) { - nothinghappens(); - // you know it's out - f = hasflag(o->flags, F_CHARGES); - f->known = B_TRUE; - return B_FALSE; - } - } - } - // ask for target, if required f = hasflag(o->flags, F_OPERNEEDTARGET); if (f && !where) { @@ -8140,14 +8161,57 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } if (touch(lf, o)) { + taketime(lf, getactspeed(lf)); return B_TRUE; } - if (hasflag(o->flags, F_DEAD)) return B_TRUE; + if (hasflag(o->flags, F_DEAD)) { + taketime(lf, getactspeed(lf)); + return B_TRUE; + } + + // objects with charges... + if (hasflag(o->flags, F_OPERUSECHARGE)) { // operating toggles on/off + if (usecharge(o) == -1) { + if (isplayer(lf)) { + nothinghappens(); + // you know it's out + f = hasflag(o->flags, F_CHARGES); + f->known = B_TRUE; + taketime(lf, getactspeed(lf)); + return B_FALSE; + } + } + } // TODO: change to be based on item type // TODO: move this to the end in case 'operate' fails taketime(lf, getactspeed(lf)); + // check for gremlins + if ((o->type->obclass->id == OC_TECH) || (o->type->obclass->id == OC_TOOLS) || + (o->type->obclass->id == OC_WAND)) { + if (lf->race->id != R_GREMLIN) { + cell_t *retcell[MAXCANDIDATES],*c; + int nretcells,i; + getradiuscells(lf->cell, 5, DT_COMPASS, B_FALSE, LOF_WALLSTOP, B_FALSE, retcell, &nretcells, 0); + for (i = 0; i < nretcells; i++) { + c = retcell[i]; + if (c->lf && (c->lf->race->id == R_GREMLIN)) { + if (isplayer(lf)) { + msg("Inexplicably, your %s doesn't seem to work.", noprefix(obname)); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s%s %s doesn't seem to work.", lfname, getpossessive(lfname), + noprefix(obname)); + } + return B_TRUE; + } + } + } + } // end if techtype affected by gremlins + + // mark obejct as tried if (isplayer(lf)) maketried(o->type->id); @@ -8271,15 +8335,17 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { // special wands } else if (o->type->id == OT_WAND_WONDER) { int power; - // random power - power = rnd(1,10); - // 1 in 3 chance of targetting yourself - if (onein(3)) { - where = lf->cell; + if (lf->race->id != R_GREMLIN) { + // override power + power = rnd(1,10); + // 1 in 3 chance of targetting yourself + if (onein(3)) { + where = lf->cell; + } } // random effect - switch (rnd(0,21)) { + switch (rnd(0,22)) { case 0: // butterflies around user willid = B_TRUE; where = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); @@ -8351,6 +8417,13 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { case 21: // teleport dospelleffects(lf, OT_S_TELEPORT, power, lf , NULL, lf->cell, o->blessed, &willid, B_FALSE); break; + case 22: // create banana peel + if (where->type->solid) { + setcelltype(where, where->map->habitat->emptycelltype); + } else { + addob(where->obpile, "3-5 banana skins"); + } + break; //oooooooooo } } @@ -8375,7 +8448,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { dospelleffects(lf, OT_S_SPARK, 1, NULL, NULL, where, B_UNCURSED, &seen, B_FALSE); // announce if (!seen) { - noise(where, NULL, NC_OTHER, 1, "something burning.", NULL); + noise(where, NULL, NC_OTHER, SV_WHISPER, "something burning.", NULL); } } else if (o->type->id == OT_GODSTONEJ) { f = hasflag(o->flags, F_CHARGES); @@ -8452,7 +8525,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } // announce if (!seen) { - noise(where, NULL, NC_OTHER, 0, "something spraying.", NULL); + noise(where, NULL, NC_OTHER, SV_WHISPER, "something spraying.", NULL); } } else if ((o->type->id == OT_EMPTYFLASK) || (o->type->id == OT_EMPTYVIAL)) { object_t *oo,*nextoo; @@ -8685,7 +8758,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (isplayer(lf)) { msg("You play a few notes on your panpipes."); } else { - noise(lf->cell, lf, NC_OTHER, 3, "the sound of panpipes.", "plays a tune on its panpipes."); + noise(lf->cell, lf, NC_OTHER, SV_CAR, "the sound of panpipes.", "plays a tune on its panpipes."); } } else if (o->type->id == OT_PICKAXE) { int ch,dir; @@ -9844,6 +9917,7 @@ int readsomething(lifeform_t *lf, object_t *o) { // only id if it does something willid = B_FALSE; } + case OT_SCR_REPLENISHMENT: case OT_SCR_ENCHANT: case OT_SCR_CREATEMONSTER: case OT_SCR_REMOVECURSE: @@ -9869,6 +9943,7 @@ int readsomething(lifeform_t *lf, object_t *o) { } break; case OT_SCR_ENCHANT: + case OT_SCR_REPLENISHMENT: needsob = B_TRUE; break; default: @@ -10581,7 +10656,7 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { seen = B_TRUE; } else { - noise(where, NULL, NC_OTHER, 3, "shattering glass.", NULL); + noise(where, NULL, NC_OTHER, SV_SHOUT, "shattering glass.", NULL); } if (target) { @@ -11800,7 +11875,6 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } } - if (thrower) { if (firearm) { practice(thrower, SK_THROWING, 1); @@ -12137,7 +12211,7 @@ void timeeffectsob(object_t *o) { chargeleft = usecharge(o); // out of power? - if (chargeleft <= 0) { + if (chargeleft == -1) { if (owner) { // announce power loss if (isplayer(owner)) { @@ -12459,7 +12533,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { } } } else if (oid == OT_TRAPALARM) { - noise(c, NULL, NC_OTHER, 10, "a blaring siren!", "A blaring siren goes off!"); + noise(c, NULL, NC_OTHER, 50, "a blaring siren!", "A blaring siren goes off!"); } else if ((oid == OT_TRAPARROW) || (oid == OT_TRAPARROWP)) { int dir,bestdir = D_NONE; cell_t *src = NULL; @@ -12508,8 +12582,10 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { dblog("ERROR: arrow trap failed (no dir)."); } } else if (oid == OT_TRAPEBLAST) { - if (haslos(player, c)) { + if (!haslos(player, c)) { msg("A blast of energy comes out of nowhere!"); + // if we DO have los, then spelleffects() will take care of the + // announcement. } // can't be dodged dospelleffects(NULL, OT_S_ENERGYBLAST, 1, NULL, NULL, c, B_UNCURSED, NULL, B_TRUE); @@ -12720,26 +12796,59 @@ int uncurseob(object_t *o, int *seen) { return B_FALSE; } -// returns charges remaining, -1 if object doesn't have the flag +// returns charges remaining, -1 if object doesn't have the flag or is +// out of charges. int usecharge(object_t *o) { - flag_t *f; + flag_t *f = NULL; + object_t *b; + + // use power from a battery first + b = hasob(o->pile, OT_BATTERY); + if (b && isknown(b)) { + f = hasflag(b->flags, F_CHARGES); + // does the battery have charges left? + if (f && (f->val[0] <= 0)) { + f = NULL; + } + } + + // if no battery, use charges from the object itself. + if (!f) { + f = hasflag(o->flags, F_CHARGES); + } + + // use up the charge. + if (f && (f->val[0] > 0)) { + f->val[0]--; + } else { + // couldn't use a charge - ran out. + return -1; + } + // always return the amount of charges the _object_ has left. + // not the battery. f = hasflag(o->flags, F_CHARGES); if (f) { - f->val[0]--; return f->val[0]; + } else { + return 0; // since technically we didn't fail if we got here. } - return -1; } // returns charges remaining, -1 if object doesn't have the flag int usecharges(object_t *o, int amt) { flag_t *f; + int i; + // use charges one at a time. + for (i = 0; i < amt; i++) { + if (usecharge(o) == -1) { + // ran out of power! + return -1; + } + } + + // return the amount of charges which the object has left. f = hasflag(o->flags, F_CHARGES); if (f) { - f->val[0] -= amt; - if (f->val[0] < 0) { - f->val[0] = 0; - } return f->val[0]; } return -1; diff --git a/spell.c b/spell.c index 8e4c6cc..91374f2 100644 --- a/spell.c +++ b/spell.c @@ -3244,6 +3244,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } } + stopsprinting(user); // start hiding addflag(user->flags, F_HIDING, penalty, NA, NA, NULL); @@ -4543,7 +4544,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ char lfname[BUFLEN]; // automatic hit getlfname(targcell->lf, lfname); - if (haslos(caster, targcell)) { + if (haslos(player, targcell)) { msg("%s %s chilled!",lfname,is(targcell->lf)); } losehp(targcell->lf, rolldie(1,8)+3, DT_COLD, caster, "a burst of coldness"); @@ -6053,7 +6054,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ flag_t *f; loc = getoblocation(o); // announce - if (haslos(caster, loc)) { + if (haslos(player, loc)) { char obname[BUFLEN]; getobname(o, obname, o->amt); msg("%s %s freeze%s some more.", @@ -6903,6 +6904,76 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (failed) { fizzle(caster); } + } else if (spellid == OT_S_NULLIFY) { + flag_t *retflag[MAXCANDIDATES],*poss[MAXCANDIDATES],*f; + int nretflags,i,ndone = 0,nposs; + target = targcell->lf; + if (!target) { + fizzle(caster); + } + + if (isplayer(target)) { + msg("^wYou are engulfed in an anti-magic field!"); + } else if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + msg("^w%s is engulfed in an anti-magic field!", lfname); + } + while (ndone < power) { + // get a list of flags which could be destroyed + nposs = 0; + // for player: + // remove memorised spells + // for monsters: + // remove racial spells AND abilities + // + // abilities/spells conferred by objects are not affected. + getflags(target->flags, retflag, &nretflags, F_CANCAST, F_CANWILL, F_NONE); + for (i = 0; i < nretflags; i++) { + int ok = B_TRUE; + if (isplayer(target)) { + if (retflag[i]->id == F_CANWILL) { + ok = B_FALSE; + } else if (retflag[i]->lifetime != PERMENANT) { + ok = B_FALSE; + } + } else { + if ((retflag[i]->lifetime != FROMRACE) && (retflag[i]->lifetime != PERMENANT)) { + ok = B_FALSE; + } + } + if (ok && isplayer(target)) { + objecttype_t *ot; + ot = findot(retflag[i]->val[0]); + if (ot->obclass->id != OC_SPELL) { + ok = B_FALSE; + } + } + if (ok) { + poss[nposs++] = retflag[i]; + } + } + + if (!nposs) { + break; + } + f = poss[rnd(0,nposs-1)]; + killflag(f); + ndone++; + } + if (isplayer(target)) { + if (!ndone) { + msg("You are unaffected."); + } + } else if (cansee(player, target)) { + char lfname[BUFLEN]; + getlfname(target, lfname); + if (ndone) { + msg("%s%s powers are nullified!", lfname, getpossessive(lfname)); + } else { + msg("%s is unaffected.", lfname); + } + } } else if (spellid == OT_S_ACCELMETAL) { char oidbuf[BUFLEN]; flag_t *f; @@ -8483,6 +8554,68 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster)) { msg("A strange odour surrounds you..."); } + } else if (spellid == OT_S_REPLENISH) { + int incamt,newamt,maxed = B_FALSE; + char obname[BUFLEN]; + flag_t *f; + + if (!targob) { + if (isplayer(caster)) { + // ask for an object + targob = askobjectwithflag(caster->pack, "Replenish which object", NULL, '\0', AO_NONE, F_REPLENISHABLE); + } + } + if (!targob) { + fizzle(caster); + return B_TRUE; + } + + f = hasflag(targob->flags, F_CHARGES); + if (!f) { + nothinghappens(); + return B_TRUE; + } + + // restores power% of maximum + incamt = pctof(power*10, f->val[1]); + limit(&incamt, 1, NA); // at least 1! + + newamt = f->val[0] + incamt; + limit(&newamt, NA, f->val[1]); + + if (f->val[0] == newamt) { + // already maxed + maxed = B_TRUE; + } + f->val[0] = newamt; + + targcell = getoblocation(targob); + + if (maxed) { + if (haslos(player, targcell)) { + nothinghappens(); + } + return B_TRUE; + } + getobname(targob, obname, targob->amt); + + if (targob->pile->owner) { + if (isplayer(targob->pile->owner)) { + msg("Your %s %s %s.", noprefix(obname), (targob->amt == 1) ? "pulses" : "pulse", (power < 5) ? "briefly" : "for a while"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } else if (cansee(player,targob->pile->owner)) { + char lfname[BUFLEN]; + getlfname(targob->pile->owner, lfname); + msg("%s%s %s %s %s.", lfname, getpossessive(lfname), + noprefix(obname), (targob->amt == 1) ? "pulses" : "pulse", (power < 5) ? "briefly" : "for a while"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } else { + if (haslos(player, targcell)) { + msg("%s %s %s.", noprefix(obname), (targob->amt == 1) ? "pulses" : "pulse", (power < 5) ? "briefly" : "for a while"); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } } else if (spellid == OT_S_REVEALHIDDEN) { int i; int seen = B_FALSE; @@ -10251,7 +10384,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ o = relinkob(o, newloc->obpile); } if (o) { - noise(caster->cell, NULL, NC_OTHER, 1, "something hitting the ground.", NULL); + noise(caster->cell, NULL, NC_OTHER, SV_WHISPER, "something hitting the ground.", NULL); if (!isblind(caster)) { msg("%s appear%s on the ground!", obname, OBS1(o)); }