diff --git a/ai.c b/ai.c index 8748ad9..8bc9921 100644 --- a/ai.c +++ b/ai.c @@ -711,9 +711,16 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { } // end if attackok // if we could see our traget, but everything we tried failed (spells, moving and ranged attack), - // just rest. + // either rest or move randomly. if (movefailed) { - rest(lf, B_TRUE); + makenoise(lf, N_FRUSTRATED); + if (onein(2)) { + rest(lf, B_TRUE); + } else { + if (dorandommove(lf, B_NOBADMOVES, B_FALSE)) { + rest(lf, B_TRUE); + } + } return B_FALSE; } } else { @@ -1494,74 +1501,78 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG f = hasflag(ot->flags, purpose); if (f) { - int range; - switch (f->val[0]) { - case ST_VICTIM: - range = getspellrange(spellid, getspellpower(lf, spellid)); - if ((range == UNLIMITED) || (getcelldist(lf->cell, victim->cell) <= range)) { + if ((f->val[1] == NA) || pctchance(f->val[1])) { + int range; + switch (f->val[0]) { + case ST_VICTIM: + range = getspellrange(spellid, getspellpower(lf, spellid)); + if ((range == UNLIMITED) || (getcelldist(lf->cell, victim->cell) <= range)) { + if (db) { + dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?"); + } + ok = B_TRUE; + } + break; + case ST_SELF: + case ST_ANYWHERE: if (db) { dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?"); } ok = B_TRUE; - } - break; - case ST_SELF: - case ST_ANYWHERE: - if (db) { - dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?"); - } - ok = B_TRUE; - break; - case ST_ADJVICTIM: - if (getcelldist(lf->cell,victim->cell) == 1) { - if (ot->id == OT_A_GRAB) { - if (lfhasflag(lf, F_GRABBING) || lfhasflag(lf, F_GRABBEDBY) || - lfhasflag(victim, F_GRABBING) || lfhasflag(victim, F_GRABBEDBY)) { + break; + case ST_ADJVICTIM: + if (getcelldist(lf->cell,victim->cell) == 1) { + if (ot->id == OT_A_GRAB) { + if (lfhasflag(lf, F_GRABBING) || lfhasflag(lf, F_GRABBEDBY) || + lfhasflag(victim, F_GRABBING) || lfhasflag(victim, F_GRABBEDBY)) { + } else { + ok = B_TRUE; + } + } else if (ot->id == OT_A_CRUSH) { + // can only crush if you first grab something + if (lfhasflag(lf, F_GRABBING)) { + ok = B_TRUE; + } + } else if (ot->id == OT_A_SUCKBLOOD) { + // must attach first + if (lfhasflag(lf, F_ATTACHEDTO)) { + ok = B_TRUE; + } } else { ok = B_TRUE; } - } else if (ot->id == OT_A_CRUSH) { - // can only crush if you first grab something - if (lfhasflag(lf, F_GRABBING)) { - ok = B_TRUE; - } - } else if (ot->id == OT_A_SUCKBLOOD) { - // must attach first - if (lfhasflag(lf, F_ATTACHEDTO)) { - ok = B_TRUE; - } - } else { + } + break; + case ST_ADJSELF: + if (getcelldist(lf->cell,victim->cell) == 1) { ok = B_TRUE; } - } - break; - case ST_ADJSELF: - if (getcelldist(lf->cell,victim->cell) == 1) { - ok = B_TRUE; - } - break; - case ST_SPECIAL: - specialcase = B_TRUE; - break; - } + break; + case ST_SPECIAL: + specialcase = B_TRUE; + break; + } - // now check for line of sight / fire - switch (f->val[0]) { - case ST_VICTIM: - case ST_ADJVICTIM: - if (needlos && (!victim || !cansee(lf, victim)) ) { - if (db) dblog(".oO { cant cast %s - no LOS to victim }", ot ? ot->name : "?unkownspell?"); - return B_FALSE; - } - if (needlof && !haslof(lf->cell, victim->cell, needlof, NULL) ) { - if (db) dblog(".oO { cant cast %s - no LOF to victim }", ot ? ot->name : "?unkownspell?"); - return B_FALSE; - } - break; - default: - break; + // now check for line of sight / fire + switch (f->val[0]) { + case ST_VICTIM: + case ST_ADJVICTIM: + if (needlos && (!victim || !cansee(lf, victim)) ) { + if (db) dblog(".oO { cant cast %s - no LOS to victim }", ot ? ot->name : "?unkownspell?"); + return B_FALSE; + } + if (needlof && !haslof(lf->cell, victim->cell, needlof, NULL) ) { + if (db) dblog(".oO { cant cast %s - no LOF to victim }", ot ? ot->name : "?unkownspell?"); + return B_FALSE; + } + break; + default: + break; + } + } else { // failed pctchance for spell + if (db) dblog(".oO { failed pct check for casting %s }", ot ? ot->name : "?unkownspell?"); + return B_FALSE; } - } else { // invalid spell for this purpose if (db) dblog(".oO { cant cast %s - not valid for given purpose }", ot ? ot->name : "?unkownspell?"); diff --git a/attack.c b/attack.c index 0d50664..b2f1d48 100644 --- a/attack.c +++ b/attack.c @@ -255,7 +255,6 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } // then use all our innate attacks.. - getflags(lf->flags, F_HASATTACK, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -2160,4 +2159,24 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { } // end if (fid == hitconfer) } + if (wep && owner && victim) { + if ((wep->type->id == OT_TEETH) && lfhasflag(owner, F_VAMPIRIC) && isbleeding(victim)) { + // drain life! + gainhp(owner, dam); + if (isplayer(owner)) { + char lfname[BUFLEN]; + char victimname[BUFLEN]; + getlfname(owner,lfname); + getlfname(victim, victimname); + msg("You suck %s%s blood!", victimname, getpossessive(victimname)); + } else if (cansee(player, owner)) { + char lfname[BUFLEN]; + char victimname[BUFLEN]; + getlfname(owner,lfname); + getlfname(victim, victimname); + msg("%s sucks %s%s blood!", lfname, victimname, getpossessive(victimname)); + } + } + } + } diff --git a/defs.h b/defs.h index 9fb8430..cbd4fa6 100644 --- a/defs.h +++ b/defs.h @@ -735,6 +735,7 @@ enum RACE { R_ANTS, R_ANTLION, R_BAT, + R_BATVAMPIRE, R_BEAR, R_BEARCUB, R_BEARGRIZZLY, @@ -895,6 +896,7 @@ enum OBTYPE { OT_TREE, // food OT_BERRY, + OT_GARLIC, OT_NUT, OT_BANANA, OT_BANANASKIN, // not really food @@ -1489,6 +1491,7 @@ enum NOISETYPE { N_FLY, N_WARCRY, N_LOWHP, + N_FRUSTRATED, }; enum LFSIZE { @@ -1838,8 +1841,10 @@ enum FLAG { //F_SPELLLETTER, // text[0] = letter to cast this spell F_AICASTTOFLEE, // AI can cast this spell to help flee/heal // v0 is who to target + // v1 is pct chance of using this F_AICASTTOATTACK, // AI can cast this spell to attack // v0 is who to target + // v1 is pct chance of using this F_AIBOOSTITEM, // ai will use this item to boost/buff itself. // if using this on wands, update aiobok() ! F_AIHEALITEM, // ai will use this item when low on hp @@ -1858,6 +1863,7 @@ enum FLAG { F_COUNTER, // generic counter flag for race abilities. F_DEBUG, // debugging enabled F_ACCURACYMOD, // modify your accuracy by val0 + F_VAMPIRIC, // successful bite attacks form this lf will heal it 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. @@ -1934,8 +1940,13 @@ enum FLAG { // v2 is counter until casting // text is: "targlfid;targobid;mapid;cellx;celly;" - F_AVOIDCURSEDOB, // for AI animals - they will avoid walking on obid 'text' + F_AVOIDOB, // for AI - they will avoid walking on obid 'text' // (text is a long) + // if v0 is not NA, then only avoid it if its blessed + // value == v0. + F_AVOIDOBTYPE, // AI won't walk on top of obtype v0. + // if v1 == B_TRUE, then avoid lfs weilding this + // object too. F_STAYINHABITAT, // lf will not walk onto a cell of a different // habitat F_STAYINROOM, // lf will not walk out of roomid v0 @@ -2048,6 +2059,7 @@ enum FLAG { // v0 = max distance to splatter (or UNLIMITED) // text = type of object to splatter F_OBESE, // double base weight for race! + F_FORCEPOLY, // when this lf polymorphs, always chance to raceid v0 F_ORIGRACE, // original player race (if you polymorphed) F_ORIGJOB, // original player job (if you polymorphed) F_POLYMORPHED, // lf has been polymorphed @@ -2113,7 +2125,8 @@ enum FLAG { // otherwise just an indicative size is shown F_DETECTMAGIC, // autodetect magic/special objects F_DETECTMETAL, // autodetect nearby metal - F_DETECTOBS, // autodetect nearby obs in orthog dist v0 + F_DETECTOBS, // autodetect nearby obs of type v1 in orthog dist v0 + // v1 = NA means everything. F_DISEASEIMMUNE, // lf can't be diseased F_DRUNK, // v1 is drunknness - 1-5. F_ENHANCESEARCH, // gives v0 bonus on search checks. diff --git a/flag.c b/flag.c index aa10fe7..5b0ced4 100644 --- a/flag.c +++ b/flag.c @@ -100,6 +100,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, f->val[1] += val2; f->val[2] += val3; // TODO: how to handle text?? + f->text = strdup(""); return f; } } @@ -303,6 +304,15 @@ flagpile_t *addflagpile(lifeform_t *owner, object_t *ob) { return fp; } +void changeflagtext(flag_t *f, char *newtext) { + free(f->text); + if (newtext) { + f->text = strdup(newtext); + } else { + f->text = strdup(""); + } +} + void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id) { flag_t *f; for (f = src->first ; f ; f = f->next) { diff --git a/flag.h b/flag.h index 762ce6d..62b0e58 100644 --- a/flag.h +++ b/flag.h @@ -8,6 +8,7 @@ flag_t *addflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char flag_t *addtempflag(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int timeleft); flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, char *text, int lifetime, int known, long obfromid); flagpile_t *addflagpile(lifeform_t *owner, object_t *o); +void changeflagtext(flag_t *f, char *newtext); void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id); void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime); int countflags(flagpile_t *fp); diff --git a/god.c b/god.c index 475de47..b200a0e 100644 --- a/god.c +++ b/god.c @@ -293,7 +293,7 @@ int godgiftmaybe(enum RACE rid) { int chance; // ie. 100 -> 2% // ie. 500 -> 10% - chance = piety / 5; + chance = piety / 50; if (pctchance(chance)) { // if this is true, you get a gift. char obtogive[BUFLEN]; int rollagain = B_TRUE; @@ -307,7 +307,7 @@ int godgiftmaybe(enum RACE rid) { flag_t *f; object_t *wep; rollagain = B_FALSE; - switch (rnd(5,5)) { + switch (rnd(1,5)) { case 1: sprintf(obtogive, "3-5 cursed potions of water"); break; @@ -338,7 +338,7 @@ int godgiftmaybe(enum RACE rid) { break; case 5: msg("\"Go forth and kill in my name!\""); - setrace(player, R_VAMPIRE, B_TRUE); + setrace(player, R_VAMPIRE, B_TRUE); // ie. don't set origrace! break; } } @@ -394,8 +394,9 @@ int godgiftmaybe(enum RACE rid) { } } - // since you got a gift, lower piety back to 100 (slightly pleased) - setpiety(rid, 101); + // since you got a gift, lower piety a little. + //setpiety(rid, 101); + modpiety(rid, -50); } // end if (pctchance enough to get a gift) } // end if (piety > 100) return gotgift; @@ -444,7 +445,7 @@ void pleasegod(enum RACE rid, int amt) { modpiety(rid, amt); // announce - //msg("You feel like %s approves of your actions.", lfname); + msg("You feel like %s approves of your actions.", lfname); godgiftmaybe(rid); } diff --git a/io.c b/io.c index abab4ef..353b1a2 100644 --- a/io.c +++ b/io.c @@ -7384,7 +7384,7 @@ void drawstatus(void) { if (hlev == H_NONE) { strcpy(buf2, ""); } else { - gethungername(gethungerlevel(f->val[0]), buf2); + gethungername(player, gethungerlevel(f->val[0]), buf2); capitalise(buf2); } } else { @@ -8162,7 +8162,7 @@ void showlfstats(lifeform_t *lf, int showall) { if (f) { doheadingsmall(mainwin, y2, x2, ftext, "Hunger"); - gethungername(gethungerlevel(f->val[0]), buf); + gethungername(lf, gethungerlevel(f->val[0]), buf); capitalise(buf); wprintw(mainwin, "%-14s", buf); y2++; /* diff --git a/lf.c b/lf.c index 51be126..ebfec6b 100644 --- a/lf.c +++ b/lf.c @@ -1236,6 +1236,16 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar // stop hiding killflagsofid(lf->flags, F_HIDING); + // willing this spell? reset counter! + // do this _before_ casting the spell, + // in case the spell causes us to lose + // the f_canwill flag (eg. polymorph) + if (willflag) { + if (willflag->val[2] != NA) { + willflag->val[1] = -1; + } + } + // cast the spell f = hasflag(sp->flags, F_CASTINGTIME); if (f) { @@ -1284,13 +1294,6 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } } - // willing this spell? reset counter! - if (willflag) { - if (willflag->val[2] != NA) { - willflag->val[1] = -1; - } - } - // successful cast? if (!rv) { practice(lf, SK_SPELLCASTING, 1); @@ -1330,6 +1333,16 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { // will you drown? if (depth >= DP_HEAD) { + if (lf->race->id == R_VAMPIRE) { + if (isplayer(lf)) { + msg("^BThe running water burns you!"); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%cThe running water burns %s!", getlfcol(lf, CC_BAD), lfname); + } + losehp(lf, roll("6d6"), DT_DIRECT, NULL, "running water"); + } if (!slev && !lfhasflag(lf, F_BREATHWATER)) { int damamt; @@ -1673,9 +1686,9 @@ void die(lifeform_t *lf) { } } - if (lf->race->id == R_VAMPIRE) { - // if are asleep, we will die normally - if (lfhasflag(lf, F_ASLEEP)) { + if ((lf->race->id == R_VAMPIRE) && !hasflag(lf->flags, F_ORIGRACE)) { + // if are asleep or killed by running water/sunlight, we will die normally + if (lfhasflag(lf, F_ASLEEP) || (lf->lastdamtype == DT_DIRECT)) { noise(lf->cell, lf, NC_OTHER, 4, "a horrified scream!", "screams in horror!"); } else if (findobinmap(lf->cell->map, OT_COFFIN)) { // coffin around? // restore 1 hp @@ -1684,7 +1697,9 @@ void die(lifeform_t *lf) { // convert into a gas cloud! dospelleffects(NULL, OT_S_GASEOUSFORM, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); // ai will now look for our coffin - if (!isplayer(lf)) { + if (isplayer(lf)) { + msg("^GYou feel the presence of a nearby coffin..."); + } else { addflag(lf->flags, F_WANTS, OT_COFFIN, B_COVETS, NA, NULL); addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); } @@ -1854,8 +1869,7 @@ void die(lifeform_t *lf) { // remember what killed us. f = hasflag(corpse->flags, F_CORPSEOF); if (f) { - free(f->text); - f->text = strdup(lf->lastdam); + changeflagtext(f, lf->lastdam); } } @@ -2894,8 +2908,7 @@ void enhanceskills(lifeform_t *lf) { break; } if (!streq(newtext, f->text)) { - free(f->text); - f->text = strdup(newtext); + changeflagtext(f, newtext); if (isplayer(lf)) msg("^gYour unarmed attack damage has increased!"); } } @@ -3252,7 +3265,6 @@ int flee(lifeform_t *lf) { } // are we fleeing? - getflags(lf->flags, F_FLEEFROM, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; @@ -4193,8 +4205,42 @@ object_t *getbestweapon(lifeform_t *lf) { object_t *bestwep = NULL; //int bestmaxdam = -999; object_t *o; + obpile_t *op = NULL; bestwep = getweapon(lf); + if (!bestwep) { + int i; + // get best innate attack + getflags(lf->flags, F_HASATTACK, F_NONE); + for (i = 0; i < nretflags; i++) { + objecttype_t *ot; + + if (!op) { + op = addobpile(NULL, NULL, NULL); + } + + ot = findot(retflag[i]->val[0]); + if (ot) { + o = addob(op, ot->name); + + if (isweapon(o) && !isfirearm(o) && canweild(lf, o) && isbetterwepthan(o, bestwep)) { + bestwep = o; + // inherit damage from hasattack flag + if (strlen(retflag[i]->text)) { + flag_t *damflag; + damflag = hasflag(bestwep->flags, F_DAM); + if (damflag) { + free(damflag->text); + damflag->text = strdup(retflag[i]->text); + } + } + } else { + killob(o); + } + } + } + + } for (o = lf->pack->first ; o ; o = o->next) { // if it does damage and we can weild it... @@ -4216,6 +4262,15 @@ object_t *getbestweapon(lifeform_t *lf) { } */ + if (bestwep && (bestwep->pile->owner == NULL)) { + // ie. best weapon is an innate attack + bestwep = NULL; + } + + if (op) { + killobpile(op); + } + return bestwep; } @@ -4442,7 +4497,7 @@ enum HUNGER gethungerlevel(int hunger) { return H_STARVED; } -char *gethungername(enum HUNGER hunger, char *buf) { +char *gethungername(lifeform_t *lf, enum HUNGER hunger, char *buf) { switch (hunger) { case H_STUFFED: strcpy(buf, "stuffed"); @@ -4451,19 +4506,39 @@ char *gethungername(enum HUNGER hunger, char *buf) { strcpy(buf, "full"); break; case H_NONE: - strcpy(buf, "not hungry"); + if (lf && (lf->race->id == R_VAMPIRE)) { + strcpy(buf, "not thirsty"); + } else { + strcpy(buf, "not hungry"); + } break; case H_PECKISH: - strcpy(buf, "peckish"); + if (lf && (lf->race->id == R_VAMPIRE)) { + strcpy(buf, "parched"); + } else { + strcpy(buf, "peckish"); + } break; case H_HUNGRY: - strcpy(buf, "hungry"); + if (lf && (lf->race->id == R_VAMPIRE)) { + strcpy(buf, "thirsty"); + } else { + strcpy(buf, "hungry"); + } break; case H_VHUNGRY: - strcpy(buf, "very hungry"); + if (lf && (lf->race->id == R_VAMPIRE)) { + strcpy(buf, "very thirsty"); + } else { + strcpy(buf, "very hungry"); + } break; case H_STARVING: - strcpy(buf, "starving"); + if (lf && (lf->race->id == R_VAMPIRE)) { + strcpy(buf, "dehydrating"); + } else { + strcpy(buf, "starving"); + } break; case H_STARVED: strcpy(buf, "starved"); @@ -6262,16 +6337,14 @@ void givejob(lifeform_t *lf, enum JOB jobid) { f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL); if (f) { // monk fists do more damage - free(f->text); - f->text = strdup("1d4"); + changeflagtext(f, "1d4"); } } else if (j->id == J_PIRATE) { flag_t *f; f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL); if (f) { f->val[0] = OT_HOOKHAND; - free(f->text); - f->text = strdup("1d4"); + changeflagtext(f, "1d4"); } } else if (j->id == J_SHOPKEEPER) { // shopkeepers are not hostile. @@ -8330,7 +8403,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roars"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roar"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "roars^a roar"); addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HEAVYBLOW, 2, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -9510,6 +9584,28 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); + addrace(R_BATVAMPIRE, "vampire bat", 6, 'B', C_BLUE, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 76, NA, ""); + addflag(lastrace->flags, F_RARITY, H_FOREST, 84, NA, ""); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, ""); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_HITDICE, 2, 4, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); + addflag(lastrace->flags, F_MAXATTACKS, 2, 2, NA, NULL); + addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL); + addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); @@ -9679,6 +9775,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling"); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addflag(lastrace->flags, F_FLEEONHPPCT, 60, NA, NA, ""); addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL); @@ -9703,6 +9801,8 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_BLINK, 2, 2, "pw:1;"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling"); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addrace(R_DOGDEATH, "death hound", 40, 'd', C_MAGENTA, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, ""); @@ -9727,6 +9827,8 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "howls^a howl"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling"); addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 24, "10-15"); addflag(lastrace->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL); addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); @@ -9751,6 +9853,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "barks^barking"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 2, NA, "growls^growling"); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian @@ -10184,6 +10288,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 8, 8, NULL); addflag(lastrace->flags, F_LEVRACE, 5, R_WOLF, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling"); addflag(lastrace->flags, F_FLEEONHPPCT, 75, NA, NA, ""); addrace(R_WOLF, "wolf", 25, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); @@ -10208,6 +10313,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling"); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); // insects @@ -10460,21 +10566,33 @@ void initrace(void) { addflag(lastrace->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "3d6"); addflag(lastrace->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 8, NA, NA, NULL); + addflag(lastrace->flags, F_AVOIDOBTYPE, OT_GARLIC, B_TRUE, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, NULL); - addflag(lastrace->flags, F_ACTIONSPEED, SP_FAST, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 8, 3, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL); addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "coffin"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6+4"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d4+3"); + addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_CANWILL, OT_S_CHARM, 3, 3, "pw:6;"); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 5, 5, "range:3;"); + addflag(lastrace->flags, F_CANWILL, OT_S_STUN, 5, 5, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_POLYMORPH, 3, 3, "pw:1;"); + addflag(lastrace->flags, F_FORCEPOLY, R_BATVAMPIRE, 20, 20, "pw:3;"); + addflag(lastrace->flags, F_DETECTOBS, 10, OT_COFFIN, NA, NULL); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pile of ash"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "hisses angrily^an angry hiss"); + // special: change to gas cloud with 1 hp on death, if not asleep + // special: flee from garlic // TODO: can shapeshift to bat - // TODO: flee from holy symbols / garlic addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); @@ -12569,6 +12687,10 @@ void modhunger(lifeform_t *lf, int amt) { return; } + if (isundead(lf) && (lf->race->id != R_VAMPIRE)) { + return; + } + // modify for effects if (amt > 0) { int multiplier = 0; @@ -12622,7 +12744,7 @@ void modhunger(lifeform_t *lf, int amt) { if (isplayer(lf)) { - gethungername(posthlev, buf); + gethungername(lf, posthlev, buf); msg("^wYou are %s%s%s%c", ((amt < 0) && (posthlev > H_NONE)) ? "still " : "", needfeeling ? "feeling " : "", @@ -12633,7 +12755,7 @@ void modhunger(lifeform_t *lf, int amt) { } else if (cansee(player, lf)) { char lfname[BUFLEN]; getlfname(lf, lfname); - gethungername(posthlev, buf); + gethungername(lf, posthlev, buf); msg("^%c%s looks %s%c", getlfcol(lf, CC_BAD), lfname, buf, (needexclam) ? '!' : '.'); } @@ -13792,6 +13914,7 @@ void setguntarget(lifeform_t *lf, lifeform_t *targ) { void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { flag_t *f,*nextf; int i; + int nkilled = 0; race_t *newrace; char buf[BUFLEN]; @@ -13862,8 +13985,10 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { nextf = f->next; if (f->lifetime == FROMRACE) { killflag(f); + nkilled++; } else if ((f->lifetime > 0) && (f->id != F_POLYMORPHED)) { killflag(f); + nkilled++; } } @@ -14475,7 +14600,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r } break; case SC_RESISTMAG: - attrib = (getattr(lf, A_CON)/4) + (getattr(lf, A_WIS)/4) + getmr(lf); + attrib = (getattr(lf, A_CON)/6) + (getattr(lf, A_WIS)/4) + getmr(lf); break; case SC_SEARCH: attrib = (getskill(lf, SK_SPOTHIDDEN)*4); @@ -15045,6 +15170,7 @@ int takeoff(lifeform_t *lf, object_t *o) { if ((gamemode == GM_GAMESTARTED)) { if (isplayer(lf)) { msg("You take off %s.", obname); + statdirty = B_TRUE; } else if (cansee(player, lf)) { getlfname(lf, buf); capitalise(buf); @@ -15335,6 +15461,18 @@ void turneffectslf(lifeform_t *lf) { if (isdead(lf)) return; } } + // vampire in sunlight? + if ((lf->race->id == R_VAMPIRE) && isoutdoors(lf->cell->map) && !isnighttime()) { + if (isplayer(lf)) { + msg("^bThe sunlight burns you!"); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%cThe sunlight burns %s!", getlfcol(lf, CC_BAD), lfname); + } + losehp(lf, roll("6d6"), DT_DIRECT, NULL, "sunlight"); + if (isdead(lf)) return; + } // float up into space? if (lf->cell->map->region->rtype->id == RG_WORLDMAP) { diff --git a/lf.h b/lf.h index 7fa9191..ea21b46 100644 --- a/lf.h +++ b/lf.h @@ -120,7 +120,7 @@ int gethidemodifier(lifeform_t *lf); int gethitdice(lifeform_t *lf); int gethppct(lifeform_t *lf); enum HUNGER gethungerlevel(int hunger); -char * gethungername(enum HUNGER hunger, char *buf); +char *gethungername(lifeform_t *lf, enum HUNGER hunger, char *buf); int gethungerval(lifeform_t *lf); job_t *getjob(lifeform_t *lf); int getlastdir(lifeform_t *lf); diff --git a/map.c b/map.c index db41445..42c8af0 100644 --- a/map.c +++ b/map.c @@ -30,6 +30,9 @@ extern lifeform_t *player; extern lifeform_t *godlf[]; extern int ngodlfs; +extern flag_t *retflag[]; +extern int nretflags; + extern glyph_t tempglyph; extern enum OBCLASS sortorder[]; @@ -1247,7 +1250,7 @@ void calclight(map_t *map) { if (isoutdoors(map)) { int hours,mins,secs; splittime(&hours,&mins,&secs); - if ((hours < 5) || (hours >= 19)) { + if (isnighttime()) { // ie. nighttime, after 7pm or before 5am } else { // ie. daytime @@ -3861,6 +3864,7 @@ int isempty(cell_t *c) { //returns TT_ based on what you can scan there int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { flag_t *f; + int i; // handle scanner f = lfhasflag(player, F_DETECTLIFE); if (f) { @@ -3933,19 +3937,30 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { return TT_MONSTER; } - f = lfhasflag(player, F_DETECTOBS); - if (f) { + // get list of all detected ob ids. + getflags(player->flags, F_DETECTOBS, F_NONE); + + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (getcelldistorth(player->cell, c) <= f->val[0]) { object_t *o; for (o = c->obpile->first ; o ; o = o->next) { - if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_DOOR)) { - *thing = o; - if (glyph) { - glyph->ch = '*'; - glyph->colour = C_GREY; + if ((f->val[1] == NA) || (o->type->id == f->val[1])) { + if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_DOOR)) { + *thing = o; + if (glyph) { + glyph->ch = '*'; + glyph->colour = C_BOLDGREEN; + } + if (desc) { + if (f->val[1] == NA) { + strcpy(desc, "a detected object"); + } else { + getobname(o, desc, o->amt); + } + } + return TT_OBJECT; } - if (desc) sprintf(desc, "an object"); - return TT_OBJECT; } } } @@ -4000,6 +4015,15 @@ int isnewcellok(cell_t *cell, char *err) { return B_TRUE; } +int isnighttime(void) { + int hours,mins,secs; + splittime(&hours,&mins,&secs); + if ((hours < 5) || (hours >= 19)) { + return B_TRUE; + } + return B_FALSE; +} + int isonmap(map_t *map, int x, int y) { if ((x < 0) || (y < 0)) { return B_FALSE; diff --git a/map.h b/map.h index 90f7ccc..b5fdb83 100644 --- a/map.h +++ b/map.h @@ -97,6 +97,7 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph); int islit(cell_t *c); int isloopdirok(cell_t *cell, int dir); int isnewcellok(cell_t *cell, char *err); +int isnighttime(void); int isonmap(map_t *map, int x, int y); int isoutdoors(map_t *m); int isroom(cell_t *c); diff --git a/move.c b/move.c index a54bc5f..5474ccc 100644 --- a/move.c +++ b/move.c @@ -26,6 +26,9 @@ extern enum GAMEMODE gamemode; extern enum ERROR reason; extern void *rdata; +extern flag_t *retflag[]; +extern int nretflags; + extern WINDOW *gamewin, *msgwin; int canandwillmove(lifeform_t *lf, int dir, enum ERROR *error) { @@ -1946,9 +1949,24 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) { reason = E_OK; // avoid this object in future sprintf(buf, "%ld",o->id); - addflag(lf->flags, F_AVOIDCURSEDOB, NA, NA, NA, buf); + addflag(lf->flags, F_AVOIDOB, B_CURSED, NA, NA, buf); return B_TRUE; - } + } else if (lfhasflagval(lf, F_AVOIDOBTYPE, o->type->id, NA, NA, NULL)) { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf,lfname); + getobname(o, buf, o->amt); + msg("%s %s away from %s!", lfname, isplayer(lf) ? "shy" : "shies", buf); + o->blessknown = B_TRUE; + if (didmsg) *didmsg = B_TRUE; + } + taketime(lf, getmovespeed(lf)); + reason = E_OK; + // avoid this object in future + sprintf(buf, "%ld",o->id); + addflag(lf->flags, F_AVOIDOB, NA, NA, NA, buf); + return B_TRUE; + } } } } @@ -2317,8 +2335,12 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { msg("You swap places with %s.", lfname); } } else { - // attack! - return attackcell(lf, cell, B_FALSE); + if (!onpurpose || canandwillmove(lf, dir, &errcode)) { + return attackcell(lf, cell, B_FALSE); + } else { + // won't attack for some reason. + return B_TRUE; + } } break; case E_CANTMOVE: @@ -2540,6 +2562,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { // don't attack other monsters if (cell->lf) { // if someone is in the way + object_t *defenderwep = NULL; if (lf->race->raceclass->id == RC_INSECT) { if (hasactivespell(cell->lf, OT_S_REPELINSECTS)) { if (error) *error = E_WONT; @@ -2547,6 +2570,14 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { } } + defenderwep = getweapon(cell->lf); + if (defenderwep) { + if (lfhasflagval(lf, F_AVOIDOBTYPE, defenderwep->type->id, B_TRUE, NA, NULL)) { + if (error) *error = E_WONT; + return B_FALSE; + } + } + if (!isplayer(lf)) { // if we are a monster // if the person in the way isn't our enemy... if (!areenemies(lf, cell->lf)) { @@ -2573,10 +2604,10 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { for (o = cell->obpile->first ; o ; o = o->next) { flag_t *f; sprintf(buf, "%ld",o->id); - f = lfhasflagval(lf, F_AVOIDCURSEDOB, NA, NA, NA, buf); + f = lfhasflagval(lf, F_AVOIDOB, NA, NA, NA, buf); if (f) { // still cursed? - if (iscursed(o)) { + if ((f->val[0] != NA) && (o->blessed == f->val[0])) { if (error) *error = E_WONT; return B_FALSE; } else { diff --git a/objects.c b/objects.c index e0ec4f1..f08bc6e 100644 --- a/objects.c +++ b/objects.c @@ -2675,6 +2675,7 @@ objecttype_t *findotn(char *name) { modname = strrep(modname, "blocks ", "block ", NULL); modname = strrep(modname, "cans ", "can ", NULL); modname = strrep(modname, "chunks ", "chunk ", NULL); + modname = strrep(modname, "cloves ", "clove ", NULL); modname = strrep(modname, "flasks ", "flask ", NULL); modname = strrep(modname, "gems ", "gem ", NULL); modname = strrep(modname, "leaves ", "leaf ", NULL); @@ -6236,6 +6237,12 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 15, NA, ""); + addot(OT_GARLIC, "clove of garlic", "A very pungent clove of raw garlic. ", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); + addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addot(OT_NUT, "peanut", "A species in the legume family.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 12, NA, ""); @@ -7088,6 +7095,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // l2 addot(OT_S_LOWERMETAB, "lower metabolism", "Slow your body's functions, decreasing your rate of hunger but also your speed. At power level V your speed is no longer affected.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); @@ -7199,6 +7207,8 @@ void initobjects(void) { addot(OT_S_POLYMORPH, "polymorph", "Transmutes the target into a new living race.\nBecomes semi-controlled at Power V, and fully-controlled at power VIII.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); // l7 addot(OT_S_GASEOUSFORM, "gaseous form", "Changes the caster into a cloud of gas.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); @@ -7390,6 +7400,7 @@ void initobjects(void) { addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, 10, NA, NULL); addot(OT_A_QUIVERINGPALM, "quivering palm", "A deadly palm strike which knocks the molecules in the target's body out of alignment.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_PRAY, "pray", "Ask for help from a higher being.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); @@ -9581,7 +9592,6 @@ int isbetterwepthan(object_t *a, object_t *b) { acca = getobaccuracy(a, a->pile->owner); accb = getobaccuracy(b, b->pile->owner); - if (db) { msg("PREACC:a=%s:%d(acc %d), b=%s:%d(acc %d)",namea,dama,(int)acca, nameb, damb,(int)accb); } @@ -12631,7 +12641,9 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE *seen = B_TRUE; } } - modhunger(lf, -pctof(0.05, (float)HUNGERCONST)); + if (!isundead(lf)) { + modhunger(lf, -pctof(0.05, (float)HUNGERCONST)); + } break; case OT_POT_BLOOD: if (lf->race->id == R_VAMPIRE) { @@ -12643,6 +12655,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE b = B_BLESSED; } dospelleffects(lf, OT_S_HEALINGMAJ,b ? 5 : 1, lf, NULL, lf->cell, b, seen, B_TRUE); + modhunger(lf, -HUNGERCONST); } else { if (isplayer(lf)) msg("Yuck, this tastes like blood!"); } diff --git a/spell.c b/spell.c index ee8fc90..88dbc76 100644 --- a/spell.c +++ b/spell.c @@ -1406,7 +1406,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef char dirch; char targetname[BUFLEN]; flag_t *f; - int heavyamt = 8; + int heavyamt = 5; int badweapon = B_FALSE; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { @@ -2183,7 +2183,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // controlled // must be within line of sight. if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; - if (!targcell) { + if (!targcell || !cellwalkable(caster, targcell, NULL)) { fizzle(caster); return B_TRUE; } @@ -4109,8 +4109,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ flag_t *f; f = hasflag(o->flags, F_WALKDAM); if (f) { - free(f->text); - f->text = strdup(dambuf); + changeflagtext(f, dambuf); } } } @@ -5819,6 +5818,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ breakallgrabs(caster); } else if (spellid == OT_S_POLYMORPH) { race_t *r = NULL; + flag_t *f; if (!validatespellcell(caster, &targcell,TT_MONSTER, spellid, power, frompot)) return B_TRUE; target = targcell->lf; @@ -5828,7 +5828,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if ((target != caster) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { if (isplayer(target)) { msg("You feel momentarily different."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -5840,46 +5840,51 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } - if (lfhasflag(caster, F_CONTROL)) { - if (power < 5) { - power = 5; + f = lfhasflag(target, F_FORCEPOLY); + if (f) { + r = findrace(f->val[0]); + } else { + if (lfhasflag(caster, F_CONTROL)) { + if (power < 5) { + power = 5; + } } - } - if (isplayer(caster) && (power >= 5)) { - if (isplayer(target)) { // ie. polymorphing yourself - askstring("What will you become", '?', buf, BUFLEN, NULL); - } else { - char buf2[BUFLEN]; - char targname[BUFLEN]; - getlfname(target, targname); - sprintf(buf2, "What will you transform %s into", targname); - askstring(buf2, '?', buf, BUFLEN, NULL); - } - r = findracebyname(buf); - - // make sure race is valid: - // - can't turn into monsters which aren't randomly generated. - // - can't turn into unique monsters - // - can't turn into undead monsters - if (r && !canpolymorphto(r->id)) r = NULL; - } else { // random - if (isplayer(target) && lfhasflag(target, F_CONTROL)) { - askstring("What will you become", '?', buf, BUFLEN, NULL); + if (isplayer(caster) && (power >= 5)) { + if (isplayer(target)) { // ie. polymorphing yourself + askstring("What will you become", '?', buf, BUFLEN, NULL); + } else { + char buf2[BUFLEN]; + char targname[BUFLEN]; + getlfname(target, targname); + sprintf(buf2, "What will you transform %s into", targname); + askstring(buf2, '?', buf, BUFLEN, NULL); + } r = findracebyname(buf); // make sure race is valid: + // - can't turn into monsters which aren't randomly generated. + // - can't turn into unique monsters + // - can't turn into undead monsters if (r && !canpolymorphto(r->id)) r = NULL; - } + } else { // random + if (isplayer(target) && lfhasflag(target, F_CONTROL)) { + askstring("What will you become", '?', buf, BUFLEN, NULL); + r = findracebyname(buf); - if (!r) { - // random race, but not the same! - r = target->race; - while ((r == target->race) || !canpolymorphto(r->id)) { - r = getrandomrace(NULL, NA); + // make sure race is valid: + if (r && !canpolymorphto(r->id)) r = NULL; + } + + if (!r) { + // random race, but not the same! + r = target->race; + while ((r == target->race) || !canpolymorphto(r->id)) { + r = getrandomrace(NULL, NA); + } } } - } + } // end if forcepoly if (r == target->race) { fizzle(caster); @@ -6984,9 +6989,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = hasflag(o->flags, F_DAM); if (f) { char buf[BUFLEN]; - free(f->text); sprintf(buf, "2d%d",power); - f->text = strdup(buf); + changeflagtext(f, buf); } } else { killob(o); diff --git a/text.c b/text.c index 947fccb..9dfe624 100644 --- a/text.c +++ b/text.c @@ -439,6 +439,8 @@ char *makeplural(char *text) { if (rv) return newtext; newtext = strrep(newtext, "chunk ", "chunks ", &rv); if (rv) return newtext; + newtext = strrep(newtext, "clove ", "cloves ", &rv); + if (rv) return newtext; newtext = strrep(newtext, "flask ", "flasks ", &rv); if (rv) return newtext; newtext = strrep(newtext, "gem ", "gems ", &rv);