1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
|
struct fpsent;
#define MAXBOTS 32
enum { AI_NONE = 0, AI_BOT, AI_MAX };
#define isaitype(a) (a >= 0 && a <= AI_MAX-1)
namespace ai
{
const int MAXWAYPOINTS = USHRT_MAX - 2;
const int MAXWAYPOINTLINKS = 6;
const int WAYPOINTRADIUS = 16;
const float MINWPDIST = 4.f; // is on top of
const float CLOSEDIST = 32.f; // is close
const float FARDIST = 128.f; // too far to remap close
const float JUMPMIN = 4.f; // decides to jump
const float JUMPMAX = 32.f; // max jump
const float SIGHTMIN = 64.f; // minimum line of sight
const float SIGHTMAX = 1024.f; // maximum line of sight
const float VIEWMIN = 90.f; // minimum field of view
const float VIEWMAX = 180.f; // maximum field of view
struct waypoint
{
vec o;
float curscore, estscore;
int weight;
ushort route, prev;
ushort links[MAXWAYPOINTLINKS];
waypoint() {}
waypoint(const vec &o, int weight = 0) : o(o), weight(weight), route(0) { memset(links, 0, sizeof(links)); }
int score() const { return int(curscore) + int(estscore); }
int find(int wp)
{
loopi(MAXWAYPOINTLINKS) if(links[i] == wp) return i;
return -1;
}
bool haslinks() { return links[0]!=0; }
};
extern vector<waypoint> waypoints;
static inline bool iswaypoint(int n)
{
return n > 0 && n < waypoints.length();
}
extern int showwaypoints, dropwaypoints;
extern int closestwaypoint(const vec &pos, float mindist, bool links, fpsent *d = NULL);
extern void findwaypointswithin(const vec &pos, float mindist, float maxdist, vector<int> &results);
extern void inferwaypoints(fpsent *d, const vec &o, const vec &v, float mindist = ai::CLOSEDIST);
struct avoidset
{
struct obstacle
{
void *owner;
int numwaypoints;
float above;
obstacle(void *owner, float above = -1) : owner(owner), numwaypoints(0), above(above) {}
};
vector<obstacle> obstacles;
vector<int> waypoints;
void clear()
{
obstacles.setsize(0);
waypoints.setsize(0);
}
void add(void *owner, float above)
{
obstacles.add(obstacle(owner, above));
}
void add(void *owner, float above, int wp)
{
if(obstacles.empty() || owner != obstacles.last().owner) add(owner, above);
obstacles.last().numwaypoints++;
waypoints.add(wp);
}
void add(avoidset &avoid)
{
waypoints.put(avoid.waypoints.getbuf(), avoid.waypoints.length());
loopv(avoid.obstacles)
{
obstacle &o = avoid.obstacles[i];
if(obstacles.empty() || o.owner != obstacles.last().owner) add(o.owner, o.above);
obstacles.last().numwaypoints += o.numwaypoints;
}
}
void avoidnear(void *owner, float above, const vec &pos, float limit);
#define loopavoid(v, d, body) \
if(!(v).obstacles.empty()) \
{ \
int cur = 0; \
loopv((v).obstacles) \
{ \
const ai::avoidset::obstacle &ob = (v).obstacles[i]; \
int next = cur + ob.numwaypoints; \
if(ob.owner != d) \
{ \
for(; cur < next; cur++) \
{ \
int wp = (v).waypoints[cur]; \
body; \
} \
} \
cur = next; \
} \
}
bool find(int n, fpsent *d) const
{
loopavoid(*this, d, { if(wp == n) return true; });
return false;
}
int remap(fpsent *d, int n, vec &pos, bool retry = false);
};
extern bool route(fpsent *d, int node, int goal, vector<int> &route, const avoidset &obstacles, int retries = 0);
extern void navigate();
extern void clearwaypoints(bool full = false);
extern void seedwaypoints();
extern void loadwaypoints(bool force = false, const char *mname = NULL);
extern void savewaypoints(bool force = false, const char *mname = NULL);
// ai state information for the owner client
enum
{
AI_S_WAIT = 0, // waiting for next command
AI_S_DEFEND, // defend goal target
AI_S_PURSUE, // pursue goal target
AI_S_INTEREST, // interest in goal entity
AI_S_MAX
};
enum
{
AI_T_NODE,
AI_T_PLAYER,
AI_T_AFFINITY,
AI_T_ENTITY,
AI_T_MAX
};
struct interest
{
int state, node, target, targtype;
float score;
interest() : state(-1), node(-1), target(-1), targtype(-1), score(0.f) {}
~interest() {}
};
struct aistate
{
int type, millis, targtype, target, idle;
bool override;
aistate(int m, int t, int r = -1, int v = -1) : type(t), millis(m), targtype(r), target(v)
{
reset();
}
~aistate() {}
void reset()
{
idle = 0;
override = false;
}
};
const int NUMPREVNODES = 6;
struct aiinfo
{
vector<aistate> state;
vector<int> route;
vec target, spot;
int enemy, enemyseen, enemymillis, weappref, prevnodes[NUMPREVNODES], targnode, targlast, targtime, targseq,
lastrun, lasthunt, lastaction, lastcheck, jumpseed, jumprand, blocktime, huntseq, blockseq, lastaimrnd;
float targyaw, targpitch, views[3], aimrnd[3];
bool dontmove, becareful, tryreset, trywipe;
aiinfo()
{
clearsetup();
reset();
loopk(3) views[k] = 0.f;
}
~aiinfo() {}
void clearsetup()
{
weappref = GUN_PISTOL;
spot = target = vec(0, 0, 0);
lastaction = lasthunt = lastcheck = enemyseen = enemymillis = blocktime = huntseq = blockseq = targtime = targseq = lastaimrnd = 0;
lastrun = jumpseed = lastmillis;
jumprand = lastmillis+5000;
targnode = targlast = enemy = -1;
}
void clear(bool prev = false)
{
if(prev) memset(prevnodes, -1, sizeof(prevnodes));
route.setsize(0);
}
void wipe(bool prev = false)
{
clear(prev);
state.setsize(0);
addstate(AI_S_WAIT);
trywipe = false;
}
void clean(bool tryit = false)
{
if(!tryit) becareful = dontmove = false;
targyaw = rnd(360);
targpitch = 0.f;
tryreset = tryit;
}
void reset(bool tryit = false) { wipe(); clean(tryit); }
bool hasprevnode(int n) const
{
loopi(NUMPREVNODES) if(prevnodes[i] == n) return true;
return false;
}
void addprevnode(int n)
{
if(prevnodes[0] != n)
{
memmove(&prevnodes[1], prevnodes, sizeof(prevnodes) - sizeof(prevnodes[0]));
prevnodes[0] = n;
}
}
aistate &addstate(int t, int r = -1, int v = -1)
{
return state.add(aistate(lastmillis, t, r, v));
}
void removestate(int index = -1)
{
if(index < 0) state.pop();
else if(state.inrange(index)) state.remove(index);
if(!state.length()) addstate(AI_S_WAIT);
}
aistate &getstate(int idx = -1)
{
if(state.inrange(idx)) return state[idx];
return state.last();
}
aistate &switchstate(aistate &b, int t, int r = -1, int v = -1)
{
if((b.type == t && b.targtype == r) || (b.type == AI_S_INTEREST && b.targtype == AI_T_NODE))
{
b.millis = lastmillis;
b.target = v;
b.reset();
return b;
}
return addstate(t, r, v);
}
};
extern avoidset obstacles;
extern vec aitarget;
extern float viewdist(int x = 101);
extern float viewfieldx(int x = 101);
extern float viewfieldy(int x = 101);
extern bool targetable(fpsent *d, fpsent *e);
extern bool cansee(fpsent *d, vec &x, vec &y, vec &targ = aitarget);
extern void init(fpsent *d, int at, int on, int sk, int bn, int pm, const char *name, const char *team);
extern void update();
extern void avoid();
extern void think(fpsent *d, bool run);
extern bool badhealth(fpsent *d);
extern bool checkothers(vector<int> &targets, fpsent *d = NULL, int state = -1, int targtype = -1, int target = -1, bool teams = false, int *members = NULL);
extern bool makeroute(fpsent *d, aistate &b, int node, bool changed = true, int retries = 0);
extern bool makeroute(fpsent *d, aistate &b, const vec &pos, bool changed = true, int retries = 0);
extern bool randomnode(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, float wander = SIGHTMAX);
extern bool randomnode(fpsent *d, aistate &b, float guard = SIGHTMIN, float wander = SIGHTMAX);
extern bool violence(fpsent *d, aistate &b, fpsent *e, int pursue = 0);
extern bool patrol(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, float wander = SIGHTMAX, int walk = 1, bool retry = false);
extern bool defend(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, float wander = SIGHTMAX, int walk = 1);
extern void assist(fpsent *d, aistate &b, vector<interest> &interests, bool all = false, bool force = false);
extern bool parseinterests(fpsent *d, aistate &b, vector<interest> &interests, bool override = false, bool ignore = false);
extern void spawned(fpsent *d);
extern void damaged(fpsent *d, fpsent *e);
extern void killed(fpsent *d, fpsent *e);
extern void itemspawned(int ent);
extern void render();
}
|