#include #include #include "ai.h" #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 "spell.h" #include "text.h" extern lifeform_t *player; extern enum ERROR reason; void aimove(lifeform_t *lf) { int wantdb = B_TRUE; int db = B_FALSE; object_t *curwep,*bestwep, *o; object_t *curgun,*bestgun; flag_t *f; //flag_t *nextf; // lifeform_t *fleefrom = NULL; lifeform_t *target; enum BODYPART bp; int x,y; cell_t *c; obpile_t *unarmedpile = NULL; flag_t *unarmedflag = NULL; if (wantdb && haslos(player, lf->cell)) { db = B_TRUE; } else { db = B_FALSE; } if (db) { char lfname[BUFLEN]; getlfname(lf, lfname); dblog("AIMOVE: %s", lfname); } /* // if lifeform isn't alive, skip turn if (isdead(lf)) { if (db) dblog(".oO { i am not alive, skipping turn. }"); taketime(lf, SPEED_DEAD); return; } */ // do we have a better weapon we could use? curwep = getweapon(lf); bestwep = getbestweapon(lf); if (curwep != bestwep) { if (db) dblog(".oO { i have a better weapon than my current one (%s > %s) }",bestwep->type->name, curwep ? curwep->type->name : "nothing"); // weild better one if (!weild(lf, bestwep)) return; } // do we have a better firearm ? curgun = getfirearm(lf); bestgun = getbestfirearm(lf); if (curgun != bestgun) { if (db) dblog(".oO { i have a better gun than my current one (%s > %s) }",bestgun->type->name, curgun ? curgun->type->name : "nothing"); // weild better one if (!weild(lf, bestgun)) return; } // do we have better armour? for (bp = BP_RIGHTHAND ; bp < MAXBODYPARTS; bp++) { object_t *curarm; curarm = getarmour(lf, bp); // do we have a better one? for (o = lf->pack->first ; o ; o = o->next) { if (isbetterarmourthan(o, curarm)) { // wear this armour instead if (!wear(lf, o)) return; } } } // now check whetehr we have ANY weapon curwep = getattackwep(lf, &unarmedpile, &unarmedflag); if (unarmedpile) killobpile(unarmedpile); // before attacking targets, // look for any object which we _covet_. // ie. if we covet something, we will pick it up // instead of attacking our target. if (db) dblog(".oO { looking for covetted objects... }"); if (lookforobs(lf, B_COVETS)) { if (db) dblog(".oO { found covetted object. returning. }"); return; } // do we already have a target we are attacking? f = hasflag(lf->flags, F_TARGET); if (f) { int targid; int lastx,lasty; if (db) dblog(".oO { i have a target... }"); targid = f->val[0]; lastx = f->val[1]; lasty = f->val[2]; target = findlf(lf->cell->map, targid); if (target) { if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name); if (haslos(lf, target->cell)) { int goingtomove = B_TRUE; enum OBTYPE spell; object_t *gun; // reset F_TARGET lifetime to full. f->lifetime = AI_FOLLOWTIME; if (db) dblog(".oO { i can see my target (at %d,%d). will move towards it. }",target->cell->x,target->cell->y); // remember last known loc f->val[1] = target->cell->x; f->val[2] = target->cell->y; goingtomove = B_TRUE; // can we attack with spells (ie. ones which target the victim)? spell = getattackspell(lf); if (spell != OT_NONE) { int spellfailed = B_FALSE; lifeform_t *spelllf = NULL; cell_t *spellcell = NULL; object_t *spellob = NULL; if (db) { objecttype_t *st; st = findot(spell); dblog(".oO { will cast attack spell: %s }", st->name); } // special cases: eg. spells like telekenesis if (spell == OT_S_TELEKINESIS) { float maxweight; object_t *poss[MAXPILEOBS]; int nposs; int i; // find nearest object which can be picked up // this is copied out of the telekenesis spell code! maxweight = getlfweight(lf, B_NOOBS) + (getlfweight(lf, B_NOOBS) * (getstatmod(lf, A_IQ) / 100)); nposs = 0; for (i = 0; i < lf->nlos; i++) { object_t *o; for (o = lf->los[i]->obpile->first ; o ; o = o->next) { if (!hasflag(o->flags, F_NOPICKUP) && getobweight(o) <= maxweight) { poss[nposs] = o; nposs++; if (nposs >= MAXPILEOBS) break; } } if (nposs >= MAXPILEOBS) break; } if (nposs > 0) { spellob = poss[rnd(0,nposs-1)]; } else { spellfailed = B_TRUE; } // cast spell at the player spelllf = target; spellcell = target->cell; } else { spelllf = target; spellcell = target->cell; spellob = NULL; } if (!spellfailed && !castspell(lf, spell, spelllf, spellob, spellcell)) { // spell succesful return; } else { if (db) dblog(".oO { cast spell failed! }"); } } // can we attack by firing something? gun = getfirearm(lf); if (goingtomove && gun && getammo(lf)) { setguntarget(lf, target); if (!shoot(lf)) { // succesful return; } else { if (db) dblog(".oO { shoot gun failed! }"); } } // can we attack by throwing something? if (goingtomove && getcelldist(lf->cell, target->cell) > 1) { // TODO: or firing! check if we have a firearm first. o = getbestmissile(lf); if (o) { if (db) dblog(".oO { will throw %s at my target instead of moving }", o->type->name); // try to throw it! if (!throwat(lf, o, target->cell)) { // succesful goingtomove = B_FALSE; } else { if (db) dblog(".oO { throw failed! }"); } } } // do we have a valid melee attack? if (!curwep) { if (db) dblog(".oO { won't move towards target - i have no weapon. }"); goingtomove = B_FALSE; } if (goingtomove) { if (!movetowards(lf, target->cell)) { // success return; } else { if (db) dblog(".oO { move towards failed! - reason = %d }",reason); } } } else { if (db) dblog(".oO { i cannot see my target. moving to last known loc %d/%d }",lastx,lasty); // can't see target. // move towards their last known location instead addflag(lf->flags, F_TARGETCELL, lastx, lasty, NA, NULL); // remove f_target killflag(f); /* // just try to move in a random direction if (db) dblog(".oO { will move randomly }"); // dorandommove will call taketime() if it fails, // so it's safe to just return dorandommove(lf, B_NOBADMOVES); return; */ } } } /* if (lookforobs(lf, B_COVETS)) { if (db) dblog(".oO { found covetted object. returning. }"); return; } */ // do we have a target cell? f = hasflag(lf->flags, F_TARGETCELL); if (f) { // if so, move towards it x = f->val[0]; y = f->val[1]; if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y); c = getcellat(lf->cell->map, x, y); if (c) { if (movetowards(lf, c)) { // couldn't move towards it for some reason. // so stop trying. if (db) dblog(".oO { couldn't walk towards f_targetcell. abandoning it. }"); killflag(f); // remember NOT to target this one. lf->ignorecell = c; } else { if (db) dblog(".oO { successfully walked towards f_targetcell. }"); // moved towards it. // reset lifetime f->lifetime = AI_FOLLOWTIME; // are we there yet? if (lf->cell == c) { if (db) dblog(".oO { arrived at f_targetcell. removing. }"); killflag(f); } } } else { if (db) dblog(".oO { f_targetcell doesn't exist. abandoning. }"); // destination doesn't exist! killflag(f); // remember NOT to target this one. lf->ignorecell = c; } return; } // look for any object which we want if (db) dblog(".oO { looking for any ob which i want. }"); if (lookforobs(lf, B_ANY)) { if (db) dblog(".oO { found ob that i want. returning. }"); return; } // not attacking anyone in particular if (db) dblog(".oO { i do not have a target or can't move towards it. }"); // are we hostile? if so, look for a target f = hasflag(lf->flags, F_HOSTILE); if (f) { int x,y; if (db) dblog(".oO { i am hostile. looking for a target. }"); // look around for a target // TODO: use our vis rang einstead of 10! for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) { for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) { c = getcellat(lf->cell->map, x, y); // cell exists and we can see it? if (c && haslos(lf, c)) { // player there? if (c->lf && (c->lf != lf) && isplayer(c->lf)) { if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name); // target them! addtempflag(lf->flags, F_TARGET, c->lf->id, NA, NA, NULL, AI_FOLLOWTIME); // tell the player if (haslos(player, lf->cell)) { makenoise(lf, N_GETANGRY); } // then move towards them... if (db) dblog(".oO { moving towards my new target }"); if (curwep) { if (!movetowards(lf, c)) return; } else { if (db) dblog(".oO { won't move towards target - i have no weapon. }"); } } } } } } // are we friendly? if so, look for a target f = hasflag(lf->flags, F_FRIENDLY); if (f) { int x,y; if (db) dblog(".oO { i am friendly to the player. looking for a target. }"); // look around for a target // TODO: use our vis rang einstead of 10! for (y = lf->cell->y - 10; y <= lf->cell->y + 10; y++) { for (x = lf->cell->x - 10; x <= lf->cell->x + 10; x++) { c = getcellat(lf->cell->map, x, y); // cell exists and we can see it? if (c && haslos(lf, c)) { // player there? if (c->lf && (c->lf != lf) && !isplayer(c->lf)) { if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name); // target them! addtempflag(lf->flags, F_TARGET, c->lf->id, NA, NA, NULL, AI_FOLLOWTIME); // then move towards them... if (db) dblog(".oO { moving towards my new target }"); if (!movetowards(lf, c)) return; } } } } } // just try to move in a random direction if (db) dblog(".oO { default - moving randomly }"); dorandommove(lf, B_NOBADMOVES); return; // if we get this far, just wait rest(lf, B_TRUE); } int aipickup(lifeform_t *lf, object_t *o) { if (isedible(o)) { return eat(lf, o); } else { return pickup(lf, o, o->amt); } return B_FALSE; } enum OBTYPE getattackspell(lifeform_t *lf) { flag_t *f; enum OBTYPE poss[MAXPILEOBS]; int nposs = 0; int db = B_TRUE; for (f = lf->flags->first ; f ; f = f->next) { if (f->id == F_CANWILL) { poss[nposs] = f->val[0]; nposs++; } else if (f->id == F_CANCAST) { objecttype_t *ot; ot = findot(f->val[0]); if (cancast(lf, f->val[0], NULL)) { if (db) { dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?"); } poss[nposs] = f->val[0]; nposs++; } else { if (db) { if (ot) { dblog(".oO { can't cast %s right now (mpcost=%d, i have %d) }", ot ? ot->name : "?unkownspell?", getmpcost(ot->id), lf->mp); } else { dblog(".oO { can't cast ?unknownspell? right now }"); } } } } } // select a random one if (nposs > 0) { int sel; sel = rnd(0,nposs-1); return poss[sel]; } return OT_NONE; } object_t *hasbetterarmour(lifeform_t *lf, obpile_t *op) { object_t *o; for (o = op->first ; o ; o = o->next) { if (isarmour(o)) { object_t *curarm; enum BODYPART bp; flag_t *f; // where does it go? f = hasflag(o->flags, F_GOESON); bp = f->val[0]; // is it better than what we have in that position? curarm = getarmour(lf, bp); if (isbetterwepthan(o, curarm)) { return o; } } } return NULL; } object_t *hasbetterweapon(lifeform_t *lf, obpile_t *op) { object_t *bestwep, *o; bestwep = getbestweapon(lf); for (o = op->first ; o ; o = o->next) { if (isweapon(o) && isbetterwepthan(o, bestwep) && canweild(lf, o)) { return o; } } return NULL; } // returns B_TRUE if we did something int lookforobs(lifeform_t *lf, int covetsonly) { object_t *o; enum OBTYPE oid[MAXPILEOBS]; int noids = 0; enum FLAG wantflag[MAXPILEOBS]; int nwantflags = 0; int db = B_TRUE; flag_t *f; cell_t *c; int n; int i; // construct a list of objects which we want noids = 0; for (f = lf->flags->first ; f ; f = f->next) { if (f->id == F_WANTS) { if (!covetsonly || (f->val[1] == B_COVETS)) { oid[noids] = f->val[0]; noids++; } } else if (f->id == F_WANTSOBFLAG) { if (!covetsonly || (f->val[1] == B_COVETS)) { wantflag[nwantflags] = f->val[0]; nwantflags++; } } } // current cell has an object we want? o = hasobmulti(lf->cell->obpile, oid, noids); if (o && (canpickup(lf, o) || caneat(lf,o)) ) { if (db) dblog(".oO { current cell has ob i want (%s) }",o->type->name); // try to pick it up if (!aipickup(lf, o)) return B_TRUE; if (db) dblog(".oO { pickup of %s failed, trying to eat! }",o->type->name); if (!eat(lf, o)) return B_TRUE; if (db) dblog(".oO { eating %s failed }",o->type->name); } // has an object with a flag we want? for (n = 0; n < nwantflags; n++) { o = hasobwithflag(lf->cell->obpile, wantflag[n]); if (o && (canpickup(lf, o) || caneat(lf,o)) ) { if (db) dblog(".oO { current cell has ob with flag i want (%s) }",o->type->name); // try to pick it up if (!aipickup(lf, o)) return B_TRUE; if (db) dblog(".oO { pickup of %s with wantflag failed, trying to eat! }",o->type->name); if (!eat(lf, o)) return B_TRUE; if (db) dblog(".oO { eating %s with wantflag failed }",o->type->name); } } // current cell has better weapon? f = hasflag(lf->flags, F_WANTSBETTERWEP); if (f ) { if (!covetsonly || (f->val[1] == B_COVETS)) { o = hasbetterweapon(lf, lf->cell->obpile); if (o && canpickup(lf, o)) { if (db) dblog(".oO { current cell has better weapon (%s) }",o->type->name); // try to pick it up if (!aipickup(lf, o)) return B_TRUE; if (db) dblog(".oO { pickup of better wep %s failed! }",o->type->name); } } } // current cell has better armour? f = hasflag(lf->flags, F_WANTSBETTERARM); if (f ) { if (!covetsonly || (f->val[1] == B_COVETS)) { o = hasbetterarmour(lf, lf->cell->obpile); if (o && canpickup(lf, o)) { if (db) dblog(".oO { current cell has better armour (%s) }",o->type->name); // try to pick it up if (!aipickup(lf, o)) return B_TRUE; if (db) dblog(".oO { pickup of better armour %s failed! }",o->type->name); } } } // look around for objects which we want, if we don't already have a targetcell. if (!hasflag(lf->flags, F_TARGETCELL)) { if (db) dblog(".oO { no targetcell, so looking for remote objects }"); for (i = 0 ; i < lf->nlos; i++) { int gothere = B_FALSE; c = lf->los[i]; if (c != lf->ignorecell) { o = hasobmulti(c->obpile, oid, noids); if (o && (canpickup(lf, o) || caneat(lf,o)) ) { if (db) dblog(".oO { remote cell has ob i want (%s). setting f_targetcell. }",o->type->name); gothere = B_TRUE; } if (!gothere) { // has an object with a flag we want? for (n = 0; n < nwantflags; n++) { o = hasobwithflag(c->obpile, wantflag[n]); if (o && (canpickup(lf, o) || caneat(lf, o)) ) { if (db) dblog(".oO { remote cell has ob with flag i want (%s) }", o->type->name); gothere = B_TRUE; } } } if (!gothere) { // remote cell has better weapon? f = hasflag(lf->flags, F_WANTSBETTERWEP); if (f) { if (!covetsonly || (f->val[1] == B_COVETS)) { o = hasbetterweapon(lf, c->obpile); if (o && canpickup(lf, o)) { if (db) dblog(".oO { remote cell has better weapon (%s). setting f_targetcell }",o->type->name); gothere = B_TRUE; } } } } if (!gothere) { // remote cell has better armour? f = hasflag(lf->flags, F_WANTSBETTERARM); if (f) { if (!covetsonly || (f->val[1] == B_COVETS)) { o = hasbetterarmour(lf, c->obpile); if (o && canpickup(lf, o)) { if (db) dblog(".oO { remote cell has better armour (%s). setting f_targetcell }",o->type->name); gothere = B_TRUE; } } } } if (gothere) { // start walking towards target cell addtempflag(lf->flags, F_TARGETCELL, c->x, c->y, NA, NULL, AI_FOLLOWTIME); // forget about people we are attacking killflagsofid(lf->flags, F_TARGET); return B_TRUE; } } } } return B_FALSE; }