#include #include #include #include #include #include "attack.h" #include "defs.h" #include "flag.h" #include "io.h" #include "lf.h" #include "map.h" #include "move.h" #include "nexus.h" #include "objects.h" #include "text.h" extern lifeform_t *player; int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) { object_t *armour = NULL; int damtaken = 0; // figure out what bit of armour was hit // special case - missiles always hit flak jacket if (damtype == DT_PROJECTILE) { object_t *o; o = getequippedob(lf->pack, BP_BODY); if (o && (o->type->id == OT_FLAKJACKET)) { armour = o; } } if (!armour) { // pick a random piece of armour armour = getrandomarmour(lf); } if (armour) { int actualdam; int ar = 0; flag_t *rust, *f; f = hasflag(armour->flags, F_ARMOURRATING); if (f) { ar = f->val[0]; } rust = hasflag(armour->flags, F_RUSTED); actualdam = dam; // adjust how much damage to do to armour if ( ((armour->type->id == OT_FLAKJACKET) && (damtype == DT_PROJECTILE)) || (damtype == DT_ACID) || hasflag(wep->flags, F_ARMOURPIERCE) || rust ) { // ALL of damage reduction goes towards armour } else { // SOME of the damage reduction goes towards the armour if (ar) { actualdam -= rnd(0,ar); limit(&actualdam, 0, NA); } } // modify for rust if (rust) { int multiplier = 1; switch (rust->val[0]) { case R_RUSTY: multiplier = 2; case R_VRUSTY: multiplier = 3; case R_TRUSTY: multiplier = 4; } actualdam *= multiplier; } // actually apply the damage to the armour damtaken = takedamage(armour,actualdam, damtype); } return damtaken; } void applyarmourdamreduction(lifeform_t *lf, object_t *wep, int reduceamt, int *dam, enum DAMTYPE damtype) { int db = B_FALSE; // armour can't stop armour-piercing weapons if (hasflag(wep->flags, F_ARMOURPIERCE)) { reduceamt = 0; } if (db) { if (reduceamt > 0) { dblog("Armour reduces dam by %d to %d.",reduceamt,dam); } else { dblog("No armour dam reduction."); } } if (dam && (reduceamt >= 0)) { *dam -= reduceamt; if (*dam < 0) *dam = 0; } } int attackcell(lifeform_t *lf, cell_t *c, int force) { int validwep[MAXCANDIDATES]; object_t *wep[MAXCANDIDATES]; flag_t *damflag[MAXCANDIDATES], *f; obpile_t *op = NULL; enum { AT_NONE = 0, AT_LF = 1, AT_OB = 2, } attacktype = AT_NONE; void *attacktarget; int nweps = 0; int innateattacks = 0; int i; int attacktime; int gotweapon = B_FALSE; int maxattacks = ALL; int lastweaponidx = -1; flag_t *sf; // anyone there? if so just attack. if (c->lf) { if (!force && isplayer(lf) && !areenemies(lf,c->lf) && (getraceclass(c->lf) != RC_PLANT)) { char ch; char victimname[BUFLEN]; char buf[BUFLEN]; getlfname(c->lf, victimname); switch (getallegiance(c->lf)) { case AL_PEACEFUL: sprintf(buf, "Really attack the peaceful %s?",noprefix(victimname)); break; case AL_FRIENDLY: sprintf(buf, "Really attack the allied %s?",noprefix(victimname)); break; default: sprintf(buf, "Really attack the allied %s?",noprefix(victimname)); break; } ch = askchar(buf, "yn","n", B_TRUE); if (ch == 'n') { // cancel. return B_TRUE; } } attacktype = AT_LF; attacktarget = c->lf; } else { object_t *o; // has an impassable object? o = hasobwithflag(c->obpile, F_IMPASSABLE); if (o) { object_t *priwep; attacktype = AT_OB; attacktarget = o; priwep = getweapon(lf); // confirm ? if (!force && isplayer(lf) && wepdullable(priwep) && (getiqname(getattr(player, A_IQ), NULL) >= IQ_SMART) ) { char obname[BUFLEN],wepname[BUFLEN],buf[BUFLEN]; char ch; real_getobname(o, obname, o->amt, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); getobname(priwep, wepname, priwep->amt); sprintf(buf, "Attacking %s might damage your %s. Proceed?", obname, noprefix(wepname)); ch = askchar(buf, "yn","n", B_TRUE); if (ch == 'n') { // cancel. return B_TRUE; } }; } else { // TODO: attack wall? if (isplayer(lf)) { msg("There is nothing there to attack!"); } return B_TRUE; } } // stop sprinting sf = lfhasflag(lf, F_SPRINTING); if (sf && sf->val[0]) { killflag(sf); } // ai code... if (lfhasflag(lf, F_DEMANDSBRIBE)) { if (!isplayer(lf) && (attacktype == AT_LF) && isplayer((lifeform_t *)attacktarget)) { if (demandbribe(lf)) { // ie. player paid. taketime(lf, getactspeed(lf)); return B_FALSE; } } } // first use our weapon... nweps = 0; wep[nweps] = getweapon(lf); if (wep[nweps]) { damflag[nweps] = hasflag(wep[nweps]->flags, F_DAM); validwep[nweps] = B_TRUE; lastweaponidx = 0; nweps++; gotweapon = B_TRUE; } // if we are skilled at twoweaponing, we can attack with our second weapon // as well, with a possible accuracy penalty depending on our skill level. if (getskill(lf, SK_TWOWEAPON)) { wep[nweps] = getsecmeleeweapon(lf); if (wep[nweps]) { if ((nweps >= 1) && (wep[nweps] == wep[nweps-1])) { // can't be the same as first one } else { damflag[nweps] = hasflag(wep[nweps]->flags, F_DAM); validwep[nweps] = B_TRUE; lastweaponidx = nweps; nweps++; gotweapon = B_TRUE; } } } // then use all our innate attacks.. for (f = lf->flags->first ; f; f = f->next) { if (f->id == F_HASATTACK) { objecttype_t *ot; if (!op) { op = addobpile(NULL, NULL); } ot = findot(f->val[0]); if (ot) { wep[nweps] = addob(op, ot->name); validwep[nweps] = B_TRUE; damflag[nweps] = f; nweps++; } } } innateattacks = countinnateattacks(lf); // stop sprinting f = lfhasflag(lf, F_SPRINTING); if (f && f->val[0]) { killflag(f); } // take time attacktime = getattackspeed(lf); taketime(lf, attacktime); if (nweps <= 0) { if (isplayer(lf)) { msg("You cannot attack!"); } return B_TRUE; } //maxattacks = nweps; // ie. all maxattacks = getmaxattacks(lf); /* // if we have a weapon, this takes the place of one of our // attacks. // - for monsters, pick which one to replace randomly. // - for players, never pick the weapon to replace randomly. */ // # valid attacks higher than our allowed attacks? if (nweps > maxattacks) { int nvalid; int first; // player never invalidates their equipped weapons if (isplayer(lf) && gotweapon) { first = lastweaponidx+1; } else { first = 0; } nvalid = 0; for (i = 0; i < nweps; i++) { if (validwep[i]) nvalid++; } while (nvalid > maxattacks) { int sel; // mark a random one as invalid sel = rnd(first,nweps-1); while (!validwep[sel]) { sel = rnd(first,nweps-1); } validwep[sel] = B_FALSE; // re-count... nvalid = 0; for (i = 0; i < nweps; i++) { if (validwep[i]) nvalid++; } } } // remember initial cells for (i = 0; i < nweps; i++) { if (validwep[i]) { if (attacktype == AT_LF) { if (!isdead((lifeform_t *)attacktarget)) { if (attacklf(lf, (lifeform_t *)attacktarget, wep[i], damflag[i])) break; } } else if (attacktype == AT_OB) { if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break; } } // stop attacking if they somehow got out of range // (eg. dodging) if (attacktype == AT_LF) { if (getcelldist(lf->cell, ((lifeform_t *)attacktarget)->cell) > 1) { break; } } } // now kill all temp obs if (op) { killobpile(op); } // now stop hiding killflagsofid(lf->flags, F_HIDING); return B_FALSE; } int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) { int dam[100]; enum DAMTYPE damtype[100]; int ndam = 0; char buf[BUFLEN]; char attackername[BUFLEN]; char victimname[BUFLEN]; int fatal = B_FALSE; int deflected = B_FALSE; int weppassthrough = B_FALSE; int firstisbackstab = B_FALSE; int hit = B_FALSE; int critical = 0; char wepname[BUFLEN]; //int acc; //int ev; int i; int willheal = B_FALSE; int isunarmed = B_FALSE; int aidb = B_FALSE; flag_t *f; if (lfhasflag(lf, F_DEBUG)) { aidb = B_TRUE; } if (hasflag(wep->flags, F_UNARMEDWEP)) { isunarmed = B_TRUE; } moveeffects(lf); if (isdead(lf)) { return B_TRUE; } // get names getlfname(lf, attackername); if (lf == victim) { if (isplayer(lf)) { strcpy(victimname, "yourself"); } else { strcpy(victimname, "itself"); } } else { getlfname(victim, victimname); } if (aidb) dblog(".oO { trying to attack %s }", victimname); getobname(wep, wepname, 1); if (aidb) dblog(".oO { my weapon is %s }", wepname); if (lf->race->raceclass->id == RC_INSECT) { if (hasactivespell(victim, OT_S_REPELINSECTS)) { if (isplayer(lf)) { msg("Something prevents you from attacking %s!", victimname); } else if (cansee(player, lf)) { msg("Something prevents %s from attacking %s!", attackername, victimname); } taketime(lf, getattackspeed(lf)); return B_FALSE; } } for (f = lf->flags->first ; f ; f = f->next) { // ie. you have been made noncorporeal if ((f->id == F_NONCORPOREAL) && (f->lifetime != FROMRACE)) { if (isplayer(lf)) { msg("Your attack passes straight through %s.", victimname); } else if (cansee(player, lf)) { msg("%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname); } taketime(lf, getattackspeed(lf)); return B_FALSE; } } // did you hit? ndam = 0; hit = rolltohit(lf, victim, wep, &critical); // weapon passing through ghosts etc? if (hit) { if (lfhasflag(victim, F_NONCORPOREAL) && !lfhasflag(lf, F_NONCORPOREAL) ) { // using a magical or blessed weapon? if so you're ok. if (wep && (ismagical(wep) || isblessed(wep)) ) { } else { weppassthrough = B_TRUE; hit = B_FALSE; ndam = 0; } } } // deflection? if (hit) { object_t *dwep; dwep = isdualweilding(victim); if (dwep && (getskill(victim, SK_TWOWEAPON) >= PR_MASTER)) { if (onein(4)) { deflected = B_TRUE; hit = B_FALSE; } } } if (hit) { if (aidb) dblog(".oO { i hit! }"); // special case if (isplayer(lf) && (victim->race->id == R_GLOWBUG)) { if ((wep->type->id == OT_EMPTYFLASK) || (wep->type->id == OT_EMPTYVIAL)) { object_t *o; // catch the glowbug! msg("You catch %s in your %s.", victimname, noprefix(wepname)); removeob(wep, 1); killlf(victim); // don't leave a corpse o = addob(lf->pack, "glowing flask"); if (o) { getobname(o, buf, o->amt); msgnocap("%c - %s.",o->letter, buf); } else { // add to the ground o = addob(lf->cell->obpile, "glowing flask"); if (o) { getobname(o, buf, o->amt); msg("%s drops to the ground.", buf); } } // stop all further attacks return B_TRUE; } } // determine base damage // determine damage dam[0] = getdamroll(wep, victim, damflag); if (critical) { // critical hit means an extra damage roll. dam[0] += getdamroll(wep, victim, damflag); } if (aidb) dblog("rolled dam[%d] = %d",0,dam[0]); if (dam[0] < 0) { willheal = B_TRUE; } // damtype? damtype[0] = getdamtype(wep); if (!willheal) { enum SKILLLEVEL slev; skill_t *sk; float loremult; // blessed vs undead if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) { // a little extra damage dam[0] = (int) ( (float)dam[0] * 1.25 ); } // modify for strength if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { dam[0] = (int)((float)dam[0] * getstrdammod(lf)); } // modify for size modifyforsize(&dam[0], lf, victim, 5, M_PCT); // backstab? if ((damtype[0] == DT_PIERCE) && // using a stabbing weapon getskill(lf, SK_BACKSTAB) && // able to backstab !cansee(victim, lf) && // victim can't see us !lfhasflagval(victim, F_STABBEDBY, lf->id, NA, NA, NULL) && // haven't stabbed them before !lfhasflagval(victim, F_TARGETLF, lf->id, NA, NA, NULL) // victim isnt attacking us ) { addflag(victim->flags, F_STABBEDBY, lf->id, NA, NA, NULL); dam[0] *= (getskill(lf, SK_BACKSTAB)*2); firstisbackstab = B_TRUE; } // extra damage for being skilled? sk = getobskill(wep); if (sk) { slev = getskill(lf, sk->id); if (slev > 1) { float pctextra; pctextra = ((slev - 1) * 10); dam[0] += pctof(pctextra, dam[0]); } } // bonus for knowledge about the other lf's race? applied LAST. slev = getlorelevel(lf, victim->race->raceclass->id); if (slev == PR_INEPT) { loremult = 1; } else { loremult = 1 + (slev * 0.1); } dam[0] = (int) ( (float)dam[0] * loremult ); } if (aidb) dblog(".oO { dealing %d %s damage }", dam[0], getdamname(damtype[0])); ndam = 1; // determine extra damage for flaming etc. // getextradam from USER too if (!willheal) { getextradamwep(wep, &dam[0], &damtype[0], &ndam); getextradamlf(lf, &dam[0], &damtype[0], &ndam); } } else { hit = B_FALSE; ndam = 0; } if (ndam > 0) { flag_t *f; for (i = 0; i < ndam; i++) { int reduceamt = 0; int backstab = B_FALSE; flag_t *rust; if (firstisbackstab && (i == 0)) backstab = B_TRUE; //dblog("initial dam[%d] = %d",i,dam[i]); if (lfhasflag(lf, F_HEAVYBLOW) || hasflag(wep->flags, F_HEAVYBLOW)) { dam[i] = (int)pctof(110,dam[i]); //dblog("heavy blow makes dam[%d] = %d",i,dam[i]); } // modify for rust rust = hasflag(wep->flags, F_RUSTED); if (rust) { switch (damtype[i]) { case DT_PIERCE: case DT_SLASH: if (rust->val[0] >= R_TRUSTY) { dam[i] -= (pctof(50, dam[i])); } else if (rust->val[0] >= R_VRUSTY) { dam[i] -= (pctof(25, dam[i])); } else { dam[i] -= (pctof(10, dam[i])); } break; default: break; } } // modify based on resistances adjustdamlf(victim, &dam[i], damtype[i]); //dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); if (!backstab) { // modify for defender's armour reduceamt = getarmourdamreduction(victim, wep, dam[i], damtype[i]); applyarmourdamreduction(victim, wep, reduceamt, &dam[i], damtype[i]); //dblog("reduced by armour to dam[%d] = %d",i,dam[i]); } // will this hit be fatal? if (dam[i] >= victim->hp) { fatal = B_TRUE; } // announce it if (isplayer(lf)) { char extradambuf[BUFLEN]; char withwep[BUFLEN]; char *verb; int needfree = B_FALSE; strcpy(extradambuf, ""); if (wep && !ismeleeweapon(wep)) { sprintf(withwep, " with %s", wepname); } else { strcpy(withwep, ""); } strcpy(extradambuf, ""); if (dam[i] == 0) { if (getlorelevel(lf, victim->race->raceclass->id) >= PR_ADEPT) { strcpy(extradambuf, " but do no damage"); } } else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) { sprintf(extradambuf, " [%d dmg]",dam[i]); } if (backstab && (i == 0)) { verb = strdup("backstab"); needfree = B_TRUE; } else if (fatal) { verb = getkillverb(victim, wep, damtype[i], dam[i], victim->maxhp); } else { if ((getlorelevel(lf, victim->race->raceclass->id) >= PR_BEGINNER) || !ismeleedam(damtype[i])) { verb = getattackverb(lf, wep, damtype[i], dam[i], victim->maxhp); } else { verb = strdup("hit"); needfree = B_TRUE; } } warn("You %s %s%s%s%s", verb, victimname, withwep,extradambuf, (fatal || backstab) ? "!" : "."); if (fatal && strstr(verb, "behead")) { addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL); } if (fatal && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { // don't also say "the xx dies" addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); } if (needfree) { free(verb); } } else { if (cansee(player, lf) || isplayer(victim)) { char withwep[BUFLEN]; char attackverb[BUFLEN]; char nodamstr[BUFLEN]; // capitalise first letter strcpy(buf, attackername); capitalise(buf); if (wep && !isunarmed && (lf->race->id != R_DANCINGWEAPON) && cansee(player, lf)) { sprintf(withwep, " with %s", wepname); } else { strcpy(withwep, ""); } strcpy(attackverb, getattackverb(lf, wep, damtype[i],dam[i],victim->maxhp)); if ((dam[i] == 0) && (damtype[i] != DT_TOUCH)) { strcpy(nodamstr, " but does no damage"); } else { strcpy(nodamstr, ""); } warn("%s %s%s %s%s%s.", buf, attackverb, needses(attackverb) ? "es" : "s", victimname,withwep, nodamstr); } noise(lf->cell, lf, 3, "sounds of fighting.", NULL); } if (willheal) { if (cansee(player, victim)) { flag_t *f; msg("%s %s healed!",victimname, isplayer(victim) ? "are" : "is"); f = hasflag(wep->flags, F_BALANCE); if (f) { f->known = B_TRUE; } gainhp(victim, dam[i]); } } else { char attackername2[BUFLEN]; real_getlfname(lf, attackername2, B_FALSE); // victim loses hp // don't adjust damage - we've already done that if (wep && !isunarmed) { char wepname[BUFLEN]; getobname(wep, wepname, 1); sprintf(buf, "%s^%s %s",attackername2, (lf == victim) ? "using" : "weilding", wepname); } else { strcpy(buf, attackername2); } losehp_real(victim, dam[i], damtype[i], lf, buf, B_FALSE); // victim's armour loses hp if (reduceamt) { applyarmourdamage(victim, wep, reduceamt, damtype[i]); } } } // end foreach damtype // special weapon effects, as long as you're not doing a heavy blow if (!lfhasflag(lf, F_HEAVYBLOW)) { wepeffects(wep->flags, victim->cell, damflag, dam[0]); } // other effects if (!isdead(victim)) { if (isunarmed) { f = lfhasflag(lf, F_FREEZINGTOUCH); if (f) { // victim turns to ice for a while! freezelf(victim, lf, rnd(5,10)); killflag(f); } } f = lfhasflag(lf, F_QUICKBITE); if (f) { if (isbleeding(victim)) { int dam; char lfname[BUFLEN]; dam = rolldie(f->val[0], f->val[1]) + f->val[2]; real_getlfname(lf, lfname, B_FALSE); losehp_real(victim, dam, DT_BITE, lf, lfname, B_FALSE); if (isplayer(victim) || cansee(player, victim)) { msg("%s bites %s!", lfname, victimname); } } } f = lfhasflag(lf, F_PACKATTACK); if (f) { int dir; cell_t *c; int nmatched = 0; char lfname[BUFLEN]; getlfname(lf, lfname); // count adjacent allies of name xx for (dir = DC_N; dir <= DC_NW; dir++) { c = getcellindir(victim->cell, dir); if (c && c->lf) { if (c->lf->race->baseid == lf->race->baseid) { nmatched++; } } } if (nmatched >= f->val[2]) { char damstring[BUFLEN]; sprintf(damstring, "%s pack", lfname); losehp(victim, f->val[0], f->val[1], lf, damstring); if (isplayer(victim) || cansee(player, victim)) { msg("%s pack attacks %s!", lfname, victimname); } } } // critical hit effects if (critical) { if (lfhasflag(lf, F_CRITKNOCKDOWN)) { fall(victim, lf, B_TRUE); } } // confer flags from attacker? wepeffects(lf->flags, victim->cell, damflag, dam[0]); // special lifeform-based effects if ((lf->race->id == R_COCKATRICE) && dam[0]) { // first saving throw... if (skillcheck(victim, SC_CON, 25, 0)) { // slowed addtempflag(victim->flags, F_SLOWACTMOVE, 15, NA, NA, NULL, 2); } else { // second saving throw... if (skillcheck(victim, SC_CON, 25, 0)) { // paralyzed addtempflag(victim->flags, F_PARALYZED, B_TRUE, NA, NA, NULL, 5); } else { if (!lfhasflag(lf, F_BEINGSTONED)) { // stoned! addflag(victim->flags, F_BEINGSTONED, 2, NA, NA, NULL); } } } } else if ((lf->race->id == R_STIRGE) || (lf->race->id == R_LEECH)) { // automatically latch on if (!lfhasflag(victim, F_NONCORPOREAL) && !hasflag(lf->flags, F_ATTACHEDTO)) { addflag(lf->flags, F_ATTACHEDTO, victim->id, NA, NA, NULL); } } } // retaliation happens even if victim died for (f = victim->flags->first ; f ; f = f->next) { if (f->id == F_RETALIATE) { int rdam; char damstring[BUFLEN]; rdam = rolldie(f->val[0], f->val[1]); if (cansee(player, victim)) { msg("%s%s %s %s %s!", victimname, getpossessive(victimname), noprefix(f->text), getattackverb(victim, NULL, f->val[2], rdam, lf->maxhp), attackername); } sprintf(damstring, "%s%s %s", victimname, getpossessive(victimname), noprefix(f->text)); losehp(lf, rdam, f->val[2], victim, damstring); } } } else { // miss! if (aidb) dblog(".oO { i missed! }"); // announce it if (weppassthrough) { if (cansee(player, lf)) { msg("%s%s attack passes straight through %s!", attackername, getpossessive(attackername), victimname); } } else if (deflected) { if (cansee(player, lf)) { msg("%s deflect%s %s%s attack.", victimname, isplayer(victim) ? "" : "s",attackername, getpossessive(attackername)); } } else if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { if (isplayer(lf) || cansee(player, lf)) { sprintf(buf, "%s",attackername); msg("%s%s magnetic shield repels %s%s attack.", victimname, getpossessive(victimname), buf, getpossessive(buf)); } } else { if (isplayer(lf)) { msg("You miss %s.", victimname); } else { if (cansee(player, lf)) { // capitalise first letter sprintf(buf, "%s",attackername); msg("%s misses %s.", buf, victimname); } } if (lfhasflag(victim, F_DODGES)) { cell_t *adj; adj = getrandomadjcell(victim->cell, WE_WALKABLE, B_NOEXPAND); if (adj) { flag_t *f; f = addflag(victim->flags, F_NOTIME, B_TRUE, NA, NA, NULL); moveto(victim, adj, B_FALSE, B_FALSE); msg("%s dodge%s!",victimname,isplayer(victim) ? "" : "s"); killflag(f); } } } fightback(victim, lf); } // practice? if (hit) { skill_t *sk; // extra damage for being skilled? sk = getobskill(wep); if (sk && !getskill(lf, sk->id)) { practice(lf, sk->id); } } // induction of fear? if (!isdead(victim)) { if (lfhasflag(victim, F_INDUCEFEAR)) { if (cansee(lf, victim)) { scare(lf, victim, rnd(2,3), 0); } } } // twoweapon? if (hit) { enum SKILLLEVEL slev; slev = getskill(lf, SK_TWOWEAPON); if (slev >= PR_SKILLED) { object_t *secwep; secwep = getsecmeleeweapon(lf); // ie. if we are using two weapons, and the current one // is the first... if (secwep && (secwep != wep)) { int bonus = 0; // next hit will have enhanced accuracy if (slev == PR_SKILLED) { bonus = 10; } else if (slev == PR_EXPERT) { bonus = 25; } else if (slev == PR_MASTER) { bonus = 40; } if (bonus) { addtempflag(lf->flags, F_ACCURACYMOD, bonus, NA, NA, NULL, 1); } } } } if (aidb) dblog(".oO { doattack about to return B_FALSE }"); return B_FALSE; } int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { int dam[100]; enum DAMTYPE damtype[100]; int ndam = 0; char attackername[BUFLEN]; char obname[BUFLEN]; flag_t *f; int isunarmed = B_FALSE; cell_t *obloc = NULL; char wepname[BUFLEN]; int i; //int aidb = B_TRUE; int maxhp; moveeffects(lf); if (isdead(lf)) return B_TRUE; // get names getlfname(lf, attackername); getobname(o, obname, o->amt); // get target object details obloc = o->pile->where; f = hasflag(o->flags, F_OBHP); if (f) { maxhp = f->val[1]; } else { maxhp = 1; } getobname(wep, wepname, 1); // don't need to figure out accuracy - we always hit. // determine damage ndam = 0; //if (unarmedflag && (unarmedflag->val[0] != NA)) { dam[ndam] = getdamroll(wep, NULL, damflag); // modify for strength if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf)); } // damtype? damtype[ndam] = getdamtype(wep); ndam++; // don't need to check for blessed vs mosnters // determine extra damage getextradamwep(wep, &dam[0], &damtype[0], &ndam); getextradamlf(lf, &dam[0], &damtype[0], &ndam); for (i = 0; i < ndam; i++) { // announce the hit if (isplayer(lf)) { char extradambuf[BUFLEN]; if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) { sprintf(extradambuf, " [%d dmg]",dam[i]); } else { strcpy(extradambuf, ""); } msg("You %s %s.", getattackverb(lf, wep, damtype[i], dam[i], maxhp), obname, extradambuf); } else if (cansee(player, lf)) { char withwep[BUFLEN]; if (wep && !isunarmed && !isblind(player)) { // announce weapon used sprintf(withwep, " with %s", wepname); } else { strcpy(withwep, ""); } msg("%s %ss %s%s.", attackername, getattackverb(lf, wep, damtype[i],dam[i],maxhp), obname,withwep); } else { noise(lf->cell, NULL, 3, "sounds of fighting.", NULL); } if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(o->flags, F_HARD)) { char buf[BUFLEN]; sprintf(buf, "punching %s", obname); if ( losehp(lf, 1, DT_BASH, lf, buf)) { if (isplayer(lf)) { msg("Ow!"); } } } // object loses hp takedamage(o, dam[i], damtype[i]); } // end foreach damtype // special weapon effects, as long as you're not doing a heavy blow if (!lfhasflag(lf, F_HEAVYBLOW)) { wepeffects(wep->flags, obloc, damflag, dam[0]); } if (isunarmed) { // touch effects touch(lf, o); } else { // weapon gets damaged ? if (wep && (ndam > 0)) { if (wepdullable(wep)) { // weapon gets duller if (rnd(1,2)) makeduller(wep, 1); } } } return B_FALSE; } // returns the amount of damage the armour blocked... int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) { int reduceamt = 0; int ar; int pctrange; object_t *o; ar = getarmourrating(lf); //reducepct = getdamreducepct(ar); //reduceamt = (int) ceil((reducepct / 100.0) * (float)dam); //reduceamt = ar/2; // between 25% and 75% of AR. // ie. with AR of 20, all damage is reduced by 5-15. pctrange = rnd(25,75); reduceamt = pctof(pctrange, ar); // special case if (damtype == DT_PROJECTILE) { o = getequippedob(lf->pack, BP_BODY); if (o && (o->type->id == OT_FLAKJACKET)) { // stop ALL missile damage reduceamt = dam; } } if (reduceamt < 0) reduceamt = 0; return reduceamt; } // returns a const char * char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) { float pct; enum LFSIZE ownersize = SZ_HUMAN; if (lf) { ownersize = getlfsize(lf); } pct = (int)(((float) dam / (float) maxhp) * 100.0); if (wep) { flag_t *f; for (f = wep->flags->first ; f ; f = f->next) { if (f->id == F_ATTACKVERB) { if ((f->val[0] == NA) && (f->val[1] == NA)) { return f->text; } else if (f->val[0]) { if (pct >= f->val[0]) { if (f->val[1] == NA) { return f->text; } else if (pct <= f->val[1]) { return f->text; } } } else if (f->val[1]) { if (pct <= f->val[1]) { return f->text; } } } } } if (damtype == DT_ACID) { return "burn"; } else if (damtype == DT_BASH) { if (pct <= 5) { return "whack"; } else if (pct <= 20) { if (onein(2)) { return "hit"; } else { return "bash"; } } else if (pct <= 30) { return "pummel"; } else { return "slam"; } } else if (damtype == DT_BITE) { if (lf && (ownersize <= SZ_SMALL)) { if (pct <= 5) { return "nip"; } else if (pct <= 30) { return "bite"; } } else { if (pct <= 5) { return "gnaw"; } else if (pct <= 30) { return "bite"; } else { return "savage"; } } } else if (damtype == DT_CHOP) { if (pct <= 5) { return "hit"; } else if (pct <= 15) { return "hack"; } else { return "chop"; } } else if (damtype == DT_COLD) { if (pct <= 10) { return "chill"; } else { return "freeze"; } } else if (damtype == DT_CRUSH) { return "crush"; } else if (damtype == DT_ELECTRIC) { if (pct <= 5) { return "zap"; } else if (pct <= 15) { return "jolt"; } else if (pct <= 20) { return "shock"; } else if (pct <= 30) { return "electrify"; } else { return "electrocute"; } } else if (damtype == DT_FIRE) { if (pct <= 5) { return "scorch"; } else if (pct <= 20) { return "burn"; } else if (pct <= 40) { return "scald"; } else { return "incinerate"; } } else if (damtype == DT_HOLY) { switch (rnd(1,2)) { case 1: return "smite"; case 2: return "cleanse"; } } else if (damtype == DT_PIERCE) { if (pct <= 5) { return "poke"; } else if (pct <= 15) { return "stab"; } else if (pct <= 30) { return "pierce"; } else if (pct <= 40) { return "spear"; } else { return "deeply stab"; } } else if (damtype == DT_POISONGAS) { return "poison"; } else if (damtype == DT_PROJECTILE) { return "hit"; } else if (damtype == DT_SLASH) { if (pct <= 5) { return "scratch"; } else if (pct <= 15) { return "hit"; } else if (pct <= 30) { return "slash"; } else { return "slice"; } } else if (damtype == DT_TOUCH) { return "touch"; } else if (damtype == DT_WATER) { // for when water-vulnerable things go into water return "hurt"; } else if (damtype == DT_UNARMED) { if (onein(2)) { return "punch"; } else { return "hit"; } } return "hit"; } /* object_t *getattackwep(lifeform_t *lf, obpile_t **unarmedpile, flag_t **unarmedflag) { object_t *wep; wep = getweapon(lf); if (!wep) { // ie. unarmed *unarmedpile = getunarmedweapon(lf, unarmedflag); if ((*unarmedpile)->first) { wep = (*unarmedpile)->first; } else { wep = NULL; } } return wep; } */ enum DAMTYPE getdamtype(object_t *wep) { flag_t *f; enum DAMTYPE dt = DT_NONE; f = hasflag(wep->flags, F_DAM); if (f) { dt = f->val[0]; } else { // default - you are just bashing with whatever // you weilded. dt = DT_BASH; } return dt; } int getextradamlf(lifeform_t *lf, int *dam, enum DAMTYPE *damtype, int *ndam) { flag_t *f; // special case - EXTRADAM goes onto INITIAL dam[] if the same type, rather than // adding a new one. for (f = lf->flags->first ; f ; f = f->next) { if (f->id == F_EXTRADAM) { int *damwhere; int *damtypewhere; int doinc = B_FALSE; if ((f->val[0] == NA) || (f->val[0] == *damtype)) { damwhere = dam; damtypewhere = damtype; *(damwhere) += roll(f->text); // addition } else { damwhere = (dam + *ndam); damtypewhere = (damtype + *ndam); *(damwhere) = roll(f->text); // set doinc = B_TRUE; } *(damtypewhere) = f->val[0]; if ((f->lifetime == FROMOBEQUIP) || (f->lifetime == FROMOBHOLD) || (f->lifetime == FROMOBACTIVATE) ) { object_t *obfrom; obfrom = findobbyid(lf->pack, f->obfrom); if (obfrom) { int bonusdam = 0; sumflags(obfrom->flags, F_BONUS, &bonusdam, NULL, NULL); *(damwhere) += bonusdam; } } if (doinc) { (*ndam)++; } } } return *dam; } int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam) { flag_t *f; for (f = wep->flags->first ; f ; f = f->next) { if (f->id == F_ONFIRE) { if (strlen(f->text)) { *(dam + *ndam) = roll(f->text); } else { *(dam + *ndam) = rolldie(2,6); } *(damtype + *ndam) = DT_FIRE; (*ndam)++; } else if (f->id == F_FROZEN) { *(dam + *ndam) = rolldie(1,4); *(damtype + *ndam) = DT_COLD; (*ndam)++; } } return *dam; } char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) { float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); if (victim->race->id == R_DANCINGWEAPON) { return "defeat"; } if (getraceclass(victim) == RC_PLANT) { return "destroy"; } if (wep) { flag_t *f; for (f = wep->flags->first ; f ; f = f->next) { if (f->id == F_KILLVERB) { if ((f->val[0] == NA) && (f->val[1] == NA)) { return f->text; } else if (f->val[0]) { if (pct >= f->val[0]) { if (f->val[1] == NA) { return f->text; } else if (pct <= f->val[1]) { return f->text; } } } else if (f->val[1]) { if (pct <= f->val[1]) { return f->text; } } } } } if ((damtype == DT_BASH) && lfhasflag(victim, F_FROZEN)) { return "shatter"; } if (damtype == DT_CRUSH) { return "crush"; } if (damtype == DT_HOLY) { return "smite"; } if (pct >= 70) { if (damtype == DT_PIERCE) return "impale"; if (damtype == DT_BASH) return "flatten"; if (damtype == DT_BITE) return "gore"; if (damtype == DT_SLASH) { if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) { return "bisect"; } else { if ((getlfsize(victim) >= SZ_MEDIUM) && onein(3)) { return "behead"; } else { return "bisect"; } } } } if (getraceclass(victim) == RC_UNDEAD) { // can't "kill" the undead return "destroy"; } return "kill"; } void getdamrange(flag_t *f, int *min, int *max) { int mindam,maxdam; if (f) { int mod,ndice,sides; texttodice(f->text, &ndice,&sides,&mod); mindam = (ndice * 1) + mod; maxdam = (ndice * sides) + mod; } else { // TODO wepaon does damage based on weight mindam = 0; maxdam = 0; } if (min) *min = mindam; if (max) *max = maxdam; } /* void getdamrangeunarmed(flag_t *f, int *min, int *max) { obpile_t *op = NULL; object_t *o = NULL; flag_t *damflag = NULL; if (strlen(f->text)) { damflag = f; } else { objecttype_t *ot; ot = findot(f->val[0]); op = addobpile(NULL, NULL); // create the fake weapon o = addob(op, ot->name); if (o) { damflag = hasflag(o->flags, F_DAM); } } if (damflag) { int ndice,nsides,mod; texttodice(damflag->text, &ndice, &nsides, &mod); if (min) *min = (ndice * 1) + mod; if (max) *max = (ndice * nsides) + mod; } else { if (min) *min = 0; if (max) *max = 0; } if (o) { killob(o); } if (op) { free(op); } } */ // roll for damage int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) { int dam; int bonusdam = 0; flag_t *f; if (damflag) { dam = roll(damflag->text); if (isblessed(o)) { int dam2; // blessed weapons get two rolls, and take the best dam2 = roll(damflag->text); if (dam2 > dam) dam = dam2; } else if (iscursed(o)) { int dam2; // cursed weapons get two rolls, and take the worst dam2 = roll(damflag->text); if (dam2 < dam) dam = dam2; } } else { // TODO weapon does bashing damage based on weight dam = rnd(1,2); } // modify for bonus sumflags(o->flags, F_BONUS, &bonusdam, NULL, NULL); dam += bonusdam; if (dam < 0) dam = 0; // special effects ? f = hasflag(o->flags, F_BALANCE); if (f) { lifeform_t *owner; owner = o->pile->owner; if (owner && victim) { float ratio; ratio = (float)owner->maxhp / (float)victim->maxhp; if (ratio >= 1.25) { // heals instead! dam = -dam; } else if (ratio <= 0.75) { // extra dam! dam = (int) ((float)dam * ratio); } } } return dam; } /* float getdamreducepct(float armourrating) { float reducepct; reducepct = (armourrating * 1.5); return reducepct; } */ /* int getunarmeddamroll(flag_t *f) { int dam; flag_t *damflag = NULL; if (f->text) { // take damage from unarmed flag damflag = f; } else { // take damage from wep type objecttype_t *ot; ot = findot(f->val[0]); assert(ot); damflag = hasflag(ot->flags, F_DAM); } dam = roll(damflag->text); assert(dam < 1000); assert(dam >= 0); return dam; } */ // returns a multiplier float getstrdammod(lifeform_t *lf) { float mod = 0; float base; // <9 = penalty // 9,10,11,12 = average // >12 = bonus if (lfhasflag(lf, F_RAGE)) { base = 20; } else { base = getattr(lf, A_STR); } if ((base >= 9) && (base <= 12)) { mod = 1; } else if (base > 12) { base -= 12; // ie. 1 - 6 // 13 = 1 = 1.1 // 14 = 2 = 1.2 // 15 = 3 = 1.3 // 16 = 4 = 1.4 // 17 = 5 = 1.6 // 18 = 6 = 1.5 mod = 1 + (base / 10.0); } else { // ie. 0 through 8 // 0 = 0.1 // 1 = 0.2 // 2 = 0.3 // 3 = 0.4 // 4 = 0.5 // 5 = 0.6 // 6 = 0.7 // 7 = 0.8 // 8 = 0.9 mod = (base * 0.1); // ie. 8 -> 0.8 or 4 -> 0.4 mod += 0.1; // ie. 8 -> 0.9 or 4 -> 0.5 } return mod; } // determine attack type for lifeform. // allocate a pile and add weapon to it. // return the pile. remember to free it! /* obpile_t *getunarmedweapon(lifeform_t *lf,flag_t **uflag) { int nposs; flag_t *f; int sel; char poss[MAXPILEOBS][BUFLEN]; obpile_t *op; flag_t *possflag[MAXPILEOBS]; op = addobpile(NULL, NULL); // pick a random attack type. nposs = 0; for (f = lf->flags->first ; f ; f = f->next) { if (f->id == F_HASATTACK) { strcpy(poss[nposs],f->text); possflag[nposs] = f; nposs++; } } if (nposs > 0) { object_t *uob; sel = rnd(0,nposs-1); uob = addob(op, poss[sel]); assert(uob); if (uflag) *uflag = possflag[sel]; } if (!op->first) { if (uflag) *uflag = NULL; } return op; } */ // ie. caused by hitting something with a melee weapon int ismeleedam(enum DAMTYPE damtype) { switch (damtype) { case DT_PIERCE: case DT_SLASH: case DT_BASH: case DT_BITE: case DT_CHOP: case DT_PROJECTILE: case DT_UNARMED: case DT_CRUSH: return B_TRUE; default: break; } return B_FALSE; } int isphysicaldam(enum DAMTYPE damtype) { switch (damtype) { case DT_BASH: case DT_BITE: case DT_CHOP: case DT_COLD: case DT_CRUSH: case DT_ELECTRIC: case DT_EXPLOSIVE: case DT_FALL: case DT_FIRE: case DT_MAGIC: case DT_PIERCE: case DT_PROJECTILE: case DT_SLASH: case DT_UNARMED: return B_TRUE; default: break; } return B_FALSE; } // 'howmuch' is the numerical amount to adjust 'val' by for every size bracket // difference. // // if lf is bigger than victim, ADD howmuch. // if lf is smaller than victim, SUBTRACT howmuch. void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, enum MODTYPE how) { enum LFSIZE szlf,szvictim; assert(val); szlf = getlfsize(lf); szvictim = getlfsize(victim); if (szvictim < szlf) { // if defender is smaller... if (how == M_VAL) { // +howmuch per size difference *val += (howmuch * (szlf - szvictim)); } else { // +(howmuch*sizediff)% of original value *val += (pctof(howmuch * (szlf - szvictim), *val)); } } else if (szvictim > szlf) { // if defender is bigger... if (how == M_VAL) { // -howmuch per size difference *val -= (howmuch * (szvictim - szlf)); } else { // +(howmuch*sizediff)% of original value *val -= (pctof(howmuch * (szlf - szvictim), *val)); } } } // returns true if we hit int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) { int acc,ev; int gothit; enum SKILLLEVEL slev; int myroll; flag_t *f; // base 5% critical chance - check this first. if (critical) { int critroll; critroll = rnd(1,100); // default *critical = 0; // modify for lore if (slev != PR_INEPT) { myroll += (slev*5); // ie. up to 30% bonus } if (critroll >= 95) *critical = 1; } f = lfhasflag(lf, F_TRUESTRIKE); if (f) { if (f->val[0] > 1) { f->val[0]--; } else { killflag(f); } gothit = B_TRUE; } else if (critical) { gothit = B_TRUE; } else { // actually roll... acc = getlfaccuracy(lf, wep); // size difference (penalty for attacking smaller ones) modifyforsize(&acc, lf, victim, -5, M_VAL); // easier to hit victims who are prone. if (isprone(victim)) { acc += 30; } // remember lore about victim... slev = getlorelevel(lf, victim->race->raceclass->id); // modify for defender's evasion if (isprone(victim) || !cansee(victim, lf)) { ev = 0; } else { ev = getevasion(victim); } acc -= ev; // modify if we can't see the victim if (!cansee(lf, victim)) { acc -= 50; } // metal weapon versus magnetic shield? if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { acc -= 45; } // victim immobile or asleep? if (isimmobile(victim) || lfhasflag(victim, F_EATING)) { acc += 50; } limit(&acc, 0, 100); //if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc); myroll = rnd(1,100); if (slev != PR_INEPT) { myroll += (slev*10); } // modify for lore if (myroll <= acc) { gothit = B_TRUE; } } return gothit; } void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { flag_t *f; lifeform_t *victim; lifeform_t *owner = NULL; object_t *wep; if (!where) return; wep = fp->ob; if (wep) { cell_t *c; c = getoblocation(wep); if (c && c->lf) { owner = c->lf; } } else { owner = fp->owner; } victim = where->lf; for (f = fp->first ; f ; f = f->next) { if (f->id == F_FLAMESTRIKE) { if (!hasob(where->obpile, OT_FIRESMALL)) { // ignite! addob(where->obpile, "small fire"); // announce if (haslos(player, where)) { msg("A column of fire erupts from the ground!"); f->known = B_KNOWN; } } } else if ((f->id == F_REVENGE) && victim && !isdead(victim)) { if (dam) { // only works if we did damage lifeform_t *owner; owner = wep->pile->owner; if (owner && victim) { float ratio; float dampct; int maxdam; int extradam; // figure out hp percentage ratio = 1.0 - ((float)owner->hp / (float)owner->maxhp); dampct = (ratio * 100); // ie. lower hp% = higher dampct if (dampct >= 50) { getdamrange(damflag, NULL, &maxdam); extradam = (int)((dampct/100) * (float)maxdam); if (extradam > 0) { char buf[BUFLEN]; char buf2[BUFLEN]; char obname[BUFLEN]; char damstring[BUFLEN]; char victimname[BUFLEN]; getlfname(owner, buf); real_getlfname(owner, buf2, B_FALSE); getlfname(victim, victimname); getobname(wep, obname, 1); // announce if (isplayer(owner)) { msg("Your %s blasts %s!",noprefix(obname),victimname); f->known = B_TRUE; } else if (cansee(player, owner)) { msg("%s%s %s blasts %s!",buf, getpossessive(buf),noprefix(obname),victimname); f->known = B_TRUE; } sprintf(damstring, "%s%s blast of revenge",buf2, getpossessive(buf2)); losehp(victim, extradam, DT_DIRECT, owner, damstring); } } // end if dampct > 50 } } } else if ((f->id == F_DISARMATTACK) && victim && owner && !isdead(victim)) { object_t *victimwep; skill_t *sk; int skillmod; victimwep = getweapon(victim); if (victimwep) { sk = getobskill(wep); if (sk) { skillmod = getskill(owner, sk->id); if (skillmod == 0) skillmod = -5; } else { skillmod = 0; } if (skillcheckvs(owner, SC_DEX, skillmod, victim, SC_SLIP, 0)) { char lfname[BUFLEN]; char victimname[BUFLEN]; getlfname(owner,lfname); getlfname(victim, victimname); if (cansee(player, owner)) { msg("%s disarm%s %s!",lfname, isplayer(owner) ? "" : "s", victimname); } drop(victimwep, ALL); } } } else if ((f->id == F_TRIPATTACK) && victim && owner && !isdead(victim)) { skill_t *sk; int skillmod; sk = getobskill(wep); if (sk) { skillmod = getskill(owner, sk->id); if (skillmod == 0) skillmod = -5; } else { skillmod = 0; } if (skillcheckvs(owner, SC_DEX, skillmod, victim, SC_SLIP, 0)) { char lfname[BUFLEN]; char victimname[BUFLEN]; getlfname(owner,lfname); getlfname(victim, victimname); if (cansee(player, owner)) { msg("%s trip%s %s.",lfname, isplayer(owner) ? "" : "s", victimname); } fall(victim, NULL, B_TRUE); } } else if ((f->id == F_HEAVYBLOW) && victim && owner) { int dir; // knock back victim dir = getdirtowards(owner->cell, victim->cell, victim, B_FALSE, DT_COMPASS); knockback(victim, dir , 2, owner, 30); 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; 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); // 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" sprintf(frombuf, "%s%s %s",lfname,getpossessive(lfname), wepname); } else { char wepname[BUFLEN]; getobname(wep, wepname, 1); // ie "a poisoned short sword" sprintf(frombuf, "%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; ppower = 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); } } } // 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); } } } // end if (fid == hitconfer) } }