2010-12-02 12:17:54 +11:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2011-03-18 12:25:18 +11:00
|
|
|
#include <string.h>
|
2010-12-02 12:17:54 +11:00
|
|
|
#include "ai.h"
|
2011-02-01 06:16:13 +11:00
|
|
|
#include "attack.h"
|
2010-12-02 12:17:54 +11:00
|
|
|
#include "defs.h"
|
|
|
|
#include "flag.h"
|
2011-02-01 06:16:13 +11:00
|
|
|
#include "io.h"
|
2010-12-02 12:17:54 +11:00
|
|
|
#include "lf.h"
|
|
|
|
#include "map.h"
|
2011-02-01 06:16:13 +11:00
|
|
|
#include "move.h"
|
|
|
|
#include "nexus.h"
|
2010-12-02 12:17:54 +11:00
|
|
|
#include "objects.h"
|
2011-02-01 06:16:13 +11:00
|
|
|
#include "spell.h"
|
|
|
|
#include "text.h"
|
2010-12-02 12:17:54 +11:00
|
|
|
|
|
|
|
extern lifeform_t *player;
|
2011-02-01 06:16:13 +11:00
|
|
|
extern enum ERROR reason;
|
2010-12-02 12:17:54 +11:00
|
|
|
|
2011-02-16 05:21:33 +11:00
|
|
|
int wantdb = B_TRUE;
|
|
|
|
|
2011-03-25 12:23:15 +11:00
|
|
|
void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) {
|
|
|
|
int db = B_FALSE;
|
2011-04-01 10:54:44 +11:00
|
|
|
flag_t *f;
|
2011-03-25 12:23:15 +11:00
|
|
|
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-04-01 10:54:44 +11:00
|
|
|
// already targetting this lf?
|
|
|
|
f = lfhasflagval(lf, F_TARGET, victim->id, NA, NA, NULL);
|
|
|
|
if (f) {
|
|
|
|
if ((f->lifetime > 0) && (f->lifetime < timelimit)) {
|
|
|
|
f->lifetime = timelimit;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-03-25 12:23:15 +11:00
|
|
|
if (db) {
|
|
|
|
char lfname[BUFLEN],vicname[BUFLEN];
|
|
|
|
getlfname(lf, lfname);
|
|
|
|
getlfname(victim, vicname);
|
|
|
|
dblog(".oO { %s settings new target: %s }", lfname, vicname);
|
|
|
|
}
|
|
|
|
|
|
|
|
killflagsofid(lf->flags, F_TARGET);
|
|
|
|
killflagsofid(lf->flags, F_TARGETCELL);
|
|
|
|
|
|
|
|
|
|
|
|
if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) {
|
|
|
|
addflag(lf->flags, F_TARGET, victim->id, victim->cell->x, victim->cell->y, NULL);
|
|
|
|
} else {
|
|
|
|
addtempflag(lf->flags, F_TARGET, victim->id , victim->cell->x , victim->cell->y, NULL,timelimit);
|
|
|
|
}
|
|
|
|
// tell the player
|
|
|
|
if (cansee(player, lf)) {
|
|
|
|
makenoise(lf, N_GETANGRY);
|
|
|
|
}
|
|
|
|
|
|
|
|
// change allegience ?
|
|
|
|
if (!areenemies(lf, victim)) {
|
|
|
|
if (getallegiance(victim) == AL_FRIENDLY) {
|
|
|
|
if (!hasflag(lf->flags, F_HOSTILE)) {
|
|
|
|
addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2011-03-04 12:22:36 +11:00
|
|
|
|
|
|
|
enum OBTYPE aigetattackspell(lifeform_t *lf, lifeform_t *victim) {
|
2011-02-16 05:21:33 +11:00
|
|
|
flag_t *f;
|
|
|
|
enum OBTYPE poss[MAXPILEOBS];
|
|
|
|
int nposs = 0;
|
|
|
|
int db = B_FALSE;
|
|
|
|
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
2011-03-04 12:22:36 +11:00
|
|
|
if ((f->id == F_CANCAST) || (f->id == F_CANWILL)) {
|
2011-03-18 12:25:18 +11:00
|
|
|
if (aispellok(lf, f->val[0], victim, F_AICASTTOATTACK)) {
|
|
|
|
poss[nposs] = f->val[0];
|
|
|
|
nposs++;
|
2011-02-16 05:21:33 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// select a random one
|
|
|
|
if (nposs > 0) {
|
|
|
|
int sel;
|
|
|
|
sel = rnd(0,nposs-1);
|
|
|
|
return poss[sel];
|
|
|
|
}
|
|
|
|
|
|
|
|
return OT_NONE;
|
|
|
|
}
|
|
|
|
|
2011-03-16 15:45:46 +11:00
|
|
|
enum OBTYPE aigetfleespell(lifeform_t *lf) {
|
|
|
|
flag_t *f;
|
|
|
|
enum OBTYPE poss[MAXPILEOBS];
|
|
|
|
int nposs = 0;
|
|
|
|
int db = B_FALSE;
|
2011-03-18 12:25:18 +11:00
|
|
|
lifeform_t *fleefrom;
|
2011-03-16 15:45:46 +11:00
|
|
|
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-03-18 12:25:18 +11:00
|
|
|
f = lfhasflag(lf, F_FLEEFROM);
|
|
|
|
if (f) {
|
|
|
|
fleefrom = findlf(lf->cell->map, f->val[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-16 15:45:46 +11:00
|
|
|
for (f = lf->flags->first ; f ; f = f->next) {
|
|
|
|
if ((f->id == F_CANCAST) || (f->id == F_CANWILL)) {
|
2011-03-18 12:25:18 +11:00
|
|
|
if (aispellok(lf, f->val[0], fleefrom, F_AICASTTOFLEE)) {
|
|
|
|
poss[nposs] = f->val[0];
|
|
|
|
nposs++;
|
2011-03-16 15:45:46 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// select a random one
|
|
|
|
if (nposs > 0) {
|
|
|
|
int sel;
|
|
|
|
sel = rnd(0,nposs-1);
|
|
|
|
return poss[sel];
|
|
|
|
}
|
|
|
|
|
|
|
|
return OT_NONE;
|
|
|
|
}
|
|
|
|
|
2011-03-18 12:25:18 +11:00
|
|
|
void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose) {
|
|
|
|
int specialcase = B_FALSE;
|
|
|
|
flag_t *f;
|
|
|
|
|
|
|
|
// default - at victim.
|
|
|
|
if (spelllf) *spelllf = victim;
|
|
|
|
if (spellcell) *spellcell = victim->cell;
|
|
|
|
if (spellob) *spellob = NULL;
|
|
|
|
|
|
|
|
f = hasflag(spelltype->flags, purpose);
|
|
|
|
if (f) {
|
|
|
|
switch (f->val[0]) {
|
|
|
|
case ST_VICTIM:
|
|
|
|
// at victim.
|
|
|
|
if (spelllf) *spelllf = victim;
|
|
|
|
if (spellcell) *spellcell = victim->cell;
|
|
|
|
if (spellob) *spellob = NULL;
|
|
|
|
break;
|
|
|
|
case ST_ADJSELF: // cast at myself when next to victim
|
|
|
|
if (getcelldist(lf->cell, victim->cell) <= 1) {
|
|
|
|
if (spelllf) *spelllf = lf;
|
|
|
|
if (spellcell) *spellcell = lf->cell;
|
|
|
|
if (spellob) *spellob = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ST_ADJVICTIM: // cast at victim when next to victim
|
|
|
|
if (getcelldist(lf->cell, victim->cell) <= 1) {
|
|
|
|
if (spelllf) *spelllf = victim;
|
|
|
|
if (spellcell) *spellcell = victim->cell;
|
|
|
|
if (spellob) *spellob = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ST_SELF:
|
|
|
|
if (spelllf) *spelllf = lf;
|
|
|
|
if (spellcell) *spellcell = lf->cell;
|
|
|
|
if (spellob) *spellob = NULL;
|
|
|
|
break;
|
|
|
|
case ST_ANYWHERE:
|
|
|
|
if (spelllf) *spelllf = NULL;
|
|
|
|
if (spellcell) *spellcell = NULL;
|
|
|
|
if (spellob) *spellob = NULL;
|
|
|
|
break;
|
|
|
|
case ST_SPECIAL:
|
|
|
|
specialcase = B_TRUE;
|
|
|
|
break;
|
2011-03-04 12:22:36 +11:00
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
|
|
|
|
if (specialcase) {
|
|
|
|
if (spelltype->id == 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;
|
|
|
|
}
|
|
|
|
// should always be true since we check this in aispellok
|
|
|
|
if (nposs > 0) {
|
|
|
|
if (spellob) *spellob = poss[rnd(0,nposs-1)];
|
|
|
|
}
|
|
|
|
|
|
|
|
// cast spell at the victim
|
|
|
|
if (spelllf) *spelllf = victim;
|
|
|
|
if (spellcell) *spellcell = victim->cell;
|
2011-03-24 16:09:31 +11:00
|
|
|
} else if (spelltype->id == OT_S_CHARM) {
|
|
|
|
lifeform_t *l;
|
|
|
|
l = getnearbypeaceful(lf);
|
|
|
|
if (l) {
|
|
|
|
if (spelllf) *spelllf = l;
|
|
|
|
if (spellcell) *spellcell = l->cell;
|
|
|
|
if (spellob) *spellob = NULL;
|
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
}
|
2011-03-04 12:22:36 +11:00
|
|
|
}
|
2011-02-16 05:21:33 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-18 12:25:18 +11:00
|
|
|
object_t *aigetwand(lifeform_t *lf, enum FLAG purpose) {
|
2011-02-16 05:21:33 +11:00
|
|
|
object_t *o;
|
|
|
|
object_t *poss[MAXPILEOBS];
|
|
|
|
int nposs = 0;
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
|
|
// wand with charges left?
|
|
|
|
if ((o->type->obclass->id == OC_WAND) && (getcharges(o) > 0)) {
|
|
|
|
// do we know how to use it?
|
2011-03-18 12:25:18 +11:00
|
|
|
if (hasflag(o->flags, purpose)) {
|
2011-03-16 15:45:46 +11:00
|
|
|
// TODO: if castatself, check whether we actually need to (ie. healing, invis, etc)
|
2011-02-16 05:21:33 +11:00
|
|
|
poss[nposs] = o;
|
|
|
|
nposs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nposs > 0) {
|
|
|
|
return poss[rnd(0,nposs-1)];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-03-25 12:23:15 +11:00
|
|
|
void aigoto(lifeform_t *lf, cell_t *c, int timelimit) {
|
|
|
|
int db = B_FALSE;
|
|
|
|
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (db) {
|
|
|
|
char lfname[BUFLEN];
|
|
|
|
getlfname(lf, lfname);
|
|
|
|
dblog(".oO { %s going to targecell: %d, %d }", lfname, c->x, c->y);
|
|
|
|
}
|
|
|
|
|
|
|
|
killflagsofid(lf->flags, F_TARGET);
|
|
|
|
killflagsofid(lf->flags, F_TARGETCELL);
|
|
|
|
|
|
|
|
|
|
|
|
if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) {
|
|
|
|
addflag(lf->flags, F_TARGETCELL, c->x, c->y, NA, NULL);
|
|
|
|
} else {
|
|
|
|
addtempflag(lf->flags, F_TARGETCELL, c->x, c->y, NA, NULL,timelimit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-02 12:17:54 +11:00
|
|
|
void aimove(lifeform_t *lf) {
|
2010-12-07 18:34:26 +11:00
|
|
|
int db = B_FALSE;
|
2011-02-01 06:16:13 +11:00
|
|
|
object_t *curwep,*bestwep, *o;
|
|
|
|
object_t *curgun,*bestgun;
|
2010-12-02 12:17:54 +11:00
|
|
|
flag_t *f;
|
2011-02-01 06:16:13 +11:00
|
|
|
//flag_t *nextf;
|
|
|
|
// lifeform_t *fleefrom = NULL;
|
2010-12-02 12:17:54 +11:00
|
|
|
lifeform_t *target;
|
2011-02-01 06:16:13 +11:00
|
|
|
enum BODYPART bp;
|
|
|
|
int x,y;
|
|
|
|
cell_t *c;
|
|
|
|
obpile_t *unarmedpile = NULL;
|
|
|
|
flag_t *unarmedflag = NULL;
|
|
|
|
|
2010-12-07 18:34:26 +11:00
|
|
|
|
|
|
|
|
2011-02-16 05:21:33 +11:00
|
|
|
/*
|
2010-12-07 18:34:26 +11:00
|
|
|
if (wantdb && haslos(player, lf->cell)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
} else {
|
|
|
|
db = B_FALSE;
|
|
|
|
}
|
2011-02-16 05:21:33 +11:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (wantdb && lfhasflag(lf, F_DEBUG)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
} else {
|
|
|
|
db = B_FALSE;
|
|
|
|
}
|
2010-12-07 18:34:26 +11:00
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
if (db) {
|
|
|
|
char lfname[BUFLEN];
|
2011-03-25 12:23:15 +11:00
|
|
|
real_getlfname(lf, lfname, B_FALSE);
|
2011-02-01 06:16:13 +11:00
|
|
|
dblog("AIMOVE: %s", lfname);
|
|
|
|
}
|
2010-12-07 18:34:26 +11:00
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
/*
|
2010-12-02 12:17:54 +11:00
|
|
|
// if lifeform isn't alive, skip turn
|
|
|
|
if (isdead(lf)) {
|
2010-12-07 18:34:26 +11:00
|
|
|
if (db) dblog(".oO { i am not alive, skipping turn. }");
|
2010-12-02 12:17:54 +11:00
|
|
|
taketime(lf, SPEED_DEAD);
|
|
|
|
return;
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
*/
|
|
|
|
|
2010-12-02 12:17:54 +11:00
|
|
|
|
|
|
|
|
2010-12-07 18:34:26 +11:00
|
|
|
// 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
|
2011-02-01 06:16:13 +11:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-03-04 12:22:36 +11:00
|
|
|
// do we have better ammo?
|
|
|
|
if (curgun) {
|
|
|
|
object_t *curammo;
|
|
|
|
curammo = getammo(lf);
|
|
|
|
if (!curammo) {
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
|
|
testammo(lf, o); // doesn't take any time.
|
|
|
|
if (getammo(lf)) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
// 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) {
|
2011-04-01 10:54:44 +11:00
|
|
|
if (canwear(lf, o, BP_NONE) && isbetterarmourthan(o, curarm)) {
|
2011-02-01 06:16:13 +11:00
|
|
|
// 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. }");
|
2010-12-07 18:34:26 +11:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// do we already have a target we are attacking?
|
2010-12-02 12:17:54 +11:00
|
|
|
f = hasflag(lf->flags, F_TARGET);
|
|
|
|
if (f) {
|
|
|
|
int targid;
|
2011-02-01 06:16:13 +11:00
|
|
|
int lastx,lasty;
|
2010-12-07 18:34:26 +11:00
|
|
|
if (db) dblog(".oO { i have a target... }");
|
2010-12-02 12:17:54 +11:00
|
|
|
targid = f->val[0];
|
2011-02-01 06:16:13 +11:00
|
|
|
lastx = f->val[1];
|
|
|
|
lasty = f->val[2];
|
2010-12-02 12:17:54 +11:00
|
|
|
target = findlf(lf->cell->map, targid);
|
|
|
|
if (target) {
|
2010-12-07 18:34:26 +11:00
|
|
|
if (db) dblog(".oO { my target is lfid %d (%s). }", targid, target->race->name);
|
2011-03-16 15:45:46 +11:00
|
|
|
if (cansee(lf, target)) {
|
2011-02-01 06:16:13 +11:00
|
|
|
int goingtomove = B_TRUE;
|
|
|
|
enum OBTYPE spell;
|
|
|
|
object_t *gun;
|
|
|
|
|
|
|
|
// reset F_TARGET lifetime to full.
|
|
|
|
f->lifetime = AI_FOLLOWTIME;
|
2011-03-04 12:22:36 +11:00
|
|
|
if (db) dblog(".oO { i can see my target (at %d,%d). might move towards it. }",target->cell->x,target->cell->y);
|
2011-02-01 06:16:13 +11:00
|
|
|
// remember last known loc
|
|
|
|
f->val[1] = target->cell->x;
|
|
|
|
f->val[2] = target->cell->y;
|
|
|
|
|
|
|
|
goingtomove = B_TRUE;
|
|
|
|
|
|
|
|
|
2011-03-04 12:22:36 +11:00
|
|
|
// drink boost potions
|
|
|
|
if (!useitemwithflag(lf, F_AIBOOSTITEM)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-03-24 16:09:31 +11:00
|
|
|
|
|
|
|
|
|
|
|
if (goingtomove && (getcelldist(lf->cell, target->cell) == 1)) {
|
|
|
|
}
|
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
// can we attack with spells (ie. ones which target the victim)?
|
2011-03-24 16:09:31 +11:00
|
|
|
// if target is adjacent, we will normally just attack rather than try a spell.
|
2011-03-04 12:22:36 +11:00
|
|
|
spell = aigetattackspell(lf, target);
|
2011-03-24 16:09:31 +11:00
|
|
|
if ( (spell != OT_NONE) && // found a valid spell/ability to use
|
|
|
|
((getcelldist(lf->cell, target->cell) != 1) || (rnd(1,3) == 1))
|
|
|
|
) {
|
2011-02-01 06:16:13 +11:00
|
|
|
int spellfailed = B_FALSE;
|
|
|
|
lifeform_t *spelllf = NULL;
|
|
|
|
cell_t *spellcell = NULL;
|
|
|
|
object_t *spellob = NULL;
|
2011-02-16 05:21:33 +11:00
|
|
|
objecttype_t *st;
|
|
|
|
st = findot(spell);
|
2011-02-01 06:16:13 +11:00
|
|
|
if (db) {
|
|
|
|
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 {
|
2011-02-16 05:21:33 +11:00
|
|
|
// pick targets based on spell flags
|
2011-03-18 12:25:18 +11:00
|
|
|
aigetspelltarget(lf, st, target, &spelllf, &spellcell, &spellob, F_AICASTTOATTACK);
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
|
2011-03-04 12:22:36 +11:00
|
|
|
if (spellfailed) {
|
|
|
|
if (db) dblog(".oO { cast spell/ability failed (1)! }");
|
|
|
|
} else {
|
|
|
|
if (getschool(spell) == SS_ABILITY) {
|
|
|
|
spellfailed = useability(lf, spell, spelllf, spellcell);
|
|
|
|
} else {
|
|
|
|
spellfailed = castspell(lf, spell, spelllf, spellob, spellcell);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (spellfailed) {
|
2011-03-25 12:23:15 +11:00
|
|
|
if (db) dblog(".oO { cast spell/ability tried but failed (2)! reason = %d }", reason);
|
2011-03-04 12:22:36 +11:00
|
|
|
} else {
|
2011-02-01 06:16:13 +11:00
|
|
|
// spell succesful
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-16 05:21:33 +11:00
|
|
|
// if not adjacent, check for guns, wands, throwing
|
2011-03-24 16:09:31 +11:00
|
|
|
if (goingtomove && (getcelldist(lf->cell, target->cell) > 1) && haslof(lf, target->cell, B_FALSE, NULL)) {
|
2011-04-01 10:54:44 +11:00
|
|
|
// can we attack by firing a weapon?
|
2011-02-16 05:21:33 +11:00
|
|
|
gun = getfirearm(lf);
|
|
|
|
if (goingtomove && gun && getammo(lf)) {
|
2011-03-04 12:22:36 +11:00
|
|
|
if (db) {
|
|
|
|
char gunname[BUFLEN];
|
|
|
|
getobname(gun, gunname, gun->amt);
|
|
|
|
dblog(".oO { will fire my gun (%s) at target. }",gunname);
|
|
|
|
}
|
2011-02-16 05:21:33 +11:00
|
|
|
setguntarget(lf, target);
|
|
|
|
if (!shoot(lf)) {
|
|
|
|
// succesful
|
|
|
|
return;
|
|
|
|
} else {
|
2011-03-04 12:22:36 +11:00
|
|
|
if (db) dblog(".oO { shoot gun failed! reason = %d }", reason);
|
2011-02-16 05:21:33 +11:00
|
|
|
}
|
2011-03-04 12:22:36 +11:00
|
|
|
} else {
|
|
|
|
if (db) dblog(".oO { not firing out gun }");
|
2011-02-16 05:21:33 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// can we attack by throwing something?
|
2011-04-01 10:54:44 +11:00
|
|
|
if (goingtomove && hasbp(lf, BP_HANDS)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
o = getbestthrowmissile(lf);
|
2011-02-16 05:21:33 +11:00
|
|
|
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! }");
|
|
|
|
}
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
|
2011-02-16 05:21:33 +11:00
|
|
|
// do we have a wand we can zap?
|
2011-04-01 10:54:44 +11:00
|
|
|
if (lfhasflag(lf, F_HUMANOID) || hasbp(lf, BP_HANDS)) {
|
|
|
|
if (lfhasflag(lf, F_FLEEFROM)) {
|
|
|
|
o = aigetwand(lf, F_AICASTTOFLEE);
|
2011-02-16 05:21:33 +11:00
|
|
|
} else {
|
2011-04-01 10:54:44 +11:00
|
|
|
o = aigetwand(lf, F_AICASTTOATTACK);
|
2011-02-16 05:21:33 +11:00
|
|
|
}
|
2011-04-01 10:54:44 +11:00
|
|
|
if (o) {
|
|
|
|
objecttype_t *st;
|
|
|
|
cell_t *zapcell = NULL;
|
|
|
|
|
|
|
|
st = getlinkspell(o);
|
|
|
|
if (st) {
|
|
|
|
enum FLAG purpose;
|
|
|
|
if (lfhasflag(lf, F_FLEEFROM)) {
|
|
|
|
purpose = F_AICASTTOFLEE;
|
|
|
|
} else {
|
|
|
|
purpose = F_AICASTTOATTACK;
|
|
|
|
}
|
|
|
|
aigetspelltarget(lf, st, target, NULL, &zapcell, NULL, purpose);
|
|
|
|
} else {
|
|
|
|
// no linkspell - just zap it.
|
|
|
|
zapcell = NULL;
|
|
|
|
}
|
2011-02-16 05:21:33 +11:00
|
|
|
|
2011-04-01 10:54:44 +11:00
|
|
|
// zap it
|
|
|
|
if (db) dblog(".oO { will zap %s instead of moving }", o->type->name);
|
2011-02-16 05:21:33 +11:00
|
|
|
|
2011-04-01 10:54:44 +11:00
|
|
|
if (!operate(lf, o, zapcell)) {
|
|
|
|
// succesful
|
|
|
|
goingtomove = B_FALSE;
|
|
|
|
} else {
|
|
|
|
if (db) dblog(".oO { zap failed! }");
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
2011-02-16 05:21:33 +11:00
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2011-04-01 10:54:44 +11:00
|
|
|
if (!movetowards(lf, target->cell, DT_ORTH)) {
|
2011-02-01 06:16:13 +11:00
|
|
|
// success
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (db) dblog(".oO { move towards failed! - reason = %d }",reason);
|
|
|
|
}
|
|
|
|
}
|
2010-12-02 12:17:54 +11:00
|
|
|
} else {
|
2011-03-25 12:23:15 +11:00
|
|
|
cell_t *targcell;
|
2011-02-01 06:16:13 +11:00
|
|
|
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
|
2011-03-25 12:23:15 +11:00
|
|
|
targcell = getcellat(lf->cell->map, lastx, lasty);
|
|
|
|
if (targcell) {
|
|
|
|
aigoto(lf, targcell, PERMENANT);
|
|
|
|
} else {
|
|
|
|
if (db) dblog(".oO { go to target's last known loc failed! }");
|
|
|
|
}
|
2010-12-02 12:17:54 +11:00
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
/*
|
2010-12-02 12:17:54 +11:00
|
|
|
// just try to move in a random direction
|
2010-12-07 18:34:26 +11:00
|
|
|
if (db) dblog(".oO { will move randomly }");
|
2011-02-01 06:16:13 +11:00
|
|
|
// dorandommove will call taketime() if it fails,
|
|
|
|
// so it's safe to just return
|
2010-12-07 18:34:26 +11:00
|
|
|
dorandommove(lf, B_NOBADMOVES);
|
2010-12-02 12:17:54 +11:00
|
|
|
return;
|
2011-02-01 06:16:13 +11:00
|
|
|
*/
|
2010-12-02 12:17:54 +11:00
|
|
|
}
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2011-04-01 10:54:44 +11:00
|
|
|
if (movetowards(lf, c, DT_ORTH)) {
|
2011-02-01 06:16:13 +11:00
|
|
|
// 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 {
|
2011-03-25 12:23:15 +11:00
|
|
|
if (db) dblog(".oO { successfully walked towards f_targetcell. arrived at %d,%d }",lf->cell->x, lf->cell->y);
|
2011-02-01 06:16:13 +11:00
|
|
|
// 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
|
2011-03-24 16:09:31 +11:00
|
|
|
switch (getallegiance(lf)) {
|
2011-02-16 05:21:33 +11:00
|
|
|
int i;
|
2011-02-01 06:16:13 +11:00
|
|
|
int x,y;
|
2011-03-24 16:09:31 +11:00
|
|
|
case AL_HOSTILE:
|
|
|
|
if (db) dblog(".oO { i am hostile. looking for a target. }");
|
|
|
|
|
|
|
|
// look around for a target
|
|
|
|
for (i = 0; i < lf->nlos; i++) {
|
|
|
|
cell_t *c;
|
|
|
|
c = lf->los[i];
|
|
|
|
|
|
|
|
if (c->lf && cansee(lf, c->lf)) {
|
|
|
|
if (isplayer(c->lf)) { // TODO: change to if isenemy ?
|
2011-02-01 06:16:13 +11:00
|
|
|
if (db) dblog(".oO { found a target - lfid %d (%s) ! }",c->lf->id, c->lf->race->name);
|
2011-03-25 12:23:15 +11:00
|
|
|
|
|
|
|
aiattack(lf, c->lf, AI_FOLLOWTIME);
|
2011-02-01 06:16:13 +11:00
|
|
|
// then move towards them...
|
|
|
|
if (db) dblog(".oO { moving towards my new target }");
|
2011-03-24 16:09:31 +11:00
|
|
|
|
|
|
|
if (curwep) {
|
2011-04-01 10:54:44 +11:00
|
|
|
if (!movetowards(lf, c, DT_ORTH)) return;
|
2011-03-24 16:09:31 +11:00
|
|
|
} else {
|
|
|
|
if (db) dblog(".oO { won't move towards target - i have no weapon. }");
|
|
|
|
}
|
|
|
|
break;
|
2010-12-02 12:17:54 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-03-24 16:09:31 +11:00
|
|
|
break;
|
|
|
|
case AL_FRIENDLY: // are we friendly? if so, look for a target
|
|
|
|
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 && c->lf && (c->lf != lf) && cansee(lf, c->lf)) {
|
|
|
|
// player there?
|
|
|
|
if (!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, c->x, c->y, NULL, AI_FOLLOWTIME);
|
|
|
|
// then move towards them...
|
|
|
|
if (db) dblog(".oO { moving towards my new target }");
|
2011-04-01 10:54:44 +11:00
|
|
|
if (!movetowards(lf, c, DT_ORTH)) return;
|
2011-03-24 16:09:31 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
2010-12-02 12:17:54 +11:00
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
|
2011-02-16 05:21:33 +11:00
|
|
|
// need to heal?
|
|
|
|
if ((lf->hp < lf->maxhp) ||
|
2011-03-22 18:06:28 +11:00
|
|
|
((lf->mp < getmaxmp(lf)) && lfhasflag(lf, F_RESTHEALMPAMT)) ) {
|
2011-03-04 12:22:36 +11:00
|
|
|
if (lf->hp < (lf->maxhp/2)) {
|
|
|
|
if (!useitemwithflag(lf, F_AIHEALITEM)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-16 05:21:33 +11:00
|
|
|
if (db) dblog(".oO { resting }");
|
|
|
|
rest(lf, B_TRUE);
|
|
|
|
}
|
|
|
|
|
2011-03-16 15:45:46 +11:00
|
|
|
// need to train skills?
|
|
|
|
if (lf->skillpoints || lfhasflag(lf, F_STATGAINREADY)) {
|
|
|
|
if (canrest(lf)) {
|
|
|
|
// special case - monsters don't need to actually rest to gain
|
|
|
|
// skills, although they DO still need to wait until the player
|
|
|
|
// is out of sight.
|
|
|
|
enhanceskills(lf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
// just try to move in a random direction
|
|
|
|
if (db) dblog(".oO { default - moving randomly }");
|
|
|
|
dorandommove(lf, B_NOBADMOVES);
|
|
|
|
return;
|
2010-12-02 12:17:54 +11:00
|
|
|
|
|
|
|
// if we get this far, just wait
|
2011-02-01 06:16:13 +11:00
|
|
|
rest(lf, B_TRUE);
|
2010-12-02 12:17:54 +11:00
|
|
|
}
|
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
int aipickup(lifeform_t *lf, object_t *o) {
|
|
|
|
if (isedible(o)) {
|
|
|
|
return eat(lf, o);
|
|
|
|
} else {
|
2011-02-16 05:21:33 +11:00
|
|
|
return pickup(lf, o, o->amt, B_TRUE);
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
|
2011-03-16 15:45:46 +11:00
|
|
|
int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target) {
|
|
|
|
switch (o->type->id) {
|
|
|
|
case OT_POT_INVIS:
|
|
|
|
case OT_WAND_INVIS:
|
|
|
|
if (lfhasflag(target, F_INVISIBLE)) {
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OT_POT_INVULN:
|
|
|
|
if (lfhasflag(target, F_INVULNERABLE)) {
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return B_TRUE;
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
|
2011-03-18 12:25:18 +11:00
|
|
|
// is the spell 'spellid' okay for AI lifeform 'lf' to cast at 'victim', for given purpose.
|
|
|
|
// purpose could be F_AICASTTOFLEE or F_ATCASTTOATTACK
|
|
|
|
int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG purpose) {
|
|
|
|
objecttype_t *ot;
|
|
|
|
flag_t *f;
|
|
|
|
int db = B_FALSE;
|
|
|
|
int ok = B_FALSE;
|
|
|
|
int specialcase = B_FALSE;
|
2011-03-24 16:09:31 +11:00
|
|
|
int specificcheckok = B_FALSE;
|
2011-03-18 12:25:18 +11:00
|
|
|
|
|
|
|
if (lfhasflag(lf, F_DEBUG)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
}
|
|
|
|
ot = findot(spellid);
|
|
|
|
|
|
|
|
// enough mp etc?
|
|
|
|
if (!cancast(lf, spellid, NULL)) {
|
|
|
|
if (db) {
|
|
|
|
char why[BUFLEN];
|
|
|
|
if (reason == E_NOMP) {
|
|
|
|
strcpy(why, "not enough mp");
|
|
|
|
} else if (reason == E_TOOPOWERFUL) {
|
|
|
|
strcpy(why, "spell too powerful");
|
|
|
|
} else if (reason == E_NOTREADY) {
|
|
|
|
strcpy(why, "abil not ready");
|
2011-03-22 18:06:28 +11:00
|
|
|
} else if (reason == E_NEEDGRAB) {
|
|
|
|
strcpy(why, "needs grab");
|
2011-03-18 12:25:18 +11:00
|
|
|
} else {
|
|
|
|
strcpy(why, "unknown reason");
|
|
|
|
}
|
2011-03-22 18:06:28 +11:00
|
|
|
if (db) {
|
|
|
|
if (ot) {
|
|
|
|
dblog(".oO { can't cast %s right now (%s) (mpcost=%d, i have %d) }",
|
|
|
|
ot ? ot->name : "?unkownspell?", why,
|
|
|
|
getmpcost(lf, ot->id), lf->mp);
|
|
|
|
} else {
|
|
|
|
dblog(".oO { can't cast ?unknownspell? right now }");
|
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
|
2011-03-22 18:06:28 +11:00
|
|
|
// boost spell already active?
|
|
|
|
if (hasflag(ot->flags, F_ONGOING)) {
|
|
|
|
if (lfhasflagval(lf, F_BOOSTSPELL, ot->id, NA, NA, NULL)) {
|
|
|
|
if (db) {
|
|
|
|
dblog(".oO { can't cast %s - it is already active.", ot ? ot->name : "?unkownspell?");
|
|
|
|
}
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-18 12:25:18 +11:00
|
|
|
f = hasflag(ot->flags, purpose);
|
|
|
|
if (f) {
|
|
|
|
int range;
|
|
|
|
switch (f->val[0]) {
|
|
|
|
case ST_VICTIM:
|
|
|
|
range = getspellrange(spellid, getspellpower(lf, spellid));
|
|
|
|
if ((range == UNLIMITED) || (getcelldist(lf->cell, victim->cell) <= range)) {
|
|
|
|
if (db) {
|
|
|
|
dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?");
|
|
|
|
}
|
|
|
|
ok = B_TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ST_SELF:
|
|
|
|
case ST_ANYWHERE:
|
|
|
|
if (db) {
|
|
|
|
dblog(".oO { spell possibility: %s }", ot ? ot->name : "?unkownspell?");
|
|
|
|
}
|
|
|
|
ok = B_TRUE;
|
|
|
|
break;
|
|
|
|
case ST_ADJVICTIM:
|
|
|
|
if (getcelldist(lf->cell,victim->cell) == 1) {
|
|
|
|
if (ot->id == OT_A_GRAB) {
|
|
|
|
if (lfhasflag(lf, F_GRABBING) || lfhasflag(lf, F_GRABBEDBY) ||
|
|
|
|
lfhasflag(victim, F_GRABBING) || lfhasflag(victim, F_GRABBEDBY)) {
|
|
|
|
} else {
|
|
|
|
ok = B_TRUE;
|
|
|
|
}
|
|
|
|
} else if (ot->id == OT_A_CRUSH) {
|
|
|
|
// can only crush if you first grab something
|
|
|
|
if (lfhasflag(lf, F_GRABBING)) {
|
|
|
|
ok = B_TRUE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ok = B_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ST_ADJSELF:
|
|
|
|
if (getcelldist(lf->cell,victim->cell) == 1) {
|
|
|
|
ok = B_TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ST_SPECIAL:
|
|
|
|
specialcase = B_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// invalid spell for this purpose
|
|
|
|
dblog(".oO { cant cast %s - not valid for given purpose }", ot ? ot->name : "?unkownspell?");
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (specialcase) {
|
|
|
|
if (ot->id == OT_S_TELEKINESIS) {
|
|
|
|
int i,nposs;
|
|
|
|
float maxweight;
|
|
|
|
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) {
|
|
|
|
ok = B_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ok) break;
|
|
|
|
}
|
|
|
|
}
|
2011-03-24 16:09:31 +11:00
|
|
|
} else if (ot->id == OT_S_CHARM) {
|
|
|
|
if (getnearbypeaceful(lf)) {
|
|
|
|
ok = B_TRUE;
|
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
} else {
|
|
|
|
dblog(".oO { cant cast %s - specialcase conditions not yet coded }", ot ? ot->name : "?unkownspell?");
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
dblog(".oO { cant cast %s - targetting conditions cannot be met }", ot ? ot->name : "?unkownspell?");
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
|
2011-03-24 16:09:31 +11:00
|
|
|
// now check whether it meets specific spell conditions
|
|
|
|
specificcheckok = B_TRUE;
|
|
|
|
if (ot->id == OT_S_ANIMATEMETAL) {
|
|
|
|
object_t *wep;
|
|
|
|
wep = getweapon(lf);
|
|
|
|
if (!wep || !ismetal(wep->material->id)) {
|
|
|
|
specificcheckok = B_TRUE;
|
|
|
|
}
|
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
if ((ot->id == OT_S_BLINDNESS) && isblind(victim)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-18 12:25:18 +11:00
|
|
|
}
|
2011-04-01 10:54:44 +11:00
|
|
|
if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC)) {
|
|
|
|
specificcheckok = B_FALSE;
|
|
|
|
}
|
|
|
|
if (ot->id == OT_A_SWOOP) {
|
|
|
|
flag_t *srflag;
|
|
|
|
int srange = 5;
|
|
|
|
srflag = lfhasflag(lf, F_SWOOPRANGE);
|
|
|
|
if (srflag) {
|
|
|
|
srange = srflag->val[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!haslof(lf, victim->cell, LOF_NEED,NULL)) {
|
|
|
|
specificcheckok = B_FALSE;
|
|
|
|
} else if (isimmobile(lf) || !lfhasflag(lf, F_FLYING)) {
|
|
|
|
specificcheckok = B_FALSE;
|
|
|
|
} else if (getcelldist(lf->cell, victim->cell) > srange) {
|
|
|
|
specificcheckok = B_FALSE;
|
|
|
|
}
|
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
if ((ot->id == OT_S_HASTE) && lfhasflag(lf, F_FASTACT)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-18 12:25:18 +11:00
|
|
|
}
|
|
|
|
if ((ot->id == OT_S_INVISIBILITY) && lfhasflag(victim, F_INVISIBLE)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-18 12:25:18 +11:00
|
|
|
}
|
|
|
|
if ((ot->id == OT_S_PAIN) && lfhasflag(victim, F_PAIN)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-18 12:25:18 +11:00
|
|
|
}
|
|
|
|
if ((ot->id == OT_S_HEALING) && (lf->hp >= lf->maxhp)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-04 12:22:36 +11:00
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
if ((ot->id == OT_S_HEALINGMIN) && (lf->hp >= lf->maxhp)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-16 15:45:46 +11:00
|
|
|
}
|
2011-03-22 18:06:28 +11:00
|
|
|
if ((ot->id == OT_S_PARALYZE) && lfhasflag(victim, F_PARALYZED)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-22 18:06:28 +11:00
|
|
|
}
|
|
|
|
if ((ot->id == OT_S_SLEEP) && lfhasflag(victim, F_ASLEEP)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-22 18:06:28 +11:00
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
if ((ot->id == OT_S_SLOW) && lfhasflag(victim, F_SLOWACT)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-04 12:22:36 +11:00
|
|
|
}
|
2011-03-18 12:25:18 +11:00
|
|
|
if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
2011-03-04 12:22:36 +11:00
|
|
|
}
|
2011-03-22 18:06:28 +11:00
|
|
|
if ((ot->id == OT_S_WEAKEN)) {
|
|
|
|
flag_t *lff;
|
|
|
|
for (lff = lf->flags->first; lff ; lff = lff->next) {
|
|
|
|
if ((lff->id == F_ATTRMOD) && (lff->val[0] == A_STR) && (lff->obfrom == OT_S_WEAKEN)) {
|
2011-03-24 16:09:31 +11:00
|
|
|
specificcheckok = B_FALSE;
|
|
|
|
break;
|
2011-03-22 18:06:28 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-03-24 16:09:31 +11:00
|
|
|
if (!specificcheckok) {
|
|
|
|
dblog(".oO { cant cast %s - specific spell check failed }", ot ? ot->name : "?unkownspell?");
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
2011-03-04 12:22:36 +11:00
|
|
|
|
|
|
|
return B_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
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;
|
2010-12-02 12:17:54 +11:00
|
|
|
}
|
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
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;
|
|
|
|
}
|
2010-12-02 12:17:54 +11:00
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
return NULL;
|
2010-12-02 12:17:54 +11:00
|
|
|
}
|
|
|
|
|
2011-02-01 06:16:13 +11:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
flag_t *f;
|
|
|
|
cell_t *c;
|
|
|
|
int n;
|
|
|
|
int i;
|
2011-02-16 05:21:33 +11:00
|
|
|
int db = B_FALSE;
|
|
|
|
|
|
|
|
if (wantdb && lfhasflag(lf, F_DEBUG)) {
|
|
|
|
db = B_TRUE;
|
|
|
|
} else {
|
|
|
|
db = B_FALSE;
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
|
|
|
|
// 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);
|
2011-02-16 05:21:33 +11:00
|
|
|
if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf,o)) ) {
|
2011-02-01 06:16:13 +11:00
|
|
|
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]);
|
2011-02-16 05:21:33 +11:00
|
|
|
if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf,o)) ) {
|
2011-02-01 06:16:13 +11:00
|
|
|
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?
|
2011-04-01 10:54:44 +11:00
|
|
|
if (lfhasflag(lf, F_HUMANOID) && hasbp(lf, BP_WEAPON)) {
|
|
|
|
f = hasflag(lf->flags, F_WANTSBETTERWEP);
|
|
|
|
if (f) {
|
|
|
|
if (!covetsonly || (f->val[1] == B_COVETS)) {
|
|
|
|
o = hasbetterweapon(lf, lf->cell->obpile);
|
|
|
|
if (o && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
|
|
|
|
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);
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-01 10:54:44 +11:00
|
|
|
|
|
|
|
if (lfhasflag(lf, F_HUMANOID)) {
|
|
|
|
// 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 && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
|
|
|
|
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);
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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];
|
2011-04-01 10:54:44 +11:00
|
|
|
if (!c->lf && (c != lf->ignorecell)) {
|
2011-02-01 06:16:13 +11:00
|
|
|
o = hasobmulti(c->obpile, oid, noids);
|
2011-02-16 05:21:33 +11:00
|
|
|
if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf,o)) ) {
|
2011-02-01 06:16:13 +11:00
|
|
|
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]);
|
2011-02-16 05:21:33 +11:00
|
|
|
if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf, o)) ) {
|
2011-02-01 06:16:13 +11:00
|
|
|
if (db) dblog(".oO { remote cell has ob with flag i want (%s) }", o->type->name);
|
|
|
|
gothere = B_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!gothere) {
|
2011-04-01 10:54:44 +11:00
|
|
|
if (lfhasflag(lf, F_HUMANOID) && hasbp(lf, BP_WEAPON)) {
|
|
|
|
// 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 && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
|
|
|
|
if (db) dblog(".oO { remote cell has better weapon (%s). setting f_targetcell }",o->type->name);
|
|
|
|
gothere = B_TRUE;
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!gothere) {
|
2011-04-01 10:54:44 +11:00
|
|
|
if (lfhasflag(lf, F_HUMANOID)) {
|
|
|
|
// 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 && !isdangerousob(o, lf, B_TRUE) && canpickup(lf, o, 1)) {
|
|
|
|
if (db) dblog(".oO { remote cell has better armour (%s). setting f_targetcell }",o->type->name);
|
|
|
|
gothere = B_TRUE;
|
|
|
|
}
|
2011-02-01 06:16:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (gothere) {
|
|
|
|
// start walking towards target cell
|
2011-03-25 12:23:15 +11:00
|
|
|
aigoto(lf, c, AI_FOLLOWTIME);
|
2011-02-01 06:16:13 +11:00
|
|
|
return B_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-16 05:21:33 +11:00
|
|
|
if (db) dblog(".oO { didn't find any obs i want }");
|
2011-02-01 06:16:13 +11:00
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
|
2011-03-16 15:45:46 +11:00
|
|
|
// try to use an item with the given flag on ourself.
|
|
|
|
// returns B_FALSE if successful
|
|
|
|
int useitemwithflag(lifeform_t *lf, enum FLAG whichflag) {
|
|
|
|
object_t *o;
|
|
|
|
for (o = lf->pack->first ; o ; o = o->next) {
|
|
|
|
if (hasflag(o->flags, whichflag)) {
|
|
|
|
if (aiobok(lf, o, lf)) {
|
|
|
|
if (o->type->obclass->id == OC_POTION) {
|
|
|
|
if (canquaff(lf, o)) {
|
|
|
|
quaff(lf, o);
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
} else if (o->type->obclass->id == OC_SCROLL) {
|
|
|
|
if (!readsomething(lf, o)) {
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
} else if ((o->type->obclass->id == OC_WAND) && getcharges(o)) {
|
|
|
|
// if wand, use it on ourself
|
|
|
|
if (!operate(lf, o, lf->cell)) {
|
|
|
|
return B_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// failed to use an item
|
|
|
|
return B_TRUE;
|
|
|
|
}
|