diff --git a/ai.c b/ai.c index e6625cb..a7b2095 100644 --- a/ai.c +++ b/ai.c @@ -199,8 +199,11 @@ enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) { if (ok) { // lycanthropes always change to animal form at midnight. if (gettimephase() == TP_MIDNIGHT) { + flag_t *lyf; + + lyf = lfhasflag(lf, F_LYCANTHROPE); if ((f->val[0] == OT_S_SHAPESHIFT) && - lfhasflag(lf, F_LYCANTHROPE)) { + lyf && (lyf->val[0] != 0)) { if (ispolymorphed(lf)) { // never change to human form. ok = B_FALSE; @@ -1775,6 +1778,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { } if (!movetowards(lf, target->cell, DT_ORTH, B_FALSE)) { + dblog(".oO { successfully moved towards target. }"); turntoface(lf, target->cell); // success return B_FALSE; @@ -2615,9 +2619,6 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG specificcheckok = B_FALSE; } } - if ((ot->id == OT_S_INVISIBILITY) && lfhasflag(victim, F_INVISIBLE)) { - specificcheckok = B_FALSE; - } if ((ot->id == OT_S_PAIN) && lfhasflag(victim, F_PAIN)) { specificcheckok = B_FALSE; } @@ -2627,6 +2628,12 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_S_HEALINGMIN) && (lf->hp >= lf->maxhp)) { specificcheckok = B_FALSE; } + if ((ot->id == OT_S_INVISIBILITY) && lfhasflag(victim, F_INVISIBLE)) { + specificcheckok = B_FALSE; + } + if ((ot->id == OT_A_IRONFIST) && getweapon(lf)) { + specificcheckok = B_FALSE; + } if ((ot->id == OT_S_PARALYZE) && lfhasflag(victim, F_PARALYZED)) { specificcheckok = B_FALSE; } @@ -3126,6 +3133,12 @@ void makewantedoblist(lifeform_t *lf, int *noids, enum OBTYPE *oid, int *oidcove // returns B_FALSE if successful int useitemwithflag(lifeform_t *lf, enum FLAG whichflag) { object_t *o; + + // can't use anything if enraged + if (lfhasflag(lf, F_RAGE)) return B_TRUE; + // aicontrolled human won't use items + if (lfhasflag(lf, F_AICONTROLLED)) return B_TRUE; + for (o = lf->pack->first ; o ; o = o->next) { if (hasflag(o->flags, whichflag)) { if (aiobok(lf, o, lf)) { diff --git a/attack.c b/attack.c index 71536a7..6cd0af5 100644 --- a/attack.c +++ b/attack.c @@ -205,6 +205,15 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { if (c->lf) { // warnings if (!force && isplayer(lf)) { + int h,m,s; + splittime(&h,&m,&s); + + if (godprayedto(R_GODLIFE) && (h == 6)) { + if (!warnabout("Really attack during Glorana's Peace?")) { + return B_TRUE; + } + } + if (isprone(lf)) { if (!warnabout("Really attack while prone (-4 accuracy)?")) { return B_TRUE; @@ -463,8 +472,14 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { if (nweps <= 0) { if (isplayer(lf)) { msg("You cannot attack!"); + } else if (lfhasflag(lf, F_DEBUG)) { + msg("DB: %s cannot attack!",lf->race->name); } if (op) killobpile(op); + if (!isplayer(lf)) { + // avoid infinite loops + taketime(lf, getactspeed(lf)); + } return B_TRUE; } @@ -639,6 +654,8 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { if (isplayer(lf) && attacktarget) { if (attacktype == AT_LF) { if (!isgod(attacktarget)) { + int h,m,s; + splittime(&h,&m,&s); if (attackedfriend) { angergodmaybe(R_GODMERCY, 25, GA_ATTACKALLY); angergodmaybe(R_GODPURITY, 100, GA_ATTACKALLY); @@ -686,6 +703,9 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { killflagsofid(lf->flags, F_USEDPOISON); if (isplayer(lf)) god_usepoison_response(); } + if (godprayedto(R_GODLIFE) && (h == 6)) { + angergodmaybe(R_GODLIFE, 30, GA_PEACEHOUR); + } } } else if (attacktype == AT_OB) { angergodmaybe(R_GODNATURE, 10, GA_ATTACKOBJECT); @@ -865,6 +885,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) ndam = 0; hit = rolltohit(lf, victim, wep, &critical, &fumble); + if (lfhasflag(victim, F_HEAVENARM)) { + critical = B_FALSE; + } if (critical && !lfhasflag(lf, F_PHANTASM)) { object_t *armour; @@ -1397,7 +1420,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (!isdead(victim) && !blocked && !dodged) { // special weapon effects, as long as you're not doing a heavy blow if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) { - wepeffects(wep->flags, victim->cell, damflag, dam[0]); + wepeffects(wep->flags, victim->cell, damflag, dam[0], isunarmed); } if (isunarmed) { f = lfhasflag(lf, F_FREEZINGTOUCH); @@ -1423,7 +1446,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // confer flags from attacker? if (dam[0]) { - wepeffects(lf->flags, victim->cell, damflag, dam[0]); + wepeffects(lf->flags, victim->cell, damflag, dam[0], isunarmed); } // special lifeform-based effects @@ -1471,7 +1494,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (cansee(player, lf) || cansee(player, victim)) { char wepname[BUFLEN]; real_getobname(wep, wepname, 1, B_PREMODS, B_NOCONDITION, B_NOBLINDADJUST, B_BLESSINGS, B_NOUSED, B_NOSHOWALL); - msg("^%d%s%s %s %s to %s!", getlfcol(lf, CC_BAD), + msg("^%c%s%s %s %s to %s!", getlfcol(lf, CC_BAD), attackername, getpossessive(attackername), noprefix(wepname), (wep->amt == 1) ? "sticks" : "stick", victimname); } @@ -1542,9 +1565,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (fumble) { if (wep && !isunarmed) { if (isplayer(lf)) { - msg("^%dYou fumble your attack!", getlfcol(lf, CC_BAD)); + msg("^%cYou fumble your attack!", getlfcol(lf, CC_BAD)); } else if (cansee(player, lf)) { - msg("^%d%s fumbles its attack!", getlfcol(lf, CC_BAD), attackername); + msg("^%c%s fumbles its attack!", getlfcol(lf, CC_BAD), attackername); } drop(wep, ALL); wep = NULL; @@ -1771,7 +1794,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { if (!isdeadob(o)) { // special weapon effects, as long as you're not doing a heavy blow if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) { - wepeffects(wep->flags, obloc, damflag, dam[0]); + wepeffects(wep->flags, obloc, damflag, dam[0], isunarmed); } } @@ -2006,7 +2029,7 @@ int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE da if (cansee(player, lf) || cansee(player, victim)) { char attname[BUFLEN]; getlfname(lf, attname); - msg("^%d%s%s %s %s to %s!", getlfcol(victim, CC_BAD), + msg("^%c%s%s %s %s to %s!", getlfcol(victim, CC_BAD), victimname, getpossessive(victimname), noprefix(shname), (shield[i]->amt == 1) ? "sticks" : "stick", attname); } @@ -2073,7 +2096,7 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, objec } else { strcpy(lfname, "Something"); } - msg("^%d%s slice%s off %s%s %s!", getlfcol(victim, CC_VBAD), + msg("^%c%s slice%s off %s%s %s!", getlfcol(victim, CC_VBAD), lfname, isplayer(lf) ? "" : "s", vname, getpossessive(vname), bpname); } // take extra damage based on number of severable limbs @@ -2848,7 +2871,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical, return gothit; } -void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { +void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isunarmed) { flag_t *f; lifeform_t *victim; lifeform_t *owner = NULL; @@ -2888,6 +2911,12 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { // ie "a poisoned short sword" snprintf(frombuf, BUFLEN, "%s", wepname); } + } else { + if (owner) { + real_getlfname(owner, frombuf, NULL, B_SHOWALL, B_REALRACE); + } else { + strcpy(frombuf, "something unknown"); + } } getflags(fp, retflag, &nretflags, F_FLAMESTRIKE, F_HEAVYBLOW, F_HITCONFER, F_RACESLAY, F_REVENGE, F_RUSTED, F_NONE); @@ -2982,6 +3011,14 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { fid = f->val[0]; ftext = f->text; + + // hitconfer from owner can't be conferred if this was a weapon attack + // ie. if something has poisonous claws and hits you with a weapon, you + // don't get poisoned. + if (fp->owner && !isunarmed) { + continue; + } + // the f_poisoned flag stacks, others don't. if (!lfhasflag(victim, fid) || (fid == F_POISONED)) { int passedcheck = B_FALSE; @@ -3009,6 +3046,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { enum POISONTYPE ptype; int ppower; + assert(valflag); if (valflag) { ptype = valflag->val[0]; if (valflag->val[1] == NA) { @@ -3016,15 +3054,20 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { } else { ppower = valflag->val[1]; } - } else { - // should never happen. - ptype = P_VENOM; - ppower = 1; } if (!wep && strlen(ftext)) { strcpy(frombuf, ftext); + } else if (ptype == P_LYCANTHROPY) { + char *p; + // special case - we need to remember what kind of + // creature to change into. since lycanthropy isn't fatal + // as such we can use the 'what caused you damage' field for + // this information + p = readuntil(frombuf, valflag->text, '^'); + readuntil(frombuf, p, '^'); } + poison(victim, howlong, ptype, ppower, frombuf, owner ? owner->race->id : R_NONE); } else { // flag values diff --git a/attack.h b/attack.h index 726893c..e3b1893 100644 --- a/attack.h +++ b/attack.h @@ -30,4 +30,4 @@ int ismeleedam(enum DAMTYPE damtype); int isphysicaldam(enum DAMTYPE damtype); void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, enum MODTYPE how); int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical, int *fumble); -void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam); +void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam, int isunarmed); diff --git a/data.c b/data.c index 4870940..c1ccd92 100644 --- a/data.c +++ b/data.c @@ -533,7 +533,7 @@ void initjobs(void) { addflag(lastjob->flags, F_LEVFLAG, 5, F_DISEASEIMMUNE, B_TRUE, NULL); // 6: waterawlk via 'body equilibrium' (innate) addflag(lastjob->flags, F_LEVABIL, 6, OT_A_AIMEDSTRIKE, NA, NULL); - // 7: iron fist - converts all remaining stamina to damage+knockback. + addflag(lastjob->flags, F_LEVABIL, 7, OT_A_IRONFIST, NA, NULL); // 8: molecular manipulation (ie. lower hardness of physical obs by level-7, not lfs) (innate) addflag(lastjob->flags, F_LEVFLAG, 8, F_TREMORSENSE, NA, NULL); // 9: resistance to charm, hypnosis, sleep (innate) @@ -1029,6 +1029,7 @@ void initobjects(void) { addpoisontype(P_FOOD, "gastroenteritis", "Poisoned", "^bYOU vomit#S violently.", OT_VOMITPOOL, 1, 25, PS_POISON,20); addpoisontype(P_FOODBAD, "salmonella poisoning", "Poisoned", "^bYOU vomit#S violently.", OT_VOMITPOOL, 2, 33, PS_POISON, 30); addpoisontype(P_GAS, "gas inhalation", "Poisoned", "^bYOU cough#S.", OT_NONE, 1, 25, PS_POISON,0); + addpoisontype(P_LYCANTHROPY, "lycanthropy", "Cursed", "", OT_NONE, 0, 0, PS_CURSE, -1); addpoisontype(P_ROT, "the mummy's curse", "Cursed", "", OT_NONE, 0, 0, PS_CURSE, 0); addpoisontype(P_TETANUS, "tetanus", "Sick", "^bYOUR muscles spasm violently!", OT_NONE, 0, 3, PS_DISEASE, 15); addpoisontype(P_VENOM, "venom poisoning", "Poisoned", "^bYOU cough#S up blood.", OT_BLOODSPLASH, 1, 25, PS_POISON, 0); @@ -2788,6 +2789,8 @@ void initobjects(void) { addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); + addot(OT_POT_LYCANTHROPY, "potion of lycanthropy", "Infects the drinker with the curse of lycanthropy.", MT_GLASS, 1, OC_POTION, SZ_TINY); + addflag(lastot->flags, F_VALUE, 300, NA, NA, NULL); addot(OT_POT_LEVITATION, "potion of levitation", "Causes the drinker to float up in the air.", MT_GLASS, 1, OC_POTION, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); addflag(lastot->flags, F_VALUE, 150, NA, NA, NULL); @@ -4779,6 +4782,10 @@ void initobjects(void) { addflag(lastot->flags, F_STAMCOST, 4, NA, NA, NULL); addot(OT_A_INSPECT, "inspect item", "Try to identify an unknown scroll, book, wand or ring from your pack.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addot(OT_A_IRONFIST, "iron fist", "Channel all your remaining stamina into one almighty blow.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); + addflag(lastot->flags, F_STAMCOST, 1, NA, NA, NULL); addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); @@ -4972,6 +4979,7 @@ void initobjects(void) { addflag(lastot->flags, F_THE, NA, NA, NA, NULL); addflag(lastot->flags, F_INVULNERABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERWITHOUTHANDS, B_TRUE, NA, NA, NULL); addot(OT_KEYIRON, "ancient iron key", "An ancient key made from iron. It looks important.", MT_METAL, 2, OC_TOOLS, SZ_SMALL); addflag(lastot->flags, F_GLYPH, C_GREY, '[', NA, NULL); @@ -5349,6 +5357,7 @@ void initobjects(void) { addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HOLDCONFER, F_KNOWSTIME, B_FALSE, IFKNOWN, NULL); + addflag(lastot->flags, F_OPERWITHOUTHANDS, B_TRUE, NA, NA, NULL); addot(OT_DIGITALWATCH, "digital watch", "An electronic timekeeping device which shows the time as a number.", MT_METAL, 0.1, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 85, NA, NULL); addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); @@ -5356,6 +5365,7 @@ void initobjects(void) { addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_HOLDCONFER, F_KNOWSTIME, B_TRUE, IFKNOWN, NULL); + addflag(lastot->flags, F_OPERWITHOUTHANDS, B_TRUE, NA, NA, NULL); addot(OT_INSECTICIDE, "can of insecticide", "A spraycan containing poisonous chemicals.", MT_METAL, 0.5, OC_TECH, SZ_TINY); addflag(lastot->flags, F_RARITY, H_SWAMP, 85, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_ALL, 85, RR_UNCOMMON, NULL); @@ -17222,7 +17232,7 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLSPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 6, NA, NA, NULL); addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 6, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 6, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 1, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d8;"); @@ -17239,10 +17249,13 @@ void initrace(void) { addflag(lastrace->flags, F_HATESRACE, R_WERERAT, NA, NA, NULL); addflag(lastrace->flags, F_HATESRACE, R_WEREWOLF, NA, NA, NULL); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_LYCANTHROPE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_LYCANTHROPE, -1, NA, NA, "grizzly bear"); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 8, NA, NA, NULL); - addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 25, NULL); + addflag(lastrace->flags, F_HITCONFERVALS, P_LYCANTHROPY, -1, PERMENANT, "10^grizzly bear"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_LYCANTHROPY, NA, NA, NULL); addrace(R_WERERAT, "wererat", 50, '@', C_BROWN, MT_FLESH, RC_HUMANOID, "Weedy humans with shifty eyes and whiskers, wererats are known for their extreme cunning."); setbodytype(lastrace, BT_HUMANOID); @@ -17266,10 +17279,12 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, 3, NA, NA, NULL); addflag(lastrace->flags, F_TR, 3, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 1, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_SHAPESHIFT, 3, 3, "pw:1;race:plague rat;"); addflag(lastrace->flags, F_CANCAST, OT_S_SUMMONANIMALSSM, 10, 10, "pw:5;race:giant rat;count:5;"); - addflag(lastrace->flags, F_STARTOBWEPSK, 100, SK_SHORTBLADES, NA, NULL); + addflag(lastrace->flags, F_STARTOBWEPSK, 40, SK_SHORTBLADES, NA, NULL); addflag(lastrace->flags, F_STARTOB, 10, NA, NA, "potion of rum"); addflag(lastrace->flags, F_AISPELLTARGETOVERRIDE, OT_S_SHAPESHIFT, F_AICASTTOFLEE, ST_SELF, "100"); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); @@ -17279,8 +17294,11 @@ void initrace(void) { addflag(lastrace->flags, F_WANTS, OT_POT_RUM, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "twitches its nose"); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_LYCANTHROPE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_LYCANTHROPE, -1, NA, NA, "dire rat"); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 25, NULL); + addflag(lastrace->flags, F_HITCONFERVALS, P_LYCANTHROPY, -1, PERMENANT, "10^dire rat"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_LYCANTHROPY, NA, NA, NULL); addrace(R_WEREWOLF, "werewolf", 100, '@', C_BROWN, MT_FLESH, RC_HUMANOID, "Shaggy humans with the uncanny ability to shapeshift into a ferocious wolf."); setbodytype(lastrace, BT_HUMANOID); @@ -17302,7 +17320,9 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 6, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 4, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 6, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_REGENERATES, 1, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_SHAPESHIFT, 3, 3, "pw:1;race:dire wolf;"); addflag(lastrace->flags, F_CANCAST, OT_S_SUMMONANIMALSMD, 10, 10, "pw:5;race:young wolf;"); @@ -17313,11 +17333,14 @@ void initrace(void) { addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "howls"); addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_LYCANTHROPE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_LYCANTHROPE, -1, NA, NA, "dire wolf"); addflag(lastrace->flags, F_CARNIVORE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANINE, B_TRUE, NA, NA, NULL); // ie. cats will know! addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 6, NA, NA, NULL); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 25, NULL); + addflag(lastrace->flags, F_HITCONFERVALS, P_LYCANTHROPY, -1, PERMENANT, "10^dire wolf"); + addflag(lastrace->flags, F_FILLPOT, OT_POT_LYCANTHROPY, NA, NA, NULL); // special monsters addrace(R_GASCLOUD, "cloud of gas", 0.1, 'y', C_GREY, MT_GAS, RC_OTHER, "A large cloud of gas which seems to move with a life of its own..."); diff --git a/data/hiscores.db b/data/hiscores.db index fa53271..ed6cdcc 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 2c72ffb..f51032a 100644 --- a/defs.h +++ b/defs.h @@ -23,6 +23,9 @@ #define TEXT_WARN_MUTABLE "(you can now gain attributes by eating corpses)" #define TEXT_WARN_NOXP_GOODVSPEACEFUL "Warning: Only Evil players gain XP for peaceful kills." +// F_SCOREBONUS text args +#define SCB_DONATIONS "charitable donations" + // Defaults #define DEF_AIFOLLOWTIME (20) // if target lf is out of view @@ -477,6 +480,7 @@ enum SHOPACTION { #define PERMENANT (-9873) #define FROMSPELL (-9863) #define FROMPOISON (-9862) +#define FROMLYCANTHROPY (-9861) // flag lifetimes - external sources (ie. don't kill them) #define FROMEXTERNAL_HIGH (-7000) @@ -560,6 +564,7 @@ enum GODANGERREASON { GA_MERCY, // allowed something to flee GA_MONEY, // paid money to someone GA_MURDER, // killed someone peaceful + GA_PEACEHOUR, // attacked during glorana's peace GA_POISON, // used poison GA_PRAY, // pestering through constant prayer GA_RACE, // prayed while a hated race. @@ -1527,6 +1532,7 @@ enum OBTYPE { OT_POT_INVIS, OT_POT_INVULN, OT_POT_LEVITATION, + OT_POT_LYCANTHROPY, OT_POT_MAGIC, OT_POT_OIL, OT_POT_POISON, @@ -1865,6 +1871,7 @@ enum OBTYPE { OT_A_HEAVYBLOW, OT_A_HIDE, OT_A_INSPECT, + OT_A_IRONFIST, OT_A_HURRICANESTRIKE, OT_A_PICKLOCK, OT_A_POLYREVERT, @@ -2411,6 +2418,7 @@ enum POISONTYPE { P_FOOD, P_FOODBAD, P_GAS, + P_LYCANTHROPY, P_MIGRAINE, P_ROT, P_TETANUS, @@ -2705,6 +2713,8 @@ enum FLAG { // -1 means "nutrition is weight x abs(val1)" // if v2=DONTKILL, this object does NOT die when drunk. F_OPERABLE, // can operate? + F_OPERWITHOUTHANDS, // can operate without having hands or being + // humanoid F_OPERWITHOUTID, // can operate without knowing what it is? F_NOTRIED, // don't show '[tried]' or update knowledge // after you have tried this object. @@ -2795,6 +2805,8 @@ enum FLAG { F_SHARP, // does damage when you step on it. v0/1 are min/max dam F_SCARY, // gives other lfs a penalty to morale checks against you, // v0 = penalty amt. + F_SCOREBONUS, // player gains (v1*65535)+v0 points at end game. + // text = reason (ie 'donated items' etc) F_SLIPPERY, // you might slip when stepping on it. v0 is amt F_SLIPMOVE, // if someone slips on this, it will move to an adj cell F_FLAMMABLE, // object will catch alight if burnt (ie fire damage) @@ -2984,6 +2996,7 @@ enum FLAG { // OR // eating this object gives it. // player only flags + F_AICONTROLLED, // player will be controlled by the computer F_DONEBURNMSG, // tells the game not to say 'the {celltype} burns!' F_DONEDARKMSG, // tells the game not to say 'it is very dark here' F_DONELISTEN, // supress further 'you hear xx' messages this turn. @@ -3452,7 +3465,12 @@ enum FLAG { F_HUMANOID, // this race is a humanoid // (can wear armour / use weapons) F_INSECT, // this race is classed as an insect - F_LYCANTHROPE, // this race is a lycanthrope. text = what to turn into. + F_LYCANTHROPE, // this race is a lycanthrope. + // text = what to turn into. + // v0 = # of automatic full moon chnages left. + // each auto change will decrement this, down + // to zero. + // -1 means always change on full moon. F_UNDEAD, // this race is classed as undead F_COLDBLOOD, // this race is coldblooded F_NOBODYPART, // this race doesn't have bodypart val0 diff --git a/flag.c b/flag.c index 65a70bb..2409a5a 100644 --- a/flag.c +++ b/flag.c @@ -1385,6 +1385,17 @@ void timeeffectsflag(flag_t *f, int howlong) { } } +int flagretainedduringpoly(enum FLAG fid) { + switch (fid) { + case F_FLEEFROM: + case F_HOSTILE: + case F_LYCANTHROPE: + return B_TRUE; + default: break; + } + return B_FALSE; +} + int flagtomaxhp(flag_t *f) { int hp; int nsides = HITDIESIDES; diff --git a/flag.h b/flag.h index e96d18e..75ad58f 100644 --- a/flag.h +++ b/flag.h @@ -22,6 +22,7 @@ int flagcausesinterrupt(flag_t *f, enum GAINORLOSS gol); int flagcausesloscalc(enum FLAG fid); int flagcausesredraw(lifeform_t *lf, enum FLAG fid); int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid); +int flagretainedduringpoly(enum FLAG fid); int flagstacks(enum FLAG fid); int flagtomaxhp(flag_t *f); cell_t *getflagpilelocation(flagpile_t *fp); diff --git a/god.c b/god.c index 57804a4..4f129c2 100644 --- a/god.c +++ b/god.c @@ -113,6 +113,9 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { godsay(rid, B_TRUE, "Where is your sense of greed?!"); break; case GA_MURDER: godsay(rid, B_TRUE, "You have taken a life!"); break; + case GA_PEACEHOUR: + godsay(rid, B_TRUE, "You dare violate the sanctity of Glorana's Peace?"); break; + break; case GA_PRAY: dosay = B_TRUE; break; case GA_POISON: godsay(rid, B_TRUE, "I do not condone the use of poison!"); break; diff --git a/io.c b/io.c index 39c5759..d963a62 100644 --- a/io.c +++ b/io.c @@ -1316,12 +1316,18 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { } switch (f->id) { + case F_AICONTROLLED: + if (isplayer(lf)) { + msg("^%cYou lose control of your body!", getlfcol(lf, CC_VBAD)); + donesomething = B_TRUE; + } + break; case F_ANTICIPATE: if (isplayer(lf)) { lf2 = findlf(NULL, f->val[0]); if (lf2) { getlfname(lf2, buf); - msg("^%d%s%s intentions enter your mind!", getlfcol(lf, CC_GOOD), buf, getpossessive(buf)); + msg("^%c%s%s intentions enter your mind!", getlfcol(lf, CC_GOOD), buf, getpossessive(buf)); donesomething = B_TRUE; } } @@ -1610,10 +1616,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { break; case F_HEAVENARM: if (isplayer(lf)) { // don't know if monsters get it - msg("^%dYou are surrounded by a %s!", getlfcol(lf, CC_GOOD), f->text); + msg("^%cYou are surrounded by a %s!", getlfcol(lf, CC_GOOD), f->text); donesomething = B_TRUE; } else { - msg("^%d%s is surrounded by a %s!", getlfcol(lf, CC_GOOD), lfname, f->text); + msg("^%c%s is surrounded by a %s!", getlfcol(lf, CC_GOOD), lfname, f->text); donesomething = B_TRUE; } break; @@ -1693,9 +1699,9 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { pt = findpoisontype(f->val[0]); if (isplayer(lf)) { if (streq(pt->desc, "Sick") || (pt->id == P_FOOD) || (pt->id == P_FOODBAD)) { - msg("^%cYou have contracted %s.", getlfcol(lf, CC_VBAD), pt->name); - } else { msg("^%cYou are sick with %s.", getlfcol(lf, CC_VBAD), pt->name); + } else { + msg("^%cYou have contracted %s.", getlfcol(lf, CC_VBAD), pt->name); } more(); } else { @@ -2097,12 +2103,18 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { return B_FALSE; } switch (f->id) { + case F_AICONTROLLED: + if (isplayer(lf)) { + msg("You have regained control of your body."); + donesomething = B_TRUE; + } + break; case F_ANTICIPATE: if (isplayer(lf)) { lf2 = findlf(NULL, f->val[0]); if (lf2) { getlfname(lf2, buf); - msg("^%dYou no longer know %s%s intentions.", getlfcol(lf, CC_BAD), buf, getpossessive(buf)); + msg("^%cYou no longer know %s%s intentions.", getlfcol(lf, CC_BAD), buf, getpossessive(buf)); donesomething = B_TRUE; } } @@ -2387,13 +2399,13 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { break; case F_HEAVENARM: if (isplayer(lf)) { // don't know if monsters get it - msg("^%dYour %s vanishes!", getlfcol(lf, CC_BAD), f->text); + msg("^%cYour %s vanishes!", getlfcol(lf, CC_BAD), f->text); donesomething = B_TRUE; } else { char text[BUFLEN]; sprintf(text,"%s%s %s vanishes!", lfname, getpossessive(lfname), f->text); capitalise(text); - msg("^%d%s", getlfcol(lf, CC_BAD), text); + msg("^%c%s", getlfcol(lf, CC_BAD), text); donesomething = B_TRUE; } break; @@ -4231,7 +4243,12 @@ void docomms(lifeform_t *lf) { if (!isgod(lf) && ispeaceful(lf) && cantalk(lf)) { enum SKILLLEVEL slev; + job_t *j; slev = getskill(player, SK_SPEECH); + // same race or job? + j = getjob(player); + if ((slev != PR_MASTER) && j && (j == getjob(lf))) slev++; + if ((slev != PR_MASTER) && (player->race->id == lf->race->id)) slev++; if (slev >= PR_NOVICE) { addchoice(&prompt, 'x', "Any dangers nearby that I should look out for?", NULL, NULL, NULL); } @@ -4304,7 +4321,7 @@ void docomms(lifeform_t *lf) { getlfname(lf2, lfname2); msg("You say \"Attack %s!\" to %s.",isplayer(lf2) ? "me" : lfname2, lfname); - if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { msg("%s doesn't respond.", lfname); break; } @@ -4334,7 +4351,7 @@ void docomms(lifeform_t *lf) { break; case 'c': msg("You say \"Come here!\" to %s.",lfname); - if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { msg("%s doesn't respond.", lfname); break; } @@ -4548,7 +4565,7 @@ void docomms(lifeform_t *lf) { // stop attacking all current targets first... killflagsofid(lf->flags, F_TARGETLF); msg("You say \"Go over there!\" to %s.", lfname); - if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { msg("%s doesn't respond.", lfname); break; } @@ -4572,7 +4589,7 @@ void docomms(lifeform_t *lf) { case 'j': // charisma check to see if they'll join you. msg("You say \"Join me on my quest!\" to %s.", lfname); - if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { msg("%s doesn't respond.", lfname); break; } @@ -4598,7 +4615,7 @@ void docomms(lifeform_t *lf) { } if (islowhp(player) && cantalk(lf) && - canhear(lf, player->cell, SV_SHOUT) && + canhear(lf, player->cell, SV_SHOUT, NULL) && (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) > IQ_ANIMAL) && !isundead(lf)) { if (skillcheck(player, SC_SPEECH, 30, alignmod)) { @@ -4663,7 +4680,7 @@ void docomms(lifeform_t *lf) { */ case 'r': msg("You say \"Get some rest.\" to %s.", lfname); - if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { msg("%s doesn't respond.", lfname); break; } @@ -4736,7 +4753,7 @@ void docomms(lifeform_t *lf) { break; case '<': msg("You say \"Stay close!\" to %s.", lfname); - if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { msg("%s doesn't respond.", lfname); break; } @@ -4748,7 +4765,7 @@ void docomms(lifeform_t *lf) { break; case '>': msg("You say \"Keep your distance!\" to %s.", lfname); - if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) { + if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { msg("%s doesn't respond.", lfname); break; } @@ -10998,7 +11015,11 @@ void drawstatus(void) { pt = findpoisontype(f->val[0]); // find highest amount of poison if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) { - if (poisonthreatenslife(player, f)) { + if (pt->severity == PS_CURSE) { + setcol(statwin, C_RED); + wprintw(statwin, " %s", pt->desc); + unsetcol(statwin, C_RED); + } else if (poisonthreatenslife(player, f)) { setcol(statwin, C_RED); wprintw(statwin, " %s(bad)", pt->desc); unsetcol(statwin, C_RED); @@ -11304,10 +11325,14 @@ void showlfarmour(lifeform_t *lf) { enum BODYPART bp; object_t *o; object_t *arm[MAXBODYPARTS]; - int y; + int y,i; char buf[BUFLEN],ch; int keepgoing = B_TRUE; + for (i = 0; i < MAXBODYPARTS; i++) { + arm[i] = NULL; + } + while (keepgoing) { cls(); if (isplayer(lf)) { @@ -13427,13 +13452,20 @@ void showlfstats(lifeform_t *lf, int showall) { } } - snprintf(buf, BUFLEN, "%s %s sick with %s%s.", you(lf), is(lf), - pt->name, knownfatal ? ", potentially fatally" : ""); - if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT) || - (getskill(player, SK_FIRSTAID) >= PR_ADEPT) ) { - char buf2[BUFLEN]; - snprintf(buf2, BUFLEN, " [max %d turns left]", f->lifetime); - strcat(buf, buf2); + if (pt->id == P_LYCANTHROPY) { + snprintf(buf, BUFLEN, "%s %s afflicted with %s.", you(lf), is(lf), + pt->name); + } else { + snprintf(buf, BUFLEN, "%s %s sick with %s%s.", you(lf), is(lf), + pt->name, knownfatal ? ", potentially fatally" : ""); + } + if (pt->severity != PS_CURSE) { + if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT) || + (getskill(player, SK_FIRSTAID) >= PR_ADEPT) ) { + char buf2[BUFLEN]; + snprintf(buf2, BUFLEN, " [max %d turns left]", f->lifetime); + strcat(buf, buf2); + } } mvwprintw(mainwin, y, 0, buf); y++; @@ -13442,7 +13474,11 @@ void showlfstats(lifeform_t *lf, int showall) { if (f->known && (f->id == F_INCUBATING)) { poisontype_t *pt; pt = findpoisontype(f->val[0]); - snprintf(buf, BUFLEN, "%s %s incubating %s.", you(lf), is(lf), pt->name); + if (pt->id == P_LYCANTHROPY) { + snprintf(buf, BUFLEN, "%s %s afflicted with early onset %s.", you(lf), is(lf), pt->name); + } else { + snprintf(buf, BUFLEN, "%s %s incubating %s.", you(lf), is(lf), pt->name); + } mvwprintw(mainwin, y, 0, buf); y++; } diff --git a/lf.c b/lf.c index 7afa64d..1b2ff02 100644 --- a/lf.c +++ b/lf.c @@ -316,13 +316,23 @@ long calcscore(lifeform_t *lf) { flag_t *f; long points = 0; object_t *o; + flag_t *retflag[MAXCANDIDATES]; + int nretflags,i; if (lfhasflag(lf, F_NOSCORE)) { return 0; } // objects for (o = lf->pack->first ; o ; o = o->next) { + // full points points += getobpoints(o); } + // donated items etc + getflags(lf->flags, retflag, &nretflags, F_SCOREBONUS, F_NONE); + for (i = 0; i < nretflags; i++) { + long thisamt; + thisamt = (retflag[i]->val[1] * 65535) + retflag[i]->val[0]; + points += thisamt; + } // points for xp points += (lf->xp / 10); @@ -869,7 +879,7 @@ int canhaverandombehaviour(lifeform_t *lf) { } // ie. will sound from 'dest' reach the ears of 'lf' -int canhear(lifeform_t *lf, cell_t *dest, int volume) { +int canhear(lifeform_t *lf, cell_t *dest, int volume, int *numwalls) { int numpixels; int i; int x1,y1; @@ -879,6 +889,8 @@ int canhear(lifeform_t *lf, cell_t *dest, int volume) { cell_t *retcell[MAXRETCELLS]; int celldist; + if (numwalls) *numwalls = 0; + if (!lf) return B_FALSE; if (!dest) return B_FALSE; if (!lf->cell) return B_FALSE; @@ -937,6 +949,7 @@ int canhear(lifeform_t *lf, cell_t *dest, int volume) { if (i != 0) { // solid cells decrease hearing range if (cell->type->solid) { + if (numwalls) (*numwalls)++; sounddist--; } // magic barriers stop all sound @@ -1913,7 +1926,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar if (cansee(player, lf)) { doannounce = B_TRUE; - } else if ((casttype == CT_SOUNDBASED) && canhear(player, lf->cell, SV_TALK)) { + } else if ((casttype == CT_SOUNDBASED) && canhear(player, lf->cell, SV_TALK, NULL)) { doannounce = B_TRUE; } if (doannounce) { @@ -2402,7 +2415,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%dThe running water burns %s!", getlfcol(lf, CC_BAD), lfname); + msg("^%cThe running water burns %s!", getlfcol(lf, CC_BAD), lfname); } losehp(lf, roll("6d6"), DT_DIRECT, NULL, "running water"); } @@ -2424,7 +2437,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s drowns.",getlfcol(lf, CC_BAD) , lfname); + msg("^%c%s drowns.",getlfcol(lf, CC_BAD) , lfname); didsomething = B_TRUE; } addflag(lf->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); @@ -2441,7 +2454,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s is drowning!", getlfcol(lf, CC_VBAD), lfname); + msg("^%c%s is drowning!", getlfcol(lf, CC_VBAD), lfname); didsomething = B_TRUE; } getobnametruebase(o, obname, o->amt); @@ -2523,6 +2536,22 @@ float comparelfs(lifeform_t *lf1, lifeform_t *lf2) { return ratio; } +// note: this will kill incubateflag! +void completeincubation(lifeform_t *lf, flag_t *incubateflag) { + // parse flag text to get power & whatfrom + char *p; + char buf[BUFLEN]; + int power; + enum POISONTYPE ptype; + ptype = incubateflag->val[0]; + p = readuntil(buf, incubateflag->text, '^'); + power = atoi(buf); + readuntil(buf, p, '^'); + addtempflag(lf->flags, F_POISONED, ptype, power, incubateflag->obfrom, buf, incubateflag->val[2]); + poisoneffects(lf, ptype, power); + killflag(incubateflag); +} + int confuse(lifeform_t *lf, int howlong) { flag_t *f; f = lfhasflag(lf, F_CONFUSED); @@ -3182,7 +3211,7 @@ void die(lifeform_t *lf) { // intelligent monsters will say something if (!hasflag(lf->flags, F_NODEATHSPEECH) && !lfhasflag(lf, F_SUMMONEDBY)) { if (ispetof(lf, player)) { - if (cantalk(lf) && canhear(player, lf->cell, 4)) { + if (cantalk(lf) && canhear(player, lf->cell, 4, NULL)) { sayphrase(lf, SP_DIE, SV_SHOUT, NA, NULL); } else if (!cansee(player, lf)) { warn("You feel a profound sense of loss."); @@ -3203,14 +3232,14 @@ void die(lifeform_t *lf) { if (cansee(player, lf)) { getlfname(lf, buf); if (lf->lastdamtype == DT_EXPLOSIVE) { - msg("^%d%s is vaporised!",getlfcol(lf, CC_BAD), buf); + msg("^%c%s is vaporised!",getlfcol(lf, CC_BAD), buf); vaporised = B_TRUE; } else if (lf->lastdamtype == DT_MELT) { - msg("^%d%s completely melts.",getlfcol(lf, CC_BAD), buf); + msg("^%c%s completely melts.",getlfcol(lf, CC_BAD), buf); } else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { - msg("^%d%s shatters!",getlfcol(lf, CC_BAD), buf); + msg("^%c%s shatters!",getlfcol(lf, CC_BAD), buf); } else { - msg("^%d%s dies.",getlfcol(lf, CC_BAD), buf); + msg("^%c%s dies.",getlfcol(lf, CC_BAD), buf); } } } @@ -3347,7 +3376,7 @@ void die(lifeform_t *lf) { if (isplayer(souleater)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%dYou consume %s%s soul!", getlfcol(souleater, CC_VGOOD), lfname, getpossessive(lfname)); + msg("^%cYou consume %s%s soul!", getlfcol(souleater, CC_VGOOD), lfname, getpossessive(lfname)); soulflag->known = B_TRUE; revealflagob(souleater, soulflag); @@ -3355,7 +3384,7 @@ void die(lifeform_t *lf) { char lfname[BUFLEN]; getlfname(lf, lfname); getlfname(souleater, buf); - msg("^%d%s consumes %s%s soul!", getlfcol(souleater, CC_VGOOD), 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); @@ -4875,7 +4904,7 @@ void endlfturn(lifeform_t *lf) { if (islowhp(lf) && onein(3) && !hasflag(lf->flags, F_ASLEEP)) { // TODO: replace 4 if (ispetof(lf, player)) { - if (!canhear(player, lf->cell, 4)) { + if (!canhear(player, lf->cell, 4, NULL)) { char realname[BUFLEN]; real_getlfname(lf, realname, NULL, B_NOSHOWALL, B_REALRACE); warn("You feel worried about %s%s.", lfhasflag(lf, F_NAME) ? "" : "your ", noprefix(realname)); @@ -5931,6 +5960,38 @@ subjob_t *findsubjob(enum SUBJOB sjid) { return NULL; } +// returns true if we did somethign +int fixcurses(lifeform_t *lf) { + int donesomething = B_FALSE; + flag_t *f,*nextf; + for (f = lf->flags->first ; f ; f = nextf) { + nextf = f->next; + if (f->id == F_LYCANTHROPE) { + donesomething = B_TRUE; + killflag(f); + continue; + } else if ((f->id == F_INCUBATING) || (f->id == F_POISONED)) { + poisontype_t *pt; + pt = findpoisontype(f->val[0]); + if (pt->severity == PS_CURSE) { + donesomething = B_TRUE; + killflag(f); + continue; + } + } else if (f->lifetime == FROMLYCANTHROPY) { + donesomething = B_TRUE; + killflag(f); + continue; + } + } + if (donesomething) { + if (isplayer(lf)) { + msg("^%cYour curses are lifted!", getlfcol(lf, CC_VGOOD)); + } + } + return donesomething; +} + // try to actually do the 'run away' action for // anyone we are fleeing from. // returns TRUE if we ran away from something @@ -9023,8 +9084,8 @@ char *real_getlfname(lifeform_t *lf, char *buf, lifeform_t *usevis, int showall, } if (!lfrace) { - if (lfhasflag(lf, F_LYCANTHROPE)) { - // lycanthropes appear as human unless you know better + if (lfhasflag(lf, F_LYCANTHROPE) && !ispolymorphed(lf)) { + // lycanthropes in human form appear as human unless you know better if ((getlorelevel(player, RC_HUMANOID) >= PR_ADEPT) || (getlorelevel(player, RC_MAGIC) >= PR_BEGINNER)) { lfrace = lf->race; @@ -9199,8 +9260,8 @@ char *real_getlfnamea(lifeform_t *lf, char *buf, lifeform_t * usevis, int showal } if (!lfrace) { - if (lfhasflag(lf, F_LYCANTHROPE)) { - // lycanthropes appear as human unless you know better + if (lfhasflag(lf, F_LYCANTHROPE) && !ispolymorphed(lf)) { + // lycanthropes in human form appear as human unless you know better if (getlorelevel(player, RC_HUMANOID) >= PR_ADEPT) { lfrace = lf->race; } else { @@ -9803,6 +9864,35 @@ race_t *getrandomrace(cell_t *c, int forcedepth) { return r; } +race_t *getrandomracewithflag(enum FLAG fid) { + race_t **poss; + race_t *r; + int nposs = 0; + int sel; + int count = 0; + + // count races + for (r = firstrace ; r ; r = r->next) { + if (hasflag(r->flags, fid)) { + count++; + } + } + + + poss = malloc(count * sizeof(race_t *)); + + for (r = firstrace ; r ; r = r->next) { + if (hasflag(r->flags, fid)) { + poss[nposs] = r; + nposs++; + } + } + sel = rnd(0,nposs-1); + r = poss[sel]; + free(poss); + return r; +} + race_t *getreallyrandomrace(enum RACECLASS wantrc) { race_t **poss; race_t *r; @@ -11769,7 +11859,7 @@ void growhydrahead(lifeform_t *lf, int announce) { getlfname(lf, vname); // regrow if (cansee(player, lf)) { - msg("^%d%s grow%s two more heads!", getlfcol(lf, CC_GOOD), vname, isplayer(lf) ? "" : "s"); + msg("^%c%s grow%s two more heads!", getlfcol(lf, CC_GOOD), vname, isplayer(lf) ? "" : "s"); } } @@ -12147,7 +12237,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR if (isplayer(lf)) { msg("^BYour brain is ruptured!"); } else if (cansee(player, lf)) { - msg("^%d%s%s brain ruptures!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); + msg("^%c%s%s brain ruptures!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); } if (lf->hp > 0) { setlastdam(lf, "a ruptured brain"); @@ -12204,7 +12294,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype, enum INJUR if (isplayer(lf)) { msg("^BYour heart is pierced!"); } else if (cansee(player, lf)) { - msg("^%d%s%s heart is pierced!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); + msg("^%c%s%s heart is pierced!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); } if (lf->hp > 0) { setlastdam(lf, "a pierced heart"); @@ -14458,7 +14548,7 @@ void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) { if (isplayer(lf) || cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s choke%s on %s!", getlfcol(lf, CC_BAD), lfname, isplayer(lf) ? "" : "s", buf); + msg("^%c%s choke%s on %s!", getlfcol(lf, CC_BAD), lfname, isplayer(lf) ? "" : "s", buf); } } else { if (isplayer(lf)) { @@ -14467,7 +14557,7 @@ void applywalkdam(lifeform_t *lf, int dam, enum DAMTYPE damtype, object_t *o) { char lfname[BUFLEN]; char buf2[BUFLEN]; getlfname(lf, lfname); - snprintf(buf2, BUFLEN, "^%d%s %ss %s!", getlfcol(lf, CC_BAD), buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname); + snprintf(buf2, BUFLEN, "^%c%s %ss %s!", getlfcol(lf, CC_BAD), buf, getattackverb(NULL, NULL, damtype, dam,lf->maxhp), lfname); msg("%s", buf2); } } @@ -16235,7 +16325,7 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { break; } } - msg("^%d%s %s %s!", getlfcol(lf, (amt > 0) ? CC_GOOD : CC_BAD), lfname, verb, adverb); + msg("^%c%s %s %s!", getlfcol(lf, (amt > 0) ? CC_GOOD : CC_BAD), lfname, verb, adverb); more(); } return B_FALSE; @@ -16323,7 +16413,7 @@ void modhunger(lifeform_t *lf, int amt) { char lfname[BUFLEN]; getlfname(lf, lfname); gethungername(lf, posthlev, buf); - msg("^%d%s looks %s%c", getlfcol(lf, CC_BAD), lfname, buf, (needexclam) ? '!' : '.'); + msg("^%c%s looks %s%c", getlfcol(lf, CC_BAD), lfname, buf, (needexclam) ? '!' : '.'); } if ((posthlev >= H_VHUNGRY) && (amt > 0)) { @@ -16490,6 +16580,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, int dist; int difficulty; int lbonus; + int nwalls = 0; flag_t *f; if (l == noisemaker) continue; @@ -16524,7 +16615,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, // skillcheck to hear this if ( (isplayer(l) && haslos(l, c)) || // only player can "hear by seeing" - (canhear(l, c, volume) && (alwayshear || skillcheck(l, SC_LISTEN, difficulty, lbonus)) ) ) { + (canhear(l, c, volume, &nwalls) && (alwayshear || skillcheck(l, SC_LISTEN, difficulty, lbonus)) ) ) { flag_t *f; // announce? if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) { @@ -16564,10 +16655,38 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, char textnopunc[BUFLEN]; char punc; int dist; + int muffled = B_FALSE; + char prefix[BUFLEN]; + enum SKILLLEVEL slev; + char distbuf[BUFLEN],distbufbad[BUFLEN]; + char dirbuf[BUFLEN]; + char localtext[BUFLEN]; + if (nwalls >= 1) muffled = B_TRUE; + + if (muffled) { + char *p; + // "you hear [a xxx]" + // becomes: + // "you hear [a muffled xxx]" + p = strstartswitha(text, prefix); + if (p) { + sprintf(localtext, "%smuffled %s", prefix, p); + } else { + // "you hear [xxx]" + // becomes: + // "you hear muffled [xxx]" + // + sprintf(localtext, "muffled %s", text); + } + + } else { + strcpy(localtext, text); + } + //punc = text[strlen(text)-1]; //strncpy(textnopunc, text, strlen(text)-1); - strcpy(textnopunc, text); + strcpy(textnopunc, localtext); punc = textnopunc[strlen(textnopunc)-1]; if (punc == '\"') { // ie. someone saying something @@ -16580,18 +16699,16 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, // adjust text if you are deaf. + getdisttext(l->cell, c, distbuf, distbufbad, dirbuf); + slev = getskill(l, SK_LISTEN); + // listen skill gives you more info about monsters if (noisemaker) { - enum SKILLLEVEL slev; - char lfname[BUFLEN]; - char distbuf[BUFLEN],distbufbad[BUFLEN]; - char dirbuf[BUFLEN]; int detectdist = 0; + char lfname[BUFLEN]; real_getlfnamea(noisemaker, lfname, NULL, B_NOSHOWALL, B_CURRACE); - getdisttext(l->cell, c, distbuf, distbufbad, dirbuf); - slev = getskill(l, SK_LISTEN); detectdist = getlistendetectrange(l); // // high listen skill lets you know more info. @@ -16611,7 +16728,11 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, } // now announce it. if (slev >= PR_EXPERT) { - msg("You hear %s%s to the %s%c", lfname, distbuf, dirbuf, punc); + if (muffled) { + msg("You hear a muffled %s%s to the %s%c", noprefix(lfname), distbuf, dirbuf, punc); + } else { + msg("You hear %s%s to the %s%c", lfname, distbuf, dirbuf, punc); + } rv = B_TRUE; } else if (slev >= PR_BEGINNER) { msg("You hear %s%s to the %s%c", textnopunc, distbuf, dirbuf, punc); @@ -16620,13 +16741,18 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, msg("You hear %s%s%c", textnopunc, distbufbad, punc); rv = B_TRUE; } else { - assert(text); - msg("You hear %s", text); + msg("You hear %s", localtext); rv = B_TRUE; } } else { assert(text); - msg("You hear %s", text); + if (slev >= PR_BEGINNER) { + msg("You hear %s%s to the %s%c", textnopunc, distbuf, dirbuf, punc); + } else if (slev >= PR_NOVICE) { + msg("You hear %s%s%c", textnopunc, distbufbad, punc); + } else { + msg("You hear %s", localtext); + } rv = B_TRUE; } // can only hear one 'walk' sound per turn. @@ -16666,7 +16792,6 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, if (isplayer(l)) { char wakenoise[BUFLEN]; char *punc; - assert(text); strcpy(wakenoise, text); // omit punctuation punc = &(wakenoise[strlen(wakenoise)-1]); @@ -16951,6 +17076,11 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char pt = findpoisontype(ptype); srcrace = findrace(srcraceid); + // special case - lycanthropy only affects players + if ((pt->id == P_LYCANTHROPY) && !isplayer(lf)) { + return; + } + // are you immune to disease/poison? psev = pt->severity; switch (psev) { @@ -16991,11 +17121,11 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char // announce - announceflaggain won't be called // since this isn't a new flag. if (isplayer(lf)) { - msg("^%dYou feel more sick.", getlfcol(lf, CC_VBAD)); + msg("^%cYou feel more sick.", getlfcol(lf, CC_VBAD)); } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s looks even more sick.", getlfcol(lf, CC_VBAD), lfname); + msg("^%c%s looks even more sick.", getlfcol(lf, CC_VBAD), lfname); } found = B_TRUE; @@ -17008,25 +17138,29 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char flag_t *ii; int multiplier = 0; int tempmult; - // modify incubation time based on metabolism - sumflags(lf->flags, F_FASTMETAB, &tempmult, NULL, NULL); - multiplier += tempmult; - sumflags(lf->flags, F_SLOWMETAB, &tempmult, NULL, NULL); - multiplier -= tempmult; + if (pt->incubationtime != -1) { + // modify incubation time based on metabolism + sumflags(lf->flags, F_FASTMETAB, &tempmult, NULL, NULL); + multiplier += tempmult; + sumflags(lf->flags, F_SLOWMETAB, &tempmult, NULL, NULL); + multiplier -= tempmult; - if (multiplier > 0) { - howlong /= multiplier; - } else if (multiplier < 0) { - howlong *= abs(multiplier); + if (multiplier > 0) { + howlong /= multiplier; + } else if (multiplier < 0) { + howlong *= abs(multiplier); + } } ii = lfhasflagval(lf, F_INCUBATING, ptype, NA, NA, NULL); if (ii) { - // will happen faster - ii->val[2] /= 2; - if (ii->val[2] < 1) ii->val[2] = 1; - if (getskill(lf, SK_FIRSTAID) >= PR_BEGINNER) { - ii->known = B_TRUE; - msg("^BYou recognise the increased onset of %s.", pt->name); + if (ptype != P_LYCANTHROPY) { + // will happen faster + ii->val[2] /= 2; + if (ii->val[2] < 1) ii->val[2] = 1; + if (getskill(lf, SK_FIRSTAID) >= PR_BEGINNER) { + ii->known = B_TRUE; + msg("^BYou recognise the increased onset of %s.", pt->name); + } } } else { char ftext[BUFLEN]; @@ -18623,6 +18757,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { race_t *origrace = NULL; int nretflags; int reverting = B_FALSE; + int lycanthrope = B_FALSE; lifeform_t *l; //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging @@ -18666,6 +18801,31 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } //} + // reverting from initial lycanthrope change? + if (lfhasflagval(lf, F_POISONED, P_LYCANTHROPY, NA, NA, NULL) && + lfhasflag(lf, F_AICONTROLLED) && !lfhasflag(lf, F_LYCANTHROPE)) { + // add lycanthropy flag + addflag(lf->flags, F_LYCANTHROPE, 4, NA, NA, lf->race->name); + killflagsofid(lf->flags, F_AICONTROLLED); + killflagsofid(lf->flags, F_RAGE); + if (isplayer(lf)) killflagsofid(lf->flags, F_HATESALL); + } else { + flag_t *lyflag; + lyflag = lfhasflag(lf, F_LYCANTHROPE); + if (lyflag && (lyflag->val[0] > 0)) { + // reduce # of auto changes + lyflag->val[0]--; + if (lyflag->val[0] <= 0) { + char cwtext[BUFLEN]; + if (isplayer(lf)) { + msg("^%cYou have gained control of your lycanthropy.", getlfcol(lf, CC_GOOD)); + } + sprintf(cwtext, "pw:1;race:%s;", lf->race->name); + addtempflag(lf->flags, F_CANWILL, OT_S_SHAPESHIFT, NA, NA, cwtext, FROMLYCANTHROPY); + } + } + } + if ((lf->race->id == R_GASCLOUD) && (origrace->id == R_VAMPIRE)) { if (!isplayer(lf)) { f = lfhasflagval(lf, F_WANTS, OT_COFFIN, NA, NA, NULL); @@ -18703,19 +18863,39 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { // stop stoning. killflagsofid(lf->flags, F_BEINGSTONED); + if (lfhasflag(lf, F_LYCANTHROPE)) { + lycanthrope = B_TRUE; + } + //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging // first remove flags from existing race, or temporary ones lf->born = B_FALSE; for (f = lf->flags->first ; f ; f = nextf) { nextf = f->next; + if (frompolymorph && flagretainedduringpoly(f->id)) continue; + if (lycanthrope) { + switch (f->id) { + case F_DTVULN: + case F_MATVULN: + case F_HITCONFER: + case F_HITCONFERVALS: + case F_CANEATRAW: + case F_CARNIVORE: + case F_VEGETARIAN: + case F_FILLPOT: + continue; + break; + default: + break; + } + } + if (f->lifetime == FROMRACE) { killflag(f); nkilled++; } else if ((f->lifetime > 0) && (f->id != F_POLYMORPHED)) { // kill most temporary flags, with exceptions switch (f->id) { - case F_FLEEFROM: - break; default: killflag(f); nkilled++; @@ -18746,7 +18926,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } // don't change hostility when polymorphing if (frompolymorph) { - if (f->id == F_HOSTILE) ignorethis = B_TRUE; + if (flagretainedduringpoly(f->id)) ignorethis = B_TRUE; + //if (f->id == F_HOSTILE) ignorethis = B_TRUE; } if (!ignorethis) { //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging @@ -19764,7 +19945,7 @@ void startlfturn(lifeform_t *lf) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s is suffocating!", getlfcol(lf, CC_VBAD), lfname); + msg("^%c%s is suffocating!", getlfcol(lf, CC_VBAD), lfname); } dam = lf->maxhp / 3; limit(&dam, 1, NA); @@ -19779,7 +19960,7 @@ void startlfturn(lifeform_t *lf) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%dThe sunlight burns %s!", getlfcol(lf, CC_BAD), lfname); + msg("^%cThe sunlight burns %s!", getlfcol(lf, CC_BAD), lfname); } losehp(lf, roll("6d6"), DT_DIRECT, NULL, "sunlight"); if (isdead(lf)) return; @@ -20569,7 +20750,7 @@ void startlfturn(lifeform_t *lf) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s%s spine snaps!", getlfcol(lf, CC_VBAD), + msg("^%c%s%s spine snaps!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname)); } losehp_real(lf, lf->maxhp, DT_DIRECT, NULL, "tetanus", B_FALSE, NULL, B_FALSE, NULL, B_FALSE); @@ -20604,7 +20785,7 @@ void startlfturn(lifeform_t *lf) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s shivers.", getlfcol(lf, CC_BAD), lfname); + msg("^%c%s shivers.", getlfcol(lf, CC_BAD), lfname); } wep = getweapon(lf); if (wep) { @@ -20652,7 +20833,7 @@ void startlfturn(lifeform_t *lf) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s %s.", getlfcol(lf, CC_BAD), lfname, rnd(0,1) ? "retches" : "gags"); + msg("^%c%s %s.", getlfcol(lf, CC_BAD), lfname, rnd(0,1) ? "retches" : "gags"); } taketime(lf,getactspeed(lf)); @@ -20670,7 +20851,7 @@ void startlfturn(lifeform_t *lf) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%d%s melts a little.",getlfcol(lf, CC_BAD), lfname); + msg("^%c%s melts a little.",getlfcol(lf, CC_BAD), lfname); } } } @@ -20719,7 +20900,7 @@ void startlfturn(lifeform_t *lf) { getlfname(lf, lfname); getobname(bloodamu, obname, 1); getobname(o, bname, 1); - msg("^%d%s%s %s sucks up %s!", getlfcol(lf, CC_GOOD), lfname, getpossessive(lfname), noprefix(obname), bname); + msg("^%c%s%s %s sucks up %s!", getlfcol(lf, CC_GOOD), lfname, getpossessive(lfname), noprefix(obname), bname); makeknown(bloodamu->type->id); } } @@ -20728,6 +20909,21 @@ void startlfturn(lifeform_t *lf) { continue; } + if (o->type->id == OT_HOLYCIRCLE) { + if (isundead(lf) || lfhasflag(lf, F_LYCANTHROPE)) { + char obname[BUFLEN]; + getobname(o, obname, 1); + if (isplayer(lf)) { + msg("^%c%s burns you!^n", getlfcol(lf, CC_BAD), obname); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%c%s burns %s!^n", getlfcol(lf, CC_BAD), obname, lfname); + } + losehp(lf, rnd(10,20), DT_HOLY, NULL, "a holy circle"); + } + } + /* f = hasflag(o->flags, F_GODSTONE); if (f && (f->val[2] == B_TRUE)) { @@ -20897,21 +21093,11 @@ void startlfturn(lifeform_t *lf) { } } - if (f->id == F_INCUBATING) { + if ((f->id == F_INCUBATING) && (f->val[1] > 0)) { f->val[1]--; if (f->val[1] <= 0) { - // parse text to get power & whatfrom - char *p; - char buf[BUFLEN]; - int power; - enum POISONTYPE ptype; - ptype = f->val[0]; - p = readuntil(buf, f->text, '^'); - power = atoi(buf); - readuntil(buf, p, '^'); - addtempflag(lf->flags, F_POISONED, ptype, power, f->obfrom, buf, f->val[2]); - poisoneffects(lf, ptype, power); - killflag(f); + // note: this functino will kill f + completeincubation(lf, f); continue; } } @@ -21152,9 +21338,9 @@ int steal(lifeform_t *lf, obpile_t *op, enum FLAG wantflag) { if (op->owner) { getlfname(op->owner, targname); if (isplayer(lf)) { - msg("^%dYou steal %s from %s!", getlfcol(op->owner, CC_BAD), obname, targname); + msg("^%cYou steal %s from %s!", getlfcol(op->owner, CC_BAD), obname, targname); } else if (cansee(player, lf)) { - msg("^%d%s steals %s from %s!", getlfcol(op->owner, CC_BAD), lfname, obname, targname); + msg("^%c%s steals %s from %s!", getlfcol(op->owner, CC_BAD), lfname, obname, targname); } } else { if (isplayer(lf)) { @@ -21204,7 +21390,7 @@ int stone(lifeform_t *lf) { addflag(lf->flags, F_CORPSETYPE, B_TRUE, NA, NA, statname); if (cansee(player, lf)) { - msg("^%d%s %s to stone!", getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "turn" : "turns"); + msg("^%c%s %s to stone!", getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "turn" : "turns"); } setlastdam(lf, "petrification"); lf->hp = 0; @@ -22510,7 +22696,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { if (isimmuneto(lf->flags, DT_FALL, B_FALSE)) { msg("%s lands gently on the ground.", lfname); } else { - msg("^%d%s slams into the ground!", getlfcol(lf, CC_BAD), lfname); + msg("^%c%s slams into the ground!", getlfcol(lf, CC_BAD), lfname); } } // how far did you fall? @@ -22541,7 +22727,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { if (isplayer(lf)) { msg("^bYou slam into the roof!"); } else if (cansee(player, lf)){ - msg("^%d%s slams into the roof!",getlfcol(lf, CC_BAD), lfname); + msg("^%c%s slams into the roof!",getlfcol(lf, CC_BAD), lfname); } // how far did you fall? sumflags(lf->flags, F_FALLDISTANCE, &howfar, NULL, NULL); @@ -23657,7 +23843,7 @@ int wear(lifeform_t *lf, object_t *o) { } } else if (o->type->id == OT_AMU_CHOKING) { if (isplayer(lf)) { - msg("^%d%s starts to constrict around your neck!", getlfcol(lf, CC_VBAD), obname); + 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."); diff --git a/lf.h b/lf.h index 4203859..d8cda92 100644 --- a/lf.h +++ b/lf.h @@ -47,7 +47,7 @@ int canclimb(lifeform_t *lf, enum ERROR *reason); int candrink(lifeform_t *lf, object_t *o); int caneat(lifeform_t *lf, object_t *o); int canhaverandombehaviour(lifeform_t *lf); -int canhear(lifeform_t *lf, cell_t *c, int volume); +int canhear(lifeform_t *lf, cell_t *c, int volume, int *numwalls); int canlearn(lifeform_t *lf, enum SKILL skid); int canmakerecipe(lifeform_t *lf, recipe_t *rec); int canopendoors(lifeform_t *lf); @@ -75,6 +75,7 @@ int check_rest_ok(lifeform_t *lf); //void checkxp(enum RACE rid); lifeform_t *clonelf(lifeform_t *src, cell_t *where); float comparelfs(lifeform_t *lf1, lifeform_t *lf2); +void completeincubation(lifeform_t *lf, flag_t *incubateflag); int confuse(lifeform_t *lf, int howlong); void copycorpseflags(flagpile_t *dst, flagpile_t *src); int continuedigging(lifeform_t *lf); @@ -121,6 +122,7 @@ skill_t *findskill(enum SKILL id); skill_t *findskillbyname(char *name); enum SKILLLEVEL findskilllevbyname(char *name); subjob_t *findsubjob(enum SUBJOB sjid); +int fixcurses(lifeform_t *lf); int flee(lifeform_t *lf); void fleefrom(lifeform_t *lf, lifeform_t *enemy, int howlong, int onpurpose); int fovlist_contains(int *endx, int *endy, int nendcells, int x, int y); @@ -255,6 +257,7 @@ race_t *getrandomcorpserace(cell_t *c); job_t *getrandomjob(int onlyplayerjobs); int getrandommonlevel(race_t *r, map_t *m); race_t *getrandomrace(cell_t *c, int forcedepth); +race_t *getrandomracewithflag(enum FLAG fid); race_t *getreallyrandomrace(enum RACECLASS wantrc); enum SKILL getrandomskill(void); object_t *getrestob(lifeform_t *lf); diff --git a/map.c b/map.c index 1ffca46..a663f02 100644 --- a/map.c +++ b/map.c @@ -7472,7 +7472,7 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { int i; // handle scanner if (c->lf) { - if (areallies(player, c->lf) && !isplayer(c->lf) && canhear(player, c, SV_SHOUT)) { + if (areallies(player, c->lf) && !isplayer(c->lf) && canhear(player, c, SV_SHOUT, NULL)) { // assume that allies will keep in contact with the player, as long // as they're not asleep if (!lfhasflag(c->lf, F_ASLEEP)) { diff --git a/move.c b/move.c index 40f966e..b322e00 100644 --- a/move.c +++ b/move.c @@ -215,6 +215,12 @@ int celldangerous(lifeform_t *lf, cell_t *cell, int onlyifknown, enum ERROR *err } } } + } else if (o->type->id == OT_HOLYCIRCLE) { + if (isundead(lf) || lfhasflag(lf, F_LYCANTHROPE)) { + *error = E_AVOIDOB; + rdata = o; + return B_TRUE; + } } f = hasflag(o->flags, F_PIT); if (f && (f->val[0] == D_DOWN)) { @@ -955,7 +961,7 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc } else { // ie door or object getobname(rdata, thing, 1); } - if (seen) msg("^%d%s slam%s into %s!^n",getlfcol(lf, CC_BAD), lfname,isplayer(lf) ? "" : "s", thing); + if (seen) msg("^%c%s slam%s into %s!^n",getlfcol(lf, CC_BAD), lfname,isplayer(lf) ? "" : "s", thing); snprintf(buf, BUFLEN, "slamming into %s", thing); // 1d6 dam per cell pushed dam = rolldie(howfar, 6); @@ -2859,7 +2865,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { setfacing(lf, dir); drawscreen(); - if (isplayer(lf)) { + if (isplayer(lf) && !lfhasflag(lf, F_AICONTROLLED)) { addflagifneeded(lf->flags, F_TURNED, B_TRUE, NA, NA, NULL); lf->turncounter++; if (lf->turncounter >= 5) { diff --git a/nexus.c b/nexus.c index ee170aa..a792fd9 100644 --- a/nexus.c +++ b/nexus.c @@ -774,20 +774,72 @@ void donextturn(map_t *map) { // do we need to run away from something? if (!flee(who)) { int donormalmove = B_TRUE; - flag_t *f; + flag_t *f = NULL,*lyflag = NULL; // lycanthrope in human form at midnight? if (gettimephase() == TP_MIDNIGHT) { - flag_t *f; - f = lfhasflag(who, F_LYCANTHROPE); - if (f && !ispolymorphed(who)) { + char changerace[BUFLEN]; + int willchange = B_FALSE; + int willrage = B_FALSE; + //int mintime=20,maxtime=30; + strcpy(changerace, ""); + if (!ispolymorphed(who)) { + lyflag = lfhasflag(who, F_LYCANTHROPE); + if (lyflag && (lyflag->val[0] != 0)) { + strcpy(changerace, lyflag->text); + willchange = B_TRUE; + } else { + flag_t *incflag; + incflag = lfhasflagval(who, F_INCUBATING, P_LYCANTHROPY, NA, NA, NULL); + if (incflag) { + char *p; + char *localtext; + char buf[BUFLEN]; + // figure out race name from f_incubating flag. + localtext = strdup(incflag->text); + p = readuntil(buf, localtext, '^'); + readuntil(buf, p, '^'); + strcpy(changerace, buf); + // turn f_incubating into f_poisoned + completeincubation(who, incflag); + willchange = B_TRUE; + free(localtext); + addflag(who->flags, F_AICONTROLLED, B_TRUE, NA, NA, NULL); + if (isplayer(who)) { + addflag(who->flags, F_HATESALL, B_TRUE, NA, NA, NULL); + } + willrage = B_TRUE; + } + } + } + if (willchange) { race_t *r; if (isplayer(who)) { msg("You feel a change coming over your body!"); } - r = findracebyname(f->text); - polymorphto(who, r->id, rnd(50,100)); + r = findracebyname(changerace); + //polymorphto(who, r->id, rnd(mintime,maxtime)); + polymorphto(who, r->id, PERMENANT); donormalmove = B_FALSE; + if (willrage) { + addflag(who->flags, F_RAGE, B_TRUE, NA, NA, NULL); + } + } + } else if (ispolymorphed(who)) { + int autorevert = B_FALSE; + // not midnight. polymorphed uncontrollably? + if (lfhasflagval(who, F_POISONED, P_LYCANTHROPY, NA, NA, NULL) && + lfhasflag(who, F_AICONTROLLED)) { + autorevert = B_TRUE; + } else if (isplayer(who)) { + flag_t *lyflag; + lyflag = lfhasflag(who, F_LYCANTHROPE); + if (lyflag && (lyflag->val[0] > 0)) { + autorevert = B_TRUE; + } + } + if (autorevert) { + abilityeffects(who, OT_A_POLYREVERT, who->cell, who, NULL); } } @@ -988,7 +1040,11 @@ void donextturn(map_t *map) { if (isplayer(who)) { drawcursor(); // find out what player wants to do - handleinput(); + if (lfhasflag(who, F_AICONTROLLED)) { + aiturn(who); + } else { + handleinput(); + } if (who->bartimer) { who->bartimer--; if (who->bartimer == 0) { @@ -1231,6 +1287,14 @@ int init(void) { return B_FALSE; } +void inctime(long nunits) { + curtime += (nunits*(TIMECONST)); + // don't let it get higher than 23:59 + while (curtime >= DAYSECS) { + curtime -= DAYSECS; + } +} + // retcell[0] will be initial location void calcbresnham(map_t *m, int x1, int y1, int x2, int y2, cell_t **retcell, int *numpixels) { int xinc1,xinc2,yinc1,yinc2,dinc1,dinc2,d; @@ -1719,6 +1783,21 @@ dblog("doing sort..."); } */ +void setcurtime(int hours, int minutes) { + int h = -1,m = -1,s = -1; + + splittime(&h, &m, &s); + while ((h != hours) || (m != minutes)) { + curtime += TIMECONST; + // don't let it get higher than 23:59 + while (curtime >= DAYSECS) { + curtime -= DAYSECS; + } + + splittime(&h, &m, &s); + } + msg("DEBUG: time fastforwarded to %d:%d",hours, minutes); +} void timeeffectsworld(map_t *map, int updategametime) { @@ -1893,11 +1972,7 @@ void timeeffectsworld(map_t *map, int updategametime) { if (updategametime) { // inc game time - curtime += (firstlftime*(TIMECONST)); - // don't let it get higher than 23:59 - while (curtime >= DAYSECS) { - curtime -= DAYSECS; - } + inctime(firstlftime); // inc total gametime passed gamesecs += firstlftime; @@ -1920,7 +1995,7 @@ void timeeffectsworld(map_t *map, int updategametime) { char text[BUFLEN]; switch (rnd(1,4)) { case 1: sprintf(text, "The hour of Glorana's Peace is here."); break; - case 2: sprintf(text, "Mortal, rejoice in Glorana's Peace!"); break; + case 2: sprintf(text, "Mortal, rejoice in the hour of Glorana's Peace!"); break; case 3: sprintf(text, "Now is the time of Glorana's Peace."); break; case 4: sprintf(text, "Be healed my child - Glorana's Peace is upon you."); break; } diff --git a/nexus.h b/nexus.h index 7217be2..e679b2f 100644 --- a/nexus.h +++ b/nexus.h @@ -18,6 +18,7 @@ enum COLOUR getpctcol(float num, float max); char getpctletter(float num, float max); void getrarityrange(int depth, int *min, int *max, int range, int oodok); int init(void); +void inctime(long nunits); void calcbresnham(map_t *m, int x1, int y1, int x2, int y2, cell_t **retcell, int *numpixels); void initbresnham(int x1, int y1, int x2, int y2, int *xinc1, int *yinc1, int *dinc1, int *xinc2, int *yinc2, int *dinc2, int *numpixels, int *d); int isplayerturn(void); @@ -38,6 +39,7 @@ int roll(char *string); int rolldie(int ndice, int sides); int rollhitdice(lifeform_t *lf, int wantmax); int rollmpdice(lifeform_t *lf, int wantmax); +void setcurtime(int hours, int minutes); //void sortlf(map_t *map); void timeeffectsworld(map_t *map, int updategametime); void usage(char *progname); diff --git a/objects.c b/objects.c index 86e37ba..8ca4925 100644 --- a/objects.c +++ b/objects.c @@ -9121,11 +9121,13 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { int wastech = B_FALSE; if (!lfhasflag(lf, F_HUMANOID) || !hasbp(lf, BP_HANDS)) { - // only humanoids can zap things - if (isplayer(lf)) { - msg("You lack the manual dexterity to operate this."); + if (!hasflag(o->flags, F_OPERWITHOUTHANDS)) { + // only humanoids can zap things + if (isplayer(lf)) { + msg("You lack the manual dexterity to operate this."); + } + return B_TRUE; } - return B_TRUE; } if (lfhasflag(lf, F_RAGE)) { @@ -10915,6 +10917,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE int failed; int seenbyplayer; object_t *o2; + race_t *r; flag_t *f; if (isplayer(lf)) { @@ -11167,6 +11170,12 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE i = rnd(5,20); addtempflag(lf->flags, F_LEVITATING, B_TRUE, NA, NA, NULL, i); break; + case OT_POT_LYCANTHROPY: + if (isplayer(lf)) msg("Yuck, this tastes like blood!"); + // find random lycanthrope type + r = getrandomracewithflag(F_LYCANTHROPE); + poison(lf, PERMENANT, P_LYCANTHROPY, 1, r->name, R_NONE); + break; case OT_POT_MAGIC: if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, -10)) { if (isplayer(lf)) { @@ -11285,7 +11294,9 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE } losehp(lf, rnd(5,15), DT_HOLY, NULL, "drinking holy water"); } else { - if (isplayer(lf)) msg("Mmm, holy water."); + if (isplayer(lf)) msg("A feeling of holiness spreads through your body."); + // cure any curses, and lycanthropy + fixcurses(lf); } break; case B_UNCURSED: @@ -11882,8 +11893,6 @@ int readsomething(lifeform_t *lf, object_t *o) { } else if (o->type->id == OT_SCR_REMOVECURSE) { int seen = B_FALSE; - flag_t *retflag[MAXCANDIDATES]; - int i,nretflags = 0; object_t *oo; // remove curses! for (oo = lf->pack->first ; oo ; oo = oo->next) { @@ -11897,15 +11906,8 @@ int readsomething(lifeform_t *lf, object_t *o) { } } // fix player curses - getflags(lf->flags, retflag, &nretflags, F_POISONED, F_NONE); - for (i = 0; i < nretflags; i++) { - poisontype_t *pt; - pt = findpoisontype(retflag[i]->val[0]); - if (pt->severity == PS_CURSE) { - } else { - killflag(retflag[i]); - if (isplayer(lf) || cansee(player, lf)) seen = B_TRUE; - } + if (fixcurses(lf)) { + if (isplayer(lf) || cansee(player, lf)) seen = B_TRUE; } if (seen) { @@ -13792,7 +13794,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp applyarmourdamage(target, o, reduceamt, DT_PROJECTILE, NULL); } - wepeffects(o->flags, target->cell, hasflag(o->flags, F_DAM), dam); + wepeffects(o->flags, target->cell, hasflag(o->flags, F_DAM), dam, B_FALSE); missiledam += ((speed*2)+rnd(1,4)); @@ -13852,7 +13854,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp stuck = B_TRUE; if (cansee(player, target)) { if (thrower) { - msg("^%d%s sticks to %s!", getlfcol(thrower, CC_BAD), obname, targetname); + msg("^%c%s sticks to %s!", getlfcol(thrower, CC_BAD), obname, targetname); } else { msg("%s sticks to %s!", obname, targetname); } @@ -14381,7 +14383,7 @@ void timeeffectsob(object_t *o) { if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - msg("^%dPowerful winds pummel %s!^n", getlfcol(lf, CC_BAD), lfname); + msg("^%cPowerful winds pummel %s!^n", getlfcol(lf, CC_BAD), lfname); } // lfs here take damage if (creator) { diff --git a/shops.c b/shops.c index 238ad54..bc79847 100644 --- a/shops.c +++ b/shops.c @@ -438,7 +438,8 @@ enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *topte // validate it if (o) { - int goldgiven = 0; + long goldgiven = 0; + long multi = 0; flag_t *f; // can we remove it? if (isequipped(o)) { @@ -467,16 +468,27 @@ enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *topte } else { object_t *newob; char let; + int thisval,pct = 100; if (vm->contents->first) { let = vm->contents->last->letter + 1; } else { let = 'a'; } + + thisval = getobvalue(o); + if (!isknown(o)) { + pct -= 50; + } + if (!isidentified(o)) { + pct -= 25; + } + thisval = pctof(pct, thisval); + newob = moveob(o, vm->contents, count); newob->letter = let; (*ndonated)++; practice(player, SK_SPEECH, 1); - goldgiven += getobvalue(o); + goldgiven += thisval; } if ((vm->type->id == OT_TEMPLE) && goldgiven) { @@ -500,9 +512,29 @@ enum SHOPRETURN shopdonate(lifeform_t *lf, object_t *vm, int starty, char *topte } else { addflag(vm->flags, F_SHOPDONATED, goldgiven, NA, NA, NULL); } + + + + // remember amount donated, for addition to final score + f = lfhasflagval(lf, F_SCOREBONUS, NA, NA, NA, SCB_DONATIONS); + if (f) { + multi = f->val[1]; + goldgiven += f->val[0]; + } else { + f = addflag(lf->flags, F_SCOREBONUS, 0, NA, NA, SCB_DONATIONS); + multi = 0; + } + // cope with >= 65535 + while (goldgiven > 65535) { + goldgiven -= 65535; + multi++; + } + f->val[0] = goldgiven; + f->val[1] = multi; } else { return SR_BACK; } + angergodmaybe(R_GODTHIEVES, 10, GA_MONEY); return SR_CONTINUE; } diff --git a/spell.c b/spell.c index faa5d88..bc52472 100644 --- a/spell.c +++ b/spell.c @@ -288,6 +288,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } // find out where the other end goes... + user->changinglev = B_TRUE; c = getstairdestination(stairs, &madenewmap); // show --more-- after we have the destination @@ -295,6 +296,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (!c) { msg("These stairs don't seem to go anywhere!"); + user->changinglev = B_FALSE; return B_TRUE; } @@ -341,7 +343,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef nposs = 1; } } else { - // get all lfs within hearing of the other end + int nwalls; + // get all lfs within direct hearing (not through walls) of the other end for (lf = c->map->lf ; lf ; lf = lf->next) { if (lf == user) continue; // get movement text @@ -350,7 +353,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // overwrite name real_getlfnamea(lf, thismovetext, NULL, B_NOSHOWALL, B_CURRACE); } - if (canhear(user, lf->cell, vol)) { + if (canhear(user, lf->cell, vol, &nwalls) && (nwalls == 0)) { // already have this text? found = B_FALSE; for (n = 0; n < nposs; n++) { @@ -520,6 +523,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } } + user->changinglev = B_FALSE; // announce if (nposs) { for (n = 0; n < nposs; n++) { @@ -1732,8 +1736,11 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } - // shield gets damaged - takedamage(shield, roll("1d3"), DT_DIRECT); + if (!touch(target, shield)) { + // if the victim touching the shield didn't destroy it, the shield gets damaged + takedamage(shield, roll("1d3"), DT_DIRECT); + } + } else if (abilid == OT_A_SNATCH) { object_t *o = NULL; flag_t *f; @@ -1795,7 +1802,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef f = lfhasflagval(user, F_NOTIME, OT_A_SNATCH, NA, NA, NULL); if (f) killflag(f); } else if (abilid == OT_A_SONICBOLT) { - int volume; + int volume,nwalls; if (!validatespellcell(user, &targcell,TT_MONSTER, abilid, power, B_FALSE)) return B_TRUE; target = targcell->lf; @@ -1808,11 +1815,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } else { volume = power; } - if (target && canhear(target, user->cell, volume)) { - if (isplayer(target)) { - msg("Pain shoots through your eardrums!"); + if (target && canhear(target, user->cell, volume, &nwalls)) { + if (nwalls == 0) { + if (isplayer(target)) { + msg("Pain shoots through your eardrums!"); + } + losehp(target, roll(damstr), DT_SONIC, user, "a bolt of sound"); } - losehp(target, roll(damstr), DT_SONIC, user, "a bolt of sound"); } } else if (abilid == OT_A_SPRINT) { flag_t *f; @@ -3277,7 +3286,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef default: break; } - if (ok && canhear(target, user->cell, 4)) { + if (ok && canhear(target, user->cell, 4, NULL)) { scare(target, user, rnd(5,10), 0); } } @@ -3484,6 +3493,61 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef addflag(user->flags, F_FAILEDINSPECT, o->type->id, NA, NA, NULL); } taketime(user, getactspeed(user)); + } else if (abilid == OT_A_IRONFIST) { + char dirch,tname[BUFLEN]; + int dam,dir = D_NONE; + + if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { + if (isplayer(user)) msg("You lack the stability to invoke the iron fist manouver while swimming."); + return B_TRUE; + } + + if (getweapon(user)) { + if (isplayer(user)) msg("You must be unarmed to invoke the iron fist."); + return B_TRUE; + } + + // ask for direction + if (!targcell) { + dirch = askchar("Iron fist in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); + if (dirch == '.') { + // yourself! + targcell = user->cell; + } else { + dir = chartodir(dirch); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE ; + } else { + targcell = getcellindir(user->cell, dir); + } + } + } + + target = targcell->lf; + if (!target) { + if (isplayer(user)) msg("There is nobody there to attack!"); + return B_TRUE; + } + getlfname(target, tname); + + if (isplayer(user)) { + msg("^%cYou strike %s with THE IRON FIST!",getlfcol(user, CC_GOOD),tname); + } else if (cansee(player, user)) { + msg("^%c%s strikes %s with THE IRON FIST!",getlfcol(user, CC_GOOD),username, tname); + } + + // convert all remaining stamina into damage. + dam = getstamina(user); + + setstamina(user, 0); + sprintf(damstr, "%s%s invocation of the iron fist",username,getpossessive(username)); + losehp(target, dam, DT_DIRECT, user, damstr); + + if (dir != D_NONE) { + // knockback too + knockback(target, dir, dam, user, 0, B_TRUE); + } } // expire ability @@ -5553,10 +5617,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // all in range must pass a magic resistance check or die for (target = caster->cell->map->lf ; target ; target = target->next) { if (target != caster) { - if (canhear(target, caster->cell, SV_TALK)) { - if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) { - } else { - losehp(target, target->hp, DT_SONIC, caster, "a banshee's wail"); + int nwalls; + if (canhear(target, caster->cell, SV_TALK, &nwalls)) { + if (nwalls == 0) { + if (spellresisted(target, caster, spellid, power, seenbyplayer, B_TRUE)) { + } else { + losehp(target, target->hp, DT_SONIC, caster, "a banshee's wail"); + } } } } @@ -11918,6 +11985,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ summoner = caster; } + if (!isplayer(caster)) { + friendly = B_TRUE; + } + ngot = summonlfs(caster, caster->cell, wantrace, wantrc, wantsize, AL_NONE, nwant, lifetime, friendly); if (!ngot) { fizzle(caster); diff --git a/text.c b/text.c index 16410db..d44e76f 100644 --- a/text.c +++ b/text.c @@ -1086,7 +1086,7 @@ char *getflagsourcetext(flag_t *f) { int gethitconferlifetime(char *text, int *min, int *max) { int howlong; int localmin = -1,localmax = -1; - if (text) { + if (text && strlen(text)) { char loctext[BUFLEN]; char *word, *dummy; strcpy(loctext,text); @@ -2318,6 +2318,28 @@ char *strstarts(char *a, char *prefix) { return NULL; } +// if string starts with 'a ', 'an ' or 'the ', then return the position after it, +// and write the prefix into 'prefix'. +// otherwise return null. +// +char *strstartswitha(char *text, char *retprefix) { + char *prefix[] = { + "the ", + "an ", + "a " + }; + int nprefixes = 3,i; + for (i = 0; i < nprefixes; i++) { + if (strstarts(text, prefix[i])) { + if (retprefix) { + strcpy(retprefix, prefix[i]); + } + return text + strlen(prefix[i]); + } + } + return NULL; +} + int strlen_without_colours(char *buf) { char *p; int len = 0; diff --git a/text.h b/text.h index 659df71..cb805ef 100644 --- a/text.h +++ b/text.h @@ -70,6 +70,7 @@ char *strends(char *a, char *suffix); char *strcasestarts(char *a, char *prefix); material_t *strmatchesmaterial(char *p); char *strstarts(char *a, char *prefix); +char *strstartswitha(char *text, char *retprefix); int strlen_without_colours(char *buf); int strpixmatch(char *haystack, char *needle); int texttodice(char *text, int *ndice, int *nsides, int *bonus);