diff options
Diffstat (limited to 'src/fpsgame/ai.cpp')
| -rw-r--r-- | src/fpsgame/ai.cpp | 828 |
1 files changed, 245 insertions, 583 deletions
diff --git a/src/fpsgame/ai.cpp b/src/fpsgame/ai.cpp index 0886245..b4e631b 100644 --- a/src/fpsgame/ai.cpp +++ b/src/fpsgame/ai.cpp @@ -1,100 +1,68 @@ #include "game.h" -namespace ai -{ +namespace ai { using namespace game; - avoidset obstacles; int updatemillis = 0, iteration = 0, itermillis = 0, forcegun = -1; vec aitarget(0, 0, 0); - VAR(aidebug, 0, 0, 6); VAR(aiforcegun, -1, -1, NUMGUNS-1); - ICOMMAND(addbot, "s", (char *s), addmsg(N_ADDBOT, "ri", *s ? clamp(parseint(s), 1, 101) : -1)); ICOMMAND(delbot, "", (), addmsg(N_DELBOT, "r")); ICOMMAND(botlimit, "i", (int *n), addmsg(N_BOTLIMIT, "ri", *n)); ICOMMAND(botbalance, "i", (int *n), addmsg(N_BOTBALANCE, "ri", *n)); - - float viewdist(int x) - { + float viewdist(int x) { return x <= 100 ? clamp((SIGHTMIN+(SIGHTMAX-SIGHTMIN))/100.f*float(x), float(SIGHTMIN), 10000.0f) : 10000.0f; } - - float viewfieldx(int x) - { + float viewfieldx(int x) { return x <= 100 ? clamp((VIEWMIN+(VIEWMAX-VIEWMIN))/100.f*float(x), float(VIEWMIN), float(VIEWMAX)) : float(VIEWMAX); } - - float viewfieldy(int x) - { + float viewfieldy(int x) { return viewfieldx(x)*3.f/4.f; } - - bool canmove(fpsent *d) - { + bool canmove(fpsent *d) { return d->state != CS_DEAD && !intermission; } - - float weapmindist(int weap) - { + float weapmindist(int weap) { return max(int(guns[weap].exprad), 2); } - - float weapmaxdist(int weap) - { + float weapmaxdist(int weap) { return guns[weap].range + 4; } - - bool weaprange(fpsent *d, int weap, float dist) - { + bool weaprange(fpsent *d, int weap, float dist) { float mindist = weapmindist(weap), maxdist = weapmaxdist(weap); return dist >= mindist*mindist && dist <= maxdist*maxdist; } - - bool targetable(fpsent *d, fpsent *e) - { + bool targetable(fpsent *d, fpsent *e) { if(d == e || !canmove(d)) return false; return e->state == CS_ALIVE && !isteam(d->team, e->team); } - - bool getsight(vec &o, float yaw, float pitch, vec &q, vec &v, float mdist, float fovx, float fovy) - { + bool getsight(vec &o, float yaw, float pitch, vec &q, vec &v, float mdist, float fovx, float fovy) { float dist = o.dist(q); - - if(dist <= mdist) - { + if(dist <= mdist) { float x = fmod(fabs(asin((q.z-o.z)/dist)/RAD-pitch), 360); float y = fmod(fabs(-atan2(q.x-o.x, q.y-o.y)/RAD-yaw), 360); if(min(x, 360-x) <= fovx && min(y, 360-y) <= fovy) return raycubelos(o, q, v); } return false; } - - bool cansee(fpsent *d, vec &x, vec &y, vec &targ) - { + bool cansee(fpsent *d, vec &x, vec &y, vec &targ) { aistate &b = d->ai->getstate(); if(canmove(d) && b.type != AI_S_WAIT) return getsight(x, d->yaw, d->pitch, y, targ, d->ai->views[2], d->ai->views[0], d->ai->views[1]); return false; } - - bool canshoot(fpsent *d, fpsent *e) - { + bool canshoot(fpsent *d, fpsent *e) { if(weaprange(d, d->gunselect, e->o.squaredist(d->o)) && targetable(d, e)) return d->ammo[d->gunselect] > 0 && lastmillis - d->lastaction >= d->gunwait; return false; } - - bool canshoot(fpsent *d) - { + bool canshoot(fpsent *d) { return !d->ai->becareful && d->ammo[d->gunselect] > 0 && lastmillis - d->lastaction >= d->gunwait; } - - bool hastarget(fpsent *d, aistate &b, fpsent *e, float yaw, float pitch, float dist) - { // add margins of error - if(weaprange(d, d->gunselect, dist) || (d->skill <= 100 && !rnd(d->skill))) - { + bool hastarget(fpsent *d, aistate &b, fpsent *e, float yaw, float pitch, float dist) { + // add margins of error + if(weaprange(d, d->gunselect, dist) || (d->skill <= 100 && !rnd(d->skill))) { if(d->gunselect == GUN_FIST) return true; float skew = clamp(float(lastmillis-d->ai->enemymillis)/float((d->skill*guns[d->gunselect].attackdelay/200.f)), 0.f, guns[d->gunselect].projspeed ? 0.25f : 1e16f), offy = yaw-d->yaw, offp = pitch-d->pitch; @@ -104,16 +72,12 @@ namespace ai } return false; } - - vec getaimpos(fpsent *d, fpsent *e) - { + vec getaimpos(fpsent *d, fpsent *e) { vec o = e->o; if(d->gunselect == GUN_RL) o.z += (e->aboveeye*0.2f)-(0.8f*d->eyeheight); else if(d->gunselect != GUN_GL) o.z += (e->aboveeye-e->eyeheight)*0.5f; - if(d->skill <= 100) - { - if(lastmillis >= d->ai->lastaimrnd) - { + if(d->skill <= 100) { + if(lastmillis >= d->ai->lastaimrnd) { const int aiskew[NUMGUNS] = { 1, 10, 50, 5, 20, 1, 100 }; #define rndaioffset(r) ((rnd(int(r*aiskew[d->gunselect]*2)+1)-(r*aiskew[d->gunselect]))*(1.f/float(max(d->skill, 1)))) loopk(3) d->ai->aimrnd[k] = rndaioffset(e->radius); @@ -124,55 +88,39 @@ namespace ai } return o; } - - void create(fpsent *d) - { + void create(fpsent *d) { if(!d->ai) d->ai = new aiinfo; } - - void destroy(fpsent *d) - { + void destroy(fpsent *d) { if(d->ai) DELETEP(d->ai); } - - void init(fpsent *d, int at, int ocn, int sk, int bn, int pm, const char *name, const char *team) - { + void init(fpsent *d, int at, int ocn, int sk, int bn, int pm, const char *name, const char *team) { loadwaypoints(); - fpsent *o = newclient(ocn); - d->aitype = at; - bool resetthisguy = false; - if(!d->name[0]) - { + if(!d->name[0]) { if(aidebug) conoutf(CON_DEBUG, "%s assigned to %s at skill %d", colorname(d, name), o ? colorname(o) : "?", sk); else conoutf("\f0join:\f7 %s", colorname(d, name)); resetthisguy = true; } - else - { - if(d->ownernum != ocn) - { + else { + if(d->ownernum != ocn) { if(aidebug) conoutf(CON_DEBUG, "%s reassigned to %s", colorname(d, name), o ? colorname(o) : "?"); resetthisguy = true; } if(d->skill != sk && aidebug) conoutf(CON_DEBUG, "%s changed skill to %d", colorname(d, name), sk); } - copystring(d->name, name, MAXNAMELEN+1); copystring(d->team, team, MAXTEAMLEN+1); d->ownernum = ocn; d->plag = 0; d->skill = sk; d->playermodel = 0; - if(resetthisguy) removeweapons(d); - if(d->ownernum >= 0 && player1->clientnum == d->ownernum) - { + if(d->ownernum >= 0 && player1->clientnum == d->ownernum) { create(d); - if(d->ai) - { + if(d->ai) { d->ai->views[0] = viewfieldx(d->skill); d->ai->views[1] = viewfieldy(d->skill); d->ai->views[2] = viewdist(d->skill); @@ -180,20 +128,15 @@ namespace ai } else if(d->ai) destroy(d); } - - void update() - { + void update() { if(intermission) { loopv(players) if(players[i]->ai) players[i]->stopmoving(); } - else // fixed rate logic done out-of-sequence at 1 frame per second for each ai - { - if(totalmillis-updatemillis > 1000) - { + else { // fixed rate logic done out-of-sequence at 1 frame per second for each ai { + if(totalmillis-updatemillis > 1000) { avoid(); forcegun = multiplayer(false) ? -1 : aiforcegun; updatemillis = totalmillis; } - if(!iteration && totalmillis-itermillis > 1000) - { + if(!iteration && totalmillis-itermillis > 1000) { iteration = 1; itermillis = totalmillis; } @@ -202,12 +145,10 @@ namespace ai if(++iteration > count) iteration = 0; } } - - bool checkothers(vector<int> &targets, fpsent *d, int state, int targtype, int target, bool teams, int *members) - { // checks the states of other ai for a match + bool checkothers(vector<int> &targets, fpsent *d, int state, int targtype, int target, bool teams, int *members) { + // checks the states of other ai for a match targets.setsize(0); - loopv(players) - { + loopv(players) { fpsent *e = players[i]; if(targets.find(e->clientnum) >= 0) continue; if(teams && d && !isteam(d->team, e->team)) continue; @@ -221,13 +162,10 @@ namespace ai } return !targets.empty(); } - - bool makeroute(fpsent *d, aistate &b, int node, bool changed, int retries) - { + bool makeroute(fpsent *d, aistate &b, int node, bool changed, int retries) { if(!iswaypoint(d->lastnode)) return false; if(changed && d->ai->route.length() > 1 && d->ai->route[0] == node) return true; - if(route(d, d->lastnode, node, d->ai->route, obstacles, retries)) - { + if(route(d, d->lastnode, node, d->ai->route, obstacles, retries)) { b.override = false; return true; } @@ -235,51 +173,37 @@ namespace ai if(retries <= 1) return makeroute(d, b, node, false, retries+1); return false; } - - bool makeroute(fpsent *d, aistate &b, const vec &pos, bool changed, int retries) - { + bool makeroute(fpsent *d, aistate &b, const vec &pos, bool changed, int retries) { int node = closestwaypoint(pos, SIGHTMIN, true); return makeroute(d, b, node, changed, retries); } - - bool randomnode(fpsent *d, aistate &b, const vec &pos, float guard, float wander) - { + bool randomnode(fpsent *d, aistate &b, const vec &pos, float guard, float wander) { static vector<int> candidates; candidates.setsize(0); findwaypointswithin(pos, guard, wander, candidates); - - while(!candidates.empty()) - { + while(!candidates.empty()) { int w = rnd(candidates.length()), n = candidates.removeunordered(w); if(n != d->lastnode && !d->ai->hasprevnode(n) && !obstacles.find(n, d) && makeroute(d, b, n)) return true; } return false; } - - bool randomnode(fpsent *d, aistate &b, float guard, float wander) - { + bool randomnode(fpsent *d, aistate &b, float guard, float wander) { return randomnode(d, b, d->feetpos(), guard, wander); } - - bool badhealth(fpsent *d) - { + bool badhealth(fpsent *d) { if(d->skill <= 100) return d->health <= (111-d->skill)/4; return false; } - - bool enemy(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, int pursue = 0) - { + bool enemy(fpsent *d, aistate &b, const vec &pos, float guard = SIGHTMIN, int pursue = 0) { fpsent *t = NULL; vec dp = d->headpos(); float mindist = guard*guard, bestdist = 1e16f; - loopv(players) - { + loopv(players) { fpsent *e = players[i]; if(e == d || !targetable(d, e)) continue; vec ep = getaimpos(d, e); float dist = ep.squaredist(dp); - if(dist < bestdist && (cansee(d, dp, ep) || dist <= mindist)) - { + if(dist < bestdist && (cansee(d, dp, ep) || dist <= mindist)) { t = e; bestdist = dist; } @@ -287,21 +211,16 @@ namespace ai if(t && violence(d, b, t, pursue)) return true; return false; } - - bool patrol(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk, bool retry) - { + bool patrol(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk, bool retry) { vec feet = d->feetpos(); - if(walk == 2 || b.override || (walk && feet.squaredist(pos) <= guard*guard) || !makeroute(d, b, pos)) - { // run away and back to keep ourselves busy - if(!b.override && randomnode(d, b, pos, guard, wander)) - { + if(walk == 2 || b.override || (walk && feet.squaredist(pos) <= guard*guard) || !makeroute(d, b, pos)) { + // run away and back to keep ourselves busy + if(!b.override && randomnode(d, b, pos, guard, wander)) { b.override = true; return true; } - else if(d->ai->route.empty()) - { - if(!retry) - { + else if(d->ai->route.empty()) { + if(!retry) { b.override = false; return patrol(d, b, pos, guard, wander, walk, true); } @@ -312,14 +231,10 @@ namespace ai b.override = false; return true; } - - bool defend(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk) - { + bool defend(fpsent *d, aistate &b, const vec &pos, float guard, float wander, int walk) { bool hasenemy = enemy(d, b, pos, wander, d->gunselect == GUN_FIST ? 1 : 0); - if(!walk) - { - if(d->feetpos().squaredist(pos) <= guard*guard) - { + if(!walk) { + if(d->feetpos().squaredist(pos) <= guard*guard) { b.idle = hasenemy ? 2 : 1; return true; } @@ -327,19 +242,14 @@ namespace ai } return patrol(d, b, pos, guard, wander, walk); } - - bool violence(fpsent *d, aistate &b, fpsent *e, int pursue) - { - if(e && targetable(d, e)) - { - if(pursue) - { + bool violence(fpsent *d, aistate &b, fpsent *e, int pursue) { + if(e && targetable(d, e)) { + if(pursue) { if((b.targtype != AI_T_AFFINITY || !(pursue%2)) && makeroute(d, b, e->lastnode)) d->ai->switchstate(b, AI_S_PURSUE, AI_T_PLAYER, e->clientnum); else if(pursue >= 3) return false; // can't pursue } - if(d->ai->enemy != e->clientnum) - { + if(d->ai->enemy != e->clientnum) { d->ai->enemyseen = d->ai->enemymillis = lastmillis; d->ai->enemy = e->clientnum; } @@ -347,29 +257,23 @@ namespace ai } return false; } - - bool target(fpsent *d, aistate &b, int pursue = 0, bool force = false, float mindist = 0.f) - { + bool target(fpsent *d, aistate &b, int pursue = 0, bool force = false, float mindist = 0.f) { static vector<fpsent *> hastried; hastried.setsize(0); vec dp = d->headpos(); - while(true) - { + while(true) { float dist = 1e16f; fpsent *t = NULL; - loopv(players) - { + loopv(players) { fpsent *e = players[i]; if(e == d || hastried.find(e) >= 0 || !targetable(d, e)) continue; vec ep = getaimpos(d, e); float v = ep.squaredist(dp); - if((!t || v < dist) && (mindist <= 0 || v <= mindist) && (force || cansee(d, dp, ep))) - { + if((!t || v < dist) && (mindist <= 0 || v <= mindist) && (force || cansee(d, dp, ep))) { t = e; dist = v; } } - if(t) - { + if(t) { if(violence(d, b, t, pursue)) return true; hastried.add(t); } @@ -377,21 +281,15 @@ namespace ai } return false; } - int isgoodammo(int gun) { return gun >= GUN_SG && gun <= GUN_GL; } - - bool hasgoodammo(fpsent *d) - { + bool hasgoodammo(fpsent *d) { static const int goodguns[] = { GUN_CG, GUN_RL, GUN_SG, GUN_RIFLE }; loopi(sizeof(goodguns)/sizeof(goodguns[0])) if(d->hasammo(goodguns[0])) return true; if(d->ammo[GUN_GL] > 5) return true; return false; } - - void assist(fpsent *d, aistate &b, vector<interest> &interests, bool all, bool force) - { - loopv(players) - { + void assist(fpsent *d, aistate &b, vector<interest> &interests, bool all, bool force) { + loopv(players) { fpsent *e = players[i]; if(e == d || (!all && e->aitype != AI_NONE) || !isteam(d->team, e->team)) continue; interest &n = interests.add(); @@ -402,28 +300,22 @@ namespace ai n.score = e->o.squaredist(d->o)/(hasgoodammo(d) ? 1e8f : (force ? 1e4f : 1e2f)); } } - - static void tryitem(fpsent *d, extentity &e, int id, aistate &b, vector<interest> &interests, bool force = false) - { + static void tryitem(fpsent *d, extentity &e, int id, aistate &b, vector<interest> &interests, bool force = false) { float score = 0; - switch(e.type) - { + switch(e.type) { case I_HEALTH: if(d->health < min(d->skill, 75)) score = 1e3f; break; case I_QUAD: score = 1e3f; break; case I_BOOST: score = 1e2f; break; - case I_GREENARMOUR: case I_YELLOWARMOUR: - { + case I_GREENARMOUR: case I_YELLOWARMOUR: { int atype = A_GREEN + e.type - I_GREENARMOUR; if(atype > d->armourtype) score = atype == A_YELLOW ? 1e2f : 1e1f; else if(d->armour < 50) score = 1e1f; break; } - default: - { - if(e.type >= I_SHELLS && e.type <= I_CARTRIDGES && !d->hasmaxammo(e.type)) - { + default: { + if(e.type >= I_SHELLS && e.type <= I_CARTRIDGES && !d->hasmaxammo(e.type)) { int gun = e.type - I_SHELLS + GUN_SG; // go get a weapon upgrade if(gun == d->ai->weappref) score = 1e8f; @@ -432,8 +324,7 @@ namespace ai break; } } - if(score != 0) - { + if(score != 0) { interest &n = interests.add(); n.state = AI_S_INTEREST; n.node = closestwaypoint(e.o, SIGHTMIN, true); @@ -442,61 +333,46 @@ namespace ai n.score = d->feetpos().squaredist(e.o)/(force ? -1 : score); } } - - void items(fpsent *d, aistate &b, vector<interest> &interests, bool force = false) - { - loopv(entities::ents) - { + void items(fpsent *d, aistate &b, vector<interest> &interests, bool force = false) { + loopv(entities::ents) { extentity &e = *(extentity *)entities::ents[i]; if(!e.spawned() || e.nopickup() || !d->canpickup(e.type)) continue; tryitem(d, e, i, b, interests, force); } } - static vector<int> targets; - - bool parseinterests(fpsent *d, aistate &b, vector<interest> &interests, bool override, bool ignore) - { - while(!interests.empty()) - { + bool parseinterests(fpsent *d, aistate &b, vector<interest> &interests, bool override, bool ignore) { + while(!interests.empty()) { int q = interests.length()-1; loopi(interests.length()-1) if(interests[i].score < interests[q].score) q = i; interest n = interests.removeunordered(q); bool proceed = true; - if(!ignore) switch(n.state) - { - case AI_S_DEFEND: // don't get into herds - { + if(!ignore) switch(n.state) { + case AI_S_DEFEND: { // don't get into herds { int members = 0; proceed = !checkothers(targets, d, n.state, n.targtype, n.target, true, &members) && members > 1; break; } default: break; } - if(proceed && makeroute(d, b, n.node)) - { + if(proceed && makeroute(d, b, n.node)) { d->ai->switchstate(b, n.state, n.targtype, n.target); return true; } } return false; } - - bool find(fpsent *d, aistate &b, bool override = false) - { + bool find(fpsent *d, aistate &b, bool override = false) { static vector<interest> interests; interests.setsize(0); - if(!m_noitems) - { + if(!m_noitems) { if((!m_noammo && !hasgoodammo(d)) || d->health < min(d->skill - 15, 75)) items(d, b, interests); - else - { + else { static vector<int> nearby; nearby.setsize(0); findents(I_SHELLS, I_QUAD, false, d->feetpos(), vec(32, 32, 24), nearby); - loopv(nearby) - { + loopv(nearby) { int id = nearby[i]; extentity &e = *(extentity *)entities::ents[id]; if(d->canpickup(e.type)) tryitem(d, e, id, b, interests); @@ -506,48 +382,37 @@ namespace ai if(m_teammode) assist(d, b, interests); return parseinterests(d, b, interests, override); } - - bool findassist(fpsent *d, aistate &b, bool override = false) - { + bool findassist(fpsent *d, aistate &b, bool override = false) { static vector<interest> interests; interests.setsize(0); assist(d, b, interests); - while(!interests.empty()) - { + while(!interests.empty()) { int q = interests.length()-1; loopi(interests.length()-1) if(interests[i].score < interests[q].score) q = i; interest n = interests.removeunordered(q); bool proceed = true; - switch(n.state) - { - case AI_S_DEFEND: // don't get into herds - { + switch(n.state) { + case AI_S_DEFEND: { // don't get into herds { int members = 0; proceed = !checkothers(targets, d, n.state, n.targtype, n.target, true, &members) && members > 1; break; } default: break; } - if(proceed && makeroute(d, b, n.node)) - { + if(proceed && makeroute(d, b, n.node)) { d->ai->switchstate(b, n.state, n.targtype, n.target); return true; } } return false; } - - void damaged(fpsent *d, fpsent *e) - { - if(d->ai && canmove(d) && targetable(d, e)) // see if this ai is interested in a grudge - { + void damaged(fpsent *d, fpsent *e) { + if(d->ai && canmove(d) && targetable(d, e)) { // see if this ai is interested in a grudge { aistate &b = d->ai->getstate(); if(violence(d, b, e, d->gunselect == GUN_FIST ? 1 : 0)) return; } - if(checkothers(targets, d, AI_S_DEFEND, AI_T_PLAYER, d->clientnum, true)) - { - loopv(targets) - { + if(checkothers(targets, d, AI_S_DEFEND, AI_T_PLAYER, d->clientnum, true)) { + loopv(targets) { fpsent *t = getclient(targets[i]); if(!t->ai || !canmove(t) || !targetable(t, e)) continue; aistate &c = t->ai->getstate(); @@ -555,23 +420,18 @@ namespace ai } } } - - void findorientation(vec &o, float yaw, float pitch, vec &pos) - { + void findorientation(vec &o, float yaw, float pitch, vec &pos) { vec dir; vecfromyawpitch(yaw, pitch, 1, 0, dir); if(raycubepos(o, dir, pos, 0, RAY_CLIPMAT|RAY_SKIPFIRST) == -1) pos = dir.mul(2*getworldsize()).add(o); } - - void setup(fpsent *d) - { + void setup(fpsent *d) { d->ai->clearsetup(); d->ai->reset(true); d->ai->lastrun = lastmillis; if(m_insta) d->ai->weappref = GUN_RIFLE; - else - { + else { if(forcegun >= 0 && forcegun < NUMGUNS) d->ai->weappref = forcegun; else if(m_noammo) d->ai->weappref = -1; else d->ai->weappref = rnd(GUN_GL-GUN_SG+1)+GUN_SG; @@ -579,50 +439,34 @@ namespace ai vec dp = d->headpos(); findorientation(dp, d->yaw, d->pitch, d->ai->target); } - - void spawned(fpsent *d) - { + void spawned(fpsent *d) { if(d->ai) setup(d); } - - void killed(fpsent *d, fpsent *e) - { + void killed(fpsent *d, fpsent *e) { if(d->ai) d->ai->reset(); } - - void itemspawned(int ent) - { - if(entities::ents.inrange(ent) && entities::ents[ent]->type >= I_SHELLS && entities::ents[ent]->type <= I_QUAD) - { - loopv(players) if(players[i] && players[i]->ai && players[i]->aitype == AI_BOT && players[i]->canpickup(entities::ents[ent]->type)) - { + void itemspawned(int ent) { + if(entities::ents.inrange(ent) && entities::ents[ent]->type >= I_SHELLS && entities::ents[ent]->type <= I_QUAD) { + loopv(players) if(players[i] && players[i]->ai && players[i]->aitype == AI_BOT && players[i]->canpickup(entities::ents[ent]->type)) { fpsent *d = players[i]; bool wantsitem = false; - switch(entities::ents[ent]->type) - { + switch(entities::ents[ent]->type) { case I_BOOST: - case I_HEALTH: wantsitem = badhealth(d); break; case I_GREENARMOUR: - case I_YELLOWARMOUR: - case I_QUAD: break; - default: - { + default: { itemstat &is = itemstats[entities::ents[ent]->type-I_SHELLS]; wantsitem = isgoodammo(is.info) && d->ammo[is.info] <= (d->ai->weappref == is.info ? is.add : is.add/2); break; } } - if(wantsitem) - { + if(wantsitem) { aistate &b = d->ai->getstate(); if(b.targtype == AI_T_AFFINITY) continue; - if(b.type == AI_S_INTEREST && b.targtype == AI_T_ENTITY) - { - if(entities::ents.inrange(b.target)) - { + if(b.type == AI_S_INTEREST && b.targtype == AI_T_ENTITY) { + if(entities::ents.inrange(b.target)) { if(d->o.squaredist(entities::ents[ent]->o) < d->o.squaredist(entities::ents[b.target]->o)) d->ai->switchstate(b, AI_S_INTEREST, AI_T_ENTITY, ent); } @@ -633,35 +477,27 @@ namespace ai } } } - - int dowait(fpsent *d, aistate &b) - { + int dowait(fpsent *d, aistate &b) { d->ai->clear(true); // ensure they're clean if(find(d, b)) return 1; if(target(d, b, 4, false)) return 1; if(target(d, b, 4, true)) return 1; - if(randomnode(d, b, SIGHTMIN, 1e16f)) - { + if(randomnode(d, b, SIGHTMIN, 1e16f)) { d->ai->switchstate(b, AI_S_INTEREST, AI_T_NODE, d->ai->route[0]); return 1; } return 0; // but don't pop the state } - - int dodefend(fpsent *d, aistate &b) - { - if(d->state == CS_ALIVE) - { - switch(b.targtype) - { + int dodefend(fpsent *d, aistate &b) { + if(d->state == CS_ALIVE) { + switch(b.targtype) { case AI_T_NODE: if(iswaypoint(b.target)) return defend(d, b, waypoints[b.target].o) ? 1 : 0; break; case AI_T_ENTITY: if(entities::ents.inrange(b.target)) return defend(d, b, entities::ents[b.target]->o) ? 1 : 0; break; - case AI_T_PLAYER: - { + case AI_T_PLAYER: { fpsent *e = getclient(b.target); if(e && e->state == CS_ALIVE) return defend(d, b, e->feetpos()) ? 1 : 0; break; @@ -671,12 +507,9 @@ namespace ai } return 0; } - - int dointerest(fpsent *d, aistate &b) - { + int dointerest(fpsent *d, aistate &b) { if(d->state != CS_ALIVE) return 0; - switch(b.targtype) - { + switch(b.targtype) { case AI_T_NODE: // this is like a wait state without sitting still.. if(find(d, b)) return 1; if(target(d, b, 4, true)) return 1; @@ -684,8 +517,7 @@ namespace ai return makeroute(d, b, waypoints[b.target].o) ? 1 : 0; break; case AI_T_ENTITY: - if(entities::ents.inrange(b.target)) - { + if(entities::ents.inrange(b.target)) { extentity &e = *(extentity *)entities::ents[b.target]; if(!e.spawned() || e.nopickup() || e.type < I_SHELLS || e.type > I_CARTRIDGES || d->hasmaxammo(e.type)) return 0; //if(d->feetpos().squaredist(e.o) <= CLOSEDIST*CLOSEDIST) @@ -699,25 +531,17 @@ namespace ai } return 0; } - - int dopursue(fpsent *d, aistate &b) - { - if(d->state == CS_ALIVE) - { - switch(b.targtype) - { - case AI_T_NODE: - { + int dopursue(fpsent *d, aistate &b) { + if(d->state == CS_ALIVE) { + switch(b.targtype) { + case AI_T_NODE: { if(iswaypoint(b.target)) return defend(d, b, waypoints[b.target].o) ? 1 : 0; break; } - - case AI_T_PLAYER: - { + case AI_T_PLAYER: { fpsent *e = getclient(b.target); - if(e && e->state == CS_ALIVE) - { + if(e && e->state == CS_ALIVE) { float guard = SIGHTMIN, wander = guns[d->gunselect].range; if(d->gunselect == GUN_FIST) guard = 0.f; return patrol(d, b, e->feetpos(), guard, wander) ? 1 : 0; @@ -729,20 +553,16 @@ namespace ai } return 0; } - - int closenode(fpsent *d) - { + int closenode(fpsent *d) { vec pos = d->feetpos(); int node1 = -1, node2 = -1; float mindist1 = CLOSEDIST*CLOSEDIST, mindist2 = CLOSEDIST*CLOSEDIST; - loopv(d->ai->route) if(iswaypoint(d->ai->route[i])) - { + loopv(d->ai->route) if(iswaypoint(d->ai->route[i])) { vec epos = waypoints[d->ai->route[i]].o; float dist = epos.squaredist(pos); if(dist > FARDIST*FARDIST) continue; int entid = obstacles.remap(d, d->ai->route[i], epos); - if(entid >= 0) - { + if(entid >= 0) { if(entid != i) dist = epos.squaredist(pos); if(dist < mindist1) { node1 = i; mindist1 = dist; } } @@ -750,15 +570,11 @@ namespace ai } return node1 >= 0 ? node1 : node2; } - - int wpspot(fpsent *d, int n, bool check = false) - { - if(iswaypoint(n)) loopk(2) - { + int wpspot(fpsent *d, int n, bool check = false) { + if(iswaypoint(n)) loopk(2) { vec epos = waypoints[n].o; int entid = obstacles.remap(d, n, epos, k!=0); - if(iswaypoint(entid)) - { + if(iswaypoint(entid)) { d->ai->spot = epos; d->ai->targnode = entid; return !check || d->feetpos().squaredist(epos) > MINWPDIST*MINWPDIST ? 1 : 2; @@ -766,15 +582,11 @@ namespace ai } return 0; } - - int randomlink(fpsent *d, int n) - { - if(iswaypoint(n) && waypoints[n].haslinks()) - { + int randomlink(fpsent *d, int n) { + if(iswaypoint(n) && waypoints[n].haslinks()) { waypoint &w = waypoints[n]; static vector<int> linkmap; linkmap.setsize(0); - loopi(MAXWAYPOINTLINKS) - { + loopi(MAXWAYPOINTLINKS) { if(!w.links[i]) break; if(iswaypoint(w.links[i]) && !d->ai->hasprevnode(w.links[i]) && d->ai->route.find(w.links[i]) < 0) linkmap.add(w.links[i]); @@ -783,19 +595,14 @@ namespace ai } return -1; } - - bool anynode(fpsent *d, aistate &b, int len = NUMPREVNODES) - { - if(iswaypoint(d->lastnode)) loopk(2) - { + bool anynode(fpsent *d, aistate &b, int len = NUMPREVNODES) { + if(iswaypoint(d->lastnode)) loopk(2) { d->ai->clear(k ? true : false); int n = randomlink(d, d->lastnode); - if(wpspot(d, n)) - { + if(wpspot(d, n)) { d->ai->route.add(n); d->ai->route.add(d->lastnode); - loopi(len) - { + loopi(len) { n = randomlink(d, n); if(iswaypoint(n)) d->ai->route.insert(0, n); else break; @@ -805,29 +612,23 @@ namespace ai } return false; } - - bool checkroute(fpsent *d, int n) - { + bool checkroute(fpsent *d, int n) { if(d->ai->route.empty() || !d->ai->route.inrange(n)) return false; int last = d->ai->lastcheck ? lastmillis-d->ai->lastcheck : 0; if(last < 500 || n < 3) return false; // route length is too short d->ai->lastcheck = lastmillis; int w = iswaypoint(d->lastnode) ? d->lastnode : d->ai->route[n], c = min(n-1, NUMPREVNODES); - loopj(c) // check ahead to see if we need to go around something - { + loopj(c) { // check ahead to see if we need to go around something { int p = n-j-1, v = d->ai->route[p]; - if(d->ai->hasprevnode(v) || obstacles.find(v, d)) // something is in the way, try to remap around it - { + if(d->ai->hasprevnode(v) || obstacles.find(v, d)) { // something is in the way, try to remap around it { int m = p-1; if(m < 3) return false; // route length is too short from this point - loopirev(m) - { + loopirev(m) { int t = d->ai->route[i]; - if(!d->ai->hasprevnode(t) && !obstacles.find(t, d)) - { + if(!d->ai->hasprevnode(t) && !obstacles.find(t, d)) { static vector<int> remap; remap.setsize(0); - if(route(d, w, t, remap, obstacles)) - { // kill what we don't want and put the remap in + if(route(d, w, t, remap, obstacles)) { + // kill what we don't want and put the remap in while(d->ai->route.length() > i) d->ai->route.pop(); loopvk(remap) d->ai->route.add(remap[k]); return true; @@ -840,28 +641,20 @@ namespace ai } return false; } - - bool hunt(fpsent *d, aistate &b) - { - if(!d->ai->route.empty()) - { + bool hunt(fpsent *d, aistate &b) { + if(!d->ai->route.empty()) { int n = closenode(d); if(d->ai->route.inrange(n) && checkroute(d, n)) n = closenode(d); - if(d->ai->route.inrange(n)) - { - if(!n) - { - switch(wpspot(d, d->ai->route[n], true)) - { + if(d->ai->route.inrange(n)) { + if(!n) { + switch(wpspot(d, d->ai->route[n], true)) { case 2: d->ai->clear(false); [[fallthrough]]; - case 1: return true; // not close enough to pop it yet default: break; } } - else - { + else { while(d->ai->route.length() > n+1) d->ai->route.pop(); // waka-waka-waka-waka int m = n-1; // next, please! if(d->ai->route.inrange(m) && wpspot(d, d->ai->route[m])) return true; @@ -871,30 +664,24 @@ namespace ai b.override = false; return anynode(d, b); } - - void jumpto(fpsent *d, aistate &b, const vec &pos) - { + void jumpto(fpsent *d, aistate &b, const vec &pos) { vec off = vec(pos).sub(d->feetpos()), dir(off.x, off.y, 0); bool sequenced = d->ai->blockseq || d->ai->targseq, offground = d->timeinair && !d->inwater, jump = !offground && lastmillis >= d->ai->jumpseed && (sequenced || off.z >= JUMPMIN || lastmillis >= d->ai->jumprand); - if(jump) - { + if(jump) { vec old = d->o; d->o = vec(pos).add(vec(0, 0, d->eyeheight)); if(collide(d, vec(0, 0, 1))) jump = false; d->o = old; - if(jump) - { + if(jump) { float radius = 18*18; - loopv(entities::ents) if(entities::ents[i]->type == JUMPPAD) - { + loopv(entities::ents) if(entities::ents[i]->type == JUMPPAD) { extentity &e = *(extentity *)entities::ents[i]; if(e.o.squaredist(pos) <= radius) { jump = false; break; } } } } - if(jump) - { + if(jump) { d->jumping = true; int seed = (111-d->skill)*(d->inwater ? 3 : 5); d->ai->jumpseed = lastmillis+seed+rnd(seed); @@ -902,18 +689,14 @@ namespace ai d->ai->jumprand = lastmillis+seed+rnd(seed); } } - - void fixfullrange(float &yaw, float &pitch, float &roll, bool full) - { - if(full) - { + void fixfullrange(float &yaw, float &pitch, float &roll, bool full) { + if(full) { while(pitch < -180.0f) pitch += 360.0f; while(pitch >= 180.0f) pitch -= 360.0f; while(roll < -180.0f) roll += 360.0f; while(roll >= 180.0f) roll -= 360.0f; } - else - { + else { if(pitch > 89.9f) pitch = 89.9f; if(pitch < -89.9f) pitch = -89.9f; if(roll > 89.9f) roll = 89.9f; @@ -922,95 +705,71 @@ namespace ai while(yaw < 0.0f) yaw += 360.0f; while(yaw >= 360.0f) yaw -= 360.0f; } - - void fixrange(float &yaw, float &pitch) - { + void fixrange(float &yaw, float &pitch) { float r = 0.f; fixfullrange(yaw, pitch, r, false); } - - void getyawpitch(const vec &from, const vec &pos, float &yaw, float &pitch) - { + void getyawpitch(const vec &from, const vec &pos, float &yaw, float &pitch) { float dist = from.dist(pos); yaw = -atan2(pos.x-from.x, pos.y-from.y)/RAD; pitch = asin((pos.z-from.z)/dist)/RAD; } - - void scaleyawpitch(float &yaw, float &pitch, float targyaw, float targpitch, float frame, float scale) - { + void scaleyawpitch(float &yaw, float &pitch, float targyaw, float targpitch, float frame, float scale) { if(yaw < targyaw-180.0f) yaw += 360.0f; if(yaw > targyaw+180.0f) yaw -= 360.0f; float offyaw = fabs(targyaw-yaw)*frame, offpitch = fabs(targpitch-pitch)*frame*scale; - if(targyaw > yaw) - { + if(targyaw > yaw) { yaw += offyaw; if(targyaw < yaw) yaw = targyaw; } - else if(targyaw < yaw) - { + else if(targyaw < yaw) { yaw -= offyaw; if(targyaw > yaw) yaw = targyaw; } - if(targpitch > pitch) - { + if(targpitch > pitch) { pitch += offpitch; if(targpitch < pitch) pitch = targpitch; } - else if(targpitch < pitch) - { + else if(targpitch < pitch) { pitch -= offpitch; if(targpitch > pitch) pitch = targpitch; } fixrange(yaw, pitch); } - - bool lockon(fpsent *d, fpsent *e, float maxdist) - { - if(d->gunselect == GUN_FIST && !d->blocked && !d->timeinair) - { + bool lockon(fpsent *d, fpsent *e, float maxdist) { + if(d->gunselect == GUN_FIST && !d->blocked && !d->timeinair) { vec dir = vec(e->o).sub(d->o); float xydist = dir.x*dir.x+dir.y*dir.y, zdist = dir.z*dir.z, mdist = maxdist*maxdist, ddist = d->radius*d->radius+e->radius*e->radius; if(zdist <= ddist && xydist >= ddist+4 && xydist <= mdist+ddist) return true; } return false; } - - int process(fpsent *d, aistate &b) - { + int process(fpsent *d, aistate &b) { int result = 0, stupify = d->skill <= 10+rnd(15) ? rnd(d->skill*1000) : 0, skmod = 101-d->skill; float frame = d->skill <= 100 ? float(lastmillis-d->ai->lastrun)/float(max(skmod,1)*10) : 1; vec dp = d->headpos(); - bool idle = b.idle == 1 || (stupify && stupify <= skmod); d->ai->dontmove = false; - if(idle) - { + if(idle) { d->ai->lastaction = d->ai->lasthunt = lastmillis; d->ai->dontmove = true; d->ai->spot = vec(0, 0, 0); } - else if(hunt(d, b)) - { + else if(hunt(d, b)) { getyawpitch(dp, vec(d->ai->spot).add(vec(0, 0, d->eyeheight)), d->ai->targyaw, d->ai->targpitch); d->ai->lasthunt = lastmillis; } - else - { + else { idle = d->ai->dontmove = true; d->ai->spot = vec(0, 0, 0); } - if(!d->ai->dontmove) jumpto(d, b, d->ai->spot); - fpsent *e = getclient(d->ai->enemy); bool enemyok = e && targetable(d, e); - if(!enemyok || d->skill >= 50) - { + if(!enemyok || d->skill >= 50) { fpsent *f = (fpsent *)intersectclosest(dp, d->ai->target, d); - if(f) - { - if(targetable(d, f)) - { + if(f) { + if(targetable(d, f)) { if(!enemyok) violence(d, b, f, d->gunselect == GUN_FIST ? 1 : 0); enemyok = true; e = f; @@ -1020,8 +779,7 @@ namespace ai else if(!enemyok && target(d, b, d->gunselect == GUN_FIST ? 1 : 0, false, SIGHTMIN)) enemyok = (e = getclient(d->ai->enemy)) != NULL; } - if(enemyok) - { + if(enemyok) { vec ep = getaimpos(d, e); float yaw, pitch; getyawpitch(dp, ep, yaw, pitch); @@ -1029,21 +787,17 @@ namespace ai bool insight = cansee(d, dp, ep), hasseen = d->ai->enemyseen && lastmillis-d->ai->enemyseen <= (d->skill*10)+3000, quick = d->ai->enemyseen && lastmillis-d->ai->enemyseen <= (d->gunselect == GUN_CG ? 300 : skmod)+30; if(insight) d->ai->enemyseen = lastmillis; - if(idle || insight || hasseen || quick) - { + if(idle || insight || hasseen || quick) { float sskew = insight || d->skill > 100 ? 1.5f : (hasseen ? 1.f : 0.5f); - if(insight && lockon(d, e, 16)) - { + if(insight && lockon(d, e, 16)) { d->ai->targyaw = yaw; d->ai->targpitch = pitch; if(!idle) frame *= 2; d->ai->becareful = false; } scaleyawpitch(d->yaw, d->pitch, yaw, pitch, frame, sskew); - if(insight || quick) - { - if(canshoot(d, e) && hastarget(d, b, e, yaw, pitch, dp.squaredist(ep))) - { + if(insight || quick) { + if(canshoot(d, e) && hastarget(d, b, e, yaw, pitch, dp.squaredist(ep))) { d->attacking = true; d->ai->lastaction = lastmillis; result = 3; @@ -1052,10 +806,8 @@ namespace ai } else result = 1; } - else - { - if(!d->ai->enemyseen || lastmillis-d->ai->enemyseen > (d->skill*50)+3000) - { + else { + if(!d->ai->enemyseen || lastmillis-d->ai->enemyseen > (d->skill*50)+3000) { d->ai->enemy = -1; d->ai->enemyseen = d->ai->enemymillis = 0; } @@ -1063,22 +815,17 @@ namespace ai result = 0; } } - else - { - if(!enemyok) - { + else { + if(!enemyok) { d->ai->enemy = -1; d->ai->enemyseen = d->ai->enemymillis = 0; } enemyok = false; result = 0; } - fixrange(d->ai->targyaw, d->ai->targpitch); if(!result) scaleyawpitch(d->yaw, d->pitch, d->ai->targyaw, d->ai->targpitch, frame*0.25f, 1.f); - - if(d->ai->becareful && d->physstate == PHYS_FALL) - { + if(d->ai->becareful && d->physstate == PHYS_FALL) { float offyaw, offpitch; vectoyawpitch(d->vel, offyaw, offpitch); offyaw -= d->yaw; offpitch -= d->pitch; @@ -1086,20 +833,18 @@ namespace ai else if(d->ai->becareful) d->ai->dontmove = true; } else d->ai->becareful = false; - if(d->ai->dontmove) d->move = d->strafe = 0; - else - { // our guys move one way.. but turn another?! :) - const struct aimdir { int move, strafe, offset; } aimdirs[8] = - { + else { + // our guys move one way.. but turn another?! :) + const struct aimdir { int move, strafe, offset; } aimdirs[8] = { { 1, 0, 0 }, - { 1, -1, 45 }, - { 0, -1, 90 }, - { -1, -1, 135 }, + { 1, -1, 45 }, + { 0, -1, 90 }, + { -1, -1, 135 }, { -1, 0, 180 }, - { -1, 1, 225 }, - { 0, 1, 270 }, - { 1, 1, 315 } + { -1, 1, 225 }, + { 0, 1, 270 }, + { 1, 1, 315 } }; float yaw = d->ai->targyaw-d->yaw; while(yaw < 0.0f) yaw += 360.0f; @@ -1112,31 +857,23 @@ namespace ai findorientation(dp, d->yaw, d->pitch, d->ai->target); return result; } - - bool hasrange(fpsent *d, fpsent *e, int weap) - { + bool hasrange(fpsent *d, fpsent *e, int weap) { if(!e) return true; - if(targetable(d, e)) - { + if(targetable(d, e)) { vec ep = getaimpos(d, e); float dist = ep.squaredist(d->headpos()); if(weaprange(d, weap, dist)) return true; } return false; } - - bool request(fpsent *d, aistate &b) - { + bool request(fpsent *d, aistate &b) { fpsent *e = getclient(d->ai->enemy); - if(!d->hasammo(d->gunselect) || !hasrange(d, e, d->gunselect) || (d->gunselect != d->ai->weappref && (!isgoodammo(d->gunselect) || d->hasammo(d->ai->weappref)))) - { + if(!d->hasammo(d->gunselect) || !hasrange(d, e, d->gunselect) || (d->gunselect != d->ai->weappref && (!isgoodammo(d->gunselect) || d->hasammo(d->ai->weappref)))) { static const int gunprefs[] = { GUN_CG, GUN_RL, GUN_SG, GUN_RIFLE, GUN_GL, GUN_PISTOL, GUN_FIST }; int gun = -1; if(d->hasammo(d->ai->weappref) && hasrange(d, e, d->ai->weappref)) gun = d->ai->weappref; - else - { - loopi(sizeof(gunprefs)/sizeof(gunprefs[0])) if(d->hasammo(gunprefs[i]) && hasrange(d, e, gunprefs[i])) - { + else { + loopi(sizeof(gunprefs)/sizeof(gunprefs[0])) if(d->hasammo(gunprefs[i]) && hasrange(d, e, gunprefs[i])) { gun = gunprefs[i]; break; } @@ -1145,17 +882,12 @@ namespace ai } return process(d, b) >= 2; } - - void timeouts(fpsent *d, aistate &b) - { - if(d->blocked) - { + void timeouts(fpsent *d, aistate &b) { + if(d->blocked) { d->ai->blocktime += lastmillis-d->ai->lastrun; - if(d->ai->blocktime > (d->ai->blockseq+1)*1000) - { + if(d->ai->blocktime > (d->ai->blockseq+1)*1000) { d->ai->blockseq++; - switch(d->ai->blockseq) - { + switch(d->ai->blockseq) { case 1: case 2: case 3: if(entities::ents.inrange(d->ai->targnode)) d->ai->addprevnode(d->ai->targnode); d->ai->clear(false); @@ -1167,15 +899,11 @@ namespace ai } } else d->ai->blocktime = d->ai->blockseq = 0; - - if(d->ai->targnode == d->ai->targlast) - { + if(d->ai->targnode == d->ai->targlast) { d->ai->targtime += lastmillis-d->ai->lastrun; - if(d->ai->targtime > (d->ai->targseq+1)*1000) - { + if(d->ai->targtime > (d->ai->targseq+1)*1000) { d->ai->targseq++; - switch(d->ai->targseq) - { + switch(d->ai->targseq) { case 1: case 2: case 3: if(entities::ents.inrange(d->ai->targnode)) d->ai->addprevnode(d->ai->targnode); d->ai->clear(false); @@ -1186,21 +914,16 @@ namespace ai } } } - else - { + else { d->ai->targtime = d->ai->targseq = 0; d->ai->targlast = d->ai->targnode; } - - if(d->ai->lasthunt) - { + if(d->ai->lasthunt) { int millis = lastmillis-d->ai->lasthunt; if(millis <= 1000) { d->ai->tryreset = false; d->ai->huntseq = 0; } - else if(millis > (d->ai->huntseq+1)*1000) - { + else if(millis > (d->ai->huntseq+1)*1000) { d->ai->huntseq++; - switch(d->ai->huntseq) - { + switch(d->ai->huntseq) { case 1: d->ai->reset(true); break; case 2: d->ai->reset(false); break; case 3: default: suicide(d); return; break; // this is our last resort.. @@ -1208,20 +931,15 @@ namespace ai } } } - - void logic(fpsent *d, aistate &b, bool run) - { + void logic(fpsent *d, aistate &b, bool run) { bool allowmove = canmove(d) && b.type != AI_S_WAIT; if(d->state != CS_ALIVE || !allowmove) d->stopmoving(); - if(d->state == CS_ALIVE) - { - if(allowmove) - { + if(d->state == CS_ALIVE) { + if(allowmove) { if(!request(d, b)) target(d, b, d->gunselect == GUN_FIST ? 1 : 0, b.idle ? true : false); shoot(d, d->ai->target); } - if(!intermission) - { + if(!intermission) { if(d->ragdoll) cleanragdoll(d); moveplayer(d, 10, true); if(allowmove && !b.idle) timeouts(d, b); @@ -1229,25 +947,20 @@ namespace ai entities::checkitems(d); } } - else if(d->state == CS_DEAD) - { + else if(d->state == CS_DEAD) { if(d->ragdoll) moveragdoll(d); - else if(lastmillis-d->lastpain<2000) - { + else if(lastmillis-d->lastpain<2000) { d->move = d->strafe = 0; moveplayer(d, 10, false); } } d->attacking = d->jumping = false; } - - void avoid() - { + void avoid() { // guess as to the radius of ai and other critters relying on the avoid set for now float guessradius = player1->radius; obstacles.clear(); - loopv(players) - { + loopv(players) { dynent *d = players[i]; if(d->state != CS_ALIVE) continue; obstacles.avoidnear(d, d->o.z + d->aboveeye + 1, d->feetpos(), guessradius + d->radius); @@ -1256,46 +969,36 @@ namespace ai obstacles.add(wpavoid); avoidweapons(obstacles, guessradius); } - - void think(fpsent *d, bool run) - { + void think(fpsent *d, bool run) { // the state stack works like a chain of commands, certain commands simply replace each other // others spawn new commands to the stack the ai reads the top command from the stack and executes // it or pops the stack and goes back along the history until it finds a suitable command to execute bool cleannext = false; if(d->ai->state.empty()) d->ai->addstate(AI_S_WAIT); - loopvrev(d->ai->state) - { + loopvrev(d->ai->state) { aistate &c = d->ai->state[i]; - if(cleannext) - { + if(cleannext) { c.millis = lastmillis; c.override = false; cleannext = false; } - if(d->state == CS_DEAD && d->respawned!=d->lifesequence && lastmillis - d->lastpain >= 500) - { + if(d->state == CS_DEAD && d->respawned!=d->lifesequence && lastmillis - d->lastpain >= 500) { addmsg(N_TRYSPAWN, "rc", d); d->respawned = d->lifesequence; } - else if(d->state == CS_ALIVE && run) - { + else if(d->state == CS_ALIVE && run) { int result = 0; c.idle = 0; - switch(c.type) - { + switch(c.type) { case AI_S_WAIT: result = dowait(d, c); break; case AI_S_DEFEND: result = dodefend(d, c); break; case AI_S_PURSUE: result = dopursue(d, c); break; case AI_S_INTEREST: result = dointerest(d, c); break; default: result = 0; break; } - if(result <= 0) - { - if(c.type != AI_S_WAIT) - { - switch(result) - { + if(result <= 0) { + if(c.type != AI_S_WAIT) { + switch(result) { case 0: default: d->ai->removestate(i); cleannext = true; break; case -1: i = d->ai->state.length()-1; break; } @@ -1309,17 +1012,12 @@ namespace ai if(d->ai->trywipe) d->ai->wipe(); d->ai->lastrun = lastmillis; } - - void drawroute(fpsent *d, float amt = 1.f) - { + void drawroute(fpsent *d, float amt = 1.f) { int last = -1; - loopvrev(d->ai->route) - { - if(d->ai->route.inrange(last)) - { + loopvrev(d->ai->route) { + if(d->ai->route.inrange(last)) { int index = d->ai->route[i], prev = d->ai->route[last]; - if(iswaypoint(index) && iswaypoint(prev)) - { + if(iswaypoint(index) && iswaypoint(prev)) { waypoint &e = waypoints[index], &f = waypoints[prev]; vec fr = f.o, dr = e.o; fr.z += amt; dr.z += amt; @@ -1328,45 +1026,22 @@ namespace ai } last = i; } - if(aidebug >= 5) - { - vec pos = d->feetpos(); - if(d->ai->spot != vec(0, 0, 0)) particle_flare(pos, d->ai->spot, 1, PART_LIGHTNING, 0x00FFFF); - if(iswaypoint(d->ai->targnode)) - particle_flare(pos, waypoints[d->ai->targnode].o, 1, PART_LIGHTNING, 0xFF00FF); - if(iswaypoint(d->lastnode)) - particle_flare(pos, waypoints[d->lastnode].o, 1, PART_LIGHTNING, 0xFFFF00); - loopi(NUMPREVNODES) if(iswaypoint(d->ai->prevnodes[i])) - { - particle_flare(pos, waypoints[d->ai->prevnodes[i]].o, 1, PART_LIGHTNING, 0x884400); - pos = waypoints[d->ai->prevnodes[i]].o; - } - } } - VAR(showwaypoints, 0, 0, 1); VAR(showwaypointsradius, 0, 200, 10000); - - const char *stnames[AI_S_MAX] = { - "wait", "defend", "pursue", "interest" - }, *sttypes[AI_T_MAX+1] = { - "none", "node", "player", "affinity", "entity" - }; - void render() - { - if(aidebug > 1) - { + const char *stnames[AI_S_MAX] = { "wait", "defend", "pursue", "interest" }, + *sttypes[AI_T_MAX+1] = { "none", "node", "player", "affinity", "entity" }; + void render() { + if(aidebug > 1) { int total = 0, alive = 0; loopv(players) if(players[i]->ai) total++; - loopv(players) if(players[i]->state == CS_ALIVE && players[i]->ai) - { + loopv(players) if(players[i]->state == CS_ALIVE && players[i]->ai) { fpsent *d = players[i]; vec pos = d->abovehead(); pos.z += 3; alive++; if(aidebug >= 4) drawroute(d, 4.f*(float(alive)/float(total))); - if(aidebug >= 3) - { + if(aidebug >= 3) { defformatstring(q, "node: %d route: %d (%d)", d->lastnode, !d->ai->route.empty() ? d->ai->route[0] : -1, @@ -1376,8 +1051,7 @@ namespace ai pos.z += 2; } bool top = true; - loopvrev(d->ai->state) - { + loopvrev(d->ai->state) { aistate &b = d->ai->state[i]; defformatstring(s, "%s%s (%d ms) %s:%d", top ? "\fg" : "\fy", @@ -1387,36 +1061,29 @@ namespace ai ); particle_textcopy(pos, s, PART_TEXT, 1); pos.z += 2; - if(top) - { + if(top) { if(aidebug >= 3) top = false; else break; } } - if(aidebug >= 3) - { - if(d->ai->weappref >= 0 && d->ai->weappref < NUMGUNS) - { + if(aidebug >= 3) { + if(d->ai->weappref >= 0 && d->ai->weappref < NUMGUNS) { particle_textcopy(pos, guns[d->ai->weappref].name, PART_TEXT, 1); pos.z += 2; } fpsent *e = getclient(d->ai->enemy); - if(e) - { + if(e) { particle_textcopy(pos, colorname(e), PART_TEXT, 1); pos.z += 2; } } } - if(aidebug >= 4) - { + if(aidebug >= 4) { int cur = 0; - loopv(obstacles.obstacles) - { + loopv(obstacles.obstacles) { const avoidset::obstacle &ob = obstacles.obstacles[i]; int next = cur + ob.numwaypoints; - for(; cur < next; cur++) - { + for(; cur < next; cur++) { int ent = obstacles.waypoints[cur]; if(iswaypoint(ent)) regular_particle_splash(PART_EDIT, 2, 40, waypoints[ent].o, 0xFF6600, 1.5f); @@ -1425,26 +1092,21 @@ namespace ai } } } - if(showwaypoints || aidebug >= 6) - { + if(showwaypoints || aidebug >= 6) { vector<int> close; int len = waypoints.length(); - if(showwaypointsradius) - { + if(showwaypointsradius) { findwaypointswithin(camera1->o, 0, showwaypointsradius, close); len = close.length(); } - loopi(len) - { + loopi(len) { waypoint &w = waypoints[showwaypointsradius ? close[i] : i]; - loopj(MAXWAYPOINTLINKS) - { + loopj(MAXWAYPOINTLINKS) { int link = w.links[j]; if(!link) break; particle_flare(w.o, waypoints[link].o, 1, PART_STREAK, 0x0000FF); } } - } } } |
