#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; int adam; int damtaken = 0; if ((damtype == DT_ACID) || hasflag(wep->flags, F_ARMOURPIERCE)) { // ALL of damage reduction goes towards armour adam = dam; } else { // some of damage reduction goes towards armour adam = (dam / 2); } // pick a random piece of armour armour = getrandomarmour(lf); if (armour) { damtaken = takedamage(armour,adam, 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) { // anyone there? if so just attack. if (c->lf) { attacklf(lf, c->lf); } else { object_t *o; // has an mpassable object? o = hasobwithflag(c->obpile, F_IMPASSABLE); if (o) { attackob(lf, o); } else { // TODO: attack wall? return B_TRUE; } } return B_FALSE; } int attacklf(lifeform_t *lf, lifeform_t *victim) { int dam[100]; enum DAMTYPE damtype[100]; int ndam = 0; char buf[BUFLEN]; char attackername[BUFLEN]; char victimname[BUFLEN]; int fatal = B_FALSE; flag_t *unarmedflag = NULL; object_t *wep; obpile_t *op = NULL; int attacktime; int hit = B_FALSE; int critical = 0; char wepname[BUFLEN]; //int acc; //int ev; int i; int willheal = B_FALSE; int aidb = B_FALSE; if (lfhasflag(lf, F_DEBUG)) { aidb = 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); // get weapon //wep = getweapon(lf); wep = getattackwep(lf, &op, &unarmedflag); if (!wep) { if (isplayer(lf)) { msg("You cannot attack!"); } else if (haslos(player, lf->cell)) { //msg("%s looks like it wants to attack!",attackername); } if (op) killobpile(op); return B_TRUE; } getobname(wep, wepname, 1); if (aidb) dblog(".oO { my weapon is %s %s }", wepname, unarmedflag ? "(unarmed)" : ""); // depends on weapon, race attackspeed modifier flag, etc attacktime = getattackspeed(lf); taketime(lf, attacktime); // did you hit? ndam = 0; if (rolltohit(lf, victim, &critical)) { int n; hit = B_TRUE; 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); } } if (op) { killobpile(op); } return B_FALSE; } } // determine base damage // determine damage //if (unarmed && (unarmedflag->val[0] != NA)) { // ie. if critical is 0, do this once. // if critical is 1, do this twice. // etc. dam[ndam] = 0; for (n = 0; n < critical+1; n++) { if (unarmedflag) { // this mosnter's unarmed attack will // override normal damage calculation dam[ndam] += getdamrollfromflag(unarmedflag); } else { dam[ndam] += getdamroll(wep, victim); } } if (aidb) dblog("rolled dam[%d] = %d",ndam,dam[ndam]); if (dam[ndam] < 0) { willheal = B_TRUE; } if (!willheal) { // modify for strength dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf)); } // damtype? damtype[ndam] = getdamtype(wep); if (aidb) dblog(".oO { dealing %d %s damage }", dam[ndam], getdamname(damtype[ndam])); ndam++; // blessed vs undead etc? if (!willheal) { if (isblessed(wep) && lfhasflagval(victim, F_DTVULN, DT_HOLY, NA, NA, NULL)) { // a little extra damage dam[ndam] = (int) ( (float)dam[ndam] * 1.25 ); } // determine extra damage getextradam(wep, &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; dblog("initial dam[%d] = %d",i,dam[i]); if (lfhasflag(lf, F_HEAVYBLOW)) { dam[i] = (int)((float)dam[i] * 1.5); dblog("heavy blow makes dam[%d] = %d",i,dam[i]); } // modify based on resistances adjustdamlf(victim, &dam[i], damtype[i]); dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); // 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 *verb; if (dam[i] == 0) { strcpy(extradambuf, " but do no damage"); } else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) { sprintf(extradambuf, " [%d dmg]",dam[i]); } else { strcpy(extradambuf, ""); } if (fatal) { verb = getkillverb(victim, damtype[i], dam[i], victim->maxhp); } else { verb = getattackverb(damtype[i], dam[i], victim->maxhp); } warn("You %s %s%s%s", verb, victimname, extradambuf, fatal ? "!" : "."); 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); } } else { if (haslos(player, lf->cell) || isplayer(victim)) { char withwep[BUFLEN]; char attackverb[BUFLEN]; char nodamstr[BUFLEN]; // capitalise first letter sprintf(buf, "%s",attackername); capitalise(buf); if (wep && !unarmedflag && (lf->race->id != R_DANCINGWEAPON) && haslos(player, lf->cell)) { sprintf(withwep, " with %s", wepname); } else { strcpy(withwep, ""); } strcpy(attackverb, getattackverb(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, attackverb[strlen(attackverb)-1] == 's' ? "es" : "s", victimname,withwep, nodamstr); } else { youhear(lf->cell, "sounds of fighting"); } } if (willheal) { if (haslos(player, victim->cell)) { flag_t *f; msg("%s is healed!",victimname); 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 && !unarmedflag) { char wepname[BUFLEN]; getobname(wep, wepname, 1); sprintf(buf, "%s^%s %s",attackername2, (lf == victim) ? "using" : "weilding", wepname); } else { char attackername2[BUFLEN]; 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 wepeffects(wep, victim->cell); if (!isdead(victim)) { if (unarmedflag) { 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) || haslos(player, victim->cell)) { msg("%s bites %s!", lfname, victimname); } } } f = lfhasflag(lf, F_PACKATTACK); if (f) { int dir; cell_t *c; int nmatched = 0; // count adjacent allies of name xx for (dir = DC_N; dir <= DC_NW; dir++) { c = getcellindir(victim->cell, dir); if (c && c->lf) { if (strcasestr(c->lf->race->name, f->text)) { nmatched++; } } } if (nmatched >= f->val[2]) { char damstring[BUFLEN]; sprintf(damstring, "a %s pack", f->text); losehp(victim, f->val[0], f->val[1], lf, damstring); if (isplayer(victim) || haslos(player, victim->cell)) { msg("The %s pack attacks %s!", f->text, victimname); } } } } } else { // miss! if (aidb) dblog(".oO { i missed! }"); // announce it if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { if (isplayer(lf) || haslos(player, lf->cell)) { 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 (haslos(player, lf->cell)) { // capitalise first letter sprintf(buf, "%s",attackername); msg("%s misses %s.", buf, victimname); } } if (lfhasflag(victim, F_DODGES)) { flag_t *f; cell_t *adj; f = addflag(victim->flags, F_NOTIME, B_TRUE, NA, NA, NULL); adj = getrandomadjcell(victim->cell, WE_NOTSOLID); moveto(lf, adj); msg("%s dodge%s!",victimname,isplayer(victim) ? "" : "s"); killflag(f); } } fightback(victim, lf); } // get rid of temp unarmed object pile if (op) { killobpile(op); } // induction of fear? if (!isdead(victim)) { if (lfhasflag(victim, F_INDUCEFEAR)) { scare(lf, victim, rnd(2,3)); } } if (aidb) dblog(".oO { doattack about to return B_FALSE }"); return B_FALSE; } int attackob(lifeform_t *lf, object_t *o) { int dam[100]; enum DAMTYPE damtype[100]; int ndam = 0; char attackername[BUFLEN]; char obname[BUFLEN]; flag_t *f; flag_t *unarmedflag = NULL; object_t *wep; obpile_t *op = NULL; cell_t *obloc = NULL; int attacktime; int unarmed = B_FALSE; char wepname[BUFLEN]; int i; //int aidb = B_TRUE; int maxhp; // 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; } // get weapon wep = getattackwep(lf, &op, &unarmedflag); if (!wep) { if (isplayer(lf)) { msg("You cannot attack!"); } else if (haslos(player, lf->cell)) { //msg("%s looks like it wants to attack!",attackername); } if (!isplayer(lf)) { // if ai, take some time to avoid infinite loops! taketime(lf, getactspeed(lf)); } if (op) killobpile(op); return B_TRUE; } getobname(wep, wepname, 1); // depends on weapon, race attackspeed modifier flag, etc attacktime = getattackspeed(lf); taketime(lf, attacktime); // don't need to figure out accuracy - we always hit. // determine damage ndam = 0; //if (unarmedflag && (unarmedflag->val[0] != NA)) { if (unarmedflag) { // this mosnter's unarmed attack will // override normal damage calculation dam[ndam] = getdamrollfromflag(unarmedflag); } else { dam[ndam] = getdamroll(wep, NULL); } // damtype? damtype[ndam] = getdamtype(wep); ndam++; // don't need to check for blessed vs mosnters // determine extra damage getextradam(wep, &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(damtype[i], dam[i], maxhp), obname, extradambuf); } else if (haslos(player, lf->cell)) { char withwep[BUFLEN]; if (wep && !unarmed && !isblind(player)) { // announce weapon used sprintf(withwep, " with %s", wepname); } else { strcpy(withwep, ""); } msg("%s %ss %s%s.", attackername, getattackverb(damtype[i],dam[i],maxhp), obname,withwep); } else { youhear(lf->cell, "sounds of fighting"); } if ((i == 0) && unarmedflag) { 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 wepeffects(wep, obloc); // weapon gets damaged ? if (!unarmedflag && wep && (ndam > 0)) { switch (damtype[0]) { case DT_PIERCE: case DT_SLASH: // weapon gets duller if (rnd(1,2)) makeduller(wep, 1); break; default: break; } } // hitting an object with our hands will hurt // get rid of temp unarmed object pile if (op) { killobpile(op); } 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; float reducepct; int ar; ar = getarmourrating(lf); reducepct = getdamreducepct(ar); reduceamt = (int) ceil((reducepct / 100.0) * (float)dam); if (reduceamt < 0) reduceamt = 0; return reduceamt; } // returns a const char * char *getattackverb(enum DAMTYPE damtype, int dam, int maxhp) { float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); if (damtype == DT_BASH) { if (pct <= 5) { return "whack"; } else if (pct <= 20) { if (rnd(1,2) == 1) { return "hit"; } else { return "bash"; } } else { return "pummel"; } } else if (damtype == DT_BITE) { if (pct <= 5) { return "gnaw"; } else if (pct <= 30) { return "bite"; } else { return "savage"; } } else if (damtype == DT_CLAW) { if (pct <= 5) { return "scratch"; } else if (pct <= 15) { return "claw"; } else if (pct <= 30) { return "tear"; } else if (pct <= 40) { return "rake"; } else if (pct <= 50) { return "gouge"; } else { return "eviscerate"; } } 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_UNARMED) { if (rnd(1,2) == 1) { 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_DAMTYPE); if (f) { dt = f->val[0]; } else { // default - you are just bashing with whatever // you weilded. dt = DT_BASH; } return dt; } int getextradam(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) { *(dam + *ndam) = rolldie(2,8); *(damtype + *ndam) = DT_FIRE; (*ndam)++; } } return *dam; } char *getkillverb(lifeform_t *victim, enum DAMTYPE damtype, int dam, int maxhp) { float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); 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_CLAW) return "disembowel"; if (damtype == DT_SLASH) { if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) { return "bisect"; } else { if (rnd(1,3) == 1) { return "behead"; } else { return "bisect"; } } } } return "kill"; } void getdamrange(flagpile_t *fp, int *min, int *max) { int mindam,maxdam; flag_t *f; f = hasflag(fp, F_DAM); if (f) { int mod,ndice,sides; ndice = f->val[0]; sides = f->val[1]; if (f->val[2] == NA) { mod = 0; } else { mod = f->val[2]; } 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; object_t *o; op = addobpile(NULL, NULL); o = addob(op, f->text); if (o) { int ndice,nsides,mod; flag_t *damflag; damflag = hasflag(o->flags, F_DAM); if (f->val[0] == NA) { ndice = damflag->val[0]; } else { ndice = f->val[0]; } if (f->val[1] == NA) { nsides = damflag->val[1]; } else { nsides = f->val[1]; } if (f->val[2] == NA) { if (damflag->val[2] != NA) { mod = damflag->val[2]; } else { mod = 0; } } else { mod = f->val[2]; } if (min) *min = (ndice * 1) + mod; if (max) *max = (ndice * nsides) + mod; killob(o); } else { if (min) *min = 0; if (max) *max = 0; } free(op); } // roll for damage int getdamroll(object_t *o, lifeform_t *victim) { int dam; flag_t *f; f = hasflag(o->flags, F_DAM); if (f) { dam = getdamrollfromflag(f); if (isblessed(o)) { int dam2; // blessed weapons get two rolls, and take the best dam2 = getdamrollfromflag(f); if (dam2 > dam) dam = dam2; } else if (iscursed(o)) { int dam2; // cursed weapons get two rolls, and take the worst dam2 = getdamrollfromflag(f); if (dam2 < dam) dam = dam2; } } else { // TODO wepaon does bashing damage based on weight dam = rnd(1,2); } // modify for bonus f = hasflag(o->flags, F_BONUS); if (f) { dam += f->val[0]; } 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 getdamrollfromflag(flag_t *f) { objecttype_t *ot; int dam; int ndice, sides, mod; flag_t *damflag = NULL; ot = findotn(f->text); if (ot) { damflag = hasflag(ot->flags, F_DAM); } // how many dice? ndice = f->val[0]; if (ndice == NA) { // get it from weapon definition if (damflag && (damflag->val[0] != NA)) { ndice = damflag->val[0]; } else { ndice = 1; } } sides = f->val[1]; if (sides == NA) { // get it from weapon definition if (damflag && (damflag->val[1] != NA)) { sides = damflag->val[1]; } else { sides = 1; } } mod = f->val[2]; if (mod == NA) { // get it from weapon definition if (damflag && (damflag->val[2] != NA)) { mod = damflag->val[2]; } else { mod = 0; } } dam = rolldie(ndice, sides) + mod; 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 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; } int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical) { int acc,ev; object_t *wep; obpile_t *op = NULL; int gothit; if (critical) { *critical = 0; } acc = getlfaccuracy(lf); wep = getattackwep(lf, &op, NULL); // modify for defender's evasion ev = getevasion(victim); acc -= ev; // metal weapon versus magnetic shield? if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { acc -= 45; } if (critical) { if (rnd(1,20) == 20) *critical = 1; } if (acc < 0) acc = 0; if (acc > 100) acc = 100; //if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc); if (rnd(1,100) <= acc) { gothit = B_TRUE; } else { if (critical && *critical) { // turn a miss into a hit gothit = B_TRUE; } else { gothit = B_FALSE; } } if (op) killobpile(op); return gothit; } void wepeffects(object_t *wep, cell_t *where) { flag_t *f; lifeform_t *victim; lifeform_t *owner; owner = wep->pile->owner; victim = where->lf; if (!where) return; for (f = wep->flags->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_HITCONFER) && victim && !isdead(victim)) { enum FLAG fid; int val0,val1; int min,max,howlong; fid = f->val[0]; if (!lfhasflag(victim, fid)) { val0 = f->val[1]; val1 = f->val[2]; if (f->text) { char loctext[BUFLEN]; char *word, *dummy; strcpy(loctext,f->text); word = strtok_r(loctext, "-", &dummy); if (word) { min = atoi(word); word = strtok_r(NULL, "-", &dummy); if (word) { max = atoi(word); howlong = rnd(min,max); } else { howlong = PERMENANT; } } else { howlong = PERMENANT; } } else { howlong = PERMENANT; } addtempflag(victim->flags, fid, val0, val1, NA, NULL, howlong); } } else if ((f->id == F_REVENGE) && victim && !isdead(victim)) { 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(wep->flags, NULL, &maxdam); extradam = (int)(dampct * (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 (haslos(player, owner->cell)) { 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_HEAVYBLOW) && victim && owner) { int dir; // knock back victim dir = getdirtowards(owner->cell, victim->cell, victim, B_FALSE); knockback(victim, dir , 2, owner); f->known = B_TRUE; } } }