diff --git a/ai.c b/ai.c index 366fd1b..6e7273f 100644 --- a/ai.c +++ b/ai.c @@ -1198,6 +1198,7 @@ int ai_housekeeping(lifeform_t *lf, lifeform_t *master) { msgnocap("%c - %s", o->letter, obname); } // no longer an ally + killflagsofid(lf->flags, F_FRIENDLY); killflagsofid(lf->flags, F_PETOF); killflagsofid(lf->flags, F_ISPRISONER); } @@ -1362,7 +1363,7 @@ int ai_inventory_mgt(lifeform_t *lf, int *canattack) { } // do we have a better one? for (o = lf->pack->first ; o ; o = o->next) { - if (!isdangerousob(o, lf, B_TRUE) && canwear(lf, o, BP_NONE) && isbetterarmourthan(o, curarm)) { + if (!isdangerousob(o, lf, B_TRUE) && canwear(lf, o, bp) && isbetterarmourthan(o, curarm)) { // wear this armour instead if (!wear(lf, o)) return B_TRUE; } @@ -1399,6 +1400,7 @@ int ai_movement(lifeform_t *lf) { if (lfhasflag(lf, F_DEBUG)) db = B_TRUE; if (lfhasflagval(lf, F_DOESNTMOVE, NA, NA, B_TRUE, NULL)) return B_FALSE; + if (isimmobile(lf)) return B_FALSE; // do we have a target cell? c = aigettargetcell(lf, &f); diff --git a/attack.c b/attack.c index 8d95356..eecae1f 100644 --- a/attack.c +++ b/attack.c @@ -20,6 +20,8 @@ extern lifeform_t *player; extern lifeform_t *godlf[]; +extern prompt_t prompt; + extern int needredraw; extern int statdirty; @@ -340,12 +342,46 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } }; } else { - // otehr attackable ob here? - o = hasobwithflag(c->obpile, F_ATTACKABLE); - - if (o) { + object_t *poss[MAXPILEOBS]; + int nposs = 0; + for (o = c->obpile->first ; o ; o = o->next) { + if (hasflag(o->flags, F_ATTACKABLE)) { + poss[nposs++] = o; + } + } + if (nposs == 1) { attacktype = AT_OB; - attacktarget = o; + attacktarget = poss[0]; + } else if (nposs) { + o = NULL; + if (isplayer(lf) && !lfhasflag(lf, F_HURRICANESTRIKE)) { + // ask which one to attack + char ch = 'a'; + initprompt(&prompt, "What will you attack?"); + for (i = 0; i < nposs; i++) { + char obname[BUFLEN]; + getobname(poss[i], obname, poss[i]->amt); + addchoice(&prompt, ch, obname, obname, o, NULL); + if (ch == 'z') ch = 'A'; + else ch++; + } + addchoice(&prompt, '-', "(nothing)", "(nothing)", NULL, NULL); + prompt.maycancel = B_TRUE; + + ch = getchoice(&prompt); + if (ch != '\0') o = (object_t *)prompt.result; + } else { + // pick one randomly + o = poss[rnd(0,nposs-1)]; + } + + if (o) { + attacktype = AT_OB; + attacktarget = o; + } else { + if (isplayer(lf)) msg("Cancelled."); + return B_TRUE; + } } else { if (!lfhasflag(lf, F_HURRICANESTRIKE)) { if (c->type->solid) { @@ -1165,7 +1201,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (lf->race->raceclass->id == RC_GOD) { flag_t *gf; gf = lfhasflag(lf, F_GODOF); - if (gf->val[0] == B_FEMALE) { + if (getgender(lf) == G_FEMALE) { strcat(attackername2, " the Goddess of "); } else { strcat(attackername2, " the God of "); @@ -1316,7 +1352,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // critical hit effects if (critical && damtypecausescriteffects(damtype[0])) { - criticalhit(lf, victim, critpos, dam[0], damtype[0]); + criticalhit(lf, victim, critpos, wep, dam[0], damtype[0]); } // confer flags from attacker? @@ -1645,6 +1681,36 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { } } + // still not dead? more checks + if (!isdeadob(o)) { + f = hasflag(o->flags, F_TRAPPED); + if (f && pctchance(75)) { + doobtraps(o, lf); + } else { + // if a trap didn't go off, you might break the lock + f = hasflag(o->flags, F_LOCKED); + if (f) { + int difficulty; + int unlockit = B_FALSE; + difficulty = f->val[0]; + if (rnd(0,getattr(lf, A_STR)) + dam[0] >= difficulty) { + // hit it hard enough + unlockit = B_TRUE; + } else if ( pctchance(dam[0]*3)) { + // did enough damage + unlockit = B_TRUE; + } + if (unlockit) { + // lock breaks! + if (isplayer(lf)) { + msg("You break the lock!"); + } + killflagsofid(o->flags, F_LOCKED); + } + } + } + + } return B_FALSE; } @@ -1832,7 +1898,7 @@ int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE da return B_FALSE; } -void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int dam, enum DAMTYPE damtype) { +void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, object_t *wep, int dam, enum DAMTYPE damtype) { object_t *o,*armour; int protected = B_FALSE; char lfname[BUFLEN],victimname[BUFLEN]; @@ -1890,7 +1956,18 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int d num = countflagsofid(victim->race->flags, F_CANSEVER); if (victim->race->id == R_HYDRA) { - growhydrahead(victim, B_TRUE); + int regrow = B_TRUE; + if (wep) { + if (hasflag(wep->flags, F_ONFIRE) || (wep->material->id == MT_SILVER)) { + regrow = B_FALSE; + } + } + if (regrow) { + growhydrahead(victim, B_TRUE); + } else { + // lose a head + losehydrahead(victim); + } } else { sprintf(dambuf, "a severed %s", bpname); losehp(victim, pctof(100/num, victim->maxhp), DT_DIRECT, lf, dambuf); diff --git a/attack.h b/attack.h index 298fbff..ecb31b7 100644 --- a/attack.h +++ b/attack.h @@ -9,7 +9,7 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag); enum DAMTYPE basedamagetype(enum DAMTYPE dt); int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname); //void confereffects(flagpile_t *fp, lifeform_t *victim); -void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int dam, enum DAMTYPE damtype); +void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, object_t *wep, int dam, enum DAMTYPE damtype); int damtypecausesbleed(enum DAMTYPE dt); int damtypecausescriteffects(enum DAMTYPE dt); int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype); diff --git a/data.c b/data.c index 3a6bafd..3e13066 100644 --- a/data.c +++ b/data.c @@ -299,7 +299,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 potions of healing"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "lockpick"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "rope"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "nylon rope"); // initial skills addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); @@ -493,6 +493,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 loaf of stale bread"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 cheese"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of sandals"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "nylon rope"); // initial skills addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_BEGINNER, NA, NULL); @@ -1271,7 +1272,7 @@ void initobjects(void) { addbrand(BR_ANTIMAG, "of antimagic", BP_SHOULDERS, B_UNCURSED, 0); addflag_real(lastbrand->flags, F_EQUIPCONFER, F_RESISTMAG, 10, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_SHADOWS, "of shadows", BP_SHOULDERS, B_UNCURSED, 0); - addflag_real(lastbrand->flags, F_EQUIPCONFER, F_CANWILL, OT_A_DARKWALK, NA, NULL, PERMENANT, B_UNKNOWN, -1); + addflag_real(lastbrand->flags, F_EQUIPCONFER, F_SHADOWED, 2, NA, NULL, PERMENANT, B_UNKNOWN, -1); // body addbrand(BR_HEALTH, "of health", BP_BODY, B_UNCURSED, 0); @@ -1481,7 +1482,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_OBHP, 50, 50, NA, NULL); addflag(lastobjectclass->flags, F_OBHPDRAIN, 1, DT_DECAY, NA, NULL); // ie. corpses last for 50 turns - addoc(OC_TECH, "Technology", "A strange piece of futuristic technology.", '[', C_GREY, RR_RARE); + addoc(OC_TECH, "Technology", "A strange piece of futuristic technology.", '[', C_GREY, RR_UNCOMMON); addocnoun(lastobjectclass, "technology"); addocnoun(lastobjectclass, "tech"); addflag(lastobjectclass->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); @@ -1524,6 +1525,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANBELOCKED, 20, 5, NA, NULL); addflag(lastot->flags, F_CANBETRAPPED, 5, 10, 60, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); @@ -1543,6 +1545,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANBETRAPPED, 10, 10, 60, NULL); addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); addflag(lastot->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL); @@ -1573,6 +1576,7 @@ void initobjects(void) { addflag(lastot->flags, F_DOOR, SZ_MEDIUM, SZ_MAX, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MEDIUM, SZ_MAX, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -1588,6 +1592,7 @@ void initobjects(void) { addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -1599,6 +1604,7 @@ void initobjects(void) { addflag(lastot->flags, F_DOOR, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MAX, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -1639,6 +1645,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STENCH, B_TRUE, 1, NA, NULL); addflag(lastot->flags, F_CANBELOCKED, 50, 0, NA, NULL); @@ -1744,6 +1751,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKED, B_TRUE, 40, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addot(OT_MOTEL, "motel", "A small structure providing cheap overnight rooms for rent", MT_METAL, 500, OC_BUILDING, SZ_LARGE); @@ -4278,7 +4286,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); - addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addot(OT_S_QUICKENSTONE, "quicken stone", "Crafts nearby stone into powerful stone primalities.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how many creatures will be created."); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "At power level VI, stronger creatures will be created."); @@ -4978,13 +4986,17 @@ void initobjects(void) { addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HELPSDIG, 10, NA, NA, NULL); - addot(OT_ROPE, "rope", "A long length of strong rope.", MT_CLOTH, 5, OC_TOOLS, SZ_MEDIUM); + addot(OT_ROPE, "nylon rope", "A long length of strong rope.", MT_CLOTH, 5, OC_TOOLS, SZ_MEDIUM); addflag(lastot->flags, F_GLYPH, C_BROWN, ']', NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 75, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_VALUE, 35, NA, NA, NULL); addflag(lastot->flags, F_HELPSCLIMB, 3, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_WAIST, NA, NA, NULL); // ie. can wear it as a belt + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); addot(OT_SACK, "sack", "A small cloth sack.", MT_CLOTH, 0.5, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); @@ -5102,12 +5114,20 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANBELOCKED, 100, NA, NA, NULL); addflag(lastot->flags, F_CANBETRAPPED, 20, 25, 66, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); addflag(lastot->flags, F_STARTOBRND, 50, NA, NA, NULL); + addot(OT_SHOVEL, "shovel", "A lightweight digging tool.", MT_METAL, 4, OC_TOOLS, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); + addflag(lastot->flags, F_VALUE, 45, NA, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_HELPSDIG, 5, NA, NA, NULL); + addot(OT_TORCH, "torch", "A metre-long wooden rod with a flammable end.", MT_WOOD, 2, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 85, NA, NULL); addflag(lastot->flags, F_VALUE, 25, NA, NA, NULL); @@ -5271,6 +5291,23 @@ void initobjects(void) { addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addot(OT_GRENADEICE, "dry ice grenade", "A specialised grenade which explodes into a cloud of absolute coldness.", MT_METAL, 1, OC_TECH, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, 90, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 60, NA, NA, NULL); + addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERONOFF, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CHARGES, 2, 2, NA, NULL); + addflag(lastot->flags, F_DONTSHOWCHARGES, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_RECHARGEWHENOFF, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLCLOUDONDEATH, OT_S_SNAPFREEZE, 2, B_IFACTIVATED, "OB explodes in a cloud of freezing air!^Something explodes in a cloud of freezing air!^8"); + addflag(lastot->flags, F_SPELLCLOUDONDAM, OT_S_SNAPFREEZE, 2, B_IFACTIVATED, "8"); + addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addot(OT_C4, "block of c4", "An extremely explosive plastic which explodes a medium time after activation.", MT_PLASTIC, 1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 76, RR_UNCOMMON, NULL); @@ -5287,6 +5324,14 @@ void initobjects(void) { addflag(lastot->flags, F_GRENADE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_BEGINNER, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + + addot(OT_JACKHAMMER, "jackhammer", "A heavy power tool for quickly digging into hard rock.", MT_METAL, 15, OC_TOOLS, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); + addflag(lastot->flags, F_VALUE, 100, NA, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_HELPSDIG, 25, NA, NA, NULL); + addot(OT_MOTIONSCANNER, "motion scanner", "Small scanning device which detects nearby lifeforms.", MT_METAL, 1.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_RARE, NULL); addflag(lastot->flags, F_VALUE, 200, NA, NA, NULL); @@ -5307,8 +5352,8 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, RR_UNCOMMON, NA, NULL); addflag(lastot->flags, F_VALUE, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addflag(lastot->flags, F_DAM, DT_HEAT, 5, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); + addflag(lastot->flags, F_DAM, DT_HEAT, 6, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); @@ -5403,6 +5448,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 6, 6, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANBELOCKED, 30, 10, NA, NULL); addflag(lastot->flags, F_CANBETRAPPED, 20, 20, 66, NULL); @@ -5420,6 +5466,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANBELOCKED, 60, 10, NA, NULL); addflag(lastot->flags, F_CANBETRAPPED, 50, 20, 100, NULL); addflag(lastot->flags, F_CONTAINER, B_TRUE, NA, NA, NULL); @@ -6693,6 +6740,11 @@ void initobjects(void) { addflag(lastot->flags, F_SHRINKSTO, OT_SHIELDLARGE, VT_OB, NA, NULL); // amulets + addot(OT_AMU_ACROBAT, "amulet of acrobatics", "Allows its wearer to flip or tumple like a master acrobat.", 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_JUMP, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_TUMBLE, NA, NULL); + addflag(lastot->flags, F_VALUE, 600, NA, NA, NULL); 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); @@ -6704,6 +6756,9 @@ void initobjects(void) { 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_CHOKING, "amulet of choking", "Once worn, this evil amulet will immediately begin to shrink, choking the life from its wearer!", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_VERYRARE, NULL); + addflag(lastot->flags, F_VALUE, 900, 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;"); @@ -6729,11 +6784,20 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_PARANOIA, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 900, NA, NA, NULL); + addot(OT_AMU_PIETY, "amulet of piety", "Makes it easier for the wearer to please their chosen deity.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + // no autoid! + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_VALUE, 600, 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); // no autoid! addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); + addot(OT_AMU_SOULS, "amulet of soul feasting", "Allows the caster to consume souls of the recently dead.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + // no autoid! + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CONSUMESOULS, 25, NA, NULL); + addflag(lastot->flags, F_VALUE, 900, 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); @@ -6745,6 +6809,10 @@ void initobjects(void) { 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_TRAVEL, "amulet of the traveller", "Until its wearer removes this powerful amulet they will find themselves transported elsewhere.", MT_METAL, 0.3, OC_AMULET, SZ_TINY); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_VERYRARE, NULL); + addflag(lastot->flags, F_STARTBLESSED, B_CURSED, 70, NA, NULL); + addflag(lastot->flags, F_VALUE, 900, 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); // no autoid! addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); @@ -7187,6 +7255,17 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 3, 3, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); + addot(OT_JAVELINLT, "lightning javelin", "A long, sharp missile weapon which transforms into a bolt of lightning when thrown.", MT_METAL, 4, OC_MISSILE, SZ_MEDIUM); + addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_MISSILEDAM, NA, NA, NA, "3"); + addflag(lastot->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); + addflag(lastot->flags, F_NUMAPPEAR, 1, 2, NA, NULL); + addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); + addflag(lastot->flags, F_REPLENISHABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_RNDCHARGES, 1, 5, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "javelin"); + addot(OT_ARROW, "arrow", "A sharp wooden arrow.", MT_WOOD, 0.1, OC_MISSILE, SZ_SMALL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, ""); @@ -7957,6 +8036,16 @@ void initobjects(void) { addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addflag(lastot->flags, F_CANBEDIFFMAT, MT_BONE, 33, NA, NULL); + addot(OT_CLUBSPIKE, "spiked club", "A heavy wooden club with embedded spikes.", MT_WOOD, 8, OC_WEAPON, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_RARITY, H_CAVE, 100, NA, NULL); + addflag(lastot->flags, F_DAM, DT_PIERCE, 8, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 50, 60, "10"); + addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_BONE, 33, NA, NULL); addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 15, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 50, NA, NULL); @@ -8401,7 +8490,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "armour"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "map"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "dungeon exit orb"); - addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "old iron key"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "ancient iron key"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "concealing powder"); addflag(lastrace->flags, F_FLEEONHPPCT, 40, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_ADEPT, NA, NULL); @@ -9177,6 +9266,7 @@ void initrace(void) { addflag(lastrace->flags, F_CASTCHANCE, 75, NA, NA, NULL); // god abilities addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Purity & Order"); + addflag(lastrace->flags, F_GENDER, G_MALE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_LIGHT, NA, NA, "pw:10;"); // may cast all life spells @@ -9235,7 +9325,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_ARMOUR, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SHIELDS, PR_MASTER, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, B_MALE, NA, NA, "Battle & Honour"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Battle & Honour"); + addflag(lastrace->flags, F_GENDER, G_MALE, NA, NA, NULL); addflag(lastrace->flags, F_STAMREGEN, NA, NA, NA, "10"); // ie. basically infinite addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_WARCRY, NA, NA, NULL); @@ -9291,7 +9382,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_LORE_NATURE, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_LORE_DRAGONS, PR_ADEPT, NA, NULL); // ekrub hates dragons // god abilities - addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Creation & Nature"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Creation & Nature"); + addflag(lastrace->flags, F_GENDER, G_FEMALE, NA, NA, NULL); // may cast all nature spells for (ot = objecttype ; ot ; ot = ot->next) { if ((ot->obclass->id == OC_SPELL) && (getspellschool(ot->id) == SS_NATURE)) { @@ -9344,6 +9436,7 @@ void initrace(void) { addflag(lastrace->flags, F_CASTCHANCE, 75, NA, NA, NULL); // god abilities addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Revenge & Thievery"); + addflag(lastrace->flags, F_GENDER, G_MALE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANCAST, OT_S_CALLWIND, NA, NA, "pw:10;"); @@ -9384,7 +9477,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_MASTER, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Life & Healing"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Life & Healing"); + addflag(lastrace->flags, F_GENDER, G_FEMALE, NA, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 5, NA, NA, NULL); // may cast all life spells for (ot = objecttype ; ot ; ot = ot->next) { @@ -9437,6 +9531,7 @@ void initrace(void) { addflag(lastrace->flags, F_CASTCHANCE, 75, NA, NA, NULL); // god abilities addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Death"); + addflag(lastrace->flags, F_GENDER, G_MALE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); // may cast all death spells for (ot = objecttype ; ot ; ot = ot->next) { @@ -9487,7 +9582,8 @@ void initrace(void) { addflag(lastrace->flags, F_AUTOCREATEOB, 1, NA, NA, "large fire"); addflag(lastrace->flags, F_RETALIATE, 2, 4, DT_FIRE, "roaring flames"); addflag(lastrace->flags, F_DTIMMUNE, DT_FIRE, B_TRUE, NA, NULL); - addflag(lastrace->flags, F_GODOF, B_MALE, NA, NA, "Destruction & Fire"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Destruction & Fire"); + addflag(lastrace->flags, F_GENDER, G_MALE, NA, NA, NULL); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "starting fires"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "burning objects"); addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "killing with fire"); @@ -9532,7 +9628,8 @@ void initrace(void) { } addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Magic"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Magic"); + addflag(lastrace->flags, F_GENDER, G_FEMALE, NA, NA, NULL); addflag(lastrace->flags, F_MPREGEN, NA, NA, NA, "100"); // ie. basically infinite addflag(lastrace->flags, F_GODLIKES, NA, NA, NA, "the use of magic"); addflag(lastrace->flags, F_GODDISLIKES, NA, NA, NA, "the use of missile or ranged weapons"); @@ -9570,7 +9667,8 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "raises her palms"); addflag(lastrace->flags, F_CASTCHANCE, 75, NA, NA, NULL); // god abilities - addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Mercy & Forgiveness"); + addflag(lastrace->flags, F_GODOF, NA, NA, NA, "Mercy & Forgiveness"); + addflag(lastrace->flags, F_GENDER, G_FEMALE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 10, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_CUREPOISON, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANCAST, OT_S_HEALINGMAJ, NA, NA, "pw:10;"); @@ -10845,6 +10943,7 @@ void initrace(void) { setbodytype(lastrace, BT_QUADRAPED); addbodypart(lastrace, BP_TAIL, NULL); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_FILLPOT, OT_POT_POISON, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_VERYRARE, NULL); @@ -10858,6 +10957,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_AUTOCREATEOB, -1, NA, NA, "puff of poison gas"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 4, NA, NULL); @@ -10873,6 +10973,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); @@ -12407,6 +12508,7 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); @@ -12445,6 +12547,7 @@ void initrace(void) { addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); addflag(lastrace->flags, F_NOCHARM, B_TRUE, NA, NA, NULL); @@ -15716,6 +15819,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 12, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_ACID, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, NULL); @@ -15758,6 +15862,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_DETECTLIFE, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_ACID, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); @@ -15790,6 +15895,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_ACID, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, NULL); @@ -15826,6 +15932,7 @@ void initrace(void) { addflag(lastrace->flags, F_RETALIATE, 2, 3, DT_COLD, "icy spikes"); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_ACID, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_SHARDSHOT, 5, 5, "pw:3;"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "points its arm"); @@ -15906,6 +16013,7 @@ void initrace(void) { addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_SKILLED, NA, NULL); @@ -15937,6 +16045,7 @@ void initrace(void) { addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_ADEPT, NA, NULL); @@ -15972,6 +16081,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 2, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISONGAS, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_ADEPT, NA, NULL); @@ -16788,6 +16898,7 @@ void initrace(void) { addflag(r->flags, F_BREATHWATER, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); } else if (r->raceclass->id == RC_DEMON) { + addflag(r->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_MATVULN, MT_SILVER, 200, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); @@ -16799,6 +16910,7 @@ void initrace(void) { addflag(r->flags, F_HATESRACE, R_HYDRA, NA, NA, NULL); } } else if (r->raceclass->id == RC_GOD) { + addflag(r->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); addflag(r->flags, F_PIETY, 100, NA, NA, NULL); addflag(r->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(r->flags, F_MORALE, 30, NA, NA, NULL); @@ -16814,8 +16926,10 @@ void initrace(void) { addflag(r->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL); addflag(r->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); } else if (r->raceclass->id == RC_MAGIC) { + addflag(r->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_PLANT) { + addflag(r->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DTRESIST, DT_BASH, NA, NA, NULL); addflag(r->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); @@ -16826,11 +16940,13 @@ void initrace(void) { addflag(r->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_SLIME) { + addflag(r->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); } else if (r->raceclass->id == RC_ROBOT) { addflag(r->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); + addflag(r->flags, F_NOBREATH, B_TRUE, NA, NA, NULL); addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addflag(r->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index 0f17288..3328979 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index e833105..5acaa56 100644 --- a/defs.h +++ b/defs.h @@ -1869,6 +1869,7 @@ enum OBTYPE { OT_SACKLARGE, OT_SACKHUGE, OT_SAFEBOX, + OT_SHOVEL, OT_TORCH, OT_TOWEL, OT_UNICORNHORN, @@ -1888,7 +1889,9 @@ enum OBTYPE { OT_C4, OT_FLASHBANG, OT_GRENADE, + OT_GRENADEICE, OT_GRENADESMOKE, + OT_JACKHAMMER, OT_MOTIONSCANNER, OT_NVGOGGLES, OT_POWERCORE, @@ -2038,19 +2041,24 @@ enum OBTYPE { OT_SHIELDLARGE, OT_SHIELDTOWER, // amulets + OT_AMU_ACROBAT, OT_AMU_ANGER, OT_AMU_BLOOD, OT_AMU_CHEF, + OT_AMU_CHOKING, OT_AMU_ESCAPE, OT_AMU_EVOLUTION, OT_AMU_FALLING, OT_AMU_FLIGHT, OT_AMU_LISTEN, OT_AMU_PARANOIA, + OT_AMU_PIETY, OT_AMU_SLEEP, + OT_AMU_SOULS, OT_AMU_SPELLBOOST, OT_AMU_SWIMMING, OT_AMU_THIEF, + OT_AMU_TRAVEL, OT_AMU_VICTIM, OT_AMU_VSESP, OT_AMU_VSMAGIC, @@ -2125,6 +2133,7 @@ enum OBTYPE { OT_NEEDLE, OT_NET, OT_JAVELIN, + OT_JAVELINLT, OT_BULLET, OT_RUBBERBULLET, OT_SHURIKEN, @@ -2197,6 +2206,7 @@ enum OBTYPE { OT_FLAILHEAVY, // clubs OT_CLUB, + OT_CLUBSPIKE, OT_GREATCLUB, OT_MACE, OT_MORNINGSTAR, @@ -2361,6 +2371,12 @@ enum SLEEPTYPE { }; +enum GENDER { + G_NONE = 0, + G_MALE, + G_FEMALE +}; + enum ANIMALTYPE { AT_AVIAN, AT_CANINE, @@ -2395,6 +2411,8 @@ enum FLAG { F_CREATEDBY, // object was made by lf id v0, text=real lfname F_CREATEDBYSPELL, // object was made by spell id v0 F_ENCHANTABLE, // object can get +1/-1 ect + F_FILLPOT, // can fill empty flasks with this object to create + // a potion of obtype v0. F_GEM, // this object is a gem. F_GODGIFT, // this was a gift form god with race v0. F_GROWSTO, // used for spells. v0=new oid or celltype. @@ -2413,10 +2431,15 @@ enum FLAG { // v1=depth of entrance // v2=regionthing ID of RT_REGIONLINK thing // text = what this is a map to ie. "the goblin caves" + F_ORIGMAP, // for amulet of the traveller - v0 = original map id + // where the amulet was put on. v1/v2 is x/y coords. + F_NEWMAP, // for amulet of the traveller - v0 = target map id + // where amulet takes us. v1/v2 is x/y coords. F_SIGNTEXT, // for 'sign' objects. f->text is what is says. F_IMMUTABLE, // this object cannot be damaged OR repaired. F_IDWHENUSED, // fully identify an object when worn/weilded/operated/etc F_STARTBLESSED, // v0 = b_blessed or b_cursed + // v1 = pct chance. NA = 100. F_REPELBLESSED, // v0 = b_blessed or b_cursed. repels other obejcts // of this blesstype. // if v1 == b_blessed or b_cursed, will ID these blessings/curses @@ -2458,6 +2481,7 @@ enum FLAG { // equipped on _ONE OF_ the. F_BONUS, // val0=bonus/penalty to damage+accuracy/armour. ie. +1 sword F_THROWMISSILE, // weapon would make a good thrown missle - used by AI + F_THROWNBY, // this object was thrown by lifeform id v0. F_CANHOME, // this object can have the 'homing' flag F_UNIQUE, // only one may appear F_GLYPH, // override the glyph with f->val[1] @@ -2551,6 +2575,12 @@ enum FLAG { // val2 = ifactivated, only explodes if activated. F_FLASHONDEATH, // produce a bright flash when it dies,v0=range F_FLASHONDAM, // produces a bright flash when it is damaged,v0=range,v2=ifacctivated + F_SPELLCLOUDONDEATH, // cast spell v0 in radius v1 upon death. + // v2 = ifactivated + // text = "seebuf^noseebuf^spell_power" + F_SPELLCLOUDONDAM, // cast spell v0 in radius v1 upon damage. + // v2 = ifactivated + // text = "seebuf^noseebuf^spell_power" F_LASTDAMTYPE, // object equivilant of lf->lastdamtype F_SCROLLNEEDSOB, // this scroll targets an object // v0 = B_ALWAYS (always targets an ob) @@ -2776,6 +2806,8 @@ enum FLAG { F_FIREARM, // this weapon is equipped in bp_secweapon, not _weapon. F_FIRESPEED, // how fast this weapon shoots projectiles F_AMMOOB, // v0 = what object this weapon fires. can have multiple types. + // the first flag of this type added to an object becomes + // the default ammo type. F_AMMOCAPACITY, // v0 = max ammo that can be loaded F_RANGE, // v0 = range of projectile firing weapon or spell // optional v1 = minrange (for spells only) @@ -2969,6 +3001,7 @@ enum FLAG { F_VEGETARIAN, // this lf will not eat meat. F_PARTVEGETARIAN,// this lf will only eat if hunger >= 'hungry' F_CARNIVORE, // this lf will only eat meat. + F_SHADOWED, // can't see this lf if you are > v0 away. F_SHIELDPENALTY, // lower your acc/ev by val0 due to a cumbersome // shield. lowered by sk_shield skill. // v0 is accuracy penalty, v1 is evasion penalty. @@ -3257,10 +3290,11 @@ enum FLAG { F_TR, // v0 = threat rating of this race. F_MAXHPMOD, // maxhp = pctof(v0, maxhp) F_MPDICE, // val0: # d4 to roll for maxmp per level. val1: +xx + F_GENDER, // v0 = G_MALE or G_FEMALE. default if G_NONE if this + // flag isn't set. F_JOB, // val0 = player's job // val1 = player's subjob or NA F_GODOF, // text = what this lf is the god of. use capitals. - // if v0 is b_true, means this is a goddess F_GODLIKES, // text = something this god likes (ie. incs piety) F_GODDISLIKES, // text = something this god likes (ie. decs piety) F_GODPOISON, // v0=TRUE: god likes using poison. gain v1 piety @@ -3339,8 +3373,10 @@ enum FLAG { F_NOPRINTS, // this race doesn't leave footprints F_INDUCEFEAR, // causes fear when you attack it F_POISONCORPSE, // lf's corpse will be poisonous - F_AUTOCREATEOB, // produces obtype 'text' wherever it walks, v0=radius + F_AUTOCREATEOB, // produces obtype 'text' wherever it walks,. // (only if ob of that type not already there) + // v0=radius around the lf to create it in. + // if (v0 == -1), then create object in front 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 @@ -3389,6 +3425,7 @@ enum FLAG { // this flag does not get announced. F_LOWHPABIL, // will automatically use the ability v0 when // this lf starts bleeding. + F_NOBREATH, // this lf doesn't need to breath. F_BREATHWATER, // can breath normally underwater F_CANWILL, // can cast the spell/ability val0 without using MP // v1 is counter untiluse diff --git a/flag.c b/flag.c index e7b4947..ba28f90 100644 --- a/flag.c +++ b/flag.c @@ -598,6 +598,7 @@ int flagcausesloscalc(enum FLAG fid) { case F_NIGHTVISRANGEMOD: case F_PRONE: case F_SEEINDARK: + case F_SHADOWED: case F_AWARENESS: case F_VISRANGE: case F_VISRANGEMOD: @@ -1469,6 +1470,28 @@ flag_t *modflag(flagpile_t *fp, enum FLAG fid, int val1, int val2, int val3, cha return f; } +// make the objects providing this flag be known. +void revealflagob(lifeform_t *lf, flag_t *f) { + int willid = B_FALSE; + if (!isplayer(lf)) return; + + switch (f->lifetime) { + case FROMOBEQUIP: + case FROMOBHOLD: + case FROMOBACTIVATE: + willid = B_TRUE; + break; + default: break; + } + if (willid) { + object_t *o; + o = findobbyid(lf->pack, f->obfrom); + if (o) { + makeknown(o->type->id); + } + } +} + void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2) { flag_t *f; if (val0) *val0 = 0; diff --git a/flag.h b/flag.h index 9ef5edb..d8e9b8b 100644 --- a/flag.h +++ b/flag.h @@ -41,6 +41,7 @@ int killtransitoryflagvals(flagpile_t *fp, enum FLAG fid, int val1, int val2, in void makeflagknown(flagpile_t *fp); int modcounter(flagpile_t *fp, int amt); flag_t *modflag(flagpile_t *fp, enum FLAG fid, int val1, int val2, int val3, /*@null@*/ char *text); +void revealflagob(lifeform_t *lf, flag_t *f); void sumflags(flagpile_t *fp, int id, int *val0, int *val1, int *val2); void timeeffectsflag(flag_t *f, int howlong); void timeeffectsflags(flagpile_t *fp); diff --git a/god.c b/god.c index acea119..73a0597 100644 --- a/god.c +++ b/god.c @@ -45,6 +45,11 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { god = findgod(rid); + if (hasequippedobid(player->pack, OT_AMU_PIETY)) { + amt /= 2; + limit(&amt, 1, NA); + } + modpiety(rid, -amt); piety = getpiety(rid); plev = getpietylev(rid, NULL, NULL); @@ -55,7 +60,6 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { } // if you HAVE prayed to this god before, something bad will probably happen. - switch (why) { case GA_ATTACKALLY: godsay(rid, B_TRUE, "How dare you attack an ally!"); break; @@ -1214,7 +1218,7 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { case 4: // ammo o = getfirearm(player); if (o) { - ot = getrandomammofor(o); + ot = getrandomammofor(o, B_FALSE); snprintf(obtogive, BUFLEN, "%d excellent %s", rnd(20,30), ot->name); } else { rollagain = B_TRUE; @@ -1674,6 +1678,11 @@ void pleasegodmaybe(enum RACE rid, int amt) { // ie. ECSTATIC/FURIOUS = 1 in 4 // ie. ENRAGED = 1 in 5 chance = modplev + 1; + if (hasequippedobid(player->pack, OT_AMU_PIETY)) { + chance--; + limit(&chance, 1, NA); + } + if (onein(chance)) { pleasegod(rid, amt); } @@ -2360,7 +2369,7 @@ int prayto(lifeform_t *lf, lifeform_t *god) { gun = getfirearm(lf); if (gun && !getammo(gun) && !getrandomammo(lf)) { objecttype_t *ot; - ot = getrandomammofor(gun); + ot = getrandomammofor(gun, B_FALSE); if (ot) { char obtogive[BUFLEN],ammoname[BUFLEN]; char gunname[BUFLEN]; diff --git a/io.c b/io.c index 9d42651..fe772d7 100644 --- a/io.c +++ b/io.c @@ -730,7 +730,7 @@ cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t } } else if (c->lf->race->raceclass->id == RC_GOD) { f = lfhasflag(c->lf, F_GODOF); - if (f->val[0] == B_FEMALE) { + if (getgender(c->lf) == G_FEMALE) { strcat(buf, " the goddess of "); } else { strcat(buf, " the god of "); @@ -1900,6 +1900,14 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_SHADOWED: + if (isplayer(lf)) { + msg("You are cloaked in shadows!"); + } else { + msg("%s is cloaked in shadows!", lfname); + } + donesomething = B_TRUE; + break; case F_SILENTMOVE: if (isplayer(lf)) { // don't know if monsters get it msg("You now move silently."); @@ -2588,6 +2596,14 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_SHADOWED: + if (isplayer(lf)) { + msg("The shadows around you disappate."); + } else { + msg("The shadows around %s disappate.", lfname); + } + donesomething = B_TRUE; + break; case F_SILENTMOVE: if (isplayer(lf)) { // don't know if monsters lose it msg("You no longer move silently."); @@ -2853,7 +2869,7 @@ lifeform_t *askgod(char *prompttext, int onlyprayed) { real_getlfname(lf, buf, NULL, B_NOSHOWALL, B_REALRACE); f = hasflag(lf->flags, F_GODOF); - snprintf(godof, BUFLEN, " (%s of %s)", (f->val[0] == B_FEMALE) ? "goddess" : "god", f->text); + snprintf(godof, BUFLEN, " (%s of %s)", (getgender(lf) == G_FEMALE) ? "goddess" : "god", f->text); strcat(buf, godof); makedesc_god(lf, longdesc); @@ -3812,7 +3828,7 @@ void describegod(lifeform_t *god) { f = hasflag(god->flags, F_GODOF); real_getlfname(god, godname, NULL, B_NOSHOWALL, B_REALRACE); - snprintf(goddesc, BUFLEN, "(%s of %s)", (f->val[0] == B_FEMALE) ? "goddess" : "god", f->text); + snprintf(goddesc, BUFLEN, "(%s of %s)", (getgender(god) == G_FEMALE) ? "goddess" : "god", f->text); // title snprintf(buf, BUFLEN, "God::%s %s",godname, goddesc); @@ -6017,7 +6033,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { makewearstringsingle(NULL, f, "the ", posbuf); if (i == 0) { - sprintf(buf, "It is worn %s", posbuf); + sprintf(buf, "It can be worn %s", posbuf); } else if (i == (nretflags - 1)) { strcat(buf, " and "); strcat(buf, posbuf); @@ -6816,6 +6832,10 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf2, "%s allows you to see in the dark.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; + case F_SHADOWED: + sprintf(buf2, "%s prevents distant creatures from seeing you.\n", buf); + strncat(retbuf, buf2, HUGEBUFLEN); + break; case F_SILENTMOVE: sprintf(buf2, "%s allows you to move silently.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); @@ -7267,6 +7287,7 @@ char *makedesc_race(enum RACE rid, char *retbuf, int showextra, int forplayersel 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; case F_SEEINVIS: if (lorelev >= PR_ADEPT) sprintf(buf, "Can see invisible things"); break; + case F_SHADOWED: if (lorelev >= PR_BEGINNER) sprintf(buf, "Cannot be seen from a distance."); break; case F_SILENTMOVE: if (lorelev >= PR_BEGINNER) sprintf(buf, "Moves silently"); break; case F_SPIDERCLIMB: if (lorelev >= PR_NOVICE) sprintf(buf, "Adheres to walls"); break; case F_STABILITY: if (lorelev >= PR_BEGINNER) sprintf(buf, "Will not fall on slippery ground."); break; @@ -7566,7 +7587,7 @@ char *makedesc_spell(objecttype_t *ot, char *retbuf) { god = findgod(retflag[i]->val[0]); f = lfhasflag(god, F_GODOF); sprintf(buf, "Successfully casting this spell will please %s (%s of %s).\n",god->race->name, - (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text); + (getgender(god) == B_FEMALE) ? "Goddess" : "God", f->text); strncat(retbuf, buf, BUFLEN); } @@ -12619,6 +12640,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s can see invisible things.", you(lf)); y++; } + f = hasflag_real(lf->flags, F_SHADOWED, B_TRUE, NULL, FROMRACE); + if (f) { + mvwprintw(mainwin, y, 0, "%s %s hidden from distant creatures.", you(lf), is(lf)); + y++; + } f = hasflag_real(lf->flags, F_SPIDERCLIMB, B_TRUE, NULL, FROMRACE); if (f) { mvwprintw(mainwin, y, 0, "%s adhesive skin allows %s to climb walls.", your(lf), you(lf)); diff --git a/lf.c b/lf.c index ed9fc15..3762a4c 100644 --- a/lf.c +++ b/lf.c @@ -71,6 +71,9 @@ extern int ngodlfs; extern enum ERROR reason; extern void *rdata; +extern object_t *retobs[MAXPILEOBS+1]; +extern int retobscount[MAXPILEOBS+1]; +extern int nretobs; // for xplist race_t **raceposs; @@ -133,7 +136,7 @@ void autoweild(lifeform_t *lf) { if (!isplayer(lf) && firearm && !getammo(firearm)) { objecttype_t *ot; // make some ammo - ot = getrandomammofor(firearm); + ot = getrandomammofor(firearm, B_FALSE); if (ot) { char buf[BUFLEN]; snprintf(buf, BUFLEN, "1-5 %s",ot->name); @@ -196,7 +199,7 @@ void awardxpfor(lifeform_t *killed, float pct) { } void bleed(lifeform_t *lf, int splatter) { - flag_t *f; + flag_t *f,*bloodfillflag; char obname[BUFLEN]; flag_t *retflag[MAXCANDIDATES]; int nretflags; @@ -219,9 +222,25 @@ void bleed(lifeform_t *lf, int splatter) { strcpy(obname, "splash of blood"); } + bloodfillflag = hasflag(lf->flags, F_FILLPOT); + if (strlen(obname) > 0) { - addob(lf->cell->obpile, obname); - if (splatter) addobsinradius(lf->cell, 1, DT_COMPASS, obname, B_TRUE, NULL); + object_t *o; + o = addob(lf->cell->obpile, obname); + + if (bloodfillflag) { + addflag(o->flags, F_FILLPOT, bloodfillflag->val[0], NA, NA, NULL); + } + + if (splatter) { + addobsinradius(lf->cell, 1, DT_COMPASS, obname, B_TRUE, NULL); + if (bloodfillflag) { + int i; + for (i = 0; i < nretobs; i++) { + addflag(retobs[i]->flags, F_FILLPOT, bloodfillflag->val[0], NA, NA, NULL); + } + } + } } } @@ -1199,8 +1218,9 @@ int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos) { flag_t *f; int xray = 0; int dist; - int tremordist,smelldist; + int tremordist,smelldist,darkvisdist; int invisible = B_FALSE; + if (gamemode < GM_GAMESTARTED) { return B_TRUE; @@ -1238,6 +1258,8 @@ int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos) { smelldist = -1; } + darkvisdist = getnightvisrange(viewer); + // viewer asleep? f = lfhasflag(viewer, F_ASLEEP); if (f) { @@ -1268,12 +1290,24 @@ int cansee_real(lifeform_t *viewer, lifeform_t *viewee, int uselos) { } // cloak of shadows? + /* o = getequippedob(viewee->pack, BP_SHOULDERS); if (o && hasflagval(o->flags, F_HASBRAND, BR_SHADOWS, NA, NA, NULL)) { if (!islit(viewee->cell)) { invisible = B_TRUE; } } + */ + f = lfhasflag(viewee, F_SHADOWED); + if (f && (dist > f->val[0])) { + if (dist <= darkvisdist) { + } else if ((dist <= tremordist)) { + } else if ((dist <= smelldist)) { + } else { + return B_FALSE; + } + } + // viewee hiding? if (ishidingfrom(viewee, viewer)) { @@ -1938,7 +1972,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar char lfname[BUFLEN],gbuf[BUFLEN]; getobname(protob, gbuf, protob->amt); getlfname(victim, lfname); - msg("%s%s %s protects it.", lfname, getpossessive(lfname), noprefix(gbuf) ); + msg("%s%s %s protects %s.", lfname, getpossessive(lfname), noprefix(gbuf), it(victim) ); } } else { if (isplayer(victim)) { @@ -2357,50 +2391,52 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { } losehp(lf, roll("6d6"), DT_DIRECT, NULL, "running water"); } - if ((!slev || !getstamina(lf)) && !lfhasflag(lf, F_BREATHWATER) ) { - int damamt; + if (needstobreath(lf)) { + if ((!slev || !getstamina(lf)) && !lfhasflag(lf, F_BREATHWATER) ) { + int damamt; - // take drowning damage. generally you'll die - // in around 3-4 turns. - damamt = lf->maxhp / (getattr(lf, A_CON) / 15); + // take drowning damage. generally you'll die + // in around 3-4 turns. + damamt = lf->maxhp / (getattr(lf, A_CON) / 15); - limit(&damamt, 1, NA); + limit(&damamt, 1, NA); - if (damamt >= lf->hp) { - char obname[BUFLEN]; - if (isplayer(lf)) { - msg("^BYou drown."); - didsomething = B_TRUE; - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("^%c%s drowns.",getlfcol(lf, CC_BAD) , lfname); - didsomething = B_TRUE; + if (damamt >= lf->hp) { + char obname[BUFLEN]; + if (isplayer(lf)) { + msg("^BYou drown."); + didsomething = B_TRUE; + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%c%s drowns.",getlfcol(lf, CC_BAD) , lfname); + didsomething = B_TRUE; + } + addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); + lf->hp = 0; + getobnametruebase(o, obname, o->amt); + lf->lastdamtype = DT_DIRECT; + setlastdam(lf, obname); + setkillverb(lf, "Drowned"); + } else { + char obname[BUFLEN]; + if (isplayer(lf)) { + msg("^BYou are drowning!"); + didsomething = B_TRUE; + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%c%s is drowning!", getlfcol(lf, CC_VBAD), lfname); + didsomething = B_TRUE; + } + getobnametruebase(o, obname, o->amt); + losehp(lf, damamt, DT_DIRECT, NULL, obname); + setlastdam(lf, obname); + setkillverb(lf, "Drowned"); } - addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); - lf->hp = 0; - getobnametruebase(o, obname, o->amt); - lf->lastdamtype = DT_DIRECT; - setlastdam(lf, obname); - setkillverb(lf, "Drowned"); - } else { - char obname[BUFLEN]; - if (isplayer(lf)) { - msg("^BYou are drowning!"); - didsomething = B_TRUE; - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("^%c%s is drowning!", getlfcol(lf, CC_VBAD), lfname); - didsomething = B_TRUE; - } - getobnametruebase(o, obname, o->amt); - losehp(lf, damamt, DT_DIRECT, NULL, obname); - setlastdam(lf, obname); - setkillverb(lf, "Drowned"); } - } - } + } //end if needs to breath + } // end if depth > head if (!isdead(lf)) { f = isvulnto(lf->flags, DT_WATER, B_FALSE); @@ -3079,8 +3115,14 @@ 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, "Arise, my servant..."); more(); break; - // you will rise as a monster. + if (strlen(reanimateas)) { + godsay(god->race->id, B_TRUE, "Arise, my servant..."); more(); break; + // you will rise as a monster. + } else { + godsay(god->race->id, B_TRUE, "Come to me, my servant..."); more(); + msg("Bony claws rise up and drag your body underground."); + break; + } case R_GODLIFE: msg("Your spirit ascends to the heavens."); more(); break; case R_GODTHIEVES: // lose all gold / gems @@ -3276,12 +3318,16 @@ void die(lifeform_t *lf) { if (isplayer(souleater)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%cYou consume %s%s soul!", getlfcol(souleater, CC_GOOD), lfname, getpossessive(lfname)); + msg("^%cYou consume %s%s soul!", getlfcol(souleater, CC_VGOOD), lfname, getpossessive(lfname)); + soulflag->known = B_TRUE; + + revealflagob(souleater, soulflag); } else if (cansee(player, souleater)) { char lfname[BUFLEN]; getlfname(lf, lfname); getlfname(souleater, buf); - msg("^%c%s consumes %s%s soul!", getlfcol(souleater, CC_GOOD), buf, lfname, getpossessive(lfname)); + msg("^%c%s consumes %s%s soul!", getlfcol(souleater, CC_VGOOD), buf, lfname, getpossessive(lfname)); + soulflag->known = B_TRUE; } amt = pctof( rnd(1,soulflag->val[0]), lf->maxhp); limit(&amt, 1, NA); @@ -3550,15 +3596,17 @@ void die(lifeform_t *lf) { } } - // hecta-worshippers get reanimated. + // hecta-worshippers often 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; + if (onein(3)) { + switch (rnd(1,2)) { + case 1: + sprintf(reanimateas, "zombie"); + break; + case 2: + sprintf(reanimateas, "skeleton"); + break; + } } } @@ -5226,7 +5274,7 @@ void enhanceskills(lifeform_t *lf) { // special case level-based job effects if (hasjob(lf, J_MONK)) { - // enhance fist strength + // enhance fist strength and change type //f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL); f = lfhasflag(lf, F_HASATTACK); if (f) { @@ -7395,6 +7443,15 @@ int getfootprinttime(lifeform_t *lf) { return time; } +enum GENDER getgender(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_GENDER); + if (f) { + return f->val[0]; + } + return G_NONE; +} + lifeform_t *getguntarget(lifeform_t *lf) { flag_t *f; f = hasflag(lf->flags, F_GUNTARGET); @@ -10303,7 +10360,6 @@ void givejob(lifeform_t *lf, enum JOB jobid) { // also, they always use fists, even if the race has claws etc. f = lfhasflag(lf, F_HASATTACK); if (f) { - f->val[0] = OT_FISTS; f->val[1] = 3; } } else if (j->id == J_PIRATE) { @@ -11531,6 +11587,32 @@ void growhydrahead(lifeform_t *lf, int announce) { f->val[0]++; } +void losehydrahead(lifeform_t *lf) { + flag_t *f; + int dr = 0; + f = lfhasflagval(lf, F_HASATTACK, OT_TEETH, NA, NA, NULL); + dr = f->val[1]; // remember dr + // remove one hasattack flag + killflag(f); + + // still more heads left? + if (countflagsofid(lf->flags, F_HASATTACK)) { + // adjust maxhp + lf->maxhp -= HITDIESIDES; + if (lf->hp > lf->maxhp) lf->hp = lf->maxhp; + if (isplayer(lf)) statdirty = B_TRUE; + + // adjust TR + f = hasflag(lf->flags, F_TR); + f->val[0]--; + } else { + // die! + lf->lastdamtype = DT_DIRECT; + setlastdam(lf, "decapitation"); + lf->hp = 0; + } +} + flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp) { flag_t *f, *retflag[MAXCANDIDATES]; int nretflags,i; @@ -11864,7 +11946,11 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR } else if (cansee(player, lf)) { msg("^%c%s%s brain ruptures!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); } - if (lf->hp > 0) lf->hp = 0; + if (lf->hp > 0) { + setlastdam(lf, "a ruptured brain"); + lf->lastdamtype = DT_DIRECT; + lf->hp = 0; + } inj = IJ_NONE; break; case IJ_HANDMISSING: @@ -11918,6 +12004,8 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR msg("^%c%s%s heart is pierced!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); } if (lf->hp > 0) { + setlastdam(lf, "a pierced heart"); + lf->lastdamtype = DT_DIRECT; lf->hp = 0; } inj = IJ_NONE; @@ -12007,8 +12095,10 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR case IJ_HANDSWOLLEN: desc = strdup("hand is swolled^rings cannot be put on/removed"); break; case IJ_FINGERBROKEN: desc = strdup("finger is broken^acc penalty"); break; case IJ_SHOULDERDISLOCATED: desc = strdup("shoulder is dislocated^acc penalty, cannot use heavy weapons"); break; - case IJ_ARTERYPIERCE: break; // fatal - no description - default: + case IJ_ARTERYPIERCE: desc = strdup("radial artery is pierced^constant bleeding"); break; // fatal - no description + case IJ_BRAINRUPTURED: break; // fatal - no description + case IJ_HEARTPIERCED: break; // fatal - no description + case IJ_BLINDED: break; // no injury will be added. case IJ_NONE: break; } @@ -14838,7 +14928,7 @@ int loadfirearm(lifeform_t *lf, object_t *gun, object_t *ammo) { if (lf && isplayer(lf)) { char buf[BUFLEN]; getobname(curammo, buf, curammo->amt); - msg("You unload %s from your %s.", curammo, noprefix(gunname)); + msg("You unload %s from your %s.", buf, noprefix(gunname)); } } else { return B_TRUE; @@ -15890,6 +15980,7 @@ void modhunger(lifeform_t *lf, int amt) { if (isplayer(lf)) { msg("^BYou collapse from starvation."); } + lf->lastdamtype = DT_DIRECT; setlastdam(lf, "starvation"); lf->hp = 0; } else if (prehlev != posthlev) { @@ -16032,6 +16123,13 @@ int movecausesnoise(lifeform_t *lf) { return B_TRUE; } +int needstobreath(lifeform_t *lf) { + if (lfhasflag(lf, F_NOBREATH)) { + return B_FALSE; + } + return B_TRUE; +} + // if validchars is set, we will populate it with a list of valid // choice letters for asking the player how to rest. int needstorest(lifeform_t *lf, char *validchars) { @@ -16314,7 +16412,8 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, // turn to face the sound if (isplayer(noisemaker) && cansee(l, player) && !lfhasflag(l, F_AWARENESS) && !isdead(l)) { // peaceful things only turn sometimes - if (!ispeaceful(l) || onein(6)) { + //if (!ispeaceful(l) || onein(6)) { + if (!isfriendly(l)) { char lfname[BUFLEN]; int prefacing; prefacing = l->facing; @@ -18281,7 +18380,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { f = lfhasflag(lf, F_GODOF); if (f) { msg("^w%s transforms into %s, the %s of %s!", buf, newrace->name, - (f->val[0] == B_FEMALE) ? "Goddess" : "God", f->text); + (getgender(lf) == B_FEMALE) ? "Goddess" : "God", f->text); } else { msg("^w%s transforms into %s %s!", buf, isvowel(newrace->name[0]) ? "an" : "a", newrace->name); } @@ -18996,6 +19095,9 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r if (lfhasflag(lf, F_RAGE) && (ct == SC_MORALE)) { roll = 0; } + if (hasequippedobid(lf->pack, OT_AMU_ACROBAT) && (ct == SC_TUMBLE)) { + roll = 0; + } // natural 20 will pass some checks if (roll <= 5) { @@ -19303,6 +19405,8 @@ void startlfturn(lifeform_t *lf) { //} } } + + // drown? o = hasobwithflag(lf->cell->obpile, F_DEEPWATER); if (o) { @@ -19318,19 +19422,21 @@ void startlfturn(lifeform_t *lf) { } // suffocate? - if (lfhasflag(lf, F_NEEDSWATER) && !hasobwithflag(lf->cell->obpile, F_DEEPWATER)) { - int dam; - if (isplayer(lf)) { - msg("^BYou are suffocating without water to breath!"); - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("^%c%s is suffocating!", getlfcol(lf, CC_VBAD), lfname); + if (needstobreath(lf)) { + if (lfhasflag(lf, F_NEEDSWATER) && !hasobwithflag(lf->cell->obpile, F_DEEPWATER)) { + int dam; + if (isplayer(lf)) { + msg("^BYou are suffocating without water to breath!"); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%c%s is suffocating!", getlfcol(lf, CC_VBAD), lfname); + } + dam = lf->maxhp / 3; + limit(&dam, 1, NA); + losehp(lf, dam, DT_DIRECT, NULL, "suffocation"); + if (isdead(lf)) return; } - dam = lf->maxhp / 3; - limit(&dam, 1, NA); - losehp(lf, dam, DT_DIRECT, NULL, "suffocation"); - if (isdead(lf)) return; } // vampire in sunlight? if ((lf->race->id == R_VAMPIRE) && isoutdoors(lf->cell->map) && !isnighttime()) { @@ -19384,7 +19490,7 @@ void startlfturn(lifeform_t *lf) { if (lfhasflagval(lf, F_INJURY, IJ_ARTERYPIERCE, NA, NA, NULL)) { if (!bleedfrom(lf, BP_HANDS, B_SPLATTER)) { if (isplayer(lf)) msg("^BYou bleed!"); - losehp(lf, rnd(1,8), DT_DIRECT, NULL, "blood loss"); + losehp(lf, rnd(2,8), DT_DIRECT, NULL, "blood loss"); } } @@ -19728,7 +19834,16 @@ void startlfturn(lifeform_t *lf) { if (f) { int radius; radius = f->val[0]; - addobsinradius(lf->cell, f->val[0], DT_COMPASS, f->text, B_FALSE, lf); + if (radius == -1) { + cell_t *c; + // add object in front. + c = getcellindir(lf->cell, lf->facing); + if (c && !c->type->solid) { + addob(c->obpile, f->text); + } + } else { + addobsinradius(lf->cell, f->val[0], DT_COMPASS, f->text, B_FALSE, lf); + } } // handle life objects @@ -19963,6 +20078,25 @@ void startlfturn(lifeform_t *lf) { ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// + o = hasequippedobid(lf->pack, OT_AMU_CHOKING); + if (o && needstobreath(lf)) { + int seen = B_FALSE; + if (isplayer(lf)) { + msg("Your amulet is choking you!"); + seen = B_TRUE; + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s%s amulet is choking %s!", lfname, getpossessive(lfname), it(lf)); + seen = B_TRUE; + } + if (seen && !isknown(o)) { + makeknown(o->type->id); + } + losehp(lf, rolldie(2,6), DT_DIRECT, NULL, "an amulet of choking"); + setkillverb(lf, "Strangled"); + } + if (lfhasflag(lf, F_RAGE)) { killflagsofid(lf->flags, F_HIDING); } @@ -21430,11 +21564,18 @@ int touch(lifeform_t *lf, object_t *o) { // flaming or red-hot objects? if (!isimmuneto(lf->flags, DT_FIRE, B_FALSE)) { + int resistant = B_FALSE; + if (isresistantto(lf->flags, DT_FIRE, B_FALSE)) { + resistant = B_TRUE; + } + getflags(o->flags, retflag, &nretflags, F_ONFIRE, F_HOT, F_NONE); // IMPORTANT - check ONFIRE first! for (i = 0; i < nretflags; i++) { f = retflag[i]; // flaming weapons are ok - only the blade is burning if ((f->id == F_ONFIRE) && isweapon(o)) { + } else if ((f->id == F_HOT) && resistant) { + // fire resistance will stop F_HOT, but not F_ONFIRE. } else { // wearing gloves? they get damaged. if (gloves) { @@ -21517,6 +21658,25 @@ void unequipeffects(lifeform_t *lf, object_t *o) { // revert to normal form abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL); } + + if (o->type->id == OT_AMU_TRAVEL) { + map_t *newmap = NULL; + cell_t *newcell = NULL; + f = hasflag(o->flags, F_ORIGMAP); + if (f) { + // should always be true... + newmap = findmap(f->val[0]); + newcell = getcellat(newmap, f->val[1], f->val[2]); + } + + if (newcell) { + // go there! + teleportto(lf, newcell, B_FALSE); + } + + makeknown(o->type->id); + } + } void unsummon(lifeform_t *lf, int vanishobs) { @@ -21729,6 +21889,21 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { return B_TRUE; } + if (o->type->id == OT_PORTAL) { + f = hasflag(o->flags, F_MAPLINK); + if (f->val[0] != NA) { + map_t *m; + m = findmap(f->val[0]); + if (m && (m->habitat->id == H_HEAVEN)) { + if (!hasobofclass(lf->pack, OC_GODSTONE)) { + if (isplayer(lf)) msg("The portal doesn't seem to take you anywhere."); + if (onpurpose) taketime(lf, getmovespeed(lf)); + return B_TRUE; + } + } + } + } + curmap = obcell->map; if ((o->type->id == OT_GRATINGFLOOR) && !hasflag(o->flags, F_MAPLINK)) { @@ -23036,15 +23211,84 @@ int wear(lifeform_t *lf, object_t *o) { } } - // special case: make ring of invis fully known - the HPDRAIN flag - // won't be announced, so since we don't know all the flags we would - // otherwise get "you turn invisible!" but still have the ring known - // as "a blue ring" (or whatever) - if (isplayer(lf) && (o->type->id == OT_RING_INVIS)) makeknown(o->type->id); + // special cases: + if (isplayer(lf)) { + if (o->type->id == OT_RING_INVIS) { + // make ring of invis fully known - the HPDRAIN flag + // won't be announced, so since we don't know all the flags we would + // otherwise get "you turn invisible!" but still have the ring known + // as "a blue ring" (or whatever) + makeknown(o->type->id); + } + } + + if (o->type->id == OT_AMU_TRAVEL) { + if (isplayer(lf) || cansee(player, lf)) { + makeknown(o->type->id); + } + } else if (o->type->id == OT_AMU_CHOKING) { + if (isplayer(lf)) { + msg("^%c%s starts to constrict around your neck!", getlfcol(lf, CC_VBAD), obname); + makeknown(o->type->id); + if (!needstobreath(lf)) { + msg("Luckily, you don't need to breath."); + } + } + } // give flags giveobflags(lf, o, F_EQUIPCONFER); + // special case... + if (o->type->id == OT_AMU_TRAVEL) { + map_t *newmap = NULL; + cell_t *newcell = NULL; + f = hasflag(o->flags, F_NEWMAP); + if (f) { + newmap = findmap(f->val[0]); + newcell = getcellat(newmap, f->val[1], f->val[2]); + } else { + int mindepth,maxdepth,newdepth; + region_t *newregion; + // TODO: add other planes here. they must be from regiontypes which ALWAYS + // exist (ie. which are created at the start of the game). + switch (rnd(0,1)) { + case 0: + case 1: + newregion = findregionbytype(RG_MAINDUNGEON); + break; + } + // pick a new map at least 10 levels below + maxdepth = newregion->rtype->maxdepth; + + mindepth = lf->cell->map->depth + 10; + if (mindepth >= maxdepth) { + newdepth = maxdepth; + } else { + newdepth = rnd(mindepth, maxdepth); + } + newmap = findregionmap(newregion->id, newdepth); + if (!newmap) { + // create new map + newmap = addmap(); + createmap(newmap, newdepth, newregion, NULL, D_NONE, NULL); + } + // find random cell + newcell = getrandomcell(newmap); + while (!cellwalkable(NULL, newcell, NULL) || celldangerous(lf, newcell, B_FALSE, NULL)) { + newcell = getrandomcell(newmap); + } + } + // remember orig cell + killflagsofid(o->flags, F_ORIGMAP); + addflag(o->flags, F_ORIGMAP, lf->cell->map->id, lf->cell->x, lf->cell->y, NULL); + + // go there! + teleportto(lf, newcell, B_FALSE); + + makeknown(o->type->id); + } + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { // set statdirty since this might have impacted your AR / EV statdirty = B_TRUE; diff --git a/lf.h b/lf.h index 79c113e..28951d3 100644 --- a/lf.h +++ b/lf.h @@ -164,6 +164,7 @@ int getexposedlimbs(lifeform_t *lf); object_t *getfirearm(lifeform_t *lf); enum LOFTYPE getfirearmloftype(lifeform_t *lf); int getfootprinttime(lifeform_t *lf); +enum GENDER getgender(lifeform_t *lf); lifeform_t *getguntarget(lifeform_t *lf); int getguntargetid(lifeform_t *lf); //int gethealtime(lifeform_t *lf); @@ -287,6 +288,7 @@ void givestartskills(lifeform_t *lf, flagpile_t *fp); map_t *gotolev(lifeform_t *lf, int depth, object_t *fromstairs); int gotosleep(lifeform_t *lf, int onpurpose); void growhydrahead(lifeform_t *lf, int announce); +void losehydrahead(lifeform_t *lf); flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp); int hasfreeaction(lifeform_t *lf); int real_hasfreeaction(lifeform_t *lf, enum FLAG exception); @@ -392,6 +394,7 @@ float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); void modmorale(lifeform_t *lf, int howmuch); void modstamina(lifeform_t *lf, float howmuch); int movecausesnoise(lifeform_t *lf); +int needstobreath(lifeform_t *lf); int needstorest(lifeform_t *lf, char *validchars); void noarmouron(race_t *r, enum BODYPART bp); int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext); diff --git a/map.c b/map.c index e89c382..77921e3 100644 --- a/map.c +++ b/map.c @@ -5730,7 +5730,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int // critical hit? 100% chance in middle, 60 at one cell, 20 at two cells critchance = 100 - (mydist*40); if (pctchance(critchance)) { - criticalhit(NULL, cc->lf, BP_HANDS, pctof(critchance, dam), DT_EXPLOSIVE); + criticalhit(NULL, cc->lf, BP_HANDS, NULL, pctof(critchance, dam), DT_EXPLOSIVE); } // move away from centre of explosion knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 2, NULL, 40-(mydist*10), B_TRUE); diff --git a/move.c b/move.c index a571a25..67f7d93 100644 --- a/move.c +++ b/move.c @@ -935,7 +935,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc // don't fall mightfall = B_FALSE; // 20% chance per cell pushed - if (pctchance(howfar*20)) criticalhit(NULL, lf, getrandomcorebp(lf, NULL), dam, DT_BASH); + if (pctchance(howfar*20)) criticalhit(NULL, lf, getrandomcorebp(lf, NULL), NULL, dam, DT_BASH); break; case E_SWIMMING: case E_LFINWAY: diff --git a/objects.c b/objects.c index b1d1c54..9a6f08a 100644 --- a/objects.c +++ b/objects.c @@ -496,6 +496,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum int wantrarity = RR_NONE; int wantgoodness = G_NA; int wantfoodtaint = B_FALSE; + race_t *linkrace = NULL; enum OBTYPE wantfountaintype = OT_NONE; enum LFSIZE wantarmsize = SZ_ANY; enum MATERIAL wantdiffmat = MT_NOTHING; @@ -719,6 +720,14 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum addflag(wantflags, F_HOT, 3, NA, NA, "1d4"); p += strlen("red-hot "); donesomething = B_TRUE; + // generic linkflags + } else if (strstarts(p, "linkrace:")) { + char racename[BUFLEN]; + p += strlen("linkrace:"); + // read next + p = readuntil(racename, p, ' '); + linkrace = findracebyname(racename); + donesomething = B_TRUE; // condition flags } else if (strstarts(p, "battered ")) { wanthppct = 75; @@ -1144,7 +1153,9 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum // override blessed status from flags... f = hasflag(ot->flags, F_STARTBLESSED); if (f) { - wantblessed = f->val[0]; + if ((f->val[1] == NA) || pctchance(f->val[1])) { + wantblessed = f->val[0]; + } } // don't give nopickup objects to lifeforms @@ -1356,6 +1367,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum } } + if (linkrace && (linkrace->id != R_NONE)) { + addflag(o->flags, F_LINKRACE, linkrace->id, NA, NA, NULL); + } + if (gamemode != GM_LOADING) { if (hasflag(o->flags, F_NOBLESS)) { setblessed(o, B_UNCURSED); @@ -1423,28 +1438,30 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum int val[3]; int ok = B_FALSE; if (obloc) { - // fill in flag vals - switch (doorflag[n]) { - case F_LOCKED: - val[0] = B_TRUE; - val[1] = getdoorlockdiff(obloc->map->depth); - val[2] = NA; - ok = B_TRUE; - break; - case F_JAMMED: - val[0] = rnd(1,obloc->map->depth+5); - val[1] = B_FALSE; // not known yet - val[2] = NA; - ok = B_TRUE; - break; - case F_SECRET: - val[0] = getdoorsecretdiff(obloc->map->depth); - val[1] = NA; - val[2] = NA; - ok = B_TRUE; - break; - default: - break; + if (!hasflag(o->flags, doorflag[n])) { + // fill in flag vals + switch (doorflag[n]) { + case F_LOCKED: + val[0] = B_TRUE; + val[1] = getdoorlockdiff(obloc->map->depth); + val[2] = NA; + ok = B_TRUE; + break; + case F_JAMMED: + val[0] = rnd(1,obloc->map->depth+5); + val[1] = B_FALSE; // not known yet + val[2] = NA; + ok = B_TRUE; + break; + case F_SECRET: + val[0] = getdoorsecretdiff(obloc->map->depth); + val[1] = NA; + val[2] = NA; + ok = B_TRUE; + break; + default: + break; + } } if (ok) { addflag(o->flags, doorflag[n], val[0], val[1], val[2], NULL); @@ -1491,7 +1508,13 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum int ammoamt; ammoflag = hasflag(o->flags, F_AMMOCAPACITY); ammoamt = rnd(0,ammoflag->val[0]); // note: can be 0 - ammotype = getrandomammofor(o); + + if (gamemode == GM_CHARGEN) { + ammotype = getrandomammofor(o, B_TRUE); + } else { + ammotype = getrandomammofor(o, B_FALSE); + } + if (ammotype && (ammoamt > 0)) { char ammostring[BUFLEN]; sprintf(ammostring, "%d %s",ammoamt,ammotype->name); @@ -2257,13 +2280,22 @@ void addobsinradius(cell_t *centre, int radius, int dirtype, char *name, int all if (!ot) return; getradiuscells(centre, radius, DT_ORTH, B_FALSE, LOF_WALLSTOP, (radius == 0) ? B_TRUE : B_FALSE, cell, &ncells, B_FALSE); + // global return values + nretobs = 0; + for (i = 0; i < ncells; i++) { c = cell[i]; if (!c->type->solid) { if (allowdupes || !hasob(c->obpile, ot->id)) { o = addob(c->obpile, name); - if (o && creator) { - setobcreatedby(o, creator); + if (o) { + if (creator) { + setobcreatedby(o, creator); + } + // global return values + retobs[nretobs] = o; + retobscount[nretobs] = o->amt; + nretobs++; } } } @@ -3028,15 +3060,6 @@ int checkcritprotection(lifeform_t *lf, object_t *o) { if (pctchance(getcritprotection(o))) { char obname[BUFLEN]; getobname(o, obname, o->amt); - /* - if (isplayer(lf)) { - msg("Your %s protects you.", noprefix(obname)); - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s%s %s protects it.", lfname, getpossessive(lfname), noprefix(obname)); - } - */ return B_TRUE; } return B_FALSE; @@ -4368,7 +4391,7 @@ object_t *getrandomammo(lifeform_t *lf) { return NULL; } -objecttype_t *getrandomammofor(object_t *o) { +objecttype_t *getrandomammofor(object_t *o, int usefirst) { objecttype_t *ot; objecttype_t *poss[MAXCANDIDATES]; int nposs = 0; @@ -4381,7 +4404,11 @@ objecttype_t *getrandomammofor(object_t *o) { } } if (nposs) { - ot = poss[rnd(0,nposs-1)]; + if (usefirst) { + ot = poss[0]; + } else { + ot = poss[rnd(0,nposs-1)]; + } } else { ot = NULL; } @@ -8582,6 +8609,35 @@ void obdie(object_t *o) { } } + // spell? + f = hasflag(o->flags, F_SPELLCLOUDONDEATH); + if (f) { + cell_t *where; + int power; + char obname[BUFLEN],seebuf[BUFLEN],noseebuf[BUFLEN]; + char buf[BUFLEN],*p; + where = getoblocation(o); + getobname(o, obname, 1); + p = readuntil(seebuf, f->text, '^'); + p = readuntil(noseebuf, p, '^'); + p = readuntil(buf, p, '^'); + power = atoi(buf); + + if (f->val[2] == B_IFACTIVATED) { + if (isactivated(o)) { + spellcloud(where, f->val[1], UNI_SHADELIGHT, C_RANDOM, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o); + removeob(o, o->amt); + return; + } + } else { + spellcloud(where, f->val[1], UNI_SHADELIGHT, C_RANDOM, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o); + removeob(o, o->amt); + return; + } + } + + + if (hasflag(o->flags, F_CONTAINER)) { // dump object's contents into parent container @@ -9643,7 +9699,17 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { ch = askchar(ques, "yn", "y", B_TRUE, B_FALSE); if (ch == 'y') { char newobname[BUFLEN]; - if (oo->type->id == OT_FOUNTAIN) { + flag_t *bfob; + bfob = hasflag(oo->flags, F_FILLPOT); + if (bfob) { + objecttype_t *ot; + ot = findot(bfob->val[0]); + if (ot) { + strcpy(newobname, ot->name); + } else { + strcpy(newobname, "potion of blood"); + } + } else if (oo->type->id == OT_FOUNTAIN) { objecttype_t *ot; // same type as fountain f = hasflag(oo->flags, F_LINKOB); @@ -11866,7 +11932,11 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { f = hasflag(o->flags, F_EXPLODEONDEATH); if (!f) f = hasflag(o->flags, F_EXPLODEONDAM); if (f) { - explodeob(o, f, f->val[1]); + // with explodeondam, only happen if damtype is any. + if ((f->id == F_EXPLODEONDAM) && (f->val[0] != NA)) { + } else { + explodeob(o, f, f->val[1]); + } return B_FALSE; } @@ -12368,18 +12438,57 @@ int real_takedamage(object_t *o, int howmuch, int damtype, int wantannounce) { } } + // spell cloud ? + f = hasflag(o->flags, F_SPELLCLOUDONDAM); + if (f) { + int power; + char obname[BUFLEN],seebuf[BUFLEN],noseebuf[BUFLEN]; + char buf[BUFLEN],*p; + cell_t *where; + where = getoblocation(o); + getobname(o, obname, 1); + p = readuntil(seebuf, f->text, '^'); + p = readuntil(noseebuf, p, '^'); + p = readuntil(buf, p, '^'); + power = atoi(buf); + + if (f->val[2] == B_IFACTIVATED) { + if (isactivated(o)) { + if (!hasflag(o->flags, F_SPELLCLOUDONDEATH)) { + spellcloud(where, f->val[1], UNI_SHADELIGHT, C_RANDOM, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o); + } + addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); + } + } else { + if (!hasflag(o->flags, F_SPELLCLOUDONDEATH)) { + spellcloud(where, f->val[1], UNI_SHADELIGHT, C_RANDOM, f->val[0], power, B_TRUE, seebuf, noseebuf, B_FALSE, o); + } + addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); + } + return howmuch; + } + + // flashes? f = hasflag(o->flags, F_FLASHONDAM); if (f) { + flag_t *f2; + lifeform_t *thrower = NULL; + cell_t *where; + where = getoblocation(o); + f2 = hasflag(o->flags, F_THROWNBY); + if (f2) { + thrower = findlf(where->map, f2->val[0]); + } if (f->val[2] == B_IFACTIVATED) { if (hasflag(o->flags, F_ACTIVATED)) { // flash, then object dies - brightflash(getoblocation(o),f->val[0], NULL); + brightflash(where,f->val[0], thrower); addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); } } else { // flash, then object dies - brightflash(getoblocation(o),f->val[0], NULL); + brightflash(where,f->val[0], thrower); addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); } return howmuch; @@ -12669,10 +12778,6 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp } } - if (thrower && isplayer(thrower)) { - addflag(o->flags, F_PLAYERMISSILE, B_TRUE, NA, NA, NULL); - } - // announce it ("xx throws xx" "at yy") if (announcethrow) { if (thrower && isplayer(thrower)) { @@ -12719,6 +12824,45 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp //taketime(thrower, SPEED_THROW); + // special case + if (thrower && target && (o->type->id == OT_JAVELINLT)) { + if (seen) { + msg("%s transforms into a bolt of lightning!", obname); + makeknown(o->type->id); + // refresh name + getobname(o, obname, 1); + } + dospelleffects(thrower, OT_S_LIGHTNINGBOLT, 8, target, NULL, where, B_UNCURSED, NULL, B_FALSE, o); + // use a charge. + if (usecharge(o) <= 0) { + // no charges left? change into a normal javelin. + o->type = findot(OT_JAVELIN); + // move it to target cell + newob = real_moveob(o, where->obpile, amt, B_FALSE); + if (newobptr) *newobptr = newob; + if (newob) { + killflagsofid(newob->flags, F_RNDCHARGES); + killflagsofid(newob->flags, F_CHARGES); + getobname(newob, obname, 1); + if (haslos(player, where)) { + msg("%s reforms on the ground.", obname); + } + } + } else { + // go back to caster's hand + if (isplayer(thrower)) { + msg("%s reappears in your hands!", obname); + } else if (cansee(player, thrower)) { + msg("%s reappears in %s%s hands!", obname, throwername, getpossessive(throwername)); + } + } + return B_FALSE; + } + + if (thrower && isplayer(thrower)) { + addflag(o->flags, F_PLAYERMISSILE, B_TRUE, NA, NA, NULL); + } + // some obejcts will die when thrown. if (hasflag(o->flags, F_POWDER)) { // special cases first @@ -13241,6 +13385,12 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp // fake its birth time so that it can be damaged newob->birthtime = -1; + killflagsofid(newob->flags, F_PLAYERMISSILE); + + if (thrower) { + addflag(newob->flags, F_THROWNBY, thrower->id, NA, NA, NULL); + } + // now we can get rid of the fake obpile, if we used it if (op) killobpile(op); @@ -13269,6 +13419,8 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp if (newob && !isdeadob(newob)) { + killflagsofid(newob->flags, F_THROWNBY); + if (thrower && hasactivespell(thrower, OT_S_WHATGOESUP)) { // on the ground? if ((newob->pile->where == where) && haslof(newob->pile->where, thrower->cell, LOF_NEED, NULL)) { diff --git a/objects.h b/objects.h index 01bcd39..d2ed817 100644 --- a/objects.h +++ b/objects.h @@ -99,7 +99,7 @@ object_t *getoutercontainerop(obpile_t *op); object_t *getammo(object_t *gun); objecttype_t *getbasicweaponforskill(enum SKILL skid); object_t *getrandomammo(lifeform_t *lf); -objecttype_t *getrandomammofor(object_t *o); +objecttype_t *getrandomammofor(object_t *o, int usefirst); brand_t *getrandombrandfor(objecttype_t *ot); int getrandomgrimoirelev(void); objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity, lifeform_t *forlf); diff --git a/spell.c b/spell.c index 0ae68a6..56df679 100644 --- a/spell.c +++ b/spell.c @@ -6230,7 +6230,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(target, targetname); msg("Unseen forces rip into %s%s flesh!", targetname, getpossessive(targetname)); } - criticalhit(caster, target, getrandomcorebp(target, NULL), rnd(1,6), DT_SLASH); + criticalhit(caster, target, getrandomcorebp(target, NULL), NULL, rnd(1,6), DT_SLASH); } else if (spellid == OT_S_GLYPHWARDING) { char buf[BUFLEN]; sprintf(buf, "^g*WARD%d*^n", power/2); @@ -6657,7 +6657,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int amt; char obname[BUFLEN]; getobname(o, obname, o->amt); - msg("Your %s glows %s for a moment.", noprefix(obname), (blessed == B_CURSED) ? "black" : "green"); + msg("Your %s glow%s %s for a moment.", noprefix(obname), (o->amt == 1) ? "s" : "", + (blessed == B_CURSED) ? "black" : "green"); if (seenbyplayer) *seenbyplayer = B_TRUE; if (blessed == B_CURSED) { amt = -1; @@ -9145,7 +9146,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcells); animcells(caster->cell, &retcell[1], nretcells-1, B_FALSE, '/', '\\', C_WHITE); if (cansee(player, caster)) { - msg("%s shoot%s a bolt of electricity!",castername, isplayer(caster) ? "" : "s"); + // if fromob is set, this was from a lightning javelin. instead of announcing + // the bolt firing, announce it hitting people (since we've already said + // "the javelin turns into lightning"). + if (!fromob) { + msg("%s shoot%s a bolt of electricity!",castername, isplayer(caster) ? "" : "s"); + } } // don't hit the caster cell on fire! @@ -9163,6 +9169,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ nhits--; } if (haslos(player, c)) { + if (fromob) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("The bolt of lightning strikes %s!", lfname); + } needredraw = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -13634,13 +13645,39 @@ int schoolappearsinbooks(enum SPELLSCHOOL ss) { void spellcloud(cell_t *srcloc, int radius, int ch, enum COLOUR col, enum OBTYPE sid, int power, int frompot, char *seetext, char *noseetext, int aimedateyes, object_t *fromob) { int x,y; + char *see = NULL, *nosee = NULL; objecttype_t *ot; ot = findot(sid); if (!ot) return; - if (ch != '\0') { - animradial(srcloc, radius, ch, col, DT_ORTH, seetext, noseetext); + if (seetext) { + see = strdup(seetext); } + if (noseetext) { + nosee = strdup(noseetext); + } + + if (fromob) { + char obname[BUFLEN]; + // replace "OB" in seetext/noseetext based on fromob + getobname(fromob, obname, 1); + if (see) { + see = strrep(see, "OB", obname, NULL); + capitalise(see); + } + if (nosee) { + nosee = strrep(nosee, "OB", obname, NULL); + capitalise(nosee); + } + } + + + if (ch != '\0') { + animradial(srcloc, radius, ch, col, DT_ORTH, see, nosee); + } + if (see) free(see); + if (nosee) free(nosee); + for (y = srcloc->y - radius ; y <= srcloc->y + radius; y++) { for (x = srcloc->x - radius ; x <= srcloc->x + radius; x++) { cell_t *c; diff --git a/text.c b/text.c index 1e769a5..ab8fb8d 100644 --- a/text.c +++ b/text.c @@ -470,22 +470,35 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam if (damtype == DT_ACID) { return "burn"; } else if (damtype == DT_BASH) { - if (dam <= 2) { - return "whack"; - } else if (dam <= 6) { - if (onein(2)) { - return "hit"; - } else { - return "bash"; + // chance of special monk attack verb + if (lf && hasjob(lf, J_MONK) && wep && hasflag(wep->flags, F_UNARMEDWEP) && onein(2)) { + switch (rnd(1,7)) { + case 1: return "punch"; + case 2: return "palmstrike"; + case 3: return "elbow"; + case 4: return "kick"; + case 5: return "roundhouse kick"; + case 6: return "karate chop"; + case 7: return "strike"; } - } else if (dam <= 12) { - return "pound"; - } else if (dam <= 16) { - return "slam"; - } else if (dam <= 20) { - return "pummel"; } else { - return "clobber"; + if (dam <= 2) { + return "whack"; + } else if (dam <= 6) { + if (onein(2)) { + return "hit"; + } else { + return "bash"; + } + } else if (dam <= 12) { + return "pound"; + } else if (dam <= 16) { + return "slam"; + } else if (dam <= 20) { + return "pummel"; + } else { + return "clobber"; + } } } else if (damtype == DT_BITE) { if (lf && (ownersize <= SZ_SMALL)) { @@ -1669,6 +1682,18 @@ char *is(lifeform_t *lf) { else return "is"; } +char *it(lifeform_t *lf) { + if (isplayer(lf)) return "you"; + + switch (getgender(lf)) { + case G_MALE: return "him"; + case G_FEMALE: return "her"; + default: break; + } + + return "it"; +} + int isvowel (char c) { switch (c) { case 'a': diff --git a/text.h b/text.h index 317d90c..39ef9d6 100644 --- a/text.h +++ b/text.h @@ -44,6 +44,7 @@ char *gettimetextfuzzy(char *retbuf, int wantpm); char *getwaterdepthname(enum DEPTH d); char *getweighttext(float weight, char *buf, int shortfmt); char *is(lifeform_t *lf); +char *it(lifeform_t *lf); int isvowel(char c); void makegunaimstring(lifeform_t *lf, int lfid, char *retbuf); char *makekillertext(char *retbuf, char *killverb, char *lastdam, map_t *where, int wantextra, int wantlocation);