diff --git a/ai.c b/ai.c index 098ec79..b35fa4d 100644 --- a/ai.c +++ b/ai.c @@ -571,6 +571,8 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { if (attackok) { objecttype_t *st; + flag_t *f; + int spellchance = 0; // drink boost potions if (!useitemwithflag(lf, F_AIBOOSTITEM)) { return B_FALSE; @@ -579,7 +581,17 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { // try spells first. // can we attack with spells (ie. ones which target the victim)? // if target is adjacent, we will normally just attack rather than try a spell. - spell = aigetattackspell(lf, target); + + // random chance of casting a spell + f = lfhasflag(lf, F_CASTCHANCE); + if (f) spellchance = f->val[0]; + else spellchance = 15; + + if (pctchance(spellchance)) { + spell = aigetattackspell(lf, target); + } else { + spell = OT_NONE; + } st = findot(spell); if ( (spell != OT_NONE) && // found a valid spell/ability to use ((dist != 1) || // there is distance between us and target @@ -1237,20 +1249,27 @@ void aiturn(lifeform_t *lf) { // do we already have a target we are attacking? if (target) { if (db) dblog(".oO { i have a target: lfid %d (%s). }", target->id, target->race->name); - // aquatic grabbers will try to drag their prey into the water - if (lfhasflagval(lf, F_GRABBING, target->id, NA, NA, NULL) && isaquatic(lf) ) { - if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) && - !hasobwithflag(target->cell->obpile, F_DEEPWATER)) { - // move away! - if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE, B_TRUE)) { - return; + + // target dead or unconscious? + if (isdead(target) || isunconscious(target)) { + if (db) dblog(".oO { my target is dead/ko'd }", target->id, target->race->name); + loseaitargets(lf); + } else { + // aquatic grabbers will try to drag their prey into the water + if (lfhasflagval(lf, F_GRABBING, target->id, NA, NA, NULL) && isaquatic(lf) ) { + if ( hasobwithflag(lf->cell->obpile, F_DEEPWATER) && + !hasobwithflag(target->cell->obpile, F_DEEPWATER)) { + // move away! + if (!moveawayfrom(lf, target->cell, DT_ORTH, B_FALSE, B_TRUE)) { + return; + } } } - } - // try to move towards them. - if (!aimovetolf(lf, target, B_TRUE)) { - // success - return; + // try to move towards them. + if (!aimovetolf(lf, target, B_TRUE)) { + // success + return; + } } } @@ -1375,7 +1394,7 @@ void aiturn(lifeform_t *lf) { lifeform_t *who; if (lf->los[n] != lf->cell) { who = lf->los[n]->lf; - if (who && cansee(lf, who)) { + if (who && !isdead(who) && !isunconscious(who) && cansee(lf, who)) { if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) || lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) { if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name); @@ -1391,7 +1410,7 @@ void aiturn(lifeform_t *lf) { if (lf->los[n] != lf->cell) { lifeform_t *who; who = lf->los[n]->lf; - if (who && cansee(lf, who)) { + if (who && cansee(lf, who) && !isdead(who) && !isunconscious(who)) { if (areenemies(lf, who)) { if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name); newtarget = who; diff --git a/attack.c b/attack.c index ef2315a..eeee04e 100644 --- a/attack.c +++ b/attack.c @@ -172,6 +172,8 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { int attackedfriend = B_FALSE; int attackedpeaceful = B_FALSE; + stoprunning(lf); + // anyone there? if so just attack. if (c->lf) { if (!force && isplayer(lf) && !areenemies(lf,c->lf) && (getraceclass(c->lf) != RC_PLANT)) { @@ -462,7 +464,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } // god effects... - if (attacktype == AT_LF) { + if ((attacktype == AT_LF) && isplayer(lf)) { if (attackedfriend) { angergodmaybe(R_GODMERCY, 100); angergodmaybe(R_GODPURITY, 100); @@ -587,6 +589,22 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } + if (wep && lfhasflagval(victim, F_ASLEEP, NA, ST_KO, NA, NULL)) { + f = hasflag(wep->flags, F_MERCIFUL); + if (f) { + if (isplayer(lf)) { + msg("^wYour %s refuses to attack %s!", noprefix(wepname), victimname); + if (!f->known) f->known = B_TRUE; + } else if (cansee(player, lf)) { + msg("^w%s%s %s refuses to attack %s!", attackername, getpossessive(attackername), + noprefix(wepname), victimname); + if (!f->known) f->known = B_TRUE; + } + taketime(lf, getattackspeed(lf)); + return B_FALSE; + } + } + getflags(lf->flags, retflag, &nretflags, F_NONCORPOREAL, F_NONE); for (i = 0; i < nretflags; i++) { @@ -613,10 +631,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) critpos = getrandomcorebp(victim); // replace victicname to include body part if ((lf == victim) && !isplayer(lf)) { - snprintf(victimbpname, BUFLEN, "its %s", getbodypartname(critpos)); + snprintf(victimbpname, BUFLEN, "its %s", getbodypartname(victim, critpos)); } else { getlfname(victim, buf); - snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), getbodypartname(critpos)); + snprintf(victimbpname, BUFLEN, "%s%s %s", buf, getpossessive(buf), getbodypartname(victim, critpos)); } } else { strcpy(victimbpname, ""); @@ -751,7 +769,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) dam[0] *= 2; } - // bonus for knowledge about the other lf's race? applied LAST. slev = getlorelevel(lf, victim->race->raceclass->id); if (slev == PR_INEPT) { @@ -907,7 +924,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) strcpy(extradambuf, ""); if (dam[i] == 0) { - if (getlorelevel(lf, victim->race->raceclass->id) >= PR_ADEPT) { + if (getlorelevel(lf, victim->race->raceclass->id)) { //strcpy(extradambuf, " but do no damage"); strcpy(extradambuf, " ineffectually"); } @@ -1040,7 +1057,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // other effects if (!isdead(victim) && !blocked) { // special weapon effects, as long as you're not doing a heavy blow - if (!lfhasflag(lf, F_HEAVYBLOW)) { + if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) { wepeffects(wep->flags, victim->cell, damflag, dam[0]); } if (isunarmed) { @@ -1106,7 +1123,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } // confer flags from attacker? - wepeffects(lf->flags, victim->cell, damflag, dam[0]); + if (dam[0]) { + wepeffects(lf->flags, victim->cell, damflag, dam[0]); + } // special lifeform-based effects if ((lf->race->id == R_COCKATRICE) && dam[0]) { @@ -1135,7 +1154,10 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } - fightback(victim, lf); + // if victim can still move... + if (hasfreeaction(victim)) { + fightback(victim, lf); + } } // end if !isdead(victim) // retaliation happens even if victim died @@ -1371,7 +1393,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { } // end foreach damtype // special weapon effects, as long as you're not doing a heavy blow - if (!lfhasflag(lf, F_HEAVYBLOW)) { + if (!lfhasflag(lf, F_HEAVYBLOW) && dam[0]) { wepeffects(wep->flags, obloc, damflag, dam[0]); } @@ -1393,8 +1415,8 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum DAMTYPE damtype) { - object_t *o; - char lfname[BUFLEN],victimname[BUFLEN]; + object_t *o,*armour; + char lfname[BUFLEN],victimname[BUFLEN],obname[BUFLEN]; // replace some dam types if (damtype == DT_UNARMED) damtype = DT_BASH; if (damtype == DT_BITE) damtype = DT_SLASH; @@ -1410,51 +1432,117 @@ void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, enum switch (rnd(1,2)) { case 1: fall(victim, lf, B_TRUE); break; case 2: - if (cansee(player, lf) || cansee(player, victim)) { - getlfname(lf, lfname); - getlfname(victim, victimname); - setfacing(victim, getrandomdirexcept(DT_COMPASS, victim->facing)); - msg("%s%s blow spins %s around!", lfname, getpossessive(lfname),victimname); + if (lf) { + if (cansee(player, lf) || cansee(player, victim)) { + getlfname(lf, lfname); + getlfname(victim, victimname); + setfacing(victim, getrandomdirexcept(DT_COMPASS, victim->facing)); + msg("%s%s blow spins %s around!", lfname, getpossessive(lfname),victimname); + } + } else { + if (isplayer(victim) || cansee(player, victim)) { + getlfname(victim, victimname); + setfacing(victim, getrandomdirexcept(DT_COMPASS, victim->facing)); + msg("%s is spun around!", victimname); + } } break; } } - if (!getarmour(victim, BP_BODY)) injure(victim, BP_BODY, damtype); + if ((armour = getarmour(victim, BP_BODY)) != NULL) { + getobname(armour, obname, armour->amt); + if (isplayer(victim)) { + msg("Your %s protects you.", noprefix(obname)); + } else if (cansee(player, victim)) { + msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname)); + } + } else { + injure(victim, BP_BODY, damtype); + } break; case BP_HEAD: if (pctchance(80)) fall(victim, lf, B_TRUE); - stun(victim, 1); + stun(victim, 2); + // chance of your helmet falling off o = getarmour(victim, BP_HEAD); if (o) { - if (isplayer(victim)) { - char buf[BUFLEN]; - getobname(o, buf, o->amt); - msg("Your %s falls off!", noprefix(buf)); - } else if (cansee(player, victim)) { - char buf[BUFLEN], lfname[BUFLEN]; - getobname(o, buf, o->amt); - getlfname(victim, lfname); - msg("%s%s %s falls off!", lfname, getpossessive(lfname), noprefix(buf)); + if (onein(2)) { + if (isplayer(victim)) { + char buf[BUFLEN]; + getobname(o, buf, o->amt); + msg("Your %s falls off!", noprefix(buf)); + } else if (cansee(player, victim)) { + char buf[BUFLEN], lfname[BUFLEN]; + getobname(o, buf, o->amt); + getlfname(victim, lfname); + msg("%s%s %s falls off!", lfname, getpossessive(lfname), noprefix(buf)); + } + moveob(o, victim->cell->obpile, o->amt); + } else { + if (isplayer(victim)) { + msg("Your %s protects you.", noprefix(obname)); + } else if (cansee(player, victim)) { + msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname)); + } } - moveob(o, victim->cell->obpile, o->amt); } else { injure(victim, BP_HEAD, damtype); } break; case BP_HANDS: - if (!getarmour(victim, BP_HANDS)) injure(victim, BP_HANDS, damtype); - // drop your weapon! - o = getweapon(victim); - if (o) drop(o, ALL); - break; + if ((armour = getarmour(victim, BP_HANDS)) != NULL) { + getobname(armour, obname, armour->amt); + if (isplayer(victim)) { + msg("Your %s protects you.", noprefix(obname)); + } else if (cansee(player, victim)) { + msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname)); + } + } else { + injure(victim, BP_HANDS, damtype); + } + + if (onein(2)) { + // drop your weapon! + o = getweapon(victim); + if (o) drop(o, ALL); + break; + } case BP_LEGS: if (pctchance(70)) fall(victim, lf, B_TRUE); - if (!getarmour(victim, BP_LEGS)) injure(victim, BP_LEGS, damtype); + if ((armour = getarmour(victim, BP_LEGS)) != NULL) { + getobname(armour, obname, armour->amt); + if (isplayer(victim)) { + msg("Your %s protects you.", noprefix(obname)); + } else if (cansee(player, victim)) { + msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname)); + } + } else { + injure(victim, BP_LEGS, damtype); + } break; } } else if (damtype == DT_SLASH) { - if (!getarmour(victim, hitpos)) injure(victim, hitpos, damtype); + if ((armour = getarmour(victim, hitpos)) != NULL) { + getobname(armour, obname, armour->amt); + if (isplayer(victim)) { + msg("Your %s protects you.", noprefix(obname)); + } else if (cansee(player, victim)) { + msg("%s%s %s protects it.", victimname, getpossessive(victimname), noprefix(obname)); + } + } else { + injure(victim, hitpos, damtype); + } + } else if (damtype == DT_EXPLOSIVE) { + if ((armour = getarmour(victim, hitpos)) != NULL) { + int min,max; + max = getobmaxhp(o); + min = max / 2; + limit(&min, 1, NA); + takedamage(armour, rnd(min,max), DT_EXPLOSIVE); + } else { + injure(victim, hitpos, damtype); + } } if (lf) { @@ -1581,16 +1669,18 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam } else if (damtype == DT_BASH) { if (pct <= 5) { return "whack"; - } else if (pct <= 20) { + } else if (pct <= 15) { if (onein(2)) { return "hit"; } else { return "bash"; } - } else if (pct <= 30) { + } else if (pct <= 25) { return "pummel"; - } else { + } else if (pct <= 35) { return "slam"; + } else { + return "clobber"; } } else if (damtype == DT_BITE) { if (lf && (ownersize <= SZ_SMALL)) { @@ -1807,6 +1897,10 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); + if (wep && hasflag(wep->flags, F_MERCIFUL)) { + return "knock out"; + } + if (victim->race->id == R_DANCINGWEAPON) { return "defeat"; } @@ -1876,6 +1970,11 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d // can't "kill" the undead return "destroy"; } + + // never use 'kill' for bashing since you might just knock them out + if (damtype == DT_BASH) { + return "clobber"; + } return "kill"; } @@ -2324,94 +2423,88 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { f->known = B_TRUE; } else if ((f->id == F_HITCONFER) && victim ) { // only works if we did damage - if (dam) { - enum FLAG fid; - int howlong; - flag_t *valflag = NULL; + enum FLAG fid; + int howlong; + flag_t *valflag = NULL; - fid = f->val[0]; - // the f_poisoned flag stacks, others don't. - if (!lfhasflag(victim, fid) || (fid == F_POISONED)) { - int passedcheck = B_FALSE; - // do they get a saving throw? - if (f->val[1] != NA) { - int scdiff; - if (f->val[2] == NA) { - scdiff = 20; // default - } else { - scdiff = f->val[2]; - } - if (skillcheck(victim, f->val[1], scdiff, 0)) { - passedcheck = B_TRUE; - } + fid = f->val[0]; + // the f_poisoned flag stacks, others don't. + if (!lfhasflag(victim, fid) || (fid == F_POISONED)) { + int passedcheck = B_FALSE; + // do they get a saving throw? + if (f->val[1] != NA) { + int scdiff; + if (f->val[2] == NA) { + scdiff = 20; // default + } else { + scdiff = f->val[2]; } + if (skillcheck(victim, f->val[1], scdiff, 0)) { + passedcheck = B_TRUE; + } + } - if (!passedcheck) { - - howlong = gethitconferlifetime(f->text, NULL, NULL); + if (!passedcheck) { + + howlong = gethitconferlifetime(f->text, NULL, NULL); - // get conferred flag values - valflag = hasflag(f->pile, F_HITCONFERVALS); + // get conferred flag values + valflag = hasflag(f->pile, F_HITCONFERVALS); - if (fid == F_POISONED) { - // need to fill in the name of what poisoned us - char frombuf[BUFLEN]; - enum POISONTYPE ptype; - int ppower; - if (wep) { - if (owner) { - char lfname[BUFLEN]; - char wepname[BUFLEN]; - getlfnamea(owner, lfname); - getobname(wep, wepname, 1); - // ie. "a goblin's poisoned short sword" - snprintf(frombuf, BUFLEN, "%s%s %s",lfname,getpossessive(lfname), wepname); - } else { - char wepname[BUFLEN]; - getobname(wep, wepname, 1); - // ie "a poisoned short sword" - snprintf(frombuf, BUFLEN, "%s", wepname); - } + if (fid == F_POISONED) { + // need to fill in the name of what poisoned us + char frombuf[BUFLEN]; + enum POISONTYPE ptype; + int ppower; + if (wep) { + if (owner) { + char lfname[BUFLEN]; + char wepname[BUFLEN]; + getlfnamea(owner, lfname); + getobname(wep, wepname, 1); + // ie. "a goblin's poisoned short sword" + snprintf(frombuf, BUFLEN, "%s%s %s",lfname,getpossessive(lfname), wepname); } else { - strcpy(frombuf, "something unknown"); + char wepname[BUFLEN]; + getobname(wep, wepname, 1); + // ie "a poisoned short sword" + snprintf(frombuf, BUFLEN, "%s", wepname); } + } else { + strcpy(frombuf, "something unknown"); + } - if (valflag) { - ptype = valflag->val[0]; - if (valflag->val[1] == NA) { - ppower = 1; - } else { - ppower = valflag->val[1]; - } - } else { - // should never happen. - ptype = P_VENOM; + if (valflag) { + ptype = valflag->val[0]; + if (valflag->val[1] == NA) { ppower = 1; + } else { + ppower = valflag->val[1]; } - - poison(victim, howlong, ptype, ppower, frombuf); } else { - flag_t *conferredflag; - conferredflag = addtempflag(victim->flags, fid, NA, NA, NA, NULL, howlong); - // flag values - if (valflag) { - conferredflag->val[0] = valflag->val[0]; - conferredflag->val[1] = valflag->val[1]; - conferredflag->val[2] = valflag->val[2]; - free(conferredflag->text); - conferredflag->text = strdup(valflag->text); - } + // should never happen. + ptype = P_VENOM; + ppower = 1; } - } // end if passedcheck - } // end (if victim doesn't already have the flag) - // was this from a poisoned weapon? if so the poison vanishes - if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) { - killflag(f); - if (owner && isplayer(owner)) { - addflag(owner->flags, F_USEDPOISON, B_TRUE, NA, NA, NULL); + poison(victim, howlong, ptype, ppower, frombuf); + } else { + // flag values + if (valflag) { + addtempflag(victim->flags, fid, valflag->val[0], valflag->val[1], valflag->val[2], valflag->text, howlong); + } else { + addtempflag(victim->flags, fid, NA, NA, NA, NULL, howlong); + } } + } // end if passedcheck + } // end (if victim doesn't already have the flag) + + // was this from a poisoned weapon? if so the poison vanishes + if ((f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) { + killflag(f); + if (owner && isplayer(owner)) { + addflag(owner->flags, F_USEDPOISON, B_TRUE, NA, NA, NULL); } } } // end if (fid == hitconfer) diff --git a/data.c b/data.c index 04a41cf..c9c6890 100644 --- a/data.c +++ b/data.c @@ -161,6 +161,7 @@ void initjobs(void) { // stat mods // initial objects addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 bananas"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "short sword"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 potions of healing"); @@ -178,7 +179,6 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, i, NA, NA, NULL); } // abilities - addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); @@ -268,6 +268,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_PERCEPTION, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_NATURE, PR_NOVICE, NA, NULL); // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); @@ -607,6 +608,7 @@ void initjobs(void) { f = addflag(lastjob->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 33); f = addflag(lastjob->flags, F_CANCAST, OT_S_HASTE, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 20); f = addflag(lastjob->flags, F_CANCAST, OT_S_HEALING, NA, NA, NULL); addcondition(f, FC_IFMONSTER, 20); + addflag(lastjob->flags, F_CASTCHANCE, 30, NA, NA, NULL); // non-player jobs addjob(J_SHOPKEEPER, "Shopkeeper"); @@ -742,14 +744,16 @@ void initobjects(void) { // weapons addbrand(BR_BALANCE, "of balance", BP_WEAPON); addflag_real(lastbrand->flags, F_BALANCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); + addbrand(BR_IMPACT, "of impact", BP_WEAPON); // TODO: make thisonly go ont obashing weapons + addflag_real(lastbrand->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); + addbrand(BR_MERCY, "of mercy", BP_WEAPON); + addflag_real(lastbrand->flags, F_MERCIFUL, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_PYROMANIA, "of pyromania", BP_WEAPON); addflag_real(lastbrand->flags, F_FLAMESTRIKE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_REVENGE, "of revenge", BP_WEAPON); addflag_real(lastbrand->flags, F_REVENGE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); addbrand(BR_SHARPNESS, "of sharpness", BP_WEAPON); addflag_real(lastbrand->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); - addbrand(BR_IMPACT, "of impact", BP_WEAPON); // TODO: make thisonly go ont obashing weapons - addflag_real(lastbrand->flags, F_HEAVYBLOW, B_TRUE, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); // feet addbrand(BR_LEVITATION, "of hovering", BP_FEET); @@ -3077,7 +3081,7 @@ void initobjects(void) { addflag(lastot->flags, F_CHARGELOWMSG, B_TRUE, NA, NA, "flickers"); addflag(lastot->flags, F_CHARGEOUTMSG, B_TRUE, NA, NA, "goes out"); - addot(OT_FRIDGE, "refrigerator", "An insulated household appliance, made for storing food.", MT_METAL, 80, OC_TOOLS, SZ_HUMAN); + addot(OT_FRIDGE, "refrigerator", "An insulated household appliance, made for storing food.", MT_METAL, 120, OC_TOOLS, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, "]"); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); @@ -3542,7 +3546,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DIECONVERTTEXT, NA, NA, NA, "evaporates"); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid"); - addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL); + addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3556,7 +3560,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, NA, NA, NA, "~"); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates"); - addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL); + addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3570,7 +3574,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, NA, NA, NA, ","); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBDIETEXT, NA, NA, NA, "evaporates"); - addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); + addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -4350,7 +4354,7 @@ void initobjects(void) { addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_SEEINVIS, NA, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 2, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 3, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL); addot(OT_RING_MANA, "ring of mana", "Increases the wearer's MP pool.", MT_METAL, 0.1, OC_RING, SZ_MINI); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, ""); @@ -4533,22 +4537,31 @@ void initobjects(void) { addot(OT_DART, "dart", "A small, sharp projectile weapon.", MT_WOOD, 0.5, OC_MISSILE, SZ_SMALL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); - addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, ""); + addflag(lastot->flags, F_MISSILEDAM, 1, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 15, NA, NULL); - addot(OT_NANODART, "nanodart", "A metal dart with a laser-sharpened point.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY); + addot(OT_DARTNANO, "nanodart", "A metal dart with a nanofibre point. Capable of piercing most armour.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); - addflag(lastot->flags, F_MISSILEDAM, 2, NA, NA, ""); + addflag(lastot->flags, F_MISSILEDAM, 1, NA, NA, ""); addflag(lastot->flags, F_ARMOURPIERCE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 67, NA, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_CANHAVEOBMOD, OM_POISONED, 17, NA, NULL); + addot(OT_DARTTRANQ, "tranquiliser dart", "A metal dart coated with a strong sleep-inducing serum.", MT_METAL, 0.5, OC_MISSILE, SZ_TINY); + addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_MISSILEDAM, 0, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_NUMAPPEAR, 1, 4, NA, NULL); + addflag(lastot->flags, F_HITCONFER, F_ASLEEP, SC_CON, 27, "20-30"); + addflag(lastot->flags, F_HITCONFERVALS, B_TRUE, ST_ASLEEP, NA, NULL); + addot(OT_NEEDLE, "needle", "A tiny pointed needle.", MT_METAL, 0.02, OC_MISSILE, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, ""); @@ -4618,7 +4631,6 @@ void initobjects(void) { addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, NA, NA, "1d8+1"); - addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); @@ -5196,6 +5208,9 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL); // other special stuff addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "screechs^a screech"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "talons"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right claw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left claw"); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); @@ -5207,25 +5222,39 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); - addrace(R_CYBORG, "cyborg", 150, 'R', C_GREY, MT_METAL, RC_HUMANOID); + addrace(R_CYBORG, "cyborg", 150, 'R', C_GREY, MT_FLESH, RC_HUMANOID); // stats addflag(lastrace->flags, F_PLAYABLE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_DEX, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CHA, AT_VLOW, NA, NULL); // bonuses addflag(lastrace->flags, F_EXTRAINFO, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_TECHUSAGE, PR_ADEPT, NA, NULL); // penalties addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_WATER, NA, NA, "2d6"); addflag(lastrace->flags, F_DTVULN, DT_ELECTRIC, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_BODY, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_LEGS, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_FEET, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_RIGHTFINGER, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_LEFTFINGER, NA, NA, NULL); // other special stuff addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "puddle of oil"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_EARS, NA, NA, "audio inputs"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_EYES, NA, NA, "video inputs"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "metal frame"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEGS, NA, NA, "stabilisers"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "robotic hands"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_FEET, NA, NA, "lower propulsion units"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right sensor"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left sensor"); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 75, NA, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); @@ -5273,8 +5302,6 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+3"); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); - addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); - addflag(lastrace->flags, F_MEDITATES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); addflag(lastrace->flags, F_STARTOB, 80, NA, NA, "1-50 gold coins"); @@ -5290,6 +5317,10 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); + // bonuses + addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); + addflag(lastrace->flags, F_MEDITATES, B_TRUE, NA, NA, NULL); + // human monsters... addrace(R_BANDITLDR, "bandit leader", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); @@ -5572,10 +5603,12 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "50d4"); addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "blessed longsword of mercy"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "10 blessed vials of ambrosia"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "2 rings of regeneration"); addflag(lastrace->flags, F_STARTSKILL, SK_FIRSTAID, PR_MASTER, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_LONGBLADES, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "raises her hand"); // god abilities addflag(lastrace->flags, F_GODOF, B_FEMALE, NA, NA, "Mercy"); @@ -5631,6 +5664,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_EYES, NA, NA, "eyestalks"); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); addrace(R_BUGBEAR, "bugbear", 120, 'G', C_BROWN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -5654,6 +5689,9 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_MINIONS, 50, 1, 3, "goblin"); addflag(lastrace->flags, F_MINIONS, 20, 1, 3, "goblin warrior"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_COCKATRICE, "cockatrice", 5, 'c', C_YELLOW, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_STARTATT, A_DEX, AT_VHIGH, NA, NULL); @@ -5701,6 +5739,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEFTFINGER, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:1d6;"); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); + addflag(lastrace->flags, F_CASTCHANCE, 70, NA, NA, NULL); addrace(R_DARKMANTLE, "darkmantle", 70, 'U', C_BLUE, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -5748,8 +5787,6 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_SPELLSPEED, SP_VERYSLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_MPDICE, 0, 25, NA, NULL); - addflag(lastrace->flags, F_MPREGEN, 12, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_DISPERSAL, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_GRAVBOOST, NA, NA, NULL); addflag(lastrace->flags, F_CASTTYPE, CT_GAZE, NA, NA, NULL); @@ -5764,6 +5801,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); addrace(R_GIANTHILL, "hill giant", 160, 'H', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -5854,8 +5892,6 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); - addflag(lastrace->flags, F_MPDICE, 0, 9, NA, NULL); - addflag(lastrace->flags, F_MPREGEN, 1, NA, NA, NULL); addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FIREDART, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FLAMEPILLAR, NA, NA, NULL); @@ -5922,6 +5958,9 @@ void initrace(void) { addflag(lastrace->flags, F_PACKATTACK, 3, NA, 2, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_GNOLLHM, "gnoll huntmaster", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GNOLL; @@ -5952,6 +5991,9 @@ void initrace(void) { addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_GNOLLMR, "gnoll marauder", 130, 'h', C_BROWN, MT_FLESH, RC_HUMANOID); lastrace->baseid = R_GNOLL; @@ -5981,6 +6023,9 @@ void initrace(void) { addflag(lastrace->flags, F_MINIONS, 75, 1, 2, "gnoll"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_GOBLIN, "goblin", 20, 'g', C_BROWN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -6093,14 +6138,13 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_PACKATTACK, 2, DT_SLASH, 3, NULL); - addflag(lastrace->flags, F_MPDICE, 0, 10, NA, NULL); - addflag(lastrace->flags, F_MPREGEN, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_BLINDNESS, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_PAIN, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_SPELLCASTING, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 90, 1, 2, "goblin"); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); addrace(R_HOBGOBLIN, "hobgoblin", 90, 'g', C_GREEN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -6109,7 +6153,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, 73, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 1, 2, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+3"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+3"); addflag(lastrace->flags, F_ARMOURRATING, 8, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -6180,7 +6224,7 @@ void initrace(void) { addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3-1"); addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, AT_HIGH, NA, NULL); @@ -6209,8 +6253,8 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, AT_AVERAGE, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); - addflag(lastrace->flags, F_HASATTACK, OT_TAIL, NA, NA, "1d3"); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d4"); + addflag(lastrace->flags, F_HASATTACK, OT_TAIL, NA, NA, "1d6"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "club"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "buckler"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-10 gold coins"); @@ -6268,10 +6312,12 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_EXPERT, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); + addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "roars^a roar"); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_HEAD, NA, NA, NULL); addrace(R_OGRE, "ogre", 160, 'O', C_BROWN, MT_FLESH, RC_HUMANOID); @@ -6496,8 +6542,6 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_SPELLSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_MPDICE, 0, 4, NA, NULL); - addflag(lastrace->flags, F_MPREGEN, 4, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_TELEKINESIS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures"); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); @@ -6511,6 +6555,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_ADEPT, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_XPMULTIPLY, 2, NA, NA, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); addrace(R_SATYR, "satyr", 80, 'h', C_GREEN, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -6532,8 +6577,6 @@ void initrace(void) { addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, "plays its pipes"); addflag(lastrace->flags, F_RESISTMAG, 10, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_MPDICE, 0, 16, NA, NULL); - addflag(lastrace->flags, F_MPREGEN, 8, NA, NA, NULL); addflag(lastrace->flags, F_NEEDOBFORSPELLS, OT_PANPIPES, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_CHARM, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, NA, NA, NULL); @@ -6544,6 +6587,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); addflag(lastrace->flags, F_STARTHIDDENPCT, 60, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); addrace(R_SHADOWCAT, "shadowcat", 5, 'f', C_BLUE, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -6561,6 +6605,9 @@ void initrace(void) { addflag(lastrace->flags, F_CANSEETHROUGHMAT, MT_GAS, NA, NA, NULL); addflag(lastrace->flags, F_AUTOCREATEOB, 1, NA, NA, "cloud of smoke"); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_OOZEGREY, "grey ooze", 10, 'j', C_GREY, MT_SLIME, RC_SLIME); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "pool of slime"); @@ -6571,6 +6618,7 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTFINGER, NA, NA, NULL); @@ -6602,8 +6650,6 @@ void initrace(void) { addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_MPDICE, 0, 4, NA, NULL); - addflag(lastrace->flags, F_MPREGEN, 1, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FIREDART, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, B_APPENDYOU, "gestures"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); @@ -6615,6 +6661,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); addrace(R_SPRITEICE, "ice sprite", 5, 'n', C_WHITE, MT_ICE, RC_MAGIC); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "sheet of ice"); @@ -6628,8 +6675,6 @@ void initrace(void) { addflag(lastrace->flags, F_FLYING, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_MPDICE, 4, 2, NA, NULL); - addflag(lastrace->flags, F_MPREGEN, 1, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FROSTBITE, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_FREEZEOB, NA, NA, NULL); addflag(lastrace->flags, F_CANCAST, OT_S_ICICLE, NA, NA, NULL); @@ -6641,6 +6686,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); addrace(R_TROLL, "troll", 100, 't', C_GREEN, MT_FLESH, RC_HUMANOID); @@ -6660,6 +6706,9 @@ void initrace(void) { addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL); @@ -6676,6 +6725,9 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); // fish addrace(R_CRAB, "giant crab", 250, ';', C_ORANGE, MT_FLESH, RC_AQUATIC); @@ -6691,13 +6743,16 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4"); 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_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WAIST, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); - addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); - addflag(lastrace->flags, F_NOBODYPART, BP_RIGHTFINGER, NA, NA, NULL); - addflag(lastrace->flags, F_NOBODYPART, BP_LEFTFINGER, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "pincers"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); + addflag(lastrace->flags, F_NOARMOURON, BP_RIGHTFINGER, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_LEFTFINGER, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOARMOURON, BP_FEET, NA, NA, NULL); addrace(R_PIRANHA, "piranha", 0.5, ';', C_GREEN, MT_FLESH, RC_AQUATIC); addflag(lastrace->flags, F_NEEDSWATER, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -6921,6 +6976,9 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d4;"); addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "bear cub"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_YELLOW, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_BEAR; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -6946,6 +7004,9 @@ void initrace(void) { addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_BLEEDABIL, OT_A_RAGE, NA, NA, NULL); addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "bear cub"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_BEARCUB, "bear cub", 60, 'q', C_BROWN, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_BEAR; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -6966,6 +7027,9 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_ANT, "giant ant", 20, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -7068,7 +7132,6 @@ void initrace(void) { 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_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); @@ -7076,6 +7139,9 @@ void initrace(void) { 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, ""); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -7092,7 +7158,6 @@ void initrace(void) { 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_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); @@ -7102,6 +7167,9 @@ void initrace(void) { 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_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_DOGDEATH, "death hound", 40, 'd', C_MAGENTA, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 6, NA, ""); @@ -7121,7 +7189,6 @@ void initrace(void) { 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_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); @@ -7131,6 +7198,9 @@ void initrace(void) { 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); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_DOGWAR, "war hound", 40, 'd', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 1, 4, NA, ""); @@ -7147,7 +7217,6 @@ void initrace(void) { 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_ENHANCESMELL, 6, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); @@ -7155,6 +7224,9 @@ void initrace(void) { 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"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; @@ -7290,6 +7362,7 @@ void initrace(void) { addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:4;"); addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:0d1+4;"); + addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 5, NA, NA, NULL); addrace(R_NEWT, "giant newt", 4, ':', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); @@ -7300,6 +7373,9 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d2-1"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2-1"); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_FLEEONDAM, B_TRUE, NA, NA, ""); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -7346,6 +7422,9 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_SNAKE, "brown snake", 3, 's', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, ""); addflag(lastrace->flags, F_RARITY, H_FOREST, 85, NA, ""); @@ -7414,6 +7493,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_WALK, 1, NA, "^hissing"); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, 2, 2, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addrace(R_SNAKECOBRABLACK, "black cobra", 3, 's', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, ""); @@ -7532,6 +7612,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:1;range:4;"); + addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); @@ -7539,6 +7620,8 @@ void initrace(void) { addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web"); addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "1-10 webs"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "cephalothorax"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "abdomen"); addrace(R_SPIDERFUNNELWEB, "giant funnelweb", 5, 'S', C_MAGENTA, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_SPIDER; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, ""); @@ -7558,6 +7641,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:5;range:2;"); + addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); @@ -7565,6 +7649,8 @@ void initrace(void) { addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web"); addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "20-30 webs"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "cephalothorax"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "abdomen"); addrace(R_SPIDERREDBACK, "giant redback", 5, 'S', C_RED, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_SPIDER; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, ""); @@ -7584,6 +7670,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:7;range:3;"); + addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); @@ -7591,6 +7678,8 @@ void initrace(void) { addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web"); addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "10-20 webs"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "cephalothorax"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "abdomen"); addrace(R_WOLFYOUNG, "young wolf", 10, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -7616,6 +7705,9 @@ void initrace(void) { 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, ""); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_WOLF, "wolf", 25, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -7641,6 +7733,9 @@ void initrace(void) { 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, ""); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "paws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); // insects addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL); @@ -7733,6 +7828,9 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:1d4;"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right foreclaw"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left foreclaw"); addrace(R_CENTIPEDE, "giant centipede", 3, 'w', C_GREEN, MT_FLESH, RC_INSECT); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); @@ -7894,12 +7992,27 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5"); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTOBDT, 50, DT_CHOP, NA, NULL); - addflag(lastrace->flags, F_STARTOB, 25, DT_CHOP, NA, "buckler"); + addflag(lastrace->flags, F_STARTOB, 25, NA, NA, "buckler"); addflag(lastrace->flags, F_DTVULN, DT_BASH, NA, NA, NULL); + addflag(lastrace->flags, F_DTRESIST, DT_SLASH, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOBODYPART, BP_EARS, NA, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_WEAPON, NA, NA, "right metacarpals"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_SECWEAPON, NA, NA, "left metacarpals"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_BODY, NA, NA, "ribs"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HEAD, NA, NA, "skull"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_SHOULDERS, NA, NA, "scapulas"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "carpals"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_WAIST, NA, NA, "coccyx"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEGS, NA, NA, "fibulas"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_FEET, NA, NA, "tarsals"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_RIGHTFINGER, NA, NA, "right phalange"); + addflag(lastrace->flags, F_BODYPARTNAME, BP_LEFTFINGER, NA, NA, "left phalange"); addrace(R_GHAST, "ghast", 50, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -7921,6 +8034,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); addrace(R_GHOST, "ghost", 50, 'p', C_BLUE, MT_MAGIC, RC_UNDEAD); // p for sPirit addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -7934,6 +8048,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4+2"); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NONCORPOREAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_XRAYVIS, 3, NA, NA, NULL); @@ -7964,6 +8079,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_BODYPARTNAME, BP_HANDS, NA, NA, "claws"); addrace(R_VAMPIRE, "vampire", 75, 'V', C_BLUE, MT_FLESH, RC_UNDEAD); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -7993,11 +8109,11 @@ void initrace(void) { 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_RETAINHPMPONPOLY, 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;race:vampire bat;"); + addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL); 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_SPELLCASTTEXT, NA, NA, NA, "gestures"); @@ -8030,6 +8146,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); @@ -8054,6 +8171,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); @@ -8079,6 +8197,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); @@ -8237,7 +8356,7 @@ void initskills(void) { addskilldesc(SK_SPEECH, PR_EXPERT, "^gShop item prices are reduced by 25%.^n", B_FALSE); addskilldesc(SK_SPEECH, PR_MASTER, "^gShop item prices are reduced by 30%.^n", B_FALSE); addskill(SK_SPELLCASTING, "Sorcery", "Increases the power of spells from all schools except Allomancy, Nature and Psionics.", 50); - addskilldesc(SK_SPELLCASTING, PR_NOVICE, "^gYou gain the 'study scrolls' ability.^n", B_FALSE); + addskilldesc(SK_SPELLCASTING, PR_SKILLED, "^gYou gain the 'study scrolls' ability.^n", B_FALSE); addskill(SK_PERCEPTION, "Perception", "Your ability to notice hidden details, from simple footprints to sinister traps.", 50); addskilldesc(SK_PERCEPTION, PR_INEPT, "- At higher levels this skill will also let you obscure your own tracks.", B_TRUE); addskilldesc(SK_PERCEPTION, PR_NOVICE, "^gYou can now see footprints.^n", B_TRUE); diff --git a/data/hiscores.db b/data/hiscores.db index b745cf0..70377f3 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 7a28b81..ea51464 100644 --- a/defs.h +++ b/defs.h @@ -251,7 +251,7 @@ enum RELATIVEDIR { #define SAVEDIR "data/save" #define VAULTDIR "vaults" // rank, score, name, job, killer -#define HISCOREFORMAT "%-6s%-7s%-10s%-18s%s" +#define HISCOREFORMAT "%-5s%-7s%-10s%-23s%s" // game strings #define MORESTRING "--More--" @@ -292,8 +292,8 @@ enum RELATIVEDIR { // Time periods #define TM_DRUNKTIME (10) // how long it takes for alcohol to wear off #define TM_WETTIME (10) // how long it takes for things to dry -#define TM_SCENT (15) // how long scents take to fade -#define TM_FOOTPRINT (20) // how long footprints take to fade +#define TM_SCENT (30) // how long scents take to fade +#define TM_FOOTPRINT (35) // how long footprints take to fade // object conditions for random objects #define RO_NONE 0 @@ -1503,7 +1503,8 @@ enum OBTYPE { OT_ARROW, OT_BOLT, OT_DART, - OT_NANODART, + OT_DARTNANO, + OT_DARTTRANQ, OT_NEEDLE, OT_JAVELIN, OT_BULLET, @@ -1684,6 +1685,12 @@ enum RANGEATTACK { RA_WAND, }; +enum SLEEPTYPE { + ST_ASLEEP = 0, + ST_MEDITATING, + ST_KO, +}; + enum FLAG { F_NONE = 0, // dummy flag // map flags @@ -1792,11 +1799,12 @@ enum FLAG { F_CRITKNOCKDOWN, // lf knocks down victims on a critical hit F_HITCONFER, // hitting with this gives flagid=v0 - // unless you pass a val1 skillcheck, diff val2 // with timeleft = text ("min-max") + // unless you pass a val1 skillcheck, diff val2 + // MUST ALSO HAVE HITCONFERVALS. F_HITCONFERVALS,// specifies values for conferred flag. F_ACTIVATED, // val0 = is this object turned on? - F_GRENADE, // this obkejct will drain charge when activated, then die + F_GRENADE, // this object will drain charge when activated, then die F_EXPLODEONDEATH, // explodes when it dies, deals TEXT damage. // val1 = BIG means hit surrounding cells // val2 = ifactivated, only explodes if activated. @@ -1848,6 +1856,7 @@ enum FLAG { // v2 = max trap chance F_TRAPPED, // this object HAS a trap. // v0 is the trap object type + // v1 - 'curtime' when this trap was last triggered // v2 = TRUE means we've spotted this. F_TRAP, // this object _IS_ a trap. v0 is sc_disarm/sc_spot difficulty. // (NA = impossible) @@ -1945,6 +1954,7 @@ enum FLAG { // end gun flags F_FLAMESTRIKE, // causes fires where you hit F_BALANCE, // heals target if their maxhp < your maxhp + F_MERCIFUL, // puts to sleep instead of killing. F_REVENGE, // causes damage based on your hp F_HELPSREST, // makes you heal mp/hp faster when using 'R' // reduces skillcheck difficulty by v0. @@ -1983,6 +1993,7 @@ enum FLAG { // ob identification flags F_HASHIDDENNAME, // whether this object class has a hidden name F_IDENTIFIED, // whether this object is fully identified + F_KNOWNBAD, // you know this object is somehow bad // bad flags F_DEEPWATER, // v0 = depth. F_WALKDAM, // val0 = damtype, text = dam per sec @@ -2133,6 +2144,8 @@ enum FLAG { F_LOSLOF, // v0 = whether this spell needs line of sight // v1 = whether this spell needs line of fire // MONSTER AI FLAGS + F_CASTCHANCE, // this lf has v0% chance of using spell/abil + // (default is 15%) F_DEMANDSBRIBE, // lf will demand gold from the player. F_NOSWAP, // other mosnters won't swap with this one. // cleared at start of turn. @@ -2248,7 +2261,7 @@ enum FLAG { F_ORIGRACE, // original player race (if you polymorphed) F_ORIGJOB, // original player job (if you polymorphed) F_POLYMORPHED, // lf has been polymorphed - F_RETAINHPMPONPOLY, // don't take on hp/mp of what you polymorph + F_RETAINHPONPOLY, // don't take on hp/mp of what you polymorph // into F_SHORTCUT, // spell keyboard shortcut. // v0=slot (0-9) @@ -2257,13 +2270,18 @@ enum FLAG { F_DOESNTMOVE, // this race doesn't move (but can still attack) F_AQUATIC, // this race can attack normally in water and suffers no // movement penalties + F_BODYPARTNAME, // for this race, bodypart v0 is called 'text' F_HUMANOID, // this race can wear armour / use weapons F_INSECT, // this race is classed as an insect F_UNDEAD, // this race is classed as undead F_COLDBLOOD, // this race is coldblooded + F_NOARMOURON, // this race can't wear armour on bodypart v0 + // obviously doesn't make sense to have both this + // and f_nobodypart for the same body part. F_NOBODYPART, // this race doesn't have bodypart val0 // if v0 is true or b_frominjury, you can regrow it // via a healing potion. + F_NOINJURIES, // this race cannot sustain injuries. F_NOPACK, // this race cannot hold objects F_NOSPELLS, // this race cannot cast spells F_INDUCEFEAR, // causes fear when you attack it @@ -2543,7 +2561,8 @@ enum INJURY { IJ_FINGERMISSING, IJ_EYELIDSCRAPED, IJ_EYEDESTROYED, - // + // explosive + IJ_HANDMISSING, }; @@ -2639,6 +2658,7 @@ enum ERROR { E_DRUNK, // E_NOBP, + E_DOESNTFIT, E_VEGETARIAN, E_PARTVEGETARIAN, E_CARNIVORE, @@ -3170,6 +3190,7 @@ enum OBMOD { enum BRAND { BR_BALANCE, + BR_MERCY, BR_NIMBLENESS, BR_FEEBLENESS, BR_FLIGHT, diff --git a/flag.c b/flag.c index f29f427..7b0fbbc 100644 --- a/flag.c +++ b/flag.c @@ -420,6 +420,7 @@ int flagcausesstatredraw(lifeform_t *lf, enum FLAG fid) { case F_ATTRMOD: case F_BLIND: case F_CONFUSED: + case F_DRUNK: case F_EATING: case F_FASTMOVE: case F_FLYING: diff --git a/god.c b/god.c index 33153f3..3ea5845 100644 --- a/god.c +++ b/god.c @@ -386,6 +386,22 @@ enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness) { return PL_INDIFFERENT; } +// get a random god which player has prayed to +lifeform_t *getrandomprayedgod(void) { + int i,nposs = 0; + lifeform_t *god,*poss[MAXGODS]; + for (i = 0; i < ngodlfs; i++) { + god = godlf[i]; + if (lfhasflag(god, F_PRAYEDTO)) { + poss[nposs++] = god; + } + } + if (nposs == 0) { + return NULL; + } + return poss[rnd(0,nposs-1)]; +} + lifeform_t *godappears(enum RACE rid, cell_t *where) { lifeform_t *god; char killedname[BUFLEN],godname[BUFLEN]; @@ -805,7 +821,11 @@ int prayto(lifeform_t *lf, lifeform_t *god) { msg("\"Behold, the power of death!\""); for (l = lf->cell->map->lf ; l ; l = l->next) { if ((l != lf) && lfhasflagval(l, F_TARGETLF, lf->id, NA, NA, NULL)) { - castspell(god, OT_S_PAIN, l, NULL, l->cell); + if (isundead(l)) { + makepeaceful(l); + } else { + castspell(god, OT_S_PAIN, l, NULL, l->cell); + } } } dospelleffects(god, OT_S_ANIMATEDEAD, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); diff --git a/god.h b/god.h index 2d87eab..cccff1d 100644 --- a/god.h +++ b/god.h @@ -6,6 +6,7 @@ void dooffer(void); lifeform_t *findgod(enum RACE rid); int getpiety(enum RACE rid); enum PIETYLEV getpietylev(enum RACE rid, enum COLOUR *col, char *happiness); +lifeform_t *getrandomprayedgod(void); lifeform_t *godappears(enum RACE rid, cell_t *where); int godgiftmaybe(enum RACE rid); int godisangry(enum RACE rid); diff --git a/io.c b/io.c index 1431afc..03a6fcf 100644 --- a/io.c +++ b/io.c @@ -690,8 +690,10 @@ cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *src f = lfhasflag(c->lf, F_ASLEEP); if (f) { if (strlen(extrainfo)) strcat(extrainfo, ", "); - if (f->val[1] != B_TRUE) { + if (f->val[1] == ST_MEDITATING) { strcat(extrainfo, "meditating"); + } else if (f->val[1] == ST_KO) { + strcat(extrainfo, "unconscious"); } else if (f->val[2] == NA) { strcat(extrainfo, "sleeping"); } else { @@ -1147,7 +1149,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { if (isplayer(lf) && (f->val[2] != NA)) { // ie. resting, not forced asleep object_t *restob; int meditating = B_FALSE; - if (f->val[1] != NA) meditating = B_TRUE; + if (f->val[1] == ST_MEDITATING) meditating = B_TRUE; restob = getrestob(lf); if (restob) { char restobname[BUFLEN]; @@ -1157,7 +1159,11 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("You start %s (on the ground)...", meditating ? "meditating" : "resting" ); } } else { - msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s"); + if (f->val[1] == ST_ASLEEP) { + msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s"); + } else { + msg("%s lose%s consciousness.",lfname, isplayer(lf) ? "" : "s"); + } } donesomething = B_TRUE; break; @@ -1740,10 +1746,16 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { } break; case F_ASLEEP: - if (f->val[1] == NA) { - msg("%s wake%s up.",lfname, isplayer(lf) ? "" : "s"); - } else { - msg("%s stop%s meditating.",lfname, isplayer(lf) ? "" : "s"); + switch (f->val[1]) { + case ST_ASLEEP: + msg("%s wake%s up.",lfname, isplayer(lf) ? "" : "s"); + break; + case ST_MEDITATING: + msg("%s stop%s meditating.",lfname, isplayer(lf) ? "" : "s"); + break; + case ST_KO: + msg("%s regain%s consciousness.",lfname, isplayer(lf) ? "" : "s"); + break; } donesomething = B_TRUE; break; @@ -2308,10 +2320,13 @@ void announceobflagloss(object_t *o, flag_t *f) { } -int confirm_badfeeling(void) { +int confirm_badfeeling(object_t *o) { char ch; ch = askchar("You have a bad feeling about this. Continue?", "yn", "n", B_TRUE); if (ch == 'y') return B_TRUE; + if (o && !hasflag(o->flags, F_KNOWNBAD)) { + addflag(o->flags, F_KNOWNBAD, B_TRUE, NA, NA, NULL); + } return B_FALSE; } @@ -2566,11 +2581,11 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int } // draw prompt if (strlen(numstring) > 0) { - mvwprintw(mainwin, 0, 0, "%s (%sesc to quit) [%s]: ",prompt, + mvwprintw(mainwin, 0, 0, "%s (%sESC to quit) [%s]: ",prompt, (opts & AO_INCLUDENOTHING) ? "- for nothing, " : "", numstring); } else { - mvwprintw(mainwin, 0, 0, "%s (%sesc to quit): ", prompt, + mvwprintw(mainwin, 0, 0, "%s (%sESC to quit): ", prompt, (opts & AO_INCLUDENOTHING) ? "- for nothing, " : ""); } if (nextpage != -1) { @@ -2763,11 +2778,11 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { mvwprintw(mainwin, y, 0, MORESTRING); } if (strlen(numstring) > 0) { - snprintf(pbuf, BUFLEN,"%s (%s','=all, esc to quit) [%s]: ",prompt, + snprintf(pbuf, BUFLEN,"%s (%s','=all, ESC to quit) [%s]: ",prompt, (opts & AO_INCLUDENOTHING) ? "- for nothing, " : "", numstring); } else { - snprintf(pbuf, BUFLEN,"%s (%sesc to quit): ", prompt, + snprintf(pbuf, BUFLEN,"%s (%sESC to quit): ", prompt, (opts & AO_INCLUDENOTHING) ? "- for nothing, " : ""); } @@ -3799,8 +3814,8 @@ void doeat(obpile_t *op) { eatob = askobject(op, "Eat what", NULL, AO_EDIBLE); } if (eatob) { - if (isunknownbadobject(eatob) && skillcheck(player, A_WIS, 26, 0)) { - if (!confirm_badfeeling()) { + if (isunknownbadobject(eatob) && skillcheck(player, A_WIS, 30, 0)) { + if (!confirm_badfeeling(eatob)) { msg("Cancelled."); return; } @@ -3918,8 +3933,8 @@ int dowear(obpile_t *op) { int rv; o = askobject(op, "Wear what", NULL, AO_WEARABLE); if (o) { - if (isunknownbadobject(o) && skillcheck(player, A_WIS, 26, 0)) { - if (!confirm_badfeeling()) { + if (isunknownbadobject(o) && skillcheck(player, A_WIS, 30, 0)) { + if (!confirm_badfeeling(o)) { msg("Cancelled."); return B_TRUE; } @@ -3940,8 +3955,8 @@ int doweild(obpile_t *op) { int rv; o = askobject(op, "Weild what", &count, AO_WEILDABLE | AO_INCLUDENOTHING); if (o) { - if (isunknownbadobject(o) && skillcheck(player, A_WIS, 26, 0)) { - if (!confirm_badfeeling()) { + if (isunknownbadobject(o) && skillcheck(player, A_WIS, 30, 0)) { + if (!confirm_badfeeling(o)) { msg("Cancelled."); return B_TRUE; } @@ -4433,7 +4448,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { if (isarmour(o)) { f = hasflag(o->flags, F_GOESON); if (f) { - snprintf(buf, BUFLEN, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(f->val[0])); + snprintf(buf, BUFLEN, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0])); } else { strcpy(buf, ""); } @@ -4480,7 +4495,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { // non armour, but still wearable. f = hasflag(o->flags, F_GOESON); if (f) { - snprintf(buf, BUFLEN, "It is worn %s your %s.\n",getbodypartequipname(f->val[0]), getbodypartname(f->val[0])); + snprintf(buf, BUFLEN, "It is worn %s your %s.\n",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0])); strncat(retbuf, buf, HUGEBUFLEN); } } @@ -5514,7 +5529,8 @@ void dooperate(obpile_t *op) { // operable objects here? for (o = player->cell->obpile->first; o ; o = o->next) { - if (isoperable(o) && canpickup(player, o, 1)) { + //if (isoperable(o) && canpickup(player, o, 1)) { + if (isoperable(o)) { char obname[BUFLEN],buf[BUFLEN]; char verb[BUFLEN]; int ch; @@ -5819,8 +5835,8 @@ void doquaff(obpile_t *op) { } if (liquid) { if (canquaff(player, liquid)) { - if (isunknownbadobject(liquid) && skillcheck(player, A_WIS, 26, 0)) { - if (!confirm_badfeeling()) { + if (isunknownbadobject(liquid) && skillcheck(player, A_WIS, 30, 0)) { + if (!confirm_badfeeling(liquid)) { msg("Cancelled."); return; } @@ -6139,13 +6155,17 @@ void dothrow(obpile_t *op) { if (where) { cell_t *newwhere = NULL; if (!haslof(player->cell, where, LOF_WALLSTOP, &newwhere)) { - if (newwhere) { - // update destination cell. - where = newwhere; + if (newwhere && (newwhere != player->cell)) { + char ch; + ch = askchar("Your line of fire is blocked - really throw here", "yn", "y", B_TRUE); + if (ch == 'y') { + // update destination cell. + where = newwhere; + } else return; } else { if (reason == E_NOLOS) { msg("You can't see there!"); - } else { // ie. E_NOLOF + } else { // ie. E_NOLOF and no new cell msg("You don't have a clear line of fire to there."); } return; @@ -6833,16 +6853,27 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { } if (strlen(prompt->choice[validchoice].longdesc)) { int dummy; - wmove(mainwin, 5, 0); + if (showall) y++; + wmove(mainwin, y, 0); textwithcol(mainwin, prompt->choice[validchoice].longdesc); getyx(mainwin, descendy, dummy); // remember bottom of description } - } else if ((descendy != -1) && showall) { - int yy; - // clear to bottom of screen - for (yy = y ; yy < lastline; yy++) { - wmove(mainwin, yy, 0); - wclrtoeol(mainwin); + } else if (descendy != -1) { + if (showall) { + int yy; + // clear to bottom of screen + for (yy = y ; yy < lastline; yy++) { + wmove(mainwin, yy, 0); + wclrtoeol(mainwin); + } + } else { + int yy; + char gamewinbuf[BUFLEN]; + // copy text from gamewin + for (yy = y ; yy < lastline; yy++) { + mvwinchstr(gamewin, yy-2, 0, (chtype *)gamewinbuf); + mvwaddchstr(mainwin, yy, 0,(chtype *) gamewinbuf); + } } descendy = -1; } @@ -6858,6 +6889,7 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { // if there's only one match, complete it if (nvalid == 1) { + char remainder[BUFLEN]; int cx,cy; // remember cursor pos getyx(mainwin, cy, cx); @@ -6868,13 +6900,20 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { prompt->choice[validone].text); */ - // 'validchoice' was calculated earlier - snprintf(promptstr, BUFLEN, "%s [%s%s] %s", + + /* + snprintf(promptstr, BUFLEN, "%s [%s%s] ", prompt->q[prompt->whichq], prompt->maycancel ? "ESC," : "", - showall ? "'=next page,?=toggle" : "?=list", + showall ? "'=next page,?=toggle" : "?=list"); prompt->choice[validchoice].text); - mvwprintw(mainwin, 0, 0, "%s", promptstr); + */ + // show the remainder of what we have typed. + // ('validchoice' was calculated earlier) + snprintf(remainder, BUFLEN, "^g%s",prompt->choice[validchoice].text + strlen(inpstring)); + textwithcol(mainwin, remainder); + // move cursor back + wmove(mainwin, cy, cx); } wrefresh(mainwin); @@ -7794,15 +7833,19 @@ void drawstatus(void) { // paralysed somehow? if ((f = isresting(player)) != NULL) { setcol(statwin, C_CYAN); - if (f->val[1] == NA) { + if (f->val[1] == ST_ASLEEP) { wprintw(statwin, " Resting"); } else { wprintw(statwin, " Meditating"); } unsetcol(statwin, C_CYAN); - } else if (lfhasflag(player, F_ASLEEP)) { + } else if ((f = lfhasflag(player, F_ASLEEP)) != NULL) { setcol(statwin, C_MAGENTA); - wprintw(statwin, " Asleep"); + if (f->val[2] == ST_KO) { + wprintw(statwin, " KO"); + } else { + wprintw(statwin, " Asleep"); + } unsetcol(statwin, C_MAGENTA); } else if (isprone(player)) { setcol(statwin, C_YELLOW); @@ -8131,6 +8174,11 @@ void setobcolour(WINDOW *win, object_t *o, int set) { return; } + if (hasflag(o->flags, F_KNOWNBAD)) { + funcptr(win, C_RED); + return; + } + if (o->blessknown) { if (iscursed(o)) { funcptr(win, C_RED); @@ -8200,7 +8248,7 @@ void showlfarmour(lifeform_t *lf) { if (!lfhasflagval(lf, F_NOBODYPART, bp, NA, NA, NULL)) { object_t *outerob; - snprintf(buf, BUFLEN, "%15s:%3s",getbodypartname(bp), " "); + snprintf(buf, BUFLEN, "%13s:%1s",getbodypartname(lf, bp), " "); o = getequippedob(lf->pack, bp); arm[bp] = o; // remember for later outerob = getouterequippedob(lf, bp); @@ -8678,7 +8726,6 @@ void showlfstats(lifeform_t *lf, int showall) { if (lorelev >= PR_BEGINNER) unsetcol(mainwin, lorecol); } y2++; - } // end if o } // end if fid == hasattack } // end for each flag @@ -8869,7 +8916,16 @@ void showlfstats(lifeform_t *lf, int showall) { // obvious physical effects here. f = lfhasknownflag(lf, F_ASLEEP); if (f) { - wrapprint(mainwin, &y, &x, "%s %s %s.", you(lf), is(lf), (f->val[1] == NA) ? "sleeping" : "meditating"); + char sleepname[BUFLEN]; + switch (f->val[1]) { + case ST_ASLEEP: + strcpy(sleepname, "sleeping"); break; + case ST_MEDITATING: + strcpy(sleepname, "meditating"); break; + case ST_KO: + strcpy(sleepname, "unconscious"); break; + } + wrapprint(mainwin, &y, &x, "%s %s %s.", you(lf), is(lf), sleepname); } f = lfhasknownflag(lf, F_ATTACHEDTO); if (f && (f->known)) { @@ -9022,16 +9078,16 @@ void showlfstats(lifeform_t *lf, int showall) { } if (nmissingbp) { - snprintf(buf, BUFLEN, "%s %s no %s",you(lf), isplayer(lf) ? "have" : "has", getbodypartname(missingbp[0])); + snprintf(buf, BUFLEN, "%s %s no %s",you(lf), isplayer(lf) ? "have" : "has", getbodypartname(lf, missingbp[0])); if (nmissingbp > 1) { // construct list of missing body parts for (i = 1; i < nmissingbp ; i++) { if (i == nmissingbp - 1) { // last strcat(buf, " or "); - strcat(buf, getbodypartname(missingbp[i])); + strcat(buf, getbodypartname(lf, missingbp[i])); } else { strcat(buf, ", "); - strcat(buf, getbodypartname(missingbp[i])); + strcat(buf, getbodypartname(lf, missingbp[i])); } } } @@ -9150,9 +9206,9 @@ void showlfstats(lifeform_t *lf, int showall) { if (lfhasknownflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT)) { - if (f->lifetime != PERMENANT) { + if (f->lifetime > 0) { char buf3[BUFLEN]; - snprintf(buf3, BUFLEN, "[%dt]",f->lifetime); + snprintf(buf3, BUFLEN, "[%dturns]",f->lifetime); strcat(buf2, buf3); } } diff --git a/io.h b/io.h index d4ee687..a6b816e 100644 --- a/io.h +++ b/io.h @@ -16,7 +16,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f); int announceflagloss(lifeform_t *lf, flag_t *f); int announceobflaggain(object_t *o, flag_t *f); void announceobflagloss(object_t *o, flag_t *f); -int confirm_badfeeling(void); +int confirm_badfeeling(object_t *o); lifeform_t *askgod(char *prompt); object_t *askobject(obpile_t *op, char *title, int *count, long opts); object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, enum FLAG withflag); diff --git a/lf.c b/lf.c index afca6f8..daa2ede 100644 --- a/lf.c +++ b/lf.c @@ -563,7 +563,11 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { return B_FALSE; } // how much mp does it take to cast this? - cost = getmpcost(lf, oid); + if (isplayer(lf)) { + cost = getmpcost(lf, oid); + } else { + cost = 0; + } if (mpcost) *mpcost = cost; if (lf->mp >= cost) { castable = B_TRUE; @@ -678,7 +682,8 @@ int canhear(lifeform_t *lf, cell_t *dest, int volume) { // can't hear when dead. if (isdead(lf)) return B_FALSE; - // can't hear if you are deaf + // can't hear if you are deaf or have no ears + if (!hasbp(lf, BP_EARS)) return B_FALSE; if (lfhasflag(lf, F_DEAF)) return B_FALSE; // can't hear when training @@ -992,10 +997,16 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { int nretflags; reason = E_OK; - if ((where != BP_NONE) && !hasbp(lf, where)) { - reason = E_NOBP; - return B_FALSE; + if (where != BP_NONE) { + if (!hasbp(lf, where)) { + reason = E_NOBP; + return B_FALSE; + } else if (lfhasflagval(lf, F_NOARMOURON, where, NA, NA, NULL)) { + reason = E_DOESNTFIT; + return B_FALSE; + } } + // already equipped? if (hasflag(o->flags, F_EQUIPPED)) { @@ -1295,33 +1306,39 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } // announce - if (!isplayer(lf) && cansee(player, lf)) { - char lfname[BUFLEN]; - char whattosay[BUFLEN]; - getlfname(lf, lfname); + if (!isplayer(lf)) { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + char whattosay[BUFLEN]; + getlfname(lf, lfname); - // special case - f = lfhasflag(lf,F_SPELLCASTTEXT); - if (f) { - if (strlen(f->text)) { - snprintf(whattosay, BUFLEN, "%s %s", lfname, f->text); - if (targlf && (f->val[2] == B_APPENDYOU)) { - char targname[BUFLEN]; - if (targlf == lf) { - strcpy(targname, "itself"); - } else { - getlfname(targlf, targname); + // special case + f = lfhasflag(lf, F_SPELLCASTTEXT); + if (f) { + if (strlen(f->text)) { + snprintf(whattosay, BUFLEN, "%s %s", lfname, f->text); + if (targlf && (f->val[2] == B_APPENDYOU)) { + char targname[BUFLEN]; + if (targlf == lf) { + strcpy(targname, "itself"); + } else { + getlfname(targlf, targname); + } + strcat(whattosay, " at "); + strcat(whattosay, targname); } - strcat(whattosay, " at "); - strcat(whattosay, targname); + strcat(whattosay, "."); + msg("%s", whattosay); } - strcat(whattosay, "."); - msg("%s", whattosay); - } - } else { - if (hasflag(sp->flags, F_CASTINGTIME)) { } else { - msg("%s starts casting a spell.", lfname); + if (hasflag(sp->flags, F_CASTINGTIME)) { + } else { + msg("%s starts casting a spell.", lfname); + } + } + } else { // player can't see them + if ((targlf == player) || (targcell = player->cell)) { + msg("Something casts a spell at you."); } } } @@ -1506,7 +1523,7 @@ int checkfordrowning(lifeform_t *lf, object_t *o) { flag_t *f; enum SKILLLEVEL slev; - if (!isairborne(lf)) { + if (isairborne(lf)) { return B_FALSE; } @@ -1926,6 +1943,7 @@ void die(lifeform_t *lf) { } if (isplayer(lf)) { + lifeform_t *god; // force screen redraw so you see your hp = 0 drawscreen(); @@ -1935,9 +1953,39 @@ void die(lifeform_t *lf) { } else { msg("^BYou die."); } - more(); - // force msg redraw! - drawmsg(); + more(); drawmsg(); + + // god effects... + if (!vaporised) { + god = getrandomprayedgod(); + if (god && !godisangry(god->race->id)) { + switch (god->race->id) { + case R_GODDEATH: + godsay(god->race->id, "Come to me, my servant..."); more(); + msg("Bony claws rise up and drag your corpse underground."); more(); break; + case R_GODPURITY: + msg("Your spirit ascends to the heavens."); more(); break; + case R_GODTHIEVES: + msg("All your possessions suddenly vanish!"); more(); + godsay(god->race->id, "Yoink!"); more(); + break; + case R_GODMERCY: + if (onein(10)) { + godsay(god->race->id, "I will grant you a second chance, mortal... use it wisely."); more(); + lf->hp = lf->maxhp; + lf->alive = B_TRUE; + killflagsofid(lf->flags, F_DEAD); + statdirty = B_TRUE; + // teleport somewhere different. + dospelleffects(god, OT_S_TELEPORT, 3, lf, NULL, NULL, B_UNCURSED, NULL, B_TRUE); + return; + } + break; + default: + break; + } + } + } } else { if (!hasflag(lf->flags, F_NODEATHANNOUNCE)) { if (cansee(player, lf)) { @@ -1972,6 +2020,9 @@ void die(lifeform_t *lf) { } else { // ie. neutral pleasegodmaybe(R_GODDEATH, 1); } + + // mercy god doesn't like killing + angergodmaybe(R_GODMERCY, 1); } } @@ -2396,6 +2447,8 @@ void do_eyesight_adjust(lifeform_t *lf) { int i,nlitcells = 0; int preea; + if (isblind(lf)) return; + // any lit cells within los? for (i = 0; i < lf->nlos; i++) { if (lf->los[i]->lit) { @@ -2993,7 +3046,7 @@ void enhanceskills(lifeform_t *lf) { if (lf->skillpoints >= cost) { char buf[BUFLEN]; char buf2[HUGEBUFLEN]; - snprintf(buf, BUFLEN, "%s (%s, cost:%d points)", getskillname(f->val[0]), + snprintf(buf, BUFLEN, "%s -> %s (cost:%d points)", getskillname(f->val[0]), getskilllevelname(f->val[1] + 1), cost); makedesc_skill(f->val[0], buf2); addchoice(&prompt, ch++, getskillname(f->val[0]), buf, f, buf2); @@ -3303,11 +3356,12 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) { // if you are going to sleep on purpose, use 'gotosleep'. // this function is for when it is forced upon you by a spell, etc. -int fallasleep(lifeform_t *lf, int howlong) { +int fallasleep(lifeform_t *lf, enum SLEEPTYPE how, int howlong) { if (lfhasflag(lf, F_ASLEEP)) { return B_TRUE; } - if (lfhasflag(lf, F_CAFFEINATED)) { + + if ((how == ST_ASLEEP) && lfhasflag(lf, F_CAFFEINATED)) { if (isplayer(lf)) { msg("You feel momentarily tired."); } else if (cansee(player, lf)) { @@ -3323,7 +3377,7 @@ int fallasleep(lifeform_t *lf, int howlong) { killflagsofid(lf->flags, F_RAGE); killflagsofid(lf->flags, F_TRAINING); - addtempflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL, howlong); + addtempflag(lf->flags, F_ASLEEP, B_TRUE, how, NA, NULL, howlong); return B_FALSE; } @@ -3331,7 +3385,7 @@ int fallasleep(lifeform_t *lf, int howlong) { void fightback(lifeform_t *lf, lifeform_t *attacker) { interrupt(lf); - if (lfhasflag(lf, F_FEIGNINGDEATH)) { + if (lfhasflag(lf, F_FEIGNINGDEATH) || lfhasflagval(lf, F_ASLEEP, NA, ST_KO, NA, NULL)) { // don't respond. return; } @@ -3345,8 +3399,12 @@ void fightback(lifeform_t *lf, lifeform_t *attacker) { } if (attacker) { - // wake up - killflagsofid(lf->flags, F_ASLEEP); + flag_t *f; + f = lfhasflag(lf, F_ASLEEP); + if (f && (f->val[1] != ST_KO)) { + // wake up + killflagsofid(lf->flags, F_ASLEEP); + } // monsters might flee, fight back, etc if (!isplayer(lf)) { if (isplayer(attacker) && ishirable(lf)) { @@ -4856,7 +4914,16 @@ int getbodyparthitchance(enum BODYPART bp) { return 0; // ie rings, ears, weapon } -char *getbodypartname(enum BODYPART bp) { +char *getbodypartname(lifeform_t *lf, enum BODYPART bp) { + flag_t *f; + + if (lf) { + f = lfhasflagval(lf, F_BODYPARTNAME, bp, NA, NA, NULL); + if (f) { + return f->text; + } + } + switch (bp) { case BP_WEAPON: return "right hand"; @@ -6912,6 +6979,8 @@ void givejob(lifeform_t *lf, enum JOB jobid) { for (i = 0; i < nretflags; i++) { f = retflag[i]; modattr(lf, f->val[0], f->val[1]); + // these aren't temporary. + lf->baseatt[f->val[0]] = lf->att[f->val[0]]; } // inherit all flags except: @@ -7083,13 +7152,18 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) { int flagsknown = 0, flagsfound = 0; flag_t *f,*newflag; - int held, equipped,activated; + int held = B_FALSE, equipped = B_FALSE,activated = B_FALSE; int lifetimeval; if (o->pile->owner == lf) held = B_TRUE; - if (held && hasflag(o->flags, F_EQUIPPED)) { - equipped = B_TRUE; + if (held) { + f = hasflag(o->flags, F_EQUIPPED); + // make sure it's equipped in the right place - ie. weilded rings don't + // do anything. + if (f && hasflagval(o->flags, F_GOESON, f->val[0], NA, NA, NULL)) { + equipped = B_TRUE; + } } if (held && hasflag(o->flags, F_ACTIVATED)) { activated = B_TRUE; @@ -7212,12 +7286,6 @@ int giveskill(lifeform_t *lf, enum SKILL id) { newf = addflag(lf->flags, F_CANWILL, OT_A_REPAIR, NA, NA, NULL); newf->lifetime = FROMSKILL; } - } else if (id == SK_SPELLCASTING) { - newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL); - if (!newf) { - newf = addflag(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL); - newf->lifetime = FROMSKILL; - } } else if (id == SK_THIEVERY) { newf = addflag(lf->flags, F_CANWILL, OT_A_STEAL, NA, NA, NULL); newf->lifetime = FROMSKILL; @@ -7258,6 +7326,14 @@ int giveskill(lifeform_t *lf, enum SKILL id) { lf->losdirty = B_TRUE; if (isplayer(lf)) needredraw = B_TRUE; } + } else if (id == SK_SPELLCASTING) { + if (f->val[1] == PR_SKILLED) { + newf = hasflagval(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL); + if (!newf) { + newf = addflag(lf->flags, F_CANWILL, OT_A_STUDYSCROLL, NA, NA, NULL); + newf->lifetime = FROMSKILL; + } + } } else if (id == SK_STEALTH) { if (f->val[1] == PR_BEGINNER) { newf = addflag(lf->flags, F_CANWILL, OT_A_HIDE, NA, NA, NULL); @@ -7628,13 +7704,13 @@ int gotosleep(lifeform_t *lf, int onpurpose) { return B_TRUE; } if (onpurpose) taketime(lf, getactspeed(lf)); - addflag(lf->flags, F_ASLEEP, B_TRUE, lfhasflag(lf, F_MEDITATES) ? B_TRUE : NA, onpurpose ? B_TRUE : NA, NULL); + addflag(lf->flags, F_ASLEEP, B_TRUE, lfhasflag(lf, F_MEDITATES) ? ST_MEDITATING : ST_ASLEEP, onpurpose ? B_TRUE : NA, NULL); return B_FALSE; } int hasfreeaction(lifeform_t *lf) { + if (isdead(lf)) return B_FALSE; if (isimmobile(lf)) return B_FALSE; - if (lfhasflag(lf, F_ASLEEP)) return B_FALSE; if (lfhasflag(lf, F_CASTINGSPELL)) return B_FALSE; if (lfhasflag(lf, F_EATING)) return B_FALSE; return B_TRUE; @@ -7671,8 +7747,10 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { enum BODYPART bp2; object_t *wep = NULL; int howlong; + if (where == BP_NONE) return B_TRUE; if (!hasbp(lf, where)) return B_TRUE; + if (lfhasflag(lf, F_NOINJURIES)) return B_TRUE; if (lfhasflagval(lf, F_INJURY, NA, where, NA, NULL)) return B_TRUE; howlong = rnd(30,80); // might be overridden depending on injury @@ -7759,7 +7837,7 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { o = getequippedob(lf->pack, bp2); addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL); inj = IJ_FINGERMISSING; - sprintf(buf, "%s is severed^cannot wear rings on this hand", getbodypartname(bp2)); + sprintf(buf, "%s is severed^cannot wear rings on this hand", getbodypartname(lf, bp2)); desc = strdup(buf); howlong = PERMENANT; if (o) { @@ -7811,6 +7889,62 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { } default: break; } + } else if (damtype == DT_EXPLOSIVE) { + switch (where) { + case BP_BODY: + switch (rnd(1,2)) { + case 1: + break; + case 2: + break; + } + // massive burns + // collapsed lung + break; + case BP_HANDS: + // lose limb + if (onein(2)) bp2 = BP_WEAPON; + else bp2 = BP_SECWEAPON; + if (hasbp(lf, bp2)) { + object_t *o[2]; + char buf[BUFLEN]; + int i; + // drop anyting in that hand + o[0] = getequippedob(lf->pack, bp2); + if (bp2 == BP_WEAPON) o[1] = getequippedob(lf->pack, BP_RIGHTFINGER); + else o[1] = getequippedob(lf->pack, BP_LEFTFINGER); + addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL); + inj = IJ_HANDMISSING; + sprintf(buf, "%s is destroyed^cannot use this hand", getbodypartname(lf, bp2)); + desc = strdup(buf); + howlong = PERMENANT; + for (i = 0; i < 2; i++) { + if (o[i]) { + char obname[BUFLEN]; + if (isplayer(lf)) { + getobname(o[i],obname,o[i]->amt); + msg("Your %s drops to the ground.",noprefix(obname)); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getobname(o[i],obname,o[i]->amt); + getlfname(lf,lfname); + msg("%s%s %s drops to the ground.",lfname,getpossessive(lfname),noprefix(obname)); + } + moveob(o[i], lf->cell->obpile, o[i]->amt); + } + } + } + break; + case BP_HEAD: + // ringing ears + // burnt eyes + break; + case BP_LEGS: + // lose limb + break; + default: + break; + } } if (inj == IJ_NONE) { @@ -8383,7 +8517,7 @@ int isblind(lifeform_t *lf) { if (!lf) return B_FALSE; f = lfhasflag(lf, F_ASLEEP); - if (f && (f->val[1] == NA)) { + if (f && (f->val[1] != ST_MEDITATING)) { return B_TRUE; } if (lfhasflag(lf, F_BLIND)) { @@ -8741,10 +8875,12 @@ int ispolymorphed(lifeform_t *lf) { } int isprone(lifeform_t *lf) { + flag_t *f; if (lfhasflag(lf, F_PRONE)) { return B_TRUE; } - if (lfhasflag(lf, F_ASLEEP)) { + f = lfhasflag(lf, F_ASLEEP); + if (f && (f->val[1] != ST_MEDITATING)) { return B_TRUE; } return B_FALSE; @@ -9058,10 +9194,13 @@ void addtrail(lifeform_t *lf, int dir) { object_t *footprint, *scent; flag_t *fpflag; - if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) { - // no tracks at all + // no tracks at all? + if (lf->cell->type->solid) { + return; + } else if (hasobwithflag(lf->cell->obpile, F_DEEPWATER)) { return; } + // footprints first if (!isairborne(lf) && !lfhasflag(lf, F_NONCORPOREAL)) { int fpdir; @@ -9601,6 +9740,11 @@ int isswimming(lifeform_t *lf) { return B_FALSE; } +int isunconscious(lifeform_t *lf) { + if (lfhasflagval(lf, F_ASLEEP, NA, ST_KO, NA, NULL)) return B_TRUE; + return B_FALSE; +} + int isundead(lifeform_t *lf) { if (lf->race->raceclass->id == RC_UNDEAD) { return B_TRUE; @@ -9866,7 +10010,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml char buf[BUFLEN]; char buf2[BUFLEN]; char lfname[BUFLEN]; - int prebleed = B_FALSE,postbleed = B_FALSE; + int prebleed = B_FALSE,postbleed = B_FALSE,ko = B_FALSE; flag_t *f; flag_t *retflag[MAXCANDIDATES]; int nretflags; @@ -9954,6 +10098,32 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // stop hiding killflagsofid(lf->flags, F_HIDING); + // merciful weapons + if (fromob) { + f = hasflag(fromob->flags, F_MERCIFUL); + if (f && (amt >= lf->hp)) { + amt = lf->hp - 1; // ie end up at 1hp + ko = B_TRUE; + if (fromob->pile->owner && cansee(player, fromob->pile->owner)) { + f->known = B_TRUE; + } + } + } + + // bashing damage sometimes ko's + if (!ko) { + if (damtype == DT_BASH) { + int hpleft; + hpleft = lf->hp - amt; + if ((hpleft >= -5) && (hpleft <= 0)) { + if (onein(2)) { + ko = B_TRUE; + amt = lf->hp - 1; // ie end up at 1hp + } + } + } + } + // large damage? if ((amt >= (lf->maxhp / 2)) && (amt >= 20)) { if (useringofmiracles(lf, 1)) { @@ -10057,7 +10227,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // further effects if not dead... if (!isdead(lf)) { // fight back if required - if (fromlf && retaliate) { + if (fromlf && retaliate && !ko) { fightback(lf, fromlf); } @@ -10073,8 +10243,19 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } } - // you wake up if you were hit! - killflagsofid(lf->flags, F_ASLEEP); + if (ko) { + // you are knocked unconscious for a _long_ time + fallasleep(lf, ST_KO, rnd(50,100)); + if (fromlf && isplayer(fromlf)) { + pleasegodmaybe(R_GODMERCY, 5); + } + } else { + // you wake up if you were hit, unless you were unconscious! + f = lfhasflag(lf, F_ASLEEP); + if (f && (f->val[1] != ST_KO)) { + killflagsofid(lf->flags, F_ASLEEP); + } + } // automatic onbleed abilities? if (postbleed && !prebleed) { @@ -10582,6 +10763,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha int dist; int difficulty; int lbonus; + flag_t *f; if (l == noisemaker) continue; @@ -10601,7 +10783,10 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha // listen bonus is based on sound volume lbonus = volume; - if (lfhasflag(l, F_ASLEEP)) { + f = lfhasflag(l, F_ASLEEP); + if (f) { + // can't hear while unconscious + if (f->val[1] == ST_KO) continue; lbonus -= 4; limit(&lbonus, 0, NA); } @@ -10639,9 +10824,11 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha //strncpy(textnopunc, text, strlen(text)-1); strcpy(textnopunc, text); punc = textnopunc[strlen(textnopunc)-1]; - if (punc != '\"') { // ie. not someone saying something - textnopunc[strlen(textnopunc)-1] = '\0'; + if (punc == '\"') { + // ie. someone saying something punc = '\0'; + } else { + textnopunc[strlen(textnopunc)-1] = '\0'; } dist = getcelldist(l->cell, c); @@ -10758,7 +10945,8 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, cha } // still asleep? - if (lfhasflag(l, F_ASLEEP) && cansee(player, l)) { + f = lfhasflag(l, F_ASLEEP); + if (f && (f->val[1] != ST_KO) && cansee(player, l)) { char lfname[BUFLEN]; getlfname(l, lfname); msg("%s stir%s in %s slumber...", lfname, @@ -11855,7 +12043,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,retainhpmp = B_FALSE; + int i,retainhp = B_FALSE; int nkilled = 0; race_t *newrace; char buf[BUFLEN]; @@ -11868,8 +12056,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { statdirty = B_TRUE; } - if (lfhasflag(lf, F_RETAINHPMPONPOLY)) { - retainhpmp = B_TRUE; + if (lfhasflag(lf, F_RETAINHPONPOLY)) { + retainhp = B_TRUE; } if (frompolymorph && (gamemode == GM_GAMESTARTED) && lf->race) { @@ -11946,10 +12134,23 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { // set material lf->material = lf->race->material; - // inherit flags from race + // inherit most flags from race + for (f = lf->race->flags->first ; f ; f = f->next) { + switch (f->id) { + case F_RARITY: + case F_MPDICE: + break; + default: + addflag_real(lf->flags, f->id, f->val[0], f->val[1], f->val[2], f->text, FROMRACE, f->known, -1); + break; + } + } + + /* copyflags(lf->flags, lf->race->flags, FROMRACE); // don't want certain race only flags... killflagsofid(lf->flags, F_RARITY); + */ // certain other flags are rnadom getflags(lf->flags, retflag, &nretflags, F_RNDHOSTILE, F_NONE); @@ -11969,7 +12170,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { lf->baseatt[i] = lf->att[i]; } - if (!retainhpmp) { + if (!retainhp) { // generate hp/maxhp from hit dice lf->maxhp = 0; for (i = 0; i < lf->level; i++) { @@ -11978,6 +12179,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } lf->hp = lf->maxhp; + // don't regenerate mp + /* // generate mp, if you have it. f = hasflag(lf->flags, F_MPDICE); if (f) { @@ -11990,6 +12193,7 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { lf->maxmp = 0; } lf->mp = lf->maxmp; + */ } lf->born = B_TRUE; @@ -12256,7 +12460,7 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r attrib = (getattr(lf, A_CON)/6) + (getattr(lf, A_WIS)/6) + getmr(lf); break; case SC_SEARCH: - attrib = (getskill(lf, SK_PERCEPTION)*3); + attrib = (getskill(lf, SK_PERCEPTION)*2); break; case SC_STEAL: attrib = (getskill(lf, SK_THIEVERY)); @@ -13004,7 +13208,7 @@ void startlfturn(lifeform_t *lf) { f = hasflag(o->flags, F_SECRET); if (f && (f->val[0] != NA)) { if (hasflag(o->flags, F_TRAP)) { - mod += getskill(lf, SK_TRAPS); + mod += (getskill(lf, SK_TRAPS)*2); } if (skillcheck(lf, SC_SEARCH, f->val[0], mod)) { @@ -13236,7 +13440,7 @@ void startlfturn(lifeform_t *lf) { switch (damtype) { case DT_WATER: if ((bp == BP_FEET) && isplayer(lf) && hasbp(lf, bp) && !donefeetwet) { - msg("Your %s get wet.", getbodypartname(bp)); + msg("Your %s get wet.", getbodypartname(lf, bp)); donefeetwet = B_TRUE; // don't keep repeating this } break; @@ -13542,7 +13746,7 @@ void stopresting(lifeform_t *lf) { if (f) { killflag(f); if (isplayer(lf)) { - msg("Your %s is interrupted!", (f->val[1] == NA) ? "rest" : "meditation"); + msg("Your %s is interrupted!", (f->val[1] == ST_MEDITATING) ? "meditation" : "rest"); } else if (cansee(player, lf)) { char buf[BUFLEN]; getlfname(lf, buf); @@ -13553,12 +13757,7 @@ void stopresting(lifeform_t *lf) { } void stoprunning(lifeform_t *lf) { - flag_t *f; - f = hasflag(lf->flags, F_RUNNING); - if (f) { - killflag(f); - } - + killflagsofid(lf->flags, F_RUNNING); } void stopsprinting(lifeform_t *lf) { @@ -14530,44 +14729,6 @@ int validateraces(void) { printf("ERROR in race '%s' - F_STARTOB with zero length text.\n", r->name); goterror = B_TRUE; } - } else if ((f->id == F_CANCAST) || (f->id == F_CANWILL)) { - objecttype_t *sp; - enum SPELLSCHOOL school; - sp = findot(f->val[0]); - school = getspellschool(f->val[0]); - if (sp->obclass->id == OC_SPELL) { - if ((f->id == F_CANWILL) || - hasflagval(r->flags, F_HASSKILL, SK_SPELLCASTING, NA, NA, NULL) || - hasflagval(r->flags, F_STARTSKILL, SK_SPELLCASTING, NA, NA, NULL) || - (school == SS_ALLOMANCY) || (school == SS_MENTAL) - ) { - int power; - //power = (1 + ff->val[1]) / getspelllevel(f->val[0]); - power = getspellpower(lf, f->val[0]); - if (power <= 0) { - printf("ERROR in race '%s' - %s %s (l%d) but insufficient spell power.\n", - r->name, - (f->id == F_CANWILL) ? "F_CANWILL" : "F_CANCAST", - sp->name,getspelllevel(sp->id)); - if (f->id == F_CANWILL) { - printf(" f_canwill text = '%s'\n\n",f->text); - } - goterror = B_TRUE; - } - } else { - objecttype_t *sp; - sp = findot(f->val[0]); - printf("ERROR in race '%s' - F_CANCAST %s (l%d) but no spellcasting skill\n", r->name, sp->name, getspelllevel(sp->id)); - goterror = B_TRUE; - } - } else { // ie. ability - if (f->val[0] == OT_A_SWOOP) { - if (!hasflag(r->flags, F_SWOOPRANGE)) { - printf("ERROR in race '%s' - has SWOOP ability but no F_SWOOPRANGE.\n", r->name); - goterror = B_TRUE; - } - } - } } else if (f->id == F_HITCONFER) { if (!lfhasflag(lf, F_HITCONFERVALS)) { printf("ERROR in race '%s' - F_HITCONFER, but no HITCONFERVALS defined.\n", r->name); @@ -14666,7 +14827,7 @@ int rest(lifeform_t *lf, int onpurpose) { // restore full hp lf->hp = lf->maxhp; // fall asleep for a while - fallasleep(lf, 50); + fallasleep(lf, ST_ASLEEP, 50); // mark screen as dirty needredraw = B_TRUE; if (isplayer(lf)) { @@ -14945,9 +15106,9 @@ int wear(lifeform_t *lf, object_t *o) { if (inway) { char inwayname[BUFLEN]; getobname(inway, inwayname, inway->amt); - snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(possbp[i]), inwayname); + snprintf(buf, BUFLEN, "%s (replace %s)", getbodypartname(lf, possbp[i]), inwayname); } else { - snprintf(buf, BUFLEN, "%s", getbodypartname(possbp[i])); + snprintf(buf, BUFLEN, "%s", getbodypartname(lf, possbp[i])); } addchoice(&prompt, ch++, buf, NULL, &possbp[i], NULL); } @@ -14976,6 +15137,9 @@ int wear(lifeform_t *lf, object_t *o) { case E_ALREADYUSING: if (isplayer(lf)) msg("You're already wearing that!"); break; + case E_DOESNTFIT: + if (isplayer(lf)) msg("The unnatural shape of your %s prevents this from fitting.", getbodypartname(lf, bp)); + break; case E_INJURED: if (isplayer(lf)) msg("Your injuries prevent you from wearing this."); break; @@ -15019,7 +15183,7 @@ int wear(lifeform_t *lf, object_t *o) { if (isplayer(lf)) msg("You can't wear that!"); break; case E_NOBP: - if (isplayer(lf)) msg("You have no %s on which to wear that!", getbodypartname(bp)); + if (isplayer(lf)) msg("You have no %s on which to wear that!", getbodypartname(lf, bp)); break; case E_LOWCHA: msg("You are not attractive enough to wear this."); @@ -15086,7 +15250,7 @@ int wear(lifeform_t *lf, object_t *o) { if ((gamemode == GM_GAMESTARTED) && lf->created) { if (isplayer(lf)) { if (showpos) { - msg("You are now wearing %s (%s your %s).", obname, getbodypartequipname(bp), getbodypartname(bp)); + msg("You are now wearing %s (%s your %s).", obname, getbodypartequipname(bp), getbodypartname(lf, bp)); } else { msg("You are now wearing %s.", obname); } @@ -15112,9 +15276,25 @@ int wear(lifeform_t *lf, object_t *o) { // warn if it will be cumbersome if (isplayer(lf)) { + char howmuch[BUFLEN]; f = hasflagval(o->flags, F_EQUIPCONFER, F_SHIELDPENALTY, NA, NA, NULL); - if (f && (getskill(lf, SK_SHIELDS) <= PR_INEPT) ) { - msg("^wYou find this shield very cumbersome to use."); + if (f) { + int penalty; + penalty = adjustshieldpenalty(lf, f->val[1]); + if (penalty) { + if (penalty >= 40) { + strcpy(howmuch, "incredibly"); + } else if (penalty >= 30) { + strcpy(howmuch, "extremely"); + } else if (penalty >= 20) { + strcpy(howmuch, "very"); + } else if (penalty >= 10) { + strcpy(howmuch, "quite"); + } else { + strcpy(howmuch, "slightly "); + } + msg("^wYou find this shield %s cumbersome to use.", howmuch); + } } } diff --git a/lf.h b/lf.h index a2a6e70..9dae42e 100644 --- a/lf.h +++ b/lf.h @@ -75,7 +75,7 @@ void enhanceskills(lifeform_t *lf); void extinguishlf(lifeform_t *lf); object_t *eyesshaded(lifeform_t *lf); int fall(lifeform_t *lf, lifeform_t *fromlf, int announce); -int fallasleep(lifeform_t *lf, int howlong); +int fallasleep(lifeform_t *lf, enum SLEEPTYPE how, int howlong); void fightback(lifeform_t *lf, lifeform_t *attacker); job_t *findjob(enum JOB jobid); job_t *findjobbyname(char *name); @@ -120,7 +120,7 @@ object_t *getbestthrowmissile(lifeform_t *lf); object_t *getbestweapon(lifeform_t *lf); object_t *getbestfirearm(lifeform_t *lf); int getbodyparthitchance(enum BODYPART bp); -char *getbodypartname(enum BODYPART bp); +char *getbodypartname(lifeform_t *lf, enum BODYPART bp); char *getbodypartequipname(enum BODYPART bp); object_t *getequippedob(obpile_t *op, enum BODYPART bp); int getexposedlimbs(lifeform_t *lf); @@ -273,6 +273,7 @@ flag_t *isresting(lifeform_t *lf); object_t *isstuck(lifeform_t *lf); int issmellablelf(lifeform_t *lf); int isswimming(lifeform_t *lf); +int isunconscious(lifeform_t *lf); int isundead(lifeform_t *lf); flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); int isweaponskill(enum SKILL skid); diff --git a/map.c b/map.c index 74c8def..fe77225 100644 --- a/map.c +++ b/map.c @@ -4,6 +4,7 @@ #include #include #include +#include "attack.h" #include "defs.h" #include "flag.h" #include "io.h" @@ -44,6 +45,14 @@ extern long curtime; cell_t *addcell(map_t *m, int x, int y) { cell_t *cell; + + // already allocated? + cell = m->cell[(y*m->w)+x]; + if (cell) { + clearcell(cell); + free(cell); + } + m->cell[(y*m->w)+x] = malloc(sizeof(cell_t)); cell = m->cell[(y*m->w)+x]; cell->map = m; @@ -150,6 +159,9 @@ map_t *addmap(void) { for (i = 0; i < MAXDIR_ORTH; i++) { a->nextmap[i] = -1; } + for (i = 0 ; i < MAX_MAPW*MAX_MAPH; i++) { + a->cell[i] = NULL; + } a->flags = addflagpile(NULL, NULL); a->beingcreated = B_TRUE; a->habitat = findhabitat(H_DUNGEON); // default!!! @@ -272,9 +284,13 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int } // TODO: base this on the time, and whether monster is nocturnal if (pctchance(asleepchance)) { - addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + addflag(lf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL); } } + // monsters who on dark levels can always see in the dark + if (!islit(lf->cell) && !lfhasflag(lf, F_SEEINDARK)) { + addflag(lf->flags, F_SEEINDARK, rnd(3,5), NA, NA, NULL); + } } // appears in groups? @@ -310,7 +326,10 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int // if master is asleep, minions will also be asleep if (lfhasflag(lf, F_ASLEEP)) { - addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + addflag(newlf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL); + } + if (!islit(newlf->cell) && !lfhasflag(newlf, F_SEEINDARK)) { + addflag(newlf->flags, F_SEEINDARK, rnd(3,5), NA, NA, NULL); } // minions never have certain flags. @@ -350,7 +369,11 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int jobok, int if (nadded) (*nadded)++; newlf->born = B_FALSE; - if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); + if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL); + + if (!islit(newlf->cell) && !lfhasflag(newlf, F_SEEINDARK)) { + addflag(newlf->flags, F_SEEINDARK, rnd(3,5), NA, NA, NULL); + } newlf->born = B_TRUE; } } @@ -762,7 +785,9 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in cell_t *poss[MAXCANDIDATES], *cell[MAXCANDIDATES]; // TODO: should this be maxroomw * maxroomh ? int ncells = 0, npossible = 0; int doorsadded = 0; - int db = B_FALSE; + int db = B_TRUE; + + if (db) dblog("autodoors starting"); // for each side, make list of all possible door locations // then pick one randomly. @@ -788,7 +813,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in makedoor(cell[i], dooropenchance); } else { setcelltype(cell[i], cell[i]->habitat->emptycelltype); - addflag(map->flags, F_ROOMEXIT, roomid, cell[i]->x, cell[i]->y, NULL); + addflag(map->flags, F_ROOMEXIT, roomid, cell[i]->x, cell[i]->y, "from autodoors, only way out"); } } else { // otherwise mark this as a _potential_ door location. @@ -808,7 +833,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in makedoor(poss[sel], dooropenchance); } else { setcelltype(poss[sel], poss[sel]->habitat->emptycelltype); - addflag(map->flags, F_ROOMEXIT, roomid, poss[sel]->x, poss[sel]->y, NULL); + addflag(map->flags, F_ROOMEXIT, roomid, poss[sel]->x, poss[sel]->y, "from autodoors, potential location"); } doorsadded++; @@ -856,7 +881,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in doorsadded++; } else { setcelltype(cell[sel], cell[sel]->habitat->emptycelltype); - addflag(map->flags, F_ROOMEXIT, roomid, cell[sel]->x, cell[sel]->y, NULL); + addflag(map->flags, F_ROOMEXIT, roomid, cell[sel]->x, cell[sel]->y, "from autodoors, forced at end"); doorsadded++; } } @@ -1139,7 +1164,7 @@ int dowaterspread(cell_t *c) { return B_FALSE; } -void fix_reachability(map_t *m) { +int fix_reachability(map_t *m) { int i,keepgoing = B_TRUE, nfixed = 0; int db = B_TRUE; cell_t *c = NULL; @@ -1152,7 +1177,7 @@ void fix_reachability(map_t *m) { case H_PIT: case H_VILLAGE: if (db) dblog("fix_reachability not required for this habitat."); - return; + return B_FALSE; default: break; } @@ -1164,7 +1189,7 @@ void fix_reachability(map_t *m) { } } // no empty cells in map? - if (!c) return; + if (!c) return B_FALSE; while (keepgoing) { keepgoing = B_FALSE; // mark all cells as non-filled @@ -1182,8 +1207,14 @@ void fix_reachability(map_t *m) { m->cell[i]->x, m->cell[i]->y); linkexit(m->cell[i], B_TRUE, &nadded); - if (db) dblog(" fixed unreachable area by adding %d cells.", nadded); - assert(nadded); + + if (nadded) { + if (db) dblog(" fixed unreachable area by adding %d cells.", nadded); + } else { + // didn't add anything - fail! + if (db) dblog(" fix_reachability failed."); + return B_TRUE; + } // now run the test again. // 'c' will be where the next flood will will happen. @@ -1195,6 +1226,7 @@ void fix_reachability(map_t *m) { } } if (db) dblog(" fix_reachability complete. fixed %d unreachable areas.", nfixed); + return B_FALSE; } @@ -1520,7 +1552,6 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int int includethiscell = B_FALSE; cell = getcellat(map, rx,ry); - // NEVER create a vault whcih will: // - be on top of the player (normally this can't happen, // but debugging via 'create vault' could do it) @@ -1531,6 +1562,10 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int if (hasobwithflag(cell->obpile, F_CLIMBABLE)) { valid = B_FALSE; } + // - overlap the inside of an existing room + if (cellwalkable(NULL, cell, NULL) && isroom(cell)) { + valid = B_FALSE; + } // is this cell adjacent to an empty cell and not a // corner (ie. a valid door location) @@ -2266,7 +2301,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex int i,x,y; enum HABITAT habitat; regionthing_t *thing[MAXOUTLINETHINGS]; - int nthings = 0; + int nthings = 0,failed; int db = B_FALSE; // determine habitat based on region @@ -2477,54 +2512,66 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex } if (db) dblog(" %d things remembered for later.",nthings); + failed = B_TRUE; + while (failed) { + failed = B_FALSE; + // build it... + if (db) dblog(" creating map habitat."); + createhabitat(map, depth, parentmap, exitdir, entryob); - // build it... - if (db) dblog(" creating map habitat."); - createhabitat(map, depth, parentmap, exitdir, entryob); + // add home objects + if (db) dblog(" adding home objects."); + for (lf = map->lf ; lf ; lf = lf->next) { + addhomeobs(lf); + } - // add home objects - if (db) dblog(" adding home objects."); - for (lf = map->lf ; lf ; lf = lf->next) { - addhomeobs(lf); - } + // add outline things + if (db) dblog(" adding remembered region outline things..."); + for (i = 0; i < nthings ;i++) { + vault_t *v; + // add this thing + switch (thing[i]->whatkind) { + case RT_HABITAT: // already handled above + break; + case RT_REGIONLINK: + if (db) dblog(" adding regionlink"); + createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region); + // ... don't need to do this since we know there won't be anywhere to link to. + //linkstairs(o); + break; + case RT_VAULT: + if (db) dblog(" adding vault"); + v = findvault(thing[i]->what); + assert(v); + if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) { + dblog("ERROR - couldn't create vault %s on map %s", v->id, map->name); + failed = B_TRUE; + } + break; + case RT_RNDVAULTWITHFLAG: + if (db) dblog(" adding rndvaultwithflag"); + v = findvaultwithflag(thing[i]->value); + assert(v); + if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) { + dblog("ERROR - couldn't create rndvaultwithflag %s on map %s", v->id, map->name); + failed = B_TRUE; + } + break; + } + } + // ensure there are no unreachable areas + if (!failed) { + if (fix_reachability(map)) { + failed = B_TRUE; + } + } - // add outline things - if (db) dblog(" adding remembered region outline things..."); - for (i = 0; i < nthings ;i++) { - vault_t *v; - // add this thing - switch (thing[i]->whatkind) { - case RT_HABITAT: // already handled above - break; - case RT_REGIONLINK: - if (db) dblog(" adding regionlink"); - createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region); - // ... don't need to do this since we know there won't be anywhere to link to. - //linkstairs(o); - break; - case RT_VAULT: - if (db) dblog(" adding vault"); - v = findvault(thing[i]->what); - assert(v); - if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) { - dblog("ERROR - couldn't create vault %s on map %s", v->id, map->name); - } - break; - case RT_RNDVAULTWITHFLAG: - if (db) dblog(" adding rndvaultwithflag"); - v = findvaultwithflag(thing[i]->value); - assert(v); - if (createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL)) { - dblog("ERROR - couldn't create rndvaultwithflag %s on map %s", v->id, map->name); - } - break; + if (failed) { + dblog("********* got errors - restarting map creation. *********"); } } - // ensure there are no unreachable areas - fix_reachability(map); - // special cases // village - add town walls and clear it out if (db) dblog(" finalising village creation..."); @@ -2798,7 +2845,7 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r if (calcroompos(map, w, h, xmargin, ymargin, &minx, &miny, B_TRUE)) { // forced calcroompos should never fail since it's // allowed to overlap other rooms. - dblog("** couldn't make vault room!\n"); + dblog("** couldn't find position for vault %s (roomid %d)!\n", v->id, roomid); //msg("** ALERT: couldn't make vault room!\n"); return B_TRUE; } @@ -2815,7 +2862,6 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r thisroom = &(map->room[map->nrooms]); map->nrooms++; - // now make it if (db) dblog("making vault %s at pos %d,%d on map %s", v->id, minx, miny, map->name); for (y = miny; y <= maxy; y++) { @@ -2894,10 +2940,10 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { while (c) { dist[d]++; if ((roomid >= 0) && getroomid(c) == roomid) { // same room - if (wantfilled && c->type->solid) { + //if (wantfilled && c->type->solid) { + if (c->type->solid) { // EXCEPTION: - // if we are calling this function from fix_reachability, then - // startcell will actually be a cell _inside_ the room as opposed to + // if startcell is a cell _inside_ the room as opposed to // a cell inside the room's walls. // in this case, we ARE allowed to travel through the room's walls. } else { @@ -2985,7 +3031,13 @@ int linkexit(cell_t *startcell, int wantfilled, int *ncellsadded) { startdir = startposs[rnd(0,nstartposs-1)]; } - assert(startdir != D_NONE); + if (wantfilled) { + // if startdir is D_NONE here, it means that we've called + // linkexit for a cell internal to a room. + // if we called this function from fix_reachable (ie. wantfilled=true) + // then this is a bad thing. + assert(startdir != D_NONE); + } // figure out perpendicular dirs perpdir[0] = startdir - 1; if (perpdir[0] < D_N) perpdir[0] = D_W; @@ -3256,6 +3308,9 @@ int linkexits(map_t *m, int roomid) { } assert(roomidx != -1); + // does this roomid actually exist?? + c = getrandomroomcell(m, roomid); + if (!c) return B_FALSE; if (db) { char buf[BUFLEN]; @@ -3620,6 +3675,14 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int mydist = getcelldist(c,cc); if (cc && (mydist <= (range+1))) { if (cc->lf && !isdead(cc->lf)) { + int critchance; + // critical hit? 100% chance in middle, 60 at one cell, 20 at two cells + critchance = 100 - (mydist*40); + if (pctchance(critchance)) { + //criticalhit(NULL, cc->lf, getrandomcorebp(cc->lf), DT_EXPLOSION); + criticalhit(NULL, cc->lf, BP_HANDS, DT_EXPLOSIVE); + } + // move away from centre of explosion knockback(cc->lf, getdiraway(cc, c, NULL, B_FALSE, DT_COMPASS, B_FALSE), 2, NULL, 40-(mydist*10)); } @@ -5051,6 +5114,7 @@ void mapentereffects(map_t *m) { if (m->lastplayervisit != -1) { int nturns; nturns = (curtime - m->lastplayervisit) / TICK_INTERVAL; + limit(&nturns, NA, 20); //nturns *= countlfs(m); for (i = 0; i < nturns; i++) { donextturn(m); @@ -5070,7 +5134,7 @@ enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob) { donesomething = B_FALSE; if (strstarts(p, "sleeping ")) { p += strlen("sleeping "); - if (wantflags) addflag(wantflags, F_ASLEEP, NA, NA, NA, NULL); + if (wantflags) addflag(wantflags, F_ASLEEP, NA, ST_ASLEEP, NA, NULL); donesomething = B_TRUE; } } diff --git a/map.h b/map.h index 73349de..8c6c054 100644 --- a/map.h +++ b/map.h @@ -17,7 +17,7 @@ int cellhaslos(cell_t *c1, cell_t *dest); void clearcell(cell_t *c); void clearcell_exceptflags(cell_t *c, ...); int dowaterspread(cell_t *c); -void fix_reachability(map_t *m); +int fix_reachability(map_t *m); int fix_unreachable_cell(cell_t *badcell); void floodfill(cell_t *startcell); cell_t *getcellat(map_t *map, int x, int y); @@ -51,6 +51,7 @@ void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir, object_t *entryob); void createpit(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); void createregionlink(map_t *m, cell_t *c, object_t *o, char *obname, enum REGIONTYPE newregiontype, region_t *parent); +void createregionthing(map_t *map, regionthing_t *rt); int createroom(map_t *map, int roomid, int overrideminw, int overrideminh, int xmargin, int ymargin, int *retx, int *rety, int *retw, int *reth, int doorpct, int forcewalls); int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *retx, int *rety); int dirtox(int dt, int dir); diff --git a/move.c b/move.c index 18102c1..7bef54f 100644 --- a/move.c +++ b/move.c @@ -348,6 +348,8 @@ int cellwalkable(lifeform_t *lf, cell_t *cell, enum ERROR *error) { enum RELATIVEDIR getrelativedir(lifeform_t *lf, int dir) { int tempdir; + if (lfhasflag(lf, F_AWARENESS)) return RD_FORWARDS; + // facing N, dir N == forwards if (lf->facing == dir) return RD_FORWARDS; @@ -905,7 +907,10 @@ int moveeffects(lifeform_t *lf) { int didmsg = B_FALSE; if (lfhasflagval(lf, F_INJURY, IJ_HAMSTRUNG, NA, NA, NULL)) { - if (!skillcheck(lf, SC_FALL, 20, 0)) fall(lf, NULL, B_TRUE); + if (!skillcheck(lf, SC_FALL, 20, 0)) { + fall(lf, NULL, B_TRUE); + if (isplayer(lf)) didmsg = B_TRUE; + } } if (isbleeding(lf)) { @@ -1432,7 +1437,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { } // slip on blood in new cell? - if (!isairborne(lf)) { + if (!isairborne(lf) && !isswimming(lf)) { int slip; object_t *o,*nexto; object_t *slipob; diff --git a/objects.c b/objects.c index 5dfd1d2..56b5a21 100644 --- a/objects.c +++ b/objects.c @@ -3071,7 +3071,7 @@ int getobaccuracy(object_t *wep, lifeform_t *weilder) { switch (slev) { case PR_INEPT: - acc -= 30; + acc -= 35; break; case PR_NOVICE: acc -= 10; @@ -3641,6 +3641,7 @@ int getobattackdelay(object_t *o) { return delay; } + float getobhppct(object_t *o) { float pct; flag_t *f; @@ -3653,6 +3654,16 @@ float getobhppct(object_t *o) { return pct; } +// returns '1' if object has no F_OBHP +int getobmaxhp(object_t *o) { + flag_t *f; + f = hasflag(o->flags, F_OBHP); + if (f) { + return f->val[1]; + } + return 1; +} + int getletidx(char let) { int i; for (i = 0; i < MAXPILEOBS; i++) { @@ -3941,7 +3952,7 @@ char *getobequipinfo(object_t *o, char *buf) { strcat(buf, " ("); strcat(buf, getbodypartequipname(f->val[0])); strcat(buf, " "); - strcat(buf, getbodypartname(f->val[0])); + strcat(buf, getbodypartname(o->pile->owner, f->val[0])); strcat(buf, ")"); } } @@ -3971,7 +3982,7 @@ char *getobextrainfo(object_t *o, char *buf) { } } else { if (f->val[0] > 0) { - snprintf(chargestr, BUFLEN, " (%d charges left)",f->val[0]); + snprintf(chargestr, BUFLEN, " (%d charge%s left)",f->val[0], (f->val[0] == 1) ? "" : "s"); } else { snprintf(chargestr, BUFLEN, " (empty)"); } @@ -4082,10 +4093,10 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } if (who) { char lfname[BUFLEN]; - real_getlfname(who, lfname, B_FALSE); - snprintf(buf, BUFLEN, "%s%s %sscent",lfname,getpossessive(lfname), adjective); + real_getlfnamea(who, lfname, B_FALSE); + snprintf(buf, BUFLEN, "%s%s%s %sscent",adjective,lfname,getpossessive(lfname)); } else { - snprintf(buf, BUFLEN, "%s %sscent",r->name, adjective); + snprintf(buf, BUFLEN, "%s%s scent",adjective, r->name ); } strcat(basename, buf); @@ -4530,6 +4541,10 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } } + if (hasflag(o->flags, F_KNOWNBAD)) { + strcat(localbuf, " [bad]"); + } + if (getskill(player, SK_COOKING) >= PR_BEGINNER) { if (isbadfood(o)) { strcat(localbuf, " [badfood]"); @@ -6029,11 +6044,13 @@ void killob(object_t *o) { object_t *nextone, *lastone; // debugging + /* if (o->type->id == OT_STAIRSUP) { msg("warning: removing an up staircase!"); dblog("warning: removing an up staircase!"); assert(1 == 0); } + */ // remove flags conferred by this object if (o->pile->owner) { @@ -6588,8 +6605,11 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { // triggered a trap? for (oo = dst->where->obpile->first ; oo ; oo = nextoo ) { nextoo = oo->next; - if ((oo != o) && hasflag(oo->flags, F_TRAP)) { - triggertrap(NULL, o, oo, dst->where); + if (oo != o) { + f = hasflag(oo->flags, F_TRAP); + if (f && (f->val[1] != curtime)) { + triggertrap(NULL, o, oo, dst->where); + } } } } @@ -10384,8 +10404,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // saving throws if (youhit && !willcatch && !isprone(target)) { - // can the victim see the thrower? - if (thrower && cansee(target, thrower)) { + // can the victim see where the object came from? + if (haslos(target, srcloc)) { int catchmod,dodgemod; enum LFSIZE sz; sz = getobsize(o); @@ -10413,7 +10433,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, !isimmobile(target) && skillcheck(target, SC_DEX, 15*speed, catchmod)) { willcatch = B_TRUE; - } else if (!lfhasflag(target, F_CASTINGSPELL) && skillcheck(target, SC_DODGE, 10*speed, dodgemod)) { + } else if (!lfhasflag(target, F_CASTINGSPELL) && skillcheck(target, SC_DODGE, 7*speed, dodgemod)) { // then check if we dodge it... youhit = B_FALSE; } @@ -11016,9 +11036,9 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { lf = c->lf; if (lf) getlfname(lf, lfname); - temp = findot(oid); + // saving throw? if (temp && lf) { flag_t *f; @@ -11041,6 +11061,13 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { } } } + // for actual trap objects (ie. not not doors etc), remember when we last + // triggered this trap. this is to avoid infinite loops with arrow traps! + if (trapob) { + flag_t *f; + f = hasflag(trapob->flags, F_TRAP); + if (f) f->val[1] = curtime; + } if (oid == OT_TRAPWIND) { // can't be dodged @@ -11546,6 +11573,8 @@ int getcritchance(lifeform_t *lf, object_t *o, lifeform_t *victim) { int chance = 0; if (!o) return 0; + if (hasflag(o->flags, F_MERCIFUL)) return 0; + f = hasflag(o->flags, F_CRITCHANCE); if (f) { chance += f->val[0]; diff --git a/objects.h b/objects.h index a37ae43..40ad39b 100644 --- a/objects.h +++ b/objects.h @@ -94,6 +94,7 @@ char *genhiddenname(enum OBCLASS id); char *gethiddenname(object_t *o); int getobattackdelay(object_t *o); float getobhppct(object_t *o); +int getobmaxhp(object_t *o); int getletindex(char let); int getmaterialvalue(enum MATERIAL mat ); int getmaxthrowrange(lifeform_t *lf, object_t *o); diff --git a/spell.c b/spell.c index 61d21d2..fb4c445 100644 --- a/spell.c +++ b/spell.c @@ -1972,7 +1972,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // returns TRUE on error -int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer, int frompot) { +int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_t *target, object_t *targob, cell_t *targcell, int blessed, int *seenbyplayer, int frompot) { char buf[BUFLEN]; char castername[BUFLEN]; int rv = B_FALSE; @@ -3278,10 +3278,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // announce getobname(o, obname, 1); if (isplayer(target)) { - msg("%s forms %s your %s!", obname, getbodypartequipname(bp[i]), getbodypartname(bp[i])); + msg("%s forms %s your %s!", obname, getbodypartequipname(bp[i]), getbodypartname(target, bp[i])); } else if (cansee(player, target)) { msg("%s forms %s %s%s %s!", obname, getbodypartequipname(bp[i]), - castername, getpossessive(castername), getbodypartname(bp[i])); + castername, getpossessive(castername), getbodypartname(target, bp[i])); } wear(target, o); // set its values @@ -4636,13 +4636,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (i = 0; i < nretflags; i++) { if ((retflag[i]->id == F_NOBODYPART) && (retflag[i]->val[1] == B_FROMINJURY)) { if (isplayer(target)) { - msg("Your %s grows back!", getbodypartname(retflag[0]->val[0])); + msg("Your %s grows back!", getbodypartname(target, retflag[0]->val[0])); if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (cansee(player, target)) { char targname[BUFLEN]; getlfname(target, targname); msg("%s%s %s grows back!", targname, getpossessive(targname), - getbodypartname(retflag[0]->val[0])); + getbodypartname(target, retflag[0]->val[0])); if (seenbyplayer) *seenbyplayer = B_TRUE; } killflag(retflag[i]); @@ -4978,11 +4978,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if ((f->val[0] == BP_RIGHTFINGER) || (f->val[0] == BP_LEFTFINGER)) { if (isplayer(caster)) { getobname(o, buf, 1); - msg("Your %s slides off your %s!", buf, getbodypartname(f->val[0])); + msg("Your %s slides off your %s!", buf, getbodypartname(caster, f->val[0])); } else if (cansee(player, caster)) { getobname(o, buf, 1); msg("%s%s %s slides off its %s!", castername, - getpossessive(castername), buf, getbodypartname(f->val[0])); + getpossessive(castername), buf, getbodypartname(caster, f->val[0])); } moveob(o, caster->cell->obpile, o->amt); } else { @@ -6172,7 +6172,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *o; lifeform_t *l; - targcell = caster->cell; + targcell = getcellindir(caster->cell, caster->facing); + if (!targcell || targcell->type->solid) { + fizzle(caster); + return B_TRUE; + } if (haslos(player, targcell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -6194,6 +6198,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } // hack - make all monsters who can see you stop targetting you. + // otherwise they will just try to go to your last known location. for (l = caster->cell->map->lf ; l ; l = l->next) { flag_t *f; if ((l != caster) && (gethitdice(l) <= gethitdice(caster)) ) { @@ -6367,7 +6372,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // - 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; + if (r && !canpolymorphto(r->id) && !hasjob(caster, J_GOD)) { + if (isplayer(caster)) msg("As you think of a %s, magic energy dampens around you.", r->name); + r = NULL; + } } else { // random if (isplayer(target) && lfhasflag(target, F_CONTROL)) { askstring("What will you become", '?', buf, BUFLEN, NULL); @@ -6774,7 +6782,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } howlong = getspellduration(5,10,blessed) + (power/2); - fallasleep(target, howlong); + fallasleep(target, ST_ASLEEP, howlong); if (isplayer(target) || haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -6990,7 +6998,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (!validatespellcell(caster, &targcell,TT_OBJECT | TT_MONSTER, spellid, power, frompot)) return B_TRUE; if (haslos(player, targcell)) { - msg("A small spark of flame appears."); + if (targcell->lf && cansee(player, targcell->lf)) { + char lfname[BUFLEN]; + getlfname(targcell->lf, lfname); + msg("A small spark of flame singes %s.", lfname); + } else { + msg("A small spark of flame appears."); + } if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -7293,9 +7307,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int nallies = 0; // target is always the caster - target = caster; + if (!target) target = caster; - if (spellresisted(target, caster, spellid, power, seenbyplayer, B_FALSE)) { if (isplayer(target)) { msg("You flicker."); @@ -8672,35 +8685,40 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { //////////////////////////////////// // HOW POWERFUL IS THIS SPELL? //////////////////////////////////// - if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) { - // always okay - usesorcery = B_FALSE; - } else if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) { - // dont need spellcasting skill for mental/allomancy - usesorcery = B_FALSE; - } else { - usesorcery = B_TRUE; - } + if (isplayer(lf)) { + if (hasjob(lf, J_DRUID) && (school == SS_NATURE)) { + // always okay + usesorcery = B_FALSE; + } else if ((school == SS_ALLOMANCY) || (school == SS_MENTAL)) { + // dont need spellcasting skill for mental/allomancy + usesorcery = B_FALSE; + } else { + usesorcery = B_TRUE; + } - power = 1; // base power of 1. - // plus either your hitdice/3 OR your sorcery skill - if (usesorcery) { - power += spellcastskill; - } else { - power += (gethitdice(lf)/3); - } + power = 1; // base power of 1. + // plus either your hitdice/3 OR your sorcery skill + if (usesorcery) { + power += spellcastskill; + } else { + power += (gethitdice(lf)/3); + } - // plus intelligence modifier - if (school == SS_MENTAL) { - // +/- 2 for iq - power += (getstatmod(lf, A_IQ) / 25); - } else if (school == SS_NATURE) { - // +/- 1 for wisdom - power += (getstatmod(lf, A_WIS) / 50); - // TODO: clerical +/- 2 for wisdom + // plus intelligence modifier + if (school == SS_MENTAL) { + // +/- 2 for iq + power += (getstatmod(lf, A_IQ) / 25); + } else if (school == SS_NATURE) { + // +/- 1 for wisdom + power += (getstatmod(lf, A_WIS) / 50); + // TODO: clerical +/- 2 for wisdom + } else { + // +/- 1 for iq + power += (getstatmod(lf, A_IQ) / 50); + } } else { - // +/- 1 for iq - power += (getstatmod(lf, A_IQ) / 50); + // for monsters, just based on hitdice: + power = gethitdice(lf); } limit(&power, 0, getspellmaxpower(spellid)); @@ -9018,6 +9036,13 @@ int spellisfromschool(int spellid, enum SPELLSCHOOL school) { // returns true if the spell was resisted. int spellresisted(lifeform_t *target, lifeform_t *caster, int spellid, int power, int *seenbyplayer, int announce) { char text[BUFLEN],buf[BUFLEN]; + + // cannot resist spells from gods when they are on their home plane + if (caster && (caster->race->raceclass->id == RC_GOD)) { + if (caster->cell && (caster->cell->map->region->rtype->id == RG_HEAVEN)) { + return B_FALSE; + } + } if (announce) { getlfname(target, buf); diff --git a/text.c b/text.c index ed23569..a72e6f9 100644 --- a/text.c +++ b/text.c @@ -423,6 +423,8 @@ char *gettimetextfuzzy(char *retbuf, int wantpm) { hours -= 12; pm = B_TRUE; } + + if (hours == 0) hours = 12; if (mins == 0) { snprintf(retbuf, BUFLEN, "exactly %d o'clock", hours);