From 69cd41a714931e48c39fb1b7b26f54a86feec40f Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Mon, 5 Mar 2012 10:31:21 +0000 Subject: [PATCH] - [+] make zombies eat flesh. - [+] warn before eating your own kind if it will anger your god, and you wisdom is high. - [+] make disease way worse if you eat your own race's corpse! - [+] CRASH when i try to cook firebug corpse * [+] bones files: - [+] when your leg is bleeding, don't lose hp for ATTACKING, only for MOVING. - [+] bug: issue with skill display if you learn higher than your max level by reading a book! - [+] in this case, reading the book should fail. - [+] when you start worshipping felix, allow you to learn lockpicking & thievery to full level! - [+] infinite loop when an ashkari enters rage while already eating. - [+] felix prayer should always unlock all nearby doors - [+] if you add f_calwill xxx, v1=112312 v2=NA, make v2 = v1. - [+] that way we can confer it! - [+] say "this is xxx!" after wearing a new amulet. - [+] fork / knife should make you eat faster. - [+] double the hp of most armour again AMULETS - [+] add new bodypart = neck - [+] object hiddennames * [+] nouns * [+] adjectives - [+] flight (canwill fly) - [+] enhance spell power - [+] victimization (makes everything hostile) (no auto id) - [+] blinking - [+] anger (canwill rage) - [+] vs poison (poison immune) - [+] vs magic (magic resistance) - [+] common - [+] feather fall (dt_fall dmg = 0) - [+] don't "slam into the ground", just "float gently to the ground" - [+] of amplification (boost listening skillchecks, allow you to listen at stairs) - [+] peaceful sleep (don't get woken up by sound, cursed) - [+] chef's amulet(lower metabolism) - [+] thief's amulet (lockpicking) --- attack.c | 48 +---- data.c | 186 ++++++++++++------ data/hiscores.db | Bin 14336 -> 14336 bytes defs.h | 57 ++++-- doc/add_bodypart.txt | 4 + flag.c | 9 + god.c | 50 +++-- io.c | 2 - lf.c | 437 +++++++++++++++++++++++++++++++++++-------- lf.h | 3 +- map.c | 112 ++++++++--- map.h | 2 +- move.c | 51 +++-- move.h | 2 +- nexus.c | 8 +- objects.c | 165 ++++++++++++++-- objects.h | 2 + save.c | 165 ++++++++++++++++ save.h | 3 + spell.c | 13 +- text.c | 5 +- vault.c | 68 ++++--- vault.h | 2 +- 23 files changed, 1080 insertions(+), 314 deletions(-) diff --git a/attack.c b/attack.c index 7b4f8cf..11a8400 100644 --- a/attack.c +++ b/attack.c @@ -647,7 +647,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) isunarmed = B_TRUE; } - moveeffects(lf); + moveeffects(lf, B_FALSE); if (isdead(lf)) { return B_TRUE; @@ -1273,46 +1273,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } - f = lfhasflag(lf, F_QUICKBITE); - if (f) { - if (islowhp(victim)) { - int dam; - char lfname[BUFLEN]; - dam = rolldie(f->val[0], f->val[1]) + f->val[2]; - real_getlfname(lf, lfname, B_FALSE, B_FALSE); - if (isplayer(victim) || cansee(player, victim)) { - msg("^%c%s bites %s!", isplayer(victim) ? 'b' : 'n', lfname, victimname); - } - losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE, NULL, B_FALSE, NULL, B_TRUE); - } - } - - f = lfhasflag(lf, F_PACKATTACK); - if (f) { - int dir; - cell_t *c; - int nmatched = 0; - char lfname[BUFLEN]; - getlfname(lf, lfname); - // count adjacent allies of name xx - for (dir = DC_N; dir <= DC_NW; dir++) { - c = getcellindir(victim->cell, dir); - if (c && c->lf) { - if (c->lf->race->baseid == lf->race->baseid) { - nmatched++; - } - } - } - if (nmatched >= f->val[2]) { - char damstring[BUFLEN]; - snprintf(damstring, BUFLEN, "%s pack", lfname); - if (isplayer(victim) || cansee(player, victim)) { - msg("^%c%s pack attacks %s!", isplayer(victim) ? 'b' : 'c', lfname, victimname); - } - losehp_real(victim, f->val[0], f->val[1], lf, damstring, B_TRUE, NULL, B_FALSE, NULL, B_TRUE); - } - } - // critical hit effects if (critical && damtypecausescriteffects(damtype[0])) { criticalhit(lf, victim, critpos, dam[0], damtype[0]); @@ -1490,7 +1450,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { //int aidb = B_TRUE; int maxhp; - moveeffects(lf); + moveeffects(lf, B_FALSE); if (isdead(lf)) return B_TRUE; // get names @@ -1653,7 +1613,7 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) { int i; int maxhp; - moveeffects(lf); + moveeffects(lf, B_FALSE); if (isdead(lf)) return B_TRUE; maxhp = c->type->hp; @@ -2687,7 +2647,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { ppower = 1; } - poison(victim, howlong, ptype, ppower, frombuf); + poison(victim, howlong, ptype, ppower, frombuf, owner ? owner->race->id : R_NONE); } else { // flag values if (valflag) { diff --git a/data.c b/data.c index c93759d..09bfd44 100644 --- a/data.c +++ b/data.c @@ -33,6 +33,8 @@ extern hiddennamewithcol_t gemtype[]; extern char *ringadjective[]; extern char *techadjective[]; extern char *technoun[]; +extern char *amuletadjective[]; +extern char *amuletnoun[]; extern objecttype_t *lastot; @@ -1063,6 +1065,15 @@ void initobjects(void) { } } + for (n = 0; strlen(amuletnoun[n]); n++) { + // add it with all known adjectives + for (i = 0; strlen(ringadjective[i]) ; i++) { + char buf2[BUFLEN]; + snprintf(buf2, BUFLEN, "%s %s",amuletadjective[i], amuletnoun[n]); + addhiddenname(OC_AMULET, buf2); + } + } + for (n = 0; strlen(technoun[n]); n++) { // add it without an adjective addhiddenname(OC_TECH, technoun[n]); @@ -1088,8 +1099,23 @@ void initobjects(void) { addflag_real(lastobmod->flags, F_HEADLESS, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1); addobmod(OM_MASTERWORK,"masterwork"); addflag_real(lastobmod->flags, F_MASTERWORK, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1); + addomprefix(OM_MASTERWORK, "reinforced"); + addomprefix(OM_MASTERWORK, "studded"); + addomprefix(OM_MASTERWORK, "sturdy"); + addomprefix(OM_MASTERWORK, "tailored"); addobmod(OM_SHODDY,"shoddy"); addflag_real(lastobmod->flags, F_SHODDY, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1); + addomprefix(OM_SHODDY, "blunted"); + addomprefix(OM_SHODDY, "chipped"); + addomprefix(OM_SHODDY, "cracked"); + addomprefix(OM_SHODDY, "crumbling"); + addomprefix(OM_SHODDY, "dented"); + addomprefix(OM_SHODDY, "frayed"); + addomprefix(OM_SHODDY, "notched"); + addomprefix(OM_SHODDY, "rusted"); + addomprefix(OM_SHODDY, "rotted"); + addomprefix(OM_SHODDY, "splintered"); + addomprefix(OM_SHODDY, "torn"); addobmod(OM_POISONED,"poisoned"); addflag_real(lastobmod->flags, F_HITCONFER, F_POISONED, SC_POISON, 40, "15-30", PERMENANT, B_KNOWN, -1); addflag_real(lastobmod->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL, PERMENANT, B_KNOWN, -1); @@ -1355,6 +1381,11 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_GOESON, BP_RIGHTFINGER, NA, NA, NULL); addflag(lastobjectclass->flags, F_GOESON, BP_LEFTFINGER, NA, NA, NULL); + addoc(OC_AMULET, "Amulets", "Items of jewellery worn around the neck, usually on a short metallic chain.", '"', C_GREY, RR_VERYRARE); + addocnoun(lastobjectclass, "amulet"); + addflag(lastobjectclass->flags, F_RARITY, H_SEWER, NA, RR_UNCOMMON, NULL); + addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addflag(lastobjectclass->flags, F_GOESON, BP_NECK, NA, NA, NULL); addoc(OC_WEAPON, "Weapons", "An instrument used for the purpose of causing harm or death.", ')', C_GREY, RR_COMMON); addocnoun(lastobjectclass, "weapon"); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -5699,7 +5730,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 5, 5, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_COLD, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 80, NA, NA, NULL); @@ -5709,7 +5740,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_FIRE, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 33, NA, NA, NULL); @@ -5722,7 +5753,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 33, NA, NA, NULL); @@ -5735,7 +5766,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 5, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FIRE, NA, NULL); addflag(lastot->flags, F_DTIMMUNE, DT_FIRE, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 80, NA, NA, NULL); addflag(lastot->flags, F_STARTBLESSED, B_CURSED, NA, NA, NULL); @@ -5745,7 +5776,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 95, NA, NA, NULL); addot(OT_ARMOURRING, "suit of ring mail", "Body armour formed by a series of metallic rings sewn to a leather foundation.", MT_METAL, 15, OC_ARMOUR, SZ_MEDIUM); @@ -5755,7 +5786,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 20, 20, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 35, NA, NULL); - addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); + addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_ARMOURSCALE, "suit of scale armour", "Body armour consisting of many small scales attached to leather.", MT_METAL, 20, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); @@ -5764,7 +5795,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 10, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 30, 30, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 45, NA, NULL); - addflag(lastot->flags, F_OBHP, 35, 35, NA, NULL); + addflag(lastot->flags, F_OBHP, 70, 70, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_ARMOURCHAIN, "suit of chainmail", "Heavy body armour consisting of tightly meshed metal rings.", MT_METAL, 25, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); @@ -5773,7 +5804,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 15, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 40, 40, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 45, NA, NULL); - addflag(lastot->flags, F_OBHP, 45, 45, NA, NULL); + addflag(lastot->flags, F_OBHP, 90, 90, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_ARMOURSPLINT, "suit of splint mail", "Heavy armour, consisting of strips of metal attached to a leather backing.", MT_METAL, 35, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); @@ -5782,7 +5813,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 20, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 50, 50, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 55, NA, NULL); - addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); + addflag(lastot->flags, F_OBHP, 100, 100, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_ARMOURPLATE, "suit of plate mail", "Heavy armour with embedded metal plates.", MT_METAL, 40, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 90, RR_RARE, NULL); @@ -5791,7 +5822,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 25, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 60, 60, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 65, NA, NULL); - addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); + addflag(lastot->flags, F_OBHP, 120, 120, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour. Designed to stop a bullet, but ineffective against melee attacks.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM); @@ -5801,7 +5832,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 50, NA, NULL); - addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_OVERALLS, "pair of overalls", "Well-made, brightly coloured workman overalls.", MT_CLOTH, 1, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); @@ -5809,7 +5840,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 35, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 85, NA, NA, NULL); addot(OT_SILKSHIRT, "silk shirt", "A lightweight, comfortable white silk shirt.", MT_SILK, 0.5, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); @@ -5817,7 +5848,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 50, NA, NA, NULL); addot(OT_ROBE, "robe", "A plain robe.", MT_CLOTH, 4, OC_ARMOUR, SZ_MEDIUM); @@ -5825,14 +5856,14 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 70, NA, NA, NULL); addot(OT_VELVETROBE, "velvet robe", "A luxurious velvet robe.", MT_CLOTH, 4, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 90, RR_UNCOMMON, NULL); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 75, NA, NA, NULL); addflag(lastot->flags, F_BRANDCHANCE, 20, NA, NA, NULL); @@ -5844,7 +5875,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SHOULDERS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_WATERPROOF, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HELPSREST, 2, NA, NA, NULL); addot(OT_CLOAKFUR, "fur cloak", "A warm and lightweight fur cloak, great for winter camping trips.", MT_FLESH, 3, OC_ARMOUR, SZ_MEDIUM); @@ -5852,7 +5883,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SHOULDERS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_COLD, NA, NULL); addflag(lastot->flags, F_HELPSREST, 5, NA, NA, NULL); addot(OT_APRON, "apron", "A sturdy rubber apron, designed to protect against stains.", MT_RUBBER, 2, OC_ARMOUR, SZ_MEDIUM); @@ -5868,7 +5899,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_WAIST, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); - addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); // armour - legs addot(OT_CLOTHTROUSERS, "pair of cloth trousers", "A rough pair of cloth trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); @@ -5879,13 +5910,13 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 60, NA, NA, NULL); - addot(OT_RIDINGTROUSERS, "pair of riding trousers", "A fitted pair of leather trousers.", MT_LEATHER, 2, OC_ARMOUR, SZ_MEDIUM); + addot(OT_RIDINGTROUSERS, "pair of riding trousers", "A tight pair of durable leather trousers.", MT_LEATHER, 2, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 75, NA, NA, NULL); addot(OT_COMBATPANTS, "pair of combat pants", "An lightly-armoured pair of camoflauged trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM); @@ -5893,7 +5924,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); + addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 90, NA, NA, NULL); addot(OT_GREAVES, "set of greaves", "A set of heavy metal greaves.", MT_METAL, 4, OC_ARMOUR, SZ_MEDIUM); @@ -5901,7 +5932,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 25, 25, NA, NULL); + addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 15, 15, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 45, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); @@ -5913,7 +5944,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 30, NA, NA, NULL); addot(OT_SHOESLEATHER, "pair of leather shoes", "Cheap and rather uncomfortable leather shoes.", MT_LEATHER, 2, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); @@ -5921,7 +5952,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 35, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 85, NA, NA, NULL); addot(OT_BOOTSRUBBER, "pair of rubber boots", "A waterproof (but somewhat cumbersome) pair of rubber boots.", MT_RUBBER, 6, OC_ARMOUR, SZ_SMALL); @@ -5930,7 +5961,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 0, 5, NULL); - addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTRESIST, DT_ELECTRIC, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 95, NA, NA, NULL); @@ -5939,7 +5970,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_STABILITY, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 35, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 90, NA, NA, NULL); @@ -5949,7 +5980,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 35, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 90, NA, NA, NULL); addot(OT_BOOTSMETAL, "pair of metal boots", "A strong pair of metal boots.", MT_METAL, 5, OC_ARMOUR, SZ_SMALL); @@ -5958,7 +5989,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 35, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); // armour - gloves @@ -5968,7 +5999,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 70, NA, NA, NULL); addot(OT_GLOVESLEATHER, "pair of leather gloves", "A pair of coarse leather gloves.", MT_LEATHER, 0.25, OC_ARMOUR, SZ_SMALL); @@ -5976,7 +6007,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_HANDS, NA, NA, NULL); addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 90, NA, NA, NULL); addot(OT_GAUNTLETS, "pair of gauntlets", "A durable pair of metal gauntlets.", MT_METAL, 2, OC_ARMOUR, SZ_SMALL); @@ -5985,7 +6016,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 5, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 15, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); // armour - head @@ -6008,7 +6039,7 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ANONYMOUS, NA, NA, NULL); addot(OT_CAP, "cap", "Close-fitting headwear with a short shade visor at the front.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL); @@ -6026,12 +6057,12 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); - addot(OT_GASMASK, "gas mask", "A full face mask which protects the wearer from toxic gasses.", MT_METAL, 3.5, OC_ARMOUR, SZ_SMALL); + addot(OT_GASMASK, "gas mask", "A full face mask which protects the wearer from toxic gasses.", MT_RUBBER, 3.5, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_POISONGAS, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); @@ -6040,7 +6071,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_HELMFOOTBALL, "football helmet", "A metal helmet with a grill in front of the face.", MT_METAL, 1, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); @@ -6048,14 +6079,14 @@ void initobjects(void) { addflag(lastot->flags, F_MULTISIZE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_ACCURACYMOD, -10, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -1, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_GOLDCROWN, "golden crown", "A heavy gold crown, encrusted with jewels.", MT_GOLD, 5, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 25, RR_RARE, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 33, NA, NA, NULL); addflag(lastot->flags, F_BRANDCHANCE, 30, NA, NA, NULL); addot(OT_HELMBONE, "bone helmet", "Scary-looking helmet made from the bones of an animal (?).", MT_BONE, 1, OC_ARMOUR, SZ_SMALL); @@ -6063,14 +6094,14 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); + addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); addflag(lastot->flags, F_SCARY, 4, NA, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_POINTYHAT, "wizard hat", "A foot-long brimmed conical hat, inscribed with strange symbols.", MT_CLOTH, 1, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_HEAD, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "pointy hat"); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); @@ -6080,7 +6111,7 @@ void initobjects(void) { addot(OT_EARPLUGS, "set of earplugs", "A pair of cloth plugs designed to give the wearer a peaceful night's sleep. ", MT_CLOTH, 0.01, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GOESON, BP_EARS, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); + addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_DEAF, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); @@ -6090,7 +6121,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); killflagsofid(lastot->flags, F_ENCHANTABLE); @@ -6099,7 +6130,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); + addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); @@ -6109,7 +6140,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 0, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -1, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_NIGHTVISRANGEMOD, -1, NA, NULL); addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL); @@ -6168,6 +6199,56 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); + // amulets + addot(OT_AMU_ANGER, "amulet of anger", "Allows its wearer to enter a state of bezerk rage at will.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_RAGE, NA, NULL); + addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); + addot(OT_AMU_CHEF, "chef's amulet", "Greatly lowers its wearers' metabolism.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_SLOWMETAB, 3, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_AMU_ESCAPE, "amulet of escape", "Grants its wearer the ability to teleport short distances.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_S_BLINK, NA, "pw:6;"); + addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); + addot(OT_AMU_FALLING, "amulet of feather fall", "Limits the effects of gravity on its wearer, rendering them immune to fall damage.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_COMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FALL, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_AMU_FLIGHT, "amulet of flight", "Grants its wearer the ability to fly.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_S_FLIGHT, NA, NULL); + addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); + addot(OT_AMU_LISTEN, "amulet of amplification", "Greatly enhances the wearer's sense of hearing.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_DTVULN, DT_SONIC, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_AMU_SLEEP, "amulet of peaceful slumber", "Blocks out all sound while the wearer sleeps.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_STARTBLESSED, B_CURSED, NA, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_AMU_SPELLBOOST, "archmage's amulet", "Greatly increases the power of the wearer's spells.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, ""); + addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 5, NA, NULL); + addot(OT_AMU_THIEF, "thief's amulet", "Crafted by a master thief, it allows its wearer the uncanny ability to pick almost any lock.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_PICKLOCK, NA, NULL); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_AMU_VICTIM, "amulet of victimisation", "Causes all creatures who view the wearer to become hostile and agressive.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); + addot(OT_AMU_VSMAGIC, "amulet versus magic", "Confers a moderate level of magic resistance upon its wearer.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 66, NA, NULL); + addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); + addot(OT_AMU_VSPOISON, "amulet versus poison", "Protects its wearer from all forms of poison.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_POISON, NA, NULL); + addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); + + // rings addot(OT_RING_EDUCATION, "ring of education", "Boosts earned XP and Skill points.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); @@ -6256,9 +6337,9 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); addflag(lastot->flags, F_EQUIPCONFER, F_REGENERATES, 1, NA, NULL); addflag(lastot->flags, F_VALUE, 350, NA, NA, NULL); - addot(OT_RING_RESISTMAG, "ring of magic resistance", "Renders the wearer immune to most magical effects.", MT_METAL, 0.1, OC_RING, SZ_MINI); + addot(OT_RING_RESISTMAG, "ring of magic resistance", "Confers a minor level of magical immunity 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_EQUIPCONFER, F_RESISTMAG, 5, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 33, NA, NULL); addflag(lastot->flags, F_VALUE, 350, NA, NA, NULL); addot(OT_RING_MEDITATION, "ring of meditation", "Allows the wearer to rest by entering a state of meditation.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, RR_UNCOMMON, ""); @@ -6269,7 +6350,7 @@ void initobjects(void) { 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); + addot(OT_RING_SPELLBOOST, "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); addflag(lastot->flags, F_EQUIPCONFER, F_MAGICBOOST, 1, NA, NULL); @@ -8788,7 +8869,6 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); @@ -8827,7 +8907,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); @@ -8870,7 +8949,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SWIMMING, PR_MASTER, NA, NULL); @@ -8908,7 +8986,6 @@ void initrace(void) { addflag(lastrace->flags, F_STABILITY, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_EXPERT, NA, NULL); @@ -8943,7 +9020,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); @@ -8976,7 +9052,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_MINIONS, 70, 1, 2, "goblin"); addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); addflag(lastrace->flags, F_STARTHIDDENPCT, 75, NA, NA, NULL); @@ -9009,7 +9084,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); //addflag(lastrace->flags, F_CANCAST, OT_S_BLINDNESS, NA, NA, NULL); //addflag(lastrace->flags, F_CANCAST, OT_S_PAIN, NA, NA, NULL); addflag(lastrace->flags, F_RNDSPELLCOUNT, 2, NA, NA, NULL); @@ -9048,7 +9122,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); addflag(lastrace->flags, F_MINIONS, 90, 4, 6, "goblin"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); @@ -9618,6 +9691,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SWOOP, NA, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_SMITEEVIL, NA, NA, "pw:8;"); addflag(lastrace->flags, F_SWOOPRANGE, 4, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 4, NA, "screams in pain^screams of pain"); addflag(lastrace->flags, F_RESISTMAG, 5, NA, NA, NULL); @@ -12331,6 +12405,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "growls^a growl"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addrace(R_SKELETON, "skeleton", 20, 'Z', C_GREY, MT_BONE, RC_UNDEAD, "A walking set of bones, animated through the use of necromancy. Due to their lack of soft flesh, they have little to fear from edged weapons."); setbodytype(lastrace, BT_HUMANOID); @@ -12427,7 +12503,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_DTRESIST, DT_COLD, NA, "15"); - addrace(R_GHAST, "ghast", 50, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD, "A more slender and ghost-like form of ghoul. Ghasts are cunning and deadly, and possess a paralyzing touch."); + addrace(R_GHAST, "ghast", 50, 'Z', C_BOLDGREEN, MT_FLESH, RC_UNDEAD, "A more slender and ghost-like form of ghoul. Ghasts are cunning and deadly, and possess a paralyzing touch."); setbodytype(lastrace, BT_HUMANOID); setbodypartname(lastrace, BP_HANDS, "claws"); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index 9227e47b3a36f1773e20f1282012b4fab51f8fb8..f360394d1bcfda318e4693e394368a89a75d1ba3 100644 GIT binary patch delta 519 zcmXwzPiPZi5XHZlNxR#wRctjjsf16Bf0|UXX|!G})I+2+F{o7hM}39)9ra5Wm&6u(!SIQ(H3IJ#J0}Uyldx`OM!2!CG8^y!=9Y=B%3Qv z%K?~WZQy6%hjXwBzwj7pDDVxbPH@i@`0zJNICuBfa36ePGPr4iL8!tK`tb_>pa)KO z_qvPO?1b|r5b6wduodR+XNbTxu;B%K#SrGPiGOH>7R156Ip=!ceH0_H)u0UH494LZ zDtH+m;de^XBAN8ueHl`d;M`G%z}eM52L2Alm;_r4V>pAaXg7_~3T!P;uR|u?h_*89 ziW^;5%f)QE7FYS1%7men3p`V>Cbd+-H1!HN%#hbaJlwxam49ee4)5qamC z@Nf%C*aT7PBwm+MHH1$kr;2ed(s!DnS(@UOvUuCo2bKc>R;7kn554B|C> zh@Oh}(X2e4S2E6TIlO87FWJcku@W=@uQ@q0lGPQuP_P{WGi& z>isYW&TYbH$4p@fckn$Or98c&L!OrSxh>l}c7^=2jgT8CaPa{ROJV4g^u?8Hq-qp4 zByYxKI38mbRH#P?zEDcLhb-}INM(RO53&NzARwi?2_KArsT32^cBmNwP2L3 jYE{P5QTMmva9AxvO>F diff --git a/defs.h b/defs.h index 0465592..19b09ca 100644 --- a/defs.h +++ b/defs.h @@ -346,6 +346,7 @@ enum SHOPACTION { #define DATADIR "data" #define SAVEDIR "data" #define VAULTDIR "data/vaults" +#define BONESDIR "data/bones" // rank, score, name, job, killer #define HISCOREFORMAT "%-4s%-7s%-10s%-23s" @@ -856,6 +857,7 @@ enum DAMTYPE { enum OBCLASS { OC_NONE, OC_ABILITY, + OC_AMULET, OC_ARMOUR, OC_BOOK, OC_BUILDING, @@ -1876,6 +1878,19 @@ enum OBTYPE { OT_SHIELDHIDE, OT_SHIELDLARGE, OT_SHIELDTOWER, + // amulets + OT_AMU_ANGER, + OT_AMU_CHEF, + OT_AMU_ESCAPE, + OT_AMU_FALLING, + OT_AMU_FLIGHT, + OT_AMU_LISTEN, + OT_AMU_SLEEP, + OT_AMU_SPELLBOOST, + OT_AMU_THIEF, + OT_AMU_VICTIM, + OT_AMU_VSMAGIC, + OT_AMU_VSPOISON, // rings OT_RING_ENDURANCE, OT_RING_GREED, @@ -1894,7 +1909,7 @@ enum OBTYPE { OT_RING_MANA, OT_RING_MEDITATION, OT_RING_MIRACLES, - OT_RING_MPBOOST, + OT_RING_SPELLBOOST, OT_RING_MPREGEN, OT_RING_NOINJURY, OT_RING_PROTFIRE, @@ -2039,21 +2054,22 @@ enum BODYPART { BP_EARS = 2, BP_EYES = 3, BP_HEAD = 4, // <- core bodypart - BP_SHOULDERS = 5, - BP_BODY = 6, // <- core bodypart - BP_HANDS = 7, // <- core bodypart - BP_WAIST = 8, - BP_LEGS = 9, // <- core bodypart - BP_FEET = 10, - BP_RIGHTFINGER = 11, - BP_LEFTFINGER = 12, + BP_NECK = 5, + BP_SHOULDERS = 6, + BP_BODY = 7, // <- core bodypart + BP_HANDS = 8, // <- core bodypart + BP_WAIST = 9, + BP_LEGS = 10, // <- core bodypart + BP_FEET = 11, + BP_RIGHTFINGER = 12, + BP_LEFTFINGER = 13, // others... - BP_BACKLEGS = 13, - BP_FRONTLEGS = 14, - BP_WINGS = 15, // <- core bodypart - BP_TAIL = 16, // <- core bodypart + BP_BACKLEGS = 14, + BP_FRONTLEGS = 15, + BP_WINGS = 16, // <- core bodypart + BP_TAIL = 17, // <- core bodypart }; -#define MAXBODYPARTS (17) +#define MAXBODYPARTS (18) // depth on a human @@ -2983,7 +2999,8 @@ enum FLAG { F_SACRIFICEOBCLASS, // v0 = can sacrifice obclass v0 to this god F_SACRIFICEOBBLESSED, // v0 = can sacrifice obs with ->blessed=v0 and blessknown! - F_NAME, // text = lf's name + F_NAME, // text = lf's name. ie. lfname = "Fred" + F_NAMED, // text = lf's name. ie. lfname = "xat named Fred" F_XPMOD, // add/subtract this much from calculated xpval F_BLOODOB, // text = type of object to drop for blood F_UNSUMMONOB, // text = type of object to drop when this creature @@ -3029,9 +3046,6 @@ enum FLAG { F_POISONCORPSE, // lf's corpse will be poisonous F_AUTOCREATEOB, // produces obtype 'text' wherever it walks, v0=radius // (only if ob of that type not already there) - F_PACKATTACK, // deal v0 extra damage of type v1 if there are - // v2 or more monsters of the same baseid - // next to the attacker F_PHALANX, // gain v0 AR if v2 or more adj monsters matching f->text F_MORALE, // gain +v0 in morale checks. F_SPOTTED, // you have spotted hiding lf id v0. you lsoe this if they @@ -3121,6 +3135,8 @@ enum FLAG { F_FASTACTMOVE, // modifier for action and move speed F_POISONED, // has poisoning. v0 = poison type, // v1 = power + // v2 = if you ate a corpse, this records its race + // otherwise, NA. // text = what from.eg'a bad egg' F_FREEZINGTOUCH,// next thing touched turns to ice! // v1 = power @@ -3135,8 +3151,6 @@ enum FLAG { F_INVISIBLE, // lifeform is invisible F_INVULNERABLE,// immune to most damage // this can apply to objects too! - F_QUICKBITE, // deals v0 d d1 + d2 damage when you hit a bleeding victim - // (bypasses armour) F_GRAVBOOSTED,// cannot walk or throw stuff F_GRAVLESSENED,// knockback maeks you go further, can jump further // your current load is reduce by v0 * 15kg. @@ -4250,9 +4264,12 @@ typedef struct brand_s { struct brand_s *next, *prev; } brand_t; +#define MAXOMPREFIXES 20 typedef struct obmod_s { enum OBMOD id; char *prefix; + char *altprefix[MAXOMPREFIXES]; + int naltprefix; flagpile_t *flags; struct obmod_s *next, *prev; } obmod_t; diff --git a/doc/add_bodypart.txt b/doc/add_bodypart.txt index 63a1848..c30779f 100644 --- a/doc/add_bodypart.txt +++ b/doc/add_bodypart.txt @@ -6,3 +6,7 @@ in lf.c: update getbodypartname update getbodypartequipname update getbodyparthitchance + update canreachbp() + + + update bodyparts of BT_HUMANOID etc. to include it, if required. diff --git a/flag.c b/flag.c index d3599a4..eb7a715 100644 --- a/flag.c +++ b/flag.c @@ -89,6 +89,15 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, val3 = RR_COMMON; } + // special case which lets us confer f_canwill. (with conferred flags, we can't + // supply val[2]). + if (id == F_CANWILL) { + if ((val3 == NA) && (val2 > 0)) { + val2 = val3; + } + } + + // auto-increment order for EXTRADESC flag if ((id == F_EXTRADESC) && (val1 == NA)) { flag_t *retflag[MAXCANDIDATES]; diff --git a/god.c b/god.c index 1cba468..9ecb3ab 100644 --- a/god.c +++ b/god.c @@ -1681,6 +1681,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { int piety,i,x,y; char assisttext[BUFLEN]; enum PIETYLEV plev; + int newgod; taketime(lf, getactspeed(lf)); @@ -1703,6 +1704,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { // ie. player is expected to follow the god's rules. if (!hasflag(god->flags, F_PRAYEDTO)) { addflag(god->flags, F_PRAYEDTO, B_TRUE, NA, NA, NULL); + newgod = B_TRUE; } if (godisangry(god->race->id)) { @@ -2127,6 +2129,22 @@ int prayto(lifeform_t *lf, lifeform_t *god) { object_t *possob[MAXPILEOBS]; int npossob,i,first; object_t *o; + // unlock doors + first = B_TRUE; + for (i = 0; i < player->nlos; i++) { + cell_t *c; + object_t *o; + c = player->los[i]; + for (o = c->obpile->first ; o ; o = o->next) { + if (killflagsofid(o->flags, F_LOCKED) || killflagsofid(o->flags, F_SECRET)) { + if (first) { + msg("\"Access granted!\""); + first = B_FALSE; + } + noise(c, NULL, NC_OTHER, SV_TALK, "the click of a lock.", NULL); + } + } + } // uncurse one equipped ob if (uncurse_one_equipped(lf, "\"Curses, schmurses!\"")){ @@ -2140,24 +2158,6 @@ int prayto(lifeform_t *lf, lifeform_t *god) { msg("\"Allow me to reveal your surroundings...\""); dospelleffects(god, OT_S_MAPPING, 5, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); dospelleffects(god, OT_S_REVEALHIDDEN, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); - // unlock doors - first = B_TRUE; - for (i = 0; i < player->nlos; i++) { - cell_t *c; - object_t *o; - c = player->los[i]; - if (c != player->cell) { - o = hascloseddoor(c); - if (o && hasflag(o->flags, F_LOCKED)) { - if (first) { - msg("\"Access granted!\""); - first = B_FALSE; - } - killflagsofid(o->flags, F_LOCKED); - noise(c, NULL, NC_OTHER, SV_TALK, "the click of a lock.", NULL); - } - } - } break; case 2: // identify objects npossob = 0; @@ -2411,6 +2411,20 @@ int prayto(lifeform_t *lf, lifeform_t *god) { break; } + + // new god effects + if (newgod) { + switch (god->race->id) { + case R_GODTHIEVES: + makelearnable(lf, SK_THIEVERY); + makelearnable(lf, SK_LOCKPICKING); + break; + default: + break; + } + } + + if (god->race->id == R_GODNATURE) { addob(lf->cell->obpile, "flower"); if (haslos(player, lf->cell)) { diff --git a/io.c b/io.c index c3e4a5e..d5801b1 100644 --- a/io.c +++ b/io.c @@ -7013,10 +7013,8 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel case F_MEDITATES: if (lorelev >= PR_ADEPT) sprintf(buf, "Meditates to retain awareness while sleeping."); break; case F_MPMOD: if (f->val[0] > 0) sprintf(buf, "+%d Mana", f->val[0]); break; case F_NOSLEEP: if (lorelev >= PR_BEGINNER) sprintf(buf, "Does not sleep"); break; - case F_PACKATTACK: if (lorelev >= PR_ADEPT) sprintf(buf, "Deals extra damage when in a pack."); break; case F_PHALANX: if (lorelev >= PR_ADEPT) sprintf(buf, "Gains extra defence when in a pack."); break; case F_PHOTOMEM: sprintf(buf, "Photographic memory"); break; - case F_QUICKBITE: if (lorelev >= PR_ADEPT) sprintf(buf, "Can bite wounded enemies for extra damage"); break; case F_REGENERATES: if (lorelev >= PR_BEGINNER) sprintf(buf, "Automatically regenerates health."); break; case F_RESISTMAG: if (lorelev >= PR_BEGINNER) sprintf(buf, "Magic-resistant"); break; case F_SEEINDARK: if (lorelev >= PR_BEGINNER) sprintf(buf, "Darkvision (range %d)", f->val[0]); break; diff --git a/lf.c b/lf.c index be12640..0af4fc5 100644 --- a/lf.c +++ b/lf.c @@ -16,6 +16,7 @@ #include "move.h" #include "nexus.h" #include "objects.h" +#include "save.h" #include "shops.h" #include "spell.h" #include "text.h" @@ -732,8 +733,11 @@ int candrink(lifeform_t *lf, object_t *o) { // if false, returns why you can't eat it in 'reason' int caneat(lifeform_t *lf, object_t *o) { - // undead won't eat + // undead will only eat fleshy corpses if (getraceclass(lf) == RC_UNDEAD) { + if (hasflag(o->flags, F_CORPSEOF) && (o->material->id == MT_FLESH)) { + return B_TRUE; + } reason = E_UNDEAD; return B_FALSE; } @@ -761,15 +765,17 @@ int caneat(lifeform_t *lf, object_t *o) { if (f) { race_t *r; r = findrace(f->val[0]); - // same race? - if ((r->id == lf->race->id) || (r->baseid == lf->race->baseid)) { - enum RACECLASS rc; - rc = getraceclass(lf); - // race which doens't eat its own? - if ((rc == RC_ANIMAL) || (rc == RC_HUMANOID)) { - // no cannibulism! - reason = E_NOCANNIBUL; - return B_FALSE; + // same race? let the player do so. + if (!isplayer(lf)) { + if ((r->id == lf->race->id) || (r->baseid == lf->race->baseid)) { + enum RACECLASS rc; + rc = getraceclass(lf); + // race which doens't eat its own? + if ((rc == RC_ANIMAL) || (rc == RC_HUMANOID)) { + // no cannibulism! + reason = E_NOCANNIBUL; + return B_FALSE; + } } } } @@ -1109,6 +1115,7 @@ int canreachbp(lifeform_t *lf, lifeform_t *victim, enum BODYPART bp) { case BP_EYES: case BP_HEAD: case BP_EARS: + case BP_NECK: case BP_SHOULDERS: if (howmuchsmaller >= 1) { return B_FALSE; @@ -2473,7 +2480,6 @@ void die(lifeform_t *lf) { char buf[BUFLEN]; flag_t *f; int killedgod = B_FALSE; - cell_t *where; //int dropobs = B_TRUE; int vaporised = B_FALSE, i; int dropobs = B_TRUE; @@ -2483,6 +2489,17 @@ void die(lifeform_t *lf) { int nretflags; cell_t *corpsecell; lifeform_t *killer = NULL; + int dobonesfile = B_FALSE; + char reanimateas[BUFLEN]; + cell_t *where; + int thisisplayer = B_FALSE; + + strcpy(reanimateas, ""); + + where = lf->cell; + + thisisplayer = isplayer(lf); + if (lf->lastdamlf != -1) { killer = findlf(lf->cell->map, lf->lastdamlf); @@ -2497,7 +2514,7 @@ void die(lifeform_t *lf) { } // died after entering a new level without a chance to move? - if (isplayer(lf) && lfhasflag(lf, F_JUSTENTERED) && godprayedto(R_GODMERCY)) { + if (thisisplayer && lfhasflag(lf, F_JUSTENTERED) && godprayedto(R_GODMERCY)) { godsay(R_GODMERCY, B_TRUE, "Well, that seems unfair..."); more(); // return to full health lf->hp = lf->maxhp; @@ -2520,7 +2537,7 @@ void die(lifeform_t *lf) { } // put out fires extinguishlf(lf); - if (isplayer(lf)) { + if (thisisplayer) { statdirty = B_TRUE; } return; @@ -2542,7 +2559,7 @@ void die(lifeform_t *lf) { } if (!willbecomeghost) { - if (isplayer(lf) && hasjob(lf, J_GOD)) { + if (thisisplayer && hasjob(lf, J_GOD)) { char ch; msg("^BYou are about to die..."); more(); ch = askchar("Die", "yn", "n", B_TRUE, B_FALSE); @@ -2566,7 +2583,7 @@ void die(lifeform_t *lf) { // convert into a gas cloud! dospelleffects(NULL, OT_S_GASEOUSFORM, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); // ai will now look for our coffin - if (isplayer(lf)) { + if (thisisplayer) { msg("^GYou feel the presence of a nearby coffin..."); } else { addflag(lf->flags, F_WANTS, OT_COFFIN, B_COVETS, NA, NULL); @@ -2596,7 +2613,7 @@ void die(lifeform_t *lf) { lf->maxhp = ratio * lf->maxhp; limit(&(lf->hp), 1, lf->maxhp); } - if (isplayer(lf)) statdirty = B_TRUE; + if (thisisplayer) statdirty = B_TRUE; /* // ... but you're still dead lf->hp = 0; @@ -2609,7 +2626,7 @@ void die(lifeform_t *lf) { lf->alive = B_FALSE; } - if (isplayer(lf)) { + if (thisisplayer) { lifeform_t *god; // force screen redraw so you see your hp = 0 drawscreen(); @@ -2631,8 +2648,8 @@ void die(lifeform_t *lf) { godsay(god->race->id, B_TRUE, "Rest in peace, brave warrior."); more(); break; case R_GODDEATH: - godsay(god->race->id, B_TRUE, "Come to me, my servant..."); more(); - msg("Bony claws rise up and drag your corpse underground."); more(); break; + godsay(god->race->id, B_TRUE, "Arise, my servant..."); more(); break; + // you will rise as a monster. case R_GODLIFE: msg("Your spirit ascends to the heavens."); more(); break; case R_GODTHIEVES: // lose all gold / gems @@ -2771,7 +2788,7 @@ void die(lifeform_t *lf) { } // drop/kill all objects - if (corpsecell && (willbecomeghost || !isplayer(lf))) { + if (corpsecell && (willbecomeghost || !thisisplayer)) { while (lf->pack->first) { if (vaporised || !dropobs) { killob(lf->pack->first); @@ -2913,6 +2930,25 @@ void die(lifeform_t *lf) { changeflagtext(f, lf->lastdam); } } + + // For bones files: + if (thisisplayer) { + char pname[BUFLEN]; + getplayername(pname); + addflag(corpse->flags, F_NAMED, NA, NA, NA, pname); + if (streq(lf->killverb, "Eaten")) { + // this will cause the player's corpse description + // to show up as "partially eaten". used for + // bones files. + f = hasflag(corpse->flags, F_EDIBLE); + if (f) { + f->val[2] = f->val[1] / 2; + } + } + + } + + if (hasflag(corpse->flags, F_HEADLESS)) { object_t *headob; char headname[BUFLEN]; @@ -2955,7 +2991,7 @@ void die(lifeform_t *lf) { } // end if corpsecell // player killed last monster? - if (killer && isplayer(killer) && !isplayer(lf)) { + if (killer && isplayer(killer) && !thisisplayer) { lifeform_t *l; int battledone = B_TRUE; for (l = lf->cell->map->lf ; l ; l = l->next) { @@ -2990,14 +3026,138 @@ void die(lifeform_t *lf) { addflag(lf->flags, F_MYCORPSE, NA, NA, NA, cid); } } else { - where = lf->cell; - if (lf->controller != C_PLAYER) { - // kill lifeform + // Will the dead lf get reanimated up as a monster ? + // + if (!vaporised) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags,i; + // killed by a vampire = vampire. + if (killer) { + switch (killer->race->id) { + case R_VAMPIRE: sprintf(reanimateas, "vampire"); break; + default: break; + } + } + + // died by eating your own race = ghoul. + // died by eating a vampire corpse = vampire. + if (!strlen(reanimateas)) { + getflags(lf->flags, retflag, &nretflags, F_POISONED, F_NONE); + for (i = 0; i < nretflags; i++) { + if (retflag[i]->val[2] == R_VAMPIRE) { + sprintf(reanimateas, "vampire"); + } else if (retflag[i]->val[2] == lf->race->baseid) { + sprintf(reanimateas, "ghoul"); + } + } + } + + // hecta-worshippers get reanimated. + if (!strlen(reanimateas) && thisisplayer && godprayedto(R_GODDEATH)) { + switch (rnd(1,2)) { + case 1: + sprintf(reanimateas, "zombie"); + break; + case 2: + sprintf(reanimateas, "skeleton"); + break; + } + } + + // announce + if (strlen(reanimateas)) { + if (thisisplayer || cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%c%s%s corpse rises up as %s %s!^n", + C_MAGENTA, + lfname, getpossessive(lfname), + needan(reanimateas) ? "an" : "a", reanimateas); + } + } + } + + // now kill the lifeform. + //if (lf->controller != C_PLAYER) { + if (!thisisplayer) { + // actually kill the lifeform killlf(lf); assert(where->lf == NULL); } } + // IMPORTANT: DO NOT REFERENCE lf->xxxx AFTER THIS POINT + // UNLESS WE ARE _SURE_ IT IS THE PLAYER (ie. thisisplayer = true) + + + + // Note that if we reanimate, the new monster will appear in an + // ADJACENT cell. this solves the problem that we can't actually + // kill() the player's lf because we need to see their objects to + // show their final possessions. + if (strlen(reanimateas)) { + cell_t *c = NULL; + // announce, then add on " named playername", if required. + if (lf && isplayer(lf)) { + char pname[BUFLEN]; + getplayername(pname); + strcat(reanimateas, " named "); + strcat(reanimateas, pname); + } + + if (where->lf) { + c = getrandomadjcell(where, WE_WALKABLE, B_ALLOWEXPAND); + } else { + c = where; + } + if (c) { + // remove the corpse... + if (corpse) killob(corpse); + // add the reanimated monster + addmonster(c, R_SPECIFIED, reanimateas, B_FALSE, 1, B_FALSE, NULL); + } + } + + // Write out a bones file? A bones file might be written if: + // - the player died in a ROOM. + // AND + // - the player died in a major dungeon branch, which wasn't the realm of gods + if (thisisplayer && (where->room) && + (where->map->region->rtype->majorbranch) && + (where->map->region->rtype->id != RG_HEAVEN)) { + // If all of the above are true, the below will trigger a bones file: + // Player reanimating as some kind of monster + // Being killed by stoning + // Random chance + // + if (strlen(reanimateas)) { + dobonesfile = B_TRUE; + } else if (corpse && (corpse->type->id == OT_STATUE)) { + dobonesfile = B_TRUE; + } else if (onein(4)) { + dobonesfile = B_TRUE; + } + + if (hasjob(lf, J_GOD)) { + char ch; + char ques[BUFLEN]; + sprintf(ques, "Bones file dump = %s. Override?", dobonesfile ? "true" : "false"); + ch = askchar(ques, "yn", "n", B_TRUE, B_FALSE); + if (ch == 'y') { + ch = askchar("Dump bones file?", "yn", "n", B_TRUE, B_FALSE); + if (ch == 'y') { + dobonesfile = B_TRUE; + } else { + dobonesfile = B_FALSE; + } + } + } + } + + if (dobonesfile) { + savebones(where->map, where->room); + } + if (needredraw) { drawscreen(); } @@ -3502,6 +3662,9 @@ int eat(lifeform_t *lf, object_t *o) { enum HUNGER hlev,posthlev; int stopeating = B_FALSE; int rawmeat = B_FALSE; + race_t *corpserace = NULL; + flag_t *cf; + if (lfhasflag(lf, F_RAGE)) { if (isplayer(lf)) msg("You are too enraged to eat!"); @@ -3560,6 +3723,13 @@ int eat(lifeform_t *lf, object_t *o) { getobname(o, obname, 1); getlfname(lf, lfname); + + // is this a corpse? + cf = hasflag(o->flags, F_CORPSEOF); + if (cf) { + corpserace = findrace(cf->val[0]); + } + // get total nutrition nutrition = getnutrition(o); @@ -3593,10 +3763,10 @@ int eat(lifeform_t *lf, object_t *o) { // uncooked meat? if (iscorpse(o) && isplayer(lf)) { + int ch; + char ques[BUFLEN]; if (!hasflag(o->flags, F_PREPARED) && !lfhasflag(lf, F_CANEATRAW)) { if (!lfhasflag(lf, F_EATING) && getskill(lf, SK_COOKING)) { - int ch; - char ques[BUFLEN]; more(); sprintf(ques,"Really eat %s raw?",obname); ch = askchar(ques,"yn","y", B_TRUE, B_FALSE); @@ -3608,6 +3778,18 @@ int eat(lifeform_t *lf, object_t *o) { if (nutrition > (HUNGERCONST/3)) nutrition = (HUNGERCONST/3); rawmeat = B_TRUE; } + + // cannibulism ? + if (corpserace->id == lf->race->baseid) { + if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { + more(); + sprintf(ques,"Really eat your own race?"); + ch = askchar(ques,"yn","y", B_TRUE, B_FALSE); + if (ch != 'y') { + return B_TRUE; + } + } + } } if (touch(lf, o)) { @@ -3705,6 +3887,8 @@ int eat(lifeform_t *lf, object_t *o) { if (isrotting(o)) { char dambuf[BUFLEN]; enum POISONTYPE ptid; + int ppower = 1; + // lose hp if (isplayer(lf)) { msg("^BThat %s was bad!", drinking ? "liquid" : "food"); @@ -3720,41 +3904,42 @@ int eat(lifeform_t *lf, object_t *o) { } else { ptid = P_FOOD; } - poison(lf, rnd(20,40), ptid, 1, dambuf); + // cannibulism ? + if (corpserace->id == lf->race->baseid) { + ppower = 3; + } + poison(lf, rnd(20,40), ptid, ppower, dambuf, cf ? cf->val[0] : R_NONE); } else if (!drinking) { - char dambuf[BUFLEN]; - snprintf(dambuf, BUFLEN, "a bad %s",noprefix(obname)); - // raw meat? - if (israwmeat(o) && !lfhasflag(lf, F_CANEATRAW)) { - flag_t *cf; - race_t *corpserace = NULL; - cf = hasflag(o->flags, F_CORPSEOF); - if (cf) { - corpserace = findrace(cf->val[0]); - } - if (corpserace) { - int checkdiff; - enum POISONTYPE ptid; - int timemin,timemax; - if (hasflag(corpserace->flags, F_AVIAN)) { - checkdiff = 30; - ptid = P_FOODBAD; - timemin = 30; - timemax = 50; + if (corpserace && israwmeat(o) && !lfhasflag(lf, F_CANEATRAW)) { + int checkdiff; + enum POISONTYPE ptid; + int timemin,timemax; + int ppower = 1; + char dambuf[BUFLEN]; + snprintf(dambuf, BUFLEN, "a bad %s",noprefix(obname)); + if (hasflag(corpserace->flags, F_AVIAN)) { + checkdiff = 30; + ptid = P_FOODBAD; + timemin = 30; + timemax = 50; + } else { + checkdiff = 20; + if (onein(3)) { + ptid = P_FOOD; } else { - checkdiff = 20; - if (onein(3)) { - ptid = P_FOOD; - } else { - ptid = P_MIGRAINE; - } - timemin = 20; - timemax = 40; - } - if (!skillcheck(lf, SC_POISON, checkdiff, 0)) { - poison(lf, rnd(timemin,timemax), ptid, 1, dambuf); + ptid = P_MIGRAINE; } + timemin = 20; + timemax = 40; + } + + // cannibulism ? + if (corpserace->id == lf->race->baseid) { + ppower = 3; + } + if (!skillcheck(lf, SC_POISON, checkdiff, 0)) { + poison(lf, rnd(timemin,timemax), ptid, ppower, dambuf, corpserace ? corpserace->id : R_NONE); } } } @@ -3873,7 +4058,7 @@ int eat(lifeform_t *lf, object_t *o) { addtempflag(lf->flags, F_SEEINDARK, 3, NA, NA, NULL, rnd(20,40)); } else if (o->type->id == OT_POISONSAC) { // very bad! - poison(lf, rnd(10,20), P_VENOM, 4, "eating a venom sac"); + poison(lf, rnd(10,20), P_VENOM, 4, "eating a venom sac", R_NONE); } if (isplayer(lf)) makeknown(o->type->id); @@ -3899,6 +4084,18 @@ int eat(lifeform_t *lf, object_t *o) { if (o->pile->owner != lf) { amt += SPEED_PICKUP; } + // humanoids can use knives and forks to eat faster. + if (getraceclass(lf) == RC_HUMANOID) { + int pct = 100; + if (hasob(lf->pack, OT_FORK)) { + pct -= 25; + } + if (hasob(lf->pack, OT_KNIFE) || hasob(lf->pack, OT_STEAKKNIFE)) { + pct -= 25; + } + amt = pctof(pct, amt); + } + limit(&amt, SP_ULTRAFAST, NA); taketime(lf, amt); // special cases even if not fully eaten @@ -3918,12 +4115,19 @@ int eat(lifeform_t *lf, object_t *o) { } - - - // eating your pet is very bad! - if (isplayer(lf) && hasflagval(o->flags, F_PETOF, player->id, NA, NA, NULL)) { - angergodmaybe(R_GODPURITY, 150, GA_EAT); - stopeating = B_TRUE; + // god effects + if (isplayer(lf)) { + // eating your pet is very bad! + if (hasflagval(o->flags, F_PETOF, player->id, NA, NA, NULL)) { + angergodmaybe(R_GODPURITY, 150, GA_EAT); + stopeating = B_TRUE; + } + // cannibulism ? + if (corpserace && (corpserace->id == lf->race->baseid)) { + angergodmaybe(R_GODPURITY, 150, GA_EAT); + angergodmaybe(R_GODNATURE, 100, GA_EAT); + stopeating = B_TRUE; + } } if (lfhasflagval(lf, F_FATALFOOD, o->type->id, NA, NA, NULL)) { @@ -6400,6 +6604,7 @@ int getbodyparthitchance(enum BODYPART bp) { case BP_EARS: case BP_RIGHTFINGER: case BP_LEFTFINGER: + case BP_NECK: break; } return 0; // ie rings, ears, weapon @@ -6436,6 +6641,8 @@ char *getbodypartname(lifeform_t *lf, enum BODYPART bp) { return "eyes"; case BP_HEAD: return "head"; + case BP_NECK: + return "neck"; case BP_BODY: return "body"; case BP_SHOULDERS: @@ -6480,6 +6687,7 @@ char *getbodypartequipname(enum BODYPART bp) { case BP_SHOULDERS: return "over"; case BP_WAIST: + case BP_NECK: return "around"; } return "unknown"; @@ -7835,7 +8043,14 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis, int showall) { } else { strcpy(the, "the "); } - strcpy(lname, lf->race->name); + f = lfhasflag(lf, F_NAMED); + if (f) { // ie. "the xat named blah" + strcpy(lname, lf->race->name); + strcat(lname, " named "); + strcat(lname, f->text); + } else { // ie. "the xat" + strcpy(lname, lf->race->name); + } } // construct description string @@ -9598,7 +9813,7 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) { } // if all conferred flags now known, object is known - if (flagsfound && (flagsknown == flagsfound)) { + if (flagsfound && (flagsknown == flagsfound) && !isknown(o)) { int willmakeknown = B_FALSE; if (isplayer(lf) || cansee(player, lf)) { willmakeknown = B_TRUE; @@ -9610,6 +9825,11 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) { if (hasflag(o->flags, F_IDWHENUSED)) { identify(o); } + if (isplayer(lf)) { + char buf[BUFLEN]; + getobname(o, buf, o->amt); + msgnocap("%s %s!", (o->amt == 1) ? "This is" : "These are", buf); + } } } } @@ -11593,6 +11813,9 @@ int isdeaf(lifeform_t *lf) { if (lfhasflag(lf, F_DEAF)) return B_TRUE; if (isresting(lf) && lfhasflag(lf, F_RESTINGINMOTEL)) return B_TRUE; if (lfhasflagval(lf, F_INJURY, IJ_EARSRINGING, NA, NA, NULL)) return B_TRUE; + + if (hasequippedobid(lf->pack, OT_AMU_SLEEP) && isasleep(lf)) return B_TRUE; + return B_FALSE; } @@ -13814,6 +14037,8 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml setlastdam(lf, buf); if (fromlf && willeatlf(fromlf, lf)) { + // this string is special - die() checks for this to see whether + // to add "partially eaten" to the corpse. setkillverb(lf, "Eaten"); } else { switch (damtype) { @@ -13853,7 +14078,7 @@ void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fr } // catch a cold? if (!skillcheck(lf, SC_CON, (dam/2) + getexposedlimbs(lf), 0)) { - poison(lf, 20+(dam*3), P_COLD, 0, "the cold"); + poison(lf, 20+(dam*3), P_COLD, 0, "the cold", fromlf ? fromlf->race->id : R_NONE); } // cold will heal bruised limbs getflags(lf->flags, retflag, &nretflags, F_INJURY, F_NONE); @@ -13892,7 +14117,7 @@ void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fr } else if (damtype == DT_POISONGAS) { if (dam > 0) { if (!skillcheck(lf, SC_POISON, 35, 0)) { // HARD. - poison(lf, rnd(20,40), P_GAS, 2, "poison gas"); + poison(lf, rnd(20,40), P_GAS, 2, "poison gas", fromlf ? fromlf->race->id : R_NONE); } } } @@ -14045,6 +14270,38 @@ void makefriendly(lifeform_t *who, int howlong) { } +// make lf be able to learn the given skill +// returns TRUE if we did something. +int makelearnable(lifeform_t *lf, enum SKILL skid) { + flag_t *f,*learnable; + int changed = B_FALSE; + f = hasflagval(lf->flags, F_NOSKILL, skid[i], NA, NA, NULL); + if (f) { + killflag(f); + } + learnable = lfhasflagval(lf, F_CANLEARN, skid[i], NA, NA, NULL); + if (learnable) { + if (learnable->val[1] != NA) { + // able to learn thievery, but limitted + learnable->val[1] = NA; + changed = B_TRUE; + } + } else if (!getskill(lf, SK_THIEVERY)) { + // don't have the skill, not learnable + addflag(lf->flags, F_CANLEARN, skid[i], NA, NA, NULL); + changed = B_TRUE; + } + if (changed) { + if (isplayer(lf)) { + skill_t *sk; + sk = findskill(skid); + msg("^GYou are now capable of learning the %s skill.^n",sk->name); + } + return B_TRUE; + } + return B_FALSE; +} + int makenauseated(lifeform_t *lf, int amt, int howlong) { flag_t *f; @@ -15055,14 +15312,17 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int want return B_FALSE; } -void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat) { +void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat, enum RACE srcraceid) { flag_t *f; int found = B_FALSE,i; enum POISONSEVERITY psev; flag_t *retflag[MAXCANDIDATES]; int nretflags; + race_t *srcrace; poisontype_t *pt; + pt = findpoisontype(ptype); + srcrace = findrace(srcraceid); // are you immune to disease/poison? psev = pt->severity; @@ -15097,6 +15357,10 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char (f->lifetime > 0) ) { // extend duration f->lifetime += howlong; + // if applicable, remember what race you got it from + if (srcrace) { + f->val[2] = srcrace->id; + } // announce - announceflaggain won't be called // since this isn't a new flag. if (isplayer(lf)) { @@ -15112,7 +15376,7 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char } if (!found) { - addtempflag(lf->flags, F_POISONED, ptype, power, NA, fromwhat, howlong); + addtempflag(lf->flags, F_POISONED, ptype, power, srcrace ? srcrace->id : NA, fromwhat, howlong); // also apply specific poison effect switch (ptype) { @@ -16490,6 +16754,7 @@ void setbodytype(race_t *r, enum BODYTYPE bt) { addbodypart(r, BP_EYES, NULL); addbodypart(r, BP_EARS, NULL); addbodypart(r, BP_HEAD, NULL); + addbodypart(r, BP_NECK, NULL); addbodypart(r, BP_BODY, NULL); addbodypart(r, BP_LEGS, NULL); addbodypart(r, BP_FEET, "talons"); @@ -16504,6 +16769,7 @@ void setbodytype(race_t *r, enum BODYTYPE bt) { addbodypart(r, BP_EYES, NULL); addbodypart(r, BP_EARS, NULL); addbodypart(r, BP_HEAD, NULL); + addbodypart(r, BP_NECK, NULL); addbodypart(r, BP_BODY, NULL); addbodypart(r, BP_BACKLEGS, "back legs"); addbodypart(r, BP_FRONTLEGS, "front legs"); @@ -17217,6 +17483,10 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) { othermod += 10; } + } else if (ct == SC_LISTEN) { + if (hasequippedobid(lf->pack, OT_AMU_LISTEN)) { + othermod += 20; + } } else if (ct == SC_MORALE) { othermod += (getstatmod(lf, A_WIS) / 30); // ie. -1 to 1 } else if (ct == SC_OPENLOCKS) { @@ -17227,6 +17497,10 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r } else { othermod += (5 * slev); } + + if (hasequippedobid(lf->pack, OT_AMU_THIEF)) { + othermod += 25; + } } else if (ct == SC_POISON) { // auto pass if we are immune if (isimmuneto(lf->flags, DT_POISON, B_FALSE)) { @@ -18747,12 +19021,13 @@ int stone(lifeform_t *lf) { getlfname(lf, lfname); - snprintf(statname, BUFLEN, "statue of a %s", lf->race->name); - addob(lf->cell->obpile, statname); // kill lifeform addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); - addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); + snprintf(statname, BUFLEN, "statue of a %s", lf->race->name); + + killflagsofid(lf->flags, F_CORPSETYPE); + addflag(lf->flags, F_CORPSETYPE, B_TRUE, NA, NA, statname); if (cansee(player, lf)) { msg("^%c%s %s to stone!", getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "turn" : "turns"); @@ -19941,9 +20216,17 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { } else { int howfar; if (isplayer(lf)) { - msg("^bYou slam into the ground!"); + if (isimmuneto(lf->flags, DT_FALL, B_FALSE)) { + msg("You land gently on the ground."); + } else { + msg("^bYou slam into the ground!"); + } } else if (cansee(player, lf)){ - msg("^%c%s slams into the ground!", getlfcol(lf, CC_BAD), lfname); + if (isimmuneto(lf->flags, DT_FALL, B_FALSE)) { + msg("%s lands gently on the ground.", lfname); + } else { + msg("^%c%s slams into the ground!", getlfcol(lf, CC_BAD), lfname); + } } // how far did you fall? sumflags(lf->flags, F_FALLDISTANCE, &howfar, NULL, NULL); @@ -20472,7 +20755,7 @@ int rest(lifeform_t *lf, int onpurpose) { // pass a skill check to regain hp if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) { gainhp(lf, hpheal); - if (isplayer(lf)) { + if (isplayer(lf) && godprayedto(R_GODLIFE)) { pleasegodmaybe(R_GODLIFE, 1); } practice(lf, SK_FIRSTAID, 1); @@ -21313,6 +21596,8 @@ int willburden(lifeform_t *lf, object_t *o, int howmany) { int willeatlf(lifeform_t *eater, lifeform_t *eatee) { if (isplayer(eater)) return B_FALSE; + if (eater == eatee) return B_FALSE; // no self-cannibulism! + // doesn't want to eat if (!lfhasflagval(eater, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL)) { return B_FALSE; diff --git a/lf.h b/lf.h index 44e3792..ac8126a 100644 --- a/lf.h +++ b/lf.h @@ -364,6 +364,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml void losehpeffects(lifeform_t *lf, int dam, enum DAMTYPE damtype, lifeform_t *fromlf, object_t *fromob, int retaliate, int ko, int *waskod, int prelowhp); void losemp(lifeform_t *lf, int amt); void makefriendly(lifeform_t *lf, int howlong); +int makelearnable(lifeform_t *lf, enum SKILL skid); int makenauseated(lifeform_t *lf, int amt, int howlong); void makenoise(lifeform_t *lf, enum NOISETYPE nid); void makepeaceful(lifeform_t *lf, lifeform_t *causedby); @@ -385,7 +386,7 @@ enum NOISECLASS noisetypetoclass(enum NOISETYPE nt); void outfitlf(lifeform_t *lf); void petify(lifeform_t *lf, lifeform_t *owner); int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int antannounce); -void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat); +void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat, enum RACE srcraceid); int poisoncausesvomit(enum POISONTYPE ptype); int poisonthreatenslife(lifeform_t *lf, flag_t *f); void practice(lifeform_t *lf, enum SKILL skid, int amt); diff --git a/map.c b/map.c index 9589122..6f3cbe6 100644 --- a/map.c +++ b/map.c @@ -14,6 +14,7 @@ #include "lf.h" #include "map.h" #include "objects.h" +#include "save.h" #include "text.h" #include "vault.h" @@ -187,7 +188,7 @@ map_t *addmap(void) { // when monsters are made during level generation, autogen will be true. otherwise false; // if "rid" RR_SPECIFIED, parse racename to get the race. // otherwise just use the given race. -lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded) { +lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok, int amt, int autogen, int *nadded) { lifeform_t *lf = NULL; race_t *r; int db = B_FALSE; @@ -271,7 +272,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int lf->born = B_FALSE; if (wantjob == J_NONE) { - if (jobok) { + if (randomjobok) { int nretflags,i; flag_t *retflag[MAXCANDIDATES]; getflags(lf->flags, retflag, &nretflags, F_STARTJOB, F_NONE); @@ -370,26 +371,29 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int // NOTE: because the initial maps (world, heaven, dungeon lev1) are created BEFORE the player, // monsters on these maps will not have their hostility adjusted! if (gamemode == GM_GAMESTARTED) { - // adjust hostility based on player's alignment - switch (getalignment(player)) { - case AL_GOOD: - if (getalignment(lf) == AL_GOOD) { - killflagsofid(lf->flags, F_HOSTILE); - } else if (getalignment(lf) == AL_EVIL) { - if (!lfhasflag(lf, F_HOSTILE)) { - addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + if (hasequippedobid(player->pack, OT_AMU_VICTIM)) { + // everything is hostile. + if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } else { + // adjust hostility based on player's alignment + switch (getalignment(player)) { + case AL_GOOD: + if (getalignment(lf) == AL_GOOD) { + killflagsofid(lf->flags, F_HOSTILE); + } else if (getalignment(lf) == AL_EVIL) { + if (!lfhasflag(lf, F_HOSTILE)) addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); } - } - break; - case AL_EVIL: - if (getalignment(lf) == AL_GOOD) { - if (!lfhasflag(lf, F_HOSTILE)) { - addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + break; + case AL_EVIL: + if (getalignment(lf) == AL_GOOD) { + if (!lfhasflag(lf, F_HOSTILE)) { + addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } } - } - break; - default: - break; + break; + default: + break; + } } } @@ -496,6 +500,8 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + /* + // XXX: temporarily disbled due to slow light code if (db) dbtime("giving torches"); // humanoids on dark levels which can't see will probably have some // kind of light producing device @@ -522,6 +528,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int } } } + */ //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging @@ -4113,6 +4120,15 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r linkexits(map, roomid); } + // remove bones vault files after creation. + if (hasflagval(v->flags, F_VAULTTAG, NA, NA, NA, "bones")) { + removevaultfile(v->filename); + // also mark it as invalid, otherwise we might try + // to create it again, in which case the second call + // to removevaultfile() will fail. + v->valid = B_FALSE; + } + return B_FALSE; } @@ -7225,12 +7241,30 @@ int orthdir(int compassdir) { enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob) { int donesomething; - char *p; + char *p,*suff; job_t *j; + char named[BUFLEN]; + char *localname; + char *namestart; // get params donesomething = B_TRUE; - p = name; + + + // take a local copy so we can strip suffixes off it + if (strstarts(name, "the ")) { + namestart = name + strlen("the "); + } else if (strstarts(name, "an ")) { + namestart = name + strlen("an "); + } else if (strstarts(name, "a ")) { + namestart = name + strlen("a "); + } else { + namestart = name; + } + localname = strdup(namestart); + + + p = localname; while (donesomething) { donesomething = B_FALSE; if (strstarts(p, "sleeping ")) { @@ -7240,13 +7274,35 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum S } } + // try removing suffixes for "named xxx" + strcpy(named, ""); + suff = strends(localname, " named "); + if (suff) { + char *suffp; + char *p2; + // extract the name + p2 = named; + suffp = suff + strlen(" named "); + while (*suffp && (*suffp != ' ')) { + *p2 = *suffp; + suffp++; + p2++; + } + *p2 = '\0'; // nul-terminate name + *suff = '\0'; // strip off suffix from main string + } + if (strlen(named)) { + if (wantflags) addflag(wantflags, F_NAMED, NA, NA, NA, named); + donesomething = B_TRUE; + } + // try removing suffixes for jobs for (j = firstjob ; j ; j = j->next) { char *ep; char jobname[BUFLEN]; snprintf(jobname, BUFLEN, " %s", j->name); jobname[1] = tolower(jobname[1]); - ep = strends(name, jobname); + ep = strends(localname, jobname); if (ep) { // got it if (wantjob) *wantjob = j->id; @@ -7260,28 +7316,28 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum S int foundsubjob = B_FALSE; // search for subjob names char *ep; - ep = strends(name, "Skymage"); + ep = strends(localname, "Skymage"); if (ep && !foundsubjob) { if (wantjob) *wantjob = J_WIZARD; if (wantsubjob) *wantsubjob = SJ_AIRMAGE; *ep = '\0'; foundsubjob = B_TRUE; } - ep = strends(name, "Icemage"); + ep = strends(localname, "Icemage"); if (ep && !foundsubjob) { if (wantjob) *wantjob = J_WIZARD; if (wantsubjob) *wantsubjob = SJ_ICEMAGE; *ep = '\0'; foundsubjob = B_TRUE; } - ep = strends(name, "Firemage"); + ep = strends(localname, "Firemage"); if (ep && !foundsubjob) { if (wantjob) *wantjob = J_WIZARD; if (wantsubjob) *wantsubjob = SJ_FIREMAGE; *ep = '\0'; foundsubjob = B_TRUE; } - ep = strends(name, "Necromancer"); + ep = strends(localname, "Necromancer"); if (ep && !foundsubjob) { if (wantjob) *wantjob = J_WIZARD; if (wantsubjob) *wantsubjob = SJ_NECROMANCER; @@ -7291,6 +7347,8 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum S } + free(localname); + // now get raceid if (streq(p, "random")) { return R_RANDOM; diff --git a/map.h b/map.h index 6ecab4e..1d9be2c 100644 --- a/map.h +++ b/map.h @@ -4,7 +4,7 @@ cell_t *addcell(map_t *map, int x, int y); habitat_t *addhabitat(enum HABITAT id, char *name, enum CELLTYPE emptycell, enum CELLTYPE solidcell, int thingchance, int obchance, int vaultchance, int maxvisrange, enum OBTYPE upstairtype, enum OBTYPE downstairtype); void addhomeobs(lifeform_t *lf); map_t *addmap(void); -lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int amt, int autogen, int *nadded); +lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok, int amt, int autogen, int *nadded); object_t *addrandomob(cell_t *c); int addrandomthing(cell_t *c, int obchance, int *nadded); region_t *addregion(enum REGIONTYPE rtype, region_t *parent, int outlineid, int depthmod, int createdby); diff --git a/move.c b/move.c index 5f547e9..b1640ba 100644 --- a/move.c +++ b/move.c @@ -1046,34 +1046,37 @@ int moveclear(lifeform_t *lf, int dir, enum ERROR *error) { } -// effects which happen after player moves. +// effects which happen _after_ player moves or attacks. // IMPORTANT: don't modify lf's flagpile during this code! // particularly don't remove flags... // returns TRUE if we displayed a message -int moveeffects(lifeform_t *lf) { +int moveeffects(lifeform_t *lf, int moved) { flag_t *f; int didmsg = B_FALSE; - if (lfhasflagval(lf, F_INJURY, IJ_HAMSTRUNG, NA, NA, NULL)) { - if (!skillcheck(lf, SC_FALL, 18, 0)) { + // effects which only happen if you actually moved (not attacked) + if (moved) { + if (lfhasflagval(lf, F_INJURY, IJ_HAMSTRUNG, NA, NA, NULL)) { + if (!skillcheck(lf, SC_FALL, 18, 0)) { + fall(lf, NULL, B_TRUE); + if (isplayer(lf)) didmsg = B_TRUE; + } + } + if (onein(10) && lfhasflagval(lf, F_INJURY, IJ_TAILLACERATED, NA, NA, NULL)) { fall(lf, NULL, B_TRUE); if (isplayer(lf)) didmsg = B_TRUE; } - } - if (onein(10) && lfhasflagval(lf, F_INJURY, IJ_TAILLACERATED, NA, NA, NULL)) { - fall(lf, NULL, B_TRUE); - if (isplayer(lf)) didmsg = B_TRUE; - } - if (isbleeding(lf)) { - if (hasbleedinginjury(lf, BP_LEGS)) { - if (!bleedfrom(lf, BP_LEGS, B_FALSE)) { - if (isplayer(lf)) msg("^BYou bleed!"); - losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); - } - } else { - if (rnd(1,2) == 1) { - bleed(lf, B_FALSE); + if (isbleeding(lf)) { + if (hasbleedinginjury(lf, BP_LEGS)) { + if (!bleedfrom(lf, BP_LEGS, B_FALSE)) { + if (isplayer(lf)) msg("^BYou bleed!"); + losehp(lf, 1, DT_DIRECT, NULL, "blood loss"); + } + } else { + if (rnd(1,2) == 1) { + bleed(lf, B_FALSE); + } } } } @@ -1137,6 +1140,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { //vault_t *v; flag_t *retflag[MAXCANDIDATES]; int nretflags,i; + int autoangry = B_FALSE; assert(newcell); @@ -1259,7 +1263,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { needredraw = B_TRUE; } - didmsg = moveeffects(lf); + didmsg = moveeffects(lf, B_TRUE); if (lfhasflag(lf, F_HIDING) && (getskill(lf, SK_STEALTH) < PR_BEGINNER)) { killflagsofid(lf->flags, F_HIDING); @@ -1454,6 +1458,11 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } } + // amulet of victimisation? + if (hasequippedobid(lf->pack, OT_AMU_VICTIM)) { + autoangry = B_TRUE; + } + // does anyone else see you? for (l = newcell->map->lf ; l ; l = l->next) { if (l != lf) { @@ -1461,6 +1470,10 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (cansee(l, lf)) { int dointerrupt = B_FALSE; + if (autoangry && !isplayer(l) && !lfhasflag(l, F_HOSTILE)) { + addflag(l->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } + // much larger creatures moving will cause our los to be recalculated if (getlfsize(lf) - getlfsize(l) >= 2) { setlosdirty(l); diff --git a/move.h b/move.h index 2a785ba..0cd7837 100644 --- a/move.h +++ b/move.h @@ -16,7 +16,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc int makeorthogonal(int dir); int moveawayfrom(lifeform_t *lf, cell_t *dst, int dirtype, int keepinlof, int strafe); int moveclear(lifeform_t *lf, int dir, enum ERROR *error); -int moveeffects(lifeform_t *lf); +int moveeffects(lifeform_t *lf, int moved); int movelf(lifeform_t *lf, cell_t *newcell); int movelfsoutofway(cell_t *newcell); int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg); diff --git a/nexus.c b/nexus.c index e8b9e8c..017cc71 100644 --- a/nexus.c +++ b/nexus.c @@ -824,8 +824,12 @@ void donextturn(map_t *map) { o = findobidinmap(who->cell->map, atol(f->text)); } if (o && caneat(who, o) && (getoblocation(o) == who->cell)) { - eat(who,o); - donormalmove = B_FALSE; + if (eat(who,o)) { + // failed + killflag(f); + } else { + donormalmove = B_FALSE; + } } else { killflag(f); } diff --git a/objects.c b/objects.c index 675cec1..09a3106 100644 --- a/objects.c +++ b/objects.c @@ -80,6 +80,7 @@ enum OBCLASS sortorder[] = { OC_WAND, OC_FOOD, OC_CORPSE, + OC_AMULET, OC_RING, OC_TECH, OC_TOOLS, @@ -227,6 +228,27 @@ char *ringadjective[] = { "", }; +char *amuletadjective[] = { + "chipped", + "dusty", + "grotesque", + "lurid", + "mysterious", + "polished", + "twisted", + "", +}; + +char *amuletnoun[] = { + "charm", + "locket", + "medallion", + "necklace", + "pendant", + "talisman", + "", +}; + long nextoid = 0; brand_t *addbrand(enum BRAND id, char *suffix, enum BODYPART bp, enum BLESSTYPE blessed, int blesschance) { @@ -454,11 +476,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes int wantblessed = B_UNCURSED; race_t *corpserace = NULL; int dorandombrand = B_FALSE; + char wantnamed[BUFLEN]; brand_t *wantbrand = NULL; brand_t *br; obmod_t *om; obmod_t *wantom[MAXOBMODS]; int wanthot = B_FALSE; + int wanthppct = 100; regionthing_t *wantregionthing = NULL; int bonus = 0; int nom = 0; @@ -492,6 +516,8 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes nadded = 0; nretobs = 0; + strcpy(wantnamed, ""); + if ((gamemode == GM_GAMESTARTED) && where->where) { assert(!where->where->type->solid); } @@ -510,13 +536,42 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } } else { char *bonusstart,*p2; + char *namestart; int bonussign = 1; - localname = strdup(name); + + if (strstarts(name, "the ")) { + namestart = name + strlen("the "); + } else if (strstarts(name, "an ")) { + namestart = name + strlen("an "); + } else if (strstarts(name, "a ")) { + namestart = name + strlen("a "); + } else { + namestart = name; + } + + localname = strdup(namestart); if (db) { dblog("DB: called addobject() for %s, canstack = %d",localname, canstack); } + // check if we want a name. if so, remember it and strip off the suffix. + p2 = strstr(localname, " named "); + if (p2) { + char *wantp; + char *copyfrom; + copyfrom = p2 + strlen(" named "); + wantp = wantnamed; + while (*copyfrom && (*copyfrom != ' ')) { + *wantp = *copyfrom; + copyfrom++; + wantp++; + } + *wantp = '\0'; + // now strip the suffix + *p2 = '\0'; + } + // check for premods. eg. "flaming xxx" "frozen xxx" etc for (om = firstobmod ; om ; om = om->next) { if (db) dblog("DB: checking for '%s' in '%s'",om->prefix, localname); @@ -526,6 +581,18 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes wantom[nom] = om; nom++; + } else { + // check altprefixes. + int i; + for (i = 0; i < om->naltprefix; i++) { + if (strstr(localname, om->altprefix[i])) { + localname = strrep(localname, om->altprefix[i], "", NULL); + if (db) dblog("DB: found obmod altprefix '%s'",om->altprefix[i]); + wantom[nom] = om; + nom++; + break; + } + } } } @@ -642,6 +709,27 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes wanthot = B_TRUE; p += strlen("red-hot "); donesomething = B_TRUE; + // condition flags + } else if (strstarts(p, "battered ")) { + wanthppct = 75; + canstack = B_FALSE; + p += strlen("battered "); + donesomething = B_TRUE; + } else if (strstarts(p, "damaged ")) { + wanthppct = 50; + canstack = B_FALSE; + p += strlen("damaged "); + donesomething = B_TRUE; + } else if (strstarts(p, "very damaged ")) { + wanthppct = 25; + canstack = B_FALSE; + p += strlen("very damaged "); + donesomething = B_TRUE; + } else if (strstarts(p, "critically damaged ")) { + wanthppct = 10; + canstack = B_FALSE; + p += strlen("critically damaged "); + donesomething = B_TRUE; // armour flags } else if (strstarts(p, "gargantuan ")) { wantarmsize = SZ_ENORMOUS; @@ -747,6 +835,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes if (onein(4)) dorandombrand = B_TRUE; p += strlen("excellent "); donesomething = B_TRUE; + // object names // brands } else if (strstarts(p, "branded ")) { dorandombrand = B_TRUE; @@ -1233,6 +1322,18 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes changemat(o, wantdiffmat); } + if (strlen(wantnamed)) { + addflag(o->flags, F_NAMED, NA, NA, NA, wantnamed); + } + + if (wanthppct != 100) { + f = hasflag(o->flags, F_OBHP); + if (f) { + f->val[0] = pctof(wanthppct, f->val[1]); + limit(&(f->val[0]), 1, f->val[1]); + } + } + // extra chance of bone items being cursed if (o->type->material->id == MT_BONE) { if (pctchance(15)) { @@ -1970,6 +2071,7 @@ obmod_t *addobmod(enum OBMOD id, char *prefix) { a->id = id; snprintf(buf, BUFLEN, "%s ",prefix); a->prefix = strdup(buf); + a->naltprefix = 0; a->flags = addflagpile(NULL, NULL); @@ -1993,6 +2095,18 @@ obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob) { return op; } +void addomprefix(enum OBMOD id, char *altprefix) { + char buf[BUFLEN]; + obmod_t *om; + om = findobmod(id); + assert(om); + assert(om->naltprefix < MAXOMPREFIXES); + + snprintf(buf, BUFLEN, "%s ",altprefix); + om->altprefix[om->naltprefix] = strdup(buf); + om->naltprefix++; +} + void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes) { cell_t *cell[MAXCANDIDATES],*c; int ncells,i; @@ -5311,6 +5425,13 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } } + // show NAMED + f = hasflag(o->flags, F_NAMED); + if (f) { + strcat(localbuf, " named "); + strcat(localbuf, f->text); + } + // append inscription if (o->inscription) { strcat(localbuf, " {"); @@ -8212,6 +8333,14 @@ int obfits(object_t *o, obpile_t *op) { return B_TRUE; } +int obgoesinbones(object_t *o) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags = 0; + getflags(o->flags, retflag, &nretflags, F_CLIMBABLE, F_TRAIL, F_UNIQUE, F_NONE); + if (nretflags) return B_FALSE; + return B_TRUE; +} + enum DAMTYPE oblastdamtype(object_t *o) { flag_t *f; f = hasflag(o->flags, F_LASTDAMTYPE); @@ -8435,11 +8564,13 @@ int obsfallthrough(cell_t *c, object_t *pit) { } // fall through! - if (haslos(player, c)) { - // player can see the top of the hole - getobname(oo,obname, oo->amt); - msg("%s %s%s through %s.", obname, verb, OBS1(oo), - downholename); + if (gamemode == GM_GAMESTARTED) { + if (haslos(player, c)) { + // player can see the top of the hole + getobname(oo,obname, oo->amt); + msg("%s %s%s through %s.", obname, verb, OBS1(oo), + downholename); + } } nfallen++; @@ -8452,10 +8583,12 @@ int obsfallthrough(cell_t *c, object_t *pit) { oo = moveob(oo, belowcell->obpile, oo->amt); - if (haslos(player, belowcell)) { - // player can see the bottom of the hole - getobname(oo,obname, oo->amt); - msg("%s %s%s through %s.", obname, verb, OBS1(oo), upholename); + if (gamemode == GM_GAMESTARTED) { + if (haslos(player, belowcell)) { + // player can see the bottom of the hole + getobname(oo,obname, oo->amt); + msg("%s %s%s through %s.", obname, verb, OBS1(oo), upholename); + } } // does the object hit anyone? @@ -8464,7 +8597,7 @@ int obsfallthrough(cell_t *c, object_t *pit) { char dambuf[BUFLEN]; lf = belowcell->lf; - if (canseebelowlf) { + if ((gamemode == GM_GAMESTARTED) && canseebelowlf) { char lfname[BUFLEN]; getobname(oo,obname, oo->amt); getlfname(lf, lfname); @@ -10253,7 +10386,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } break; case OT_POT_POISON: - poison(lf, rnd(10,20), P_FOOD, 1, "a potion of poison"); + poison(lf, rnd(10,20), P_FOOD, 1, "a potion of poison", R_NONE); break; case OT_POT_POLYMORPH: if (potblessed == B_BLESSED) { @@ -11006,7 +11139,11 @@ int readsomething(lifeform_t *lf, object_t *o) { // manuals f = hasflag(o->flags, F_MANUALOF); if (f) { - giveskill(lf, f->val[0]); + if (ismaxedskill(lf, f->val[0])) { + if (isplayer(lf)) msg("This manual is too advanced for you."); + } else { + giveskill(lf, f->val[0]); + } } if (isplayer(lf)) { msg("The book crumbles to dust."); @@ -13346,7 +13483,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { } } if (!avoided) { - poison(lf, rnd(10,20), P_VENOM, 1, "a needle trap"); + poison(lf, rnd(10,20), P_VENOM, 1, "a needle trap", R_NONE); } } else { if (haslos(player, c)) { diff --git a/objects.h b/objects.h index 2c6a044..66ce3c8 100644 --- a/objects.h +++ b/objects.h @@ -15,6 +15,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes int addobburst(cell_t *where, int range, int dirtype, char *name, lifeform_t *fromlf, enum LOFTYPE needlof); obmod_t *addobmod(enum OBMOD id, char *prefix); obpile_t *addobpile(lifeform_t *owner, cell_t *where, object_t *parentob); +void addomprefix(enum OBMOD id, char *altprefix); void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int allowdupes); objecttype_t *addot(enum OBTYPE id, char *name, char *description, int material, float weight, int obclassid, enum LFSIZE size); recipe_t *addrecipe(enum OBTYPE result, ...); @@ -243,6 +244,7 @@ void obaction(object_t *o, char *text); object_t *obexists(enum OBTYPE obid); void obdie(object_t *o); int obfits(object_t *o, obpile_t *op); +int obgoesinbones(object_t *o); enum DAMTYPE oblastdamtype(object_t *o); int brandappliesto(brand_t *om, objecttype_t *ot); int obmatchescondition(object_t *o, long opts); diff --git a/save.c b/save.c index 60b2818..5a75e32 100644 --- a/save.c +++ b/save.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -767,6 +768,141 @@ int loadworlddata(FILE *f) { return B_FALSE; } +int removevaultfile(char *filename) { + if (unlink(filename)) { + msg("ERROR: Could not unlink bones file after creation ('%s')", filename); + dblog("ERROR: Could not unlink bones file after creation ('%s')", filename); + return B_TRUE; + } + return B_FALSE; +} + +// dynamically create a temporary vault file based on the given room. +int savebones(map_t *m, room_t *r) { + cell_t *c; + int x,y; + FILE *f; + char filename[BUFLEN]; + DIR *dp; + struct dirent *ep; + int maxid = 0, bonesid; + celltype_t *ct; + char ch; + char nextch = 'a'; + celltype_t *legendct[MAXCANDIDATES]; + char legendch[MAXCANDIDATES]; + int nlegends = 0,n; + + // get list of existing bones files + dp = opendir(BONESDIR); + if (dp != NULL) { + while ((ep = readdir(dp)) != NULL) { + char thisname[BUFLEN]; + char *p; + strcpy(thisname, ep->d_name); + p = strstr(thisname, "bones"); + if (p) { + char numbuf[BUFLEN]; + char *np; + int thisid; + p += 5; + for (np = numbuf; isdigit(*p); p++, np++) { + *np = *p; + } + *np = '\0'; + thisid = atoi(numbuf); + if (thisid > maxid) maxid = thisid; + } + } + closedir(dp); + } + + bonesid = maxid + 1; + + snprintf(filename, BUFLEN, "%s/bones%d.vlt",BONESDIR, bonesid); + f = fopen(filename, "wt"); + if (!f) { + msg("Could not write bones file '%s'!", filename); + return B_TRUE; + } + + fprintf(f, "@id:bones%d\n", bonesid); + + fprintf(f, "@map\n"); + for (y = r->y1; y <= r->y2; y++) { + for (x = r->x1; x <= r->x2; x++) { + c = getcellat(m, x, y); + // do we already ahve a legend entry for this celltype? + ct = NULL; + ch = '\0'; + for (n = 0; n < nlegends; n++ ){ + if (legendct[n] == c->type) { + ch = legendch[n]; + break; + } + } + if (ch == '\0') { + ch = nextch; + legendct[nlegends] = c->type; + legendch[nlegends] = ch; + nlegends++; + if (nextch == 'z') nextch = 'A'; + else if (nextch == 'Z') nextch = '0'; + else nextch++; + } + // wall + fprintf(f, "%c", ch); + } + fprintf(f, "\n"); + } + fprintf(f, "@end\n"); + fprintf(f, "@legend\n"); + for (n = 0; n < nlegends; n++){ + fprintf(f, "%c:cell:%s\n",legendch[n], legendct[n]->name); + } + fprintf(f, "@end\n"); + fprintf(f, "@flags\n"); + // contents... + for (y = r->y1; y <= r->y2; y++) { + for (x = r->x1; x <= r->x2; x++) { + c = getcellat(m, x, y); + if (c) { + object_t *o; + int relx,rely; + relx = x - r->x1; + rely = y - r->y1; + + if (c->lf) { + if (isplayer(c->lf)) { + // the lf's objects will appear in the bones file + for (o = c->lf->pack->first; o ; o = o->next) { + saveobtobones(o, f, relx, rely); + } + } else { + // the lf will appear in the bones file + char lfname[BUFLEN]; + real_getlfname(c->lf, lfname, B_FALSE, B_TRUE); + fprintf(f, "at(%d,%d) lf:%s\n", relx,rely, lfname); + } + } + for (o = c->obpile->first ; o ; o = o->next) { + saveobtobones(o, f, relx, rely); + } + } + } + } + // other flags. + fprintf(f, "tag:bones\n"); + fprintf(f, "maintainedge\n"); + fprintf(f, "rarity:frequent\n"); + fprintf(f, "goesin:%s\n", m->habitat->name); + fprintf(f, "dlevmin:%d\n", m->depth); + fprintf(f, "dlevmax:%d\n", m->depth); + fprintf(f, "@end\n"); + fclose(f); + return B_FALSE; +} + int saveflagpile(FILE *f, flagpile_t *fp) { flag_t *fl; fprintf(f, "flags:\n"); @@ -1018,6 +1154,35 @@ int saveob(FILE *f, object_t *o) { return B_FALSE; } +int saveobtobones(object_t *o, FILE *f, int x, int y) { + char obname[BUFLEN]; + if (!obgoesinbones(o)) return B_TRUE; + + // modify the object? + if (hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL)) { + // food will decay by the time someone else finds it. + return B_TRUE; + } + if (isweapon(o) || isarmour(o)) { + // weapons/armour might degrade in quality + if (hasflag(o->flags, F_MASTERWORK)) { + // masterwork -> normal + killflagsofid(o->flags, F_MASTERWORK); + } else { + if (onein(3)) { + applyobmod(o, findobmod(OM_SHODDY)); + } + if (onein(3) && ismetal(o->material->id)) { + addflag(o->flags, F_RUSTED, R_RUSTY, NA, NA, NULL); + } + } + } + + getobnametrue(o, obname, o->amt); + fprintf(f, "at(%d,%d) ob:%s\n", x,y, obname); + return B_FALSE; +} + int saveregions(FILE *f) { int i; regionoutline_t *ro; diff --git a/save.h b/save.h index 58d63c3..342e408 100644 --- a/save.h +++ b/save.h @@ -9,12 +9,15 @@ int loadob(FILE *f, obpile_t *op, long *id); int loadregions(FILE *f); int loadsavegame(void); int loadworlddata(FILE *f); +int removevaultfile(char *filename); +int savebones(map_t *m, room_t *r); int saveflagpile(FILE *f, flagpile_t *fp); int saveknowledge(FILE *f); int savelf(FILE *f, lifeform_t *l); int savegame(void); int savemap(FILE *f, map_t *m); int saveob(FILE *f, object_t *o); +int saveobtobones(object_t *o, FILE *f, int x, int y); int saveregions(FILE *f); int saveworlddata(FILE *f); int showhiscores(lifeform_t *lf, int min, int max); diff --git a/spell.c b/spell.c index c678260..c5d7e64 100644 --- a/spell.c +++ b/spell.c @@ -231,7 +231,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef getobname(stairs, obname, 1); sprintf(buf, "How will you check %s", obname); initprompt(&prompt, buf); - if ((getskill(user, SK_LISTEN) >= PR_ADEPT) && !isdeaf(user)) { + if ( ((getskill(user, SK_LISTEN) >= PR_ADEPT) && !isdeaf(user)) || + hasequippedobid(user->pack, OT_AMU_THIEF)) { addchoice(&prompt, 'l', "Listen for sounds", NULL, NULL, NULL); } if ((getskill(user, SK_PERCEPTION)) && !isblind(user)) { @@ -612,8 +613,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } if (corpse) { + getobname(corpse, obname, o->amt); if (isimmuneto(corpse->flags, DT_FIRE, B_FALSE)) { - msg("You attempt to cook %s, but it won't heat up."); + msg("You attempt to cook %s, but it won't heat up.", obname); cooktime += getactspeed(user); ncooked++; } else { @@ -4407,7 +4409,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else { if (haslos(player, targcell)) { - msg("A bolt of electricity shoots out of the air!"); + msg("A bolt of electricity arcs out of the air!"); } } @@ -7764,7 +7766,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("A glob of venom hits %s.",lfname); } if (!isimmuneto(target->flags, DT_POISON, B_FALSE)) { - poison(target, power*3, P_VENOM, (power/4)+1, "a glob of venom"); + poison(target, power*3, P_VENOM, (power/4)+1, "a glob of venom", caster ? caster->race->id : R_NONE); } } } @@ -12274,6 +12276,9 @@ int getworkablematerials(lifeform_t *lf, enum SKILL skid , enum MATERIAL *repair repairablemats[*nmats] = MT_LEATHER; cutoffpct[*nmats] = cutoff; (*nmats)++; + repairablemats[*nmats] = MT_FLESH; + cutoffpct[*nmats] = cutoff; + (*nmats)++; nworkable += 2; } } diff --git a/text.c b/text.c index c1e1093..cf6139b 100644 --- a/text.c +++ b/text.c @@ -1111,7 +1111,7 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d int canbehead = B_TRUE; if (wep) { sk = getobskill(wep->flags); - if (sk->id == SK_SHORTBLADES) { + if (sk && (sk->id == SK_SHORTBLADES)) { // short blades can't behead/bisect. canbehead = B_FALSE; } @@ -1203,6 +1203,9 @@ char *getinjurydesc(enum BODYPART where, enum DAMTYPE dt) { return ""; } +// IMPORTANT: +// all strings returned here must also be defined as an obmod altprefix! +// char *getobmodprefix(object_t *o, obmod_t *om) { // masterwork/shoddy doors have names based on material. if (isdoor(o, NULL)) { diff --git a/vault.c b/vault.c index b84b91e..c926866 100644 --- a/vault.c +++ b/vault.c @@ -1498,6 +1498,7 @@ void killvault(vault_t *v) { if (!v) return; if (v->id) free(v->id); + if (v->filename) free(v->filename); while (v->legend) { killlegend(v->legend); } @@ -1524,19 +1525,19 @@ void killvault(vault_t *v) { } } -vault_t *loadvault(char *filename) { +vault_t *loadvault(char *dir, char *filename) { FILE *f; vault_t *v; char line[BUFLEN]; char fullname[BUFLEN]; int goterrors = B_FALSE; - snprintf(fullname, BUFLEN, "%s/%s", VAULTDIR, filename); + snprintf(fullname, BUFLEN, "%s/%s", dir, filename); dblog("Loading vault file '%s'", fullname); f = fopen(fullname,"rt"); if (!f) { - dblog("error opening vault file '%s'", fullname); + dblog("error opening vault file '%s/%s'", dir,fullname); return NULL; } @@ -1545,7 +1546,7 @@ vault_t *loadvault(char *filename) { dblog("error allocating new vault"); return NULL; } - v->filename = strdup(filename); + asprintf(&v->filename, "%s/%s",dir,filename); v->state = VS_NOID; @@ -1576,34 +1577,45 @@ vault_t *loadvault(char *filename) { } void loadvaults(void) { - int nvaults = 0; - DIR *dir; - struct dirent *ent; + char *vaultdir[2]; + int i; + // - dir = opendir(VAULTDIR); - if (!dir) { - dblog("Could not open vault directory '%s'",VAULTDIR); - return; - } - nvaults = 0; - while ((ent = readdir(dir)) != NULL) { - char *p; - // ie. start of 4 char prefix - p = ent->d_name + strlen(ent->d_name) - 4; - if (!strcmp(p, ".vlt") ) { - if (loadvault(ent->d_name)) { - nvaults++; - } else { - dblog("Errors found in vaultfile %s - loading cancelled.",ent->d_name); + vaultdir[0] = strdup(VAULTDIR); + vaultdir[1] = strdup(BONESDIR); + for (i = 0; i < 2; i++) { + int nvaults = 0; + DIR *dir; + struct dirent *ent; + dir = opendir(vaultdir[i]); + if (!dir) { + dblog("Could not open vault directory '%s'",vaultdir[i]); + return; + } + nvaults = 0; + while ((ent = readdir(dir)) != NULL) { + char *p; + // ie. start of 4 char prefix + p = ent->d_name + strlen(ent->d_name) - 4; + if (!strcmp(p, ".vlt") ) { + if (loadvault(vaultdir[i], ent->d_name)) { + nvaults++; + } else { + dblog("Errors found in vaultfile %s - loading cancelled.",ent->d_name); + } } } + closedir(dir); + if (nvaults) { + dblog("Successfully loaded %d %s definition%s.", nvaults, + (i == 0) ? "fixed vault" : "bones vault", + (nvaults == 1) ? "" : "s"); + } else { + dblog("No (valid) vault definitions found.", nvaults); + } } - closedir(dir); - if (nvaults) { - dblog("Successfully loaded %d vault definition%s.", nvaults,(nvaults == 1) ? "" : "s"); - } else { - dblog("No (valid) vault definitions found.", nvaults); - } + free(vaultdir[0]); + free(vaultdir[1]); // debugging //dumpvault("jimbos_lair", 0); diff --git a/vault.h b/vault.h index ce72dfa..ac202bf 100644 --- a/vault.h +++ b/vault.h @@ -23,7 +23,7 @@ char getvaultchar(vault_t *v, int x, int y, int rotation, int *map0offset); vault_t *getvaulttype(map_t *m); int handleline(vault_t *v, char *line); void killvault(vault_t *v); -vault_t *loadvault(char *filename); +vault_t *loadvault(char *dir, char *filename); void loadvaults(void); void rotatecoords(int *x, int *y, vault_t *v, int rotation, int *retoffset); int vaultthingok(enum VAULTTHING vt, char *what);