qboolean NearestNodeLocation (vec3_t start, vec3_t node_loc, float range, qboolean vis) { int i=0, bestNodeNum=-1; float dist, best=9999; vec3_t v; if (!numnodes) return false; // get the nodenum for the closest node for ( ; i < numnodes; i++) { VectorCopy(pathnode[i], v); // ignore nodes we can't see if (vis && !G_IsClearPath(NULL, MASK_SOLID, v, start)) continue; dist = distance(v, start); if (range && dist > range) continue; if (dist < best) { best = dist; bestNodeNum = i; } } if (bestNodeNum == -1) return false; VectorCopy(pathnode[bestNodeNum], node_loc); return true; }
// returns node index of node closest to start int NearestNodeNumber (vec3_t start, float range, qboolean vis) { int i=0, bestNodeNum=-1; float dist, best=9999; vec3_t v; if (!numnodes) return -1; // get the nodenum for the closest node for ( ; i < numnodes; i++) { VectorCopy(pathnode[i], v); // ignore nodes we can't see if (vis && !G_IsClearPath(NULL, MASK_SOLID, v, start)) continue; dist = distance(v, start); if (range && dist > range) continue; if (dist < best) { best = dist; bestNodeNum = i; } } return bestNodeNum; }
qboolean LandCloserToGoal (edict_t *self, vec3_t goal_pos, vec3_t landing_pos) { // goal position path is obstructed by a wall if (!G_IsClearPath(self, MASK_SOLID, landing_pos, goal_pos)) return false; // landing position places us farther from our goal if (distance(landing_pos, goal_pos) > distance(self->s.origin, goal_pos)) return false; return true; }
void mybrain_continue (edict_t *self) { float dist, chance; vec3_t start, forward; if (!G_ValidTarget(self, self->enemy, true)) return; // higher chance to continue attack if our enemy is close dist = entdist(self, self->enemy); chance = 1-dist/1024.0; AngleVectors(self->s.angles, forward, NULL, NULL); VectorMA(self->s.origin, self->maxs[1]+8, forward , start); if (G_IsClearPath(self->enemy, MASK_SHOT, start, self->enemy->s.origin) && (random() <= chance) && (dist <= 512)) self->monsterinfo.nextframe = FRAME_attak206; mybrain_suxor(self); }
void carpetbomb_think (edict_t *self) { float ceil; qboolean failed = false; vec3_t forward, right, start, end; trace_t tr, tr1; if (!G_EntIsAlive(self->owner) || (level.time>self->delay)) { G_FreeEdict(self); return; } // move forward AngleVectors(self->s.angles, forward, NULL, NULL); VectorMA(self->s.origin, GetRandom(CARPETBOMB_DAMAGE_RADIUS/2, CARPETBOMB_DAMAGE_RADIUS+1), forward, start); tr = gi.trace(self->s.origin, NULL, NULL, start, NULL, MASK_SOLID); VectorCopy(start, end); start[2]++; end[2] -= 8192; tr1 = gi.trace(start, NULL, NULL, end, NULL, MASK_SOLID); start[2]--; if ((tr.fraction < 1) || (start[2] != tr1.endpos[2])) { //gi.dprintf("will step down, start[2] %f tr1.endpos[2] %f\n", start[2], tr1.endpos[2]); // get current ceiling height VectorCopy(start, end); end[2] += 8192; tr = gi.trace(self->s.origin, NULL, NULL, end, NULL, MASK_SOLID); ceil = tr.endpos[2]; // push down from above desired position start[2] += CARPETBOMB_STEP_SIZE; if ((start[2] > ceil)) // dont go thru ceiling start[2] = ceil; VectorCopy(start, end); end[2] -= 8192; tr = gi.trace(start, NULL, NULL, end, NULL, MASK_SOLID); // dont go thru walls if (tr.allsolid) failed = true; // try a bit lower if (tr.startsolid) { start[2] -= CARPETBOMB_STEP_SIZE; tr = gi.trace(start, NULL, NULL, end, NULL, MASK_SOLID); if (tr.startsolid || tr.allsolid) failed = true; } // dont go into water if we aren't already submerged VectorCopy(tr.endpos, start); start[2] += 8; if (!self->waterlevel && (gi.pointcontents(start) & MASK_WATER)) failed = true; } // save position VectorCopy(tr.endpos, self->s.origin); VectorCopy(tr.endpos, start); // spawn explosions on either side // FIXME: step down from these positions, otherwise we get mid-air explosions! AngleVectors(self->s.angles, NULL, right, NULL); VectorMA(self->s.origin, (crandom()*GetRandom(CARPETBOMB_CARPET_WIDTH/4, CARPETBOMB_CARPET_WIDTH/2)), right, end); // make sure path is wide enough tr = gi.trace(self->s.origin, NULL, NULL, end, self, MASK_SHOT); VectorCopy(tr.endpos, self->s.origin); self->s.origin[2] += 32; //4.08 make sure the caster can see this spot //if (!visible(self->owner, self)) if (!G_IsClearPath(self, MASK_SOLID, self->move_origin, self->s.origin)) failed = true; // make sure bombspell is in a valid location if ((gi.pointcontents(self->s.origin) & CONTENTS_SOLID) || failed) { G_FreeEdict(self); return; } T_RadiusDamage(self, self->owner, self->dmg, NULL, self->dmg_radius, MOD_BOMBS); // write explosion effects gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_EXPLOSION1); gi.WritePosition (self->s.origin); gi.multicast (self->s.origin, MULTICAST_PVS); VectorCopy(start, self->s.origin); // retrieve starting position self->nextthink = level.time + FRAMETIME; gi.linkentity(self); }