//=========================================================================== // returns qtrue if the bot is against a ladder // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_AgainstLadder(vec3_t origin) { int areanum, i, facenum, side; vec3_t org; aas_plane_t *plane; aas_face_t *face; aas_area_t *area; VectorCopy(origin, org); areanum = AAS_PointAreaNum(org); if (!areanum) { org[0] += 1; areanum = AAS_PointAreaNum(org); if (!areanum) { org[1] += 1; areanum = AAS_PointAreaNum(org); if (!areanum) { org[0] -= 2; areanum = AAS_PointAreaNum(org); if (!areanum) { org[1] -= 2; areanum = AAS_PointAreaNum(org); } //end if } //end if } //end if } //end if //if in solid... wrrr shouldn't happen if (!areanum) return qfalse; //if not in a ladder area if (!(aasworld.areasettings[areanum].areaflags & AREA_LADDER)) return qfalse; //if a crouch only area if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qfalse; // area = &aasworld.areas[areanum]; for (i = 0; i < area->numfaces; i++) { facenum = aasworld.faceindex[area->firstface + i]; side = facenum < 0; face = &aasworld.faces[abs(facenum)]; //if the face isn't a ladder face if (!(face->faceflags & FACE_LADDER)) continue; //get the plane the face is in plane = &aasworld.planes[face->planenum ^ side]; //if the origin is pretty close to the plane if (fabsf(DotProduct(plane->normal, origin) - plane->dist) < 3) { if (AAS_PointInsideFace(abs(facenum), origin, 0.1f)) return qtrue; } //end if } //end for return qfalse; } //end of the function AAS_AgainstLadder
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void BotInitInfoEntities( void ) { char classname[MAX_EPAIRKEY]; maplocation_t *ml; campspot_t *cs; int ent, numlocations, numcampspots; BotFreeInfoEntities(); // numlocations = 0; numcampspots = 0; for ( ent = AAS_NextBSPEntity( 0 ); ent; ent = AAS_NextBSPEntity( ent ) ) { if ( !AAS_ValueForBSPEpairKey( ent, "classname", classname, MAX_EPAIRKEY ) ) { continue; } //map locations if ( !strcmp( classname, "target_location" ) ) { ml = (maplocation_t *) GetClearedMemory( sizeof( maplocation_t ) ); AAS_VectorForBSPEpairKey( ent, "origin", ml->origin ); AAS_ValueForBSPEpairKey( ent, "message", ml->name, sizeof( ml->name ) ); ml->areanum = AAS_PointAreaNum( ml->origin ); ml->next = maplocations; maplocations = ml; numlocations++; } //end if //camp spots else if ( !strcmp( classname, "info_camp" ) ) { cs = (campspot_t *) GetClearedMemory( sizeof( campspot_t ) ); AAS_VectorForBSPEpairKey( ent, "origin", cs->origin ); //cs->origin[2] += 16; AAS_ValueForBSPEpairKey( ent, "message", cs->name, sizeof( cs->name ) ); AAS_FloatForBSPEpairKey( ent, "range", &cs->range ); AAS_FloatForBSPEpairKey( ent, "weight", &cs->weight ); AAS_FloatForBSPEpairKey( ent, "wait", &cs->wait ); AAS_FloatForBSPEpairKey( ent, "random", &cs->random ); cs->areanum = AAS_PointAreaNum( cs->origin ); if ( !cs->areanum ) { botimport.Print( PRT_MESSAGE, "camp spot at %1.1f %1.1f %1.1f in solid\n", cs->origin[0], cs->origin[1], cs->origin[2] ); FreeMemory( cs ); continue; } //end if cs->next = campspots; campspots = cs; //AAS_DrawPermanentCross(cs->origin, 4, LINECOLOR_YELLOW); numcampspots++; } //end else if } //end for if ( bot_developer ) { botimport.Print( PRT_MESSAGE, "%d map locations\n", numlocations ); botimport.Print( PRT_MESSAGE, "%d camp spots\n", numcampspots ); } //end if } //end of the function BotInitInfoEntities
void AAS_FloodAreas(vector3 *origin) { int areanum, cluster, *done; done = (int *) GetClearedMemory(aasworld.numareas * sizeof(int)); areanum = AAS_PointAreaNum(origin); cluster = AAS_AreaCluster(areanum); AAS_FloodAreas_r(areanum, cluster, done); }
static void BotInitInfoEntities() { BotFreeInfoEntities(); int numlocations = 0; int numcampspots = 0; for ( int ent = AAS_NextBSPEntity( 0 ); ent; ent = AAS_NextBSPEntity( ent ) ) { char classname[ MAX_EPAIRKEY ]; if ( !AAS_ValueForBSPEpairKey( ent, "classname", classname, MAX_EPAIRKEY ) ) { continue; } //map locations if ( !String::Cmp( classname, "target_location" ) ) { maplocation_t* ml = ( maplocation_t* )Mem_ClearedAlloc( sizeof ( maplocation_t ) ); AAS_VectorForBSPEpairKey( ent, "origin", ml->origin ); AAS_ValueForBSPEpairKey( ent, "message", ml->name, sizeof ( ml->name ) ); ml->areanum = AAS_PointAreaNum( ml->origin ); ml->next = maplocations; maplocations = ml; numlocations++; } //camp spots else if ( !String::Cmp( classname, "info_camp" ) ) { campspot_t* cs = ( campspot_t* )Mem_ClearedAlloc( sizeof ( campspot_t ) ); AAS_VectorForBSPEpairKey( ent, "origin", cs->origin ); AAS_ValueForBSPEpairKey( ent, "message", cs->name, sizeof ( cs->name ) ); AAS_FloatForBSPEpairKey( ent, "range", &cs->range ); AAS_FloatForBSPEpairKey( ent, "weight", &cs->weight ); AAS_FloatForBSPEpairKey( ent, "wait", &cs->wait ); AAS_FloatForBSPEpairKey( ent, "random", &cs->random ); cs->areanum = AAS_PointAreaNum( cs->origin ); if ( !cs->areanum ) { BotImport_Print( PRT_MESSAGE, "camp spot at %1.1f %1.1f %1.1f in solid\n", cs->origin[ 0 ], cs->origin[ 1 ], cs->origin[ 2 ] ); Mem_Free( cs ); continue; } cs->next = campspots; campspots = cs; numcampspots++; } } if ( bot_developer ) { BotImport_Print( PRT_MESSAGE, "%d map locations\n", numlocations ); BotImport_Print( PRT_MESSAGE, "%d camp spots\n", numcampspots ); } }
//=========================================================================== // returns the presence type at the given point // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_PointPresenceType(vec3_t point) { int areanum; if (!aasworld.loaded) return 0; areanum = AAS_PointAreaNum(point); if (!areanum) return PRESENCE_NONE; return aasworld.areasettings[areanum].presencetype; } //end of the function AAS_PointPresenceType
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_PointReachabilityAreaIndex( vec3_t origin ) { int areanum, cluster, i, index; if (!aasworld.initialized) return 0; if ( !origin ) { index = 0; for (i = 0; i < aasworld.numclusters; i++) { index += aasworld.clusters[i].numreachabilityareas; } //end for return index; } //end if areanum = AAS_PointAreaNum( origin ); if ( !areanum || !AAS_AreaReachability(areanum) ) return 0; cluster = aasworld.areasettings[areanum].cluster; areanum = aasworld.areasettings[areanum].clusterareanum; if (cluster < 0) { cluster = aasworld.portals[-cluster].frontcluster; areanum = aasworld.portals[-cluster].clusterareanum[0]; } //end if index = 0; for (i = 0; i < cluster; i++) { index += aasworld.clusters[i].numreachabilityareas; } //end for index += areanum; return index; } //end of the function AAS_PointReachabilityAreaIndex
int AAS_AlternativeRouteGoals(vec3_t start, vec3_t goal, int travelflags, aas_altroutegoal_t *altroutegoals, int maxaltroutegoals, int color) { #ifndef ENABLE_ALTROUTING return 0; #else int i, j, startareanum, goalareanum, bestareanum; int numaltroutegoals, nummidrangeareas; int starttime, goaltime, goaltraveltime; float dist, bestdist; vec3_t mid, dir; int reachnum, time; int a1, a2; /*#ifdef DEBUG int startmillisecs; startmillisecs = Sys_MilliSeconds(); #endif*/ startareanum = AAS_PointAreaNum(start); if (!startareanum) { return 0; } goalareanum = AAS_PointAreaNum(goal); if (!goalareanum) { VectorCopy(goal, dir); dir[2] += 30; goalareanum = AAS_PointAreaNum(dir); if (!goalareanum) { return 0; } } //travel time towards the goal area goaltraveltime = AAS_AreaTravelTimeToGoalArea(startareanum, start, goalareanum, travelflags); //clear the midrange areas memset(midrangeareas, 0, (*aasworld).numareas * sizeof(midrangearea_t)); numaltroutegoals = 0; // nummidrangeareas = 0; // for (i = 1; i < (*aasworld).numareas; i++) { // if (!((*aasworld).areasettings[i].contents & AREACONTENTS_ROUTEPORTAL) && !((*aasworld).areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) { continue; } //if the area has no reachabilities if (!AAS_AreaReachability(i)) { continue; } //tavel time from the area to the start area starttime = AAS_AreaTravelTimeToGoalArea(startareanum, start, i, travelflags); if (!starttime) { continue; } //if the travel time from the start to the area is greater than the shortest goal travel time if (starttime > 500 + 3.0 * goaltraveltime) { continue; } //travel time from the area to the goal area goaltime = AAS_AreaTravelTimeToGoalArea(i, NULL, goalareanum, travelflags); if (!goaltime) { continue; } //if the travel time from the area to the goal is greater than the shortest goal travel time if (goaltime > 500 + 3.0 * goaltraveltime) { continue; } //this is a mid range area midrangeareas[i].valid = qtrue; midrangeareas[i].starttime = starttime; midrangeareas[i].goaltime = goaltime; Log_Write("%d midrange area %d", nummidrangeareas, i); nummidrangeareas++; } //end for // for (i = 1; i < (*aasworld).numareas; i++) { if (!midrangeareas[i].valid) { continue; } //get the areas in one cluster numclusterareas = 0; AAS_AltRoutingFloodCluster_r(i); //now we've got a cluster with areas through which an alternative route could go //get the 'center' of the cluster VectorClear(mid); for (j = 0; j < numclusterareas; j++) { VectorAdd(mid, (*aasworld).areas[clusterareas[j]].center, mid); } //end for VectorScale(mid, 1.0 / numclusterareas, mid); //get the area closest to the center of the cluster bestdist = 999999; bestareanum = 0; for (j = 0; j < numclusterareas; j++) { VectorSubtract(mid, (*aasworld).areas[clusterareas[j]].center, dir); dist = VectorLength(dir); if (dist < bestdist) { bestdist = dist; bestareanum = clusterareas[j]; } //end if } //end for // make sure the route to the destination isn't in the same direction as the route to the source if (!AAS_AreaRouteToGoalArea(bestareanum, (*aasworld).areawaypoints[bestareanum], goalareanum, travelflags, &time, &reachnum)) { continue; } a1 = (*aasworld).reachability[reachnum].areanum; if (!AAS_AreaRouteToGoalArea(bestareanum, (*aasworld).areawaypoints[bestareanum], startareanum, travelflags, &time, &reachnum)) { continue; } a2 = (*aasworld).reachability[reachnum].areanum; if (a1 == a2) { continue; } //now we've got an area for an alternative route //FIXME: add alternative goal origin VectorCopy((*aasworld).areawaypoints[bestareanum], altroutegoals[numaltroutegoals].origin); altroutegoals[numaltroutegoals].areanum = bestareanum; altroutegoals[numaltroutegoals].starttraveltime = midrangeareas[bestareanum].starttime; altroutegoals[numaltroutegoals].goaltraveltime = midrangeareas[bestareanum].goaltime; altroutegoals[numaltroutegoals].extratraveltime = (midrangeareas[bestareanum].starttime + midrangeareas[bestareanum].goaltime) - goaltraveltime; numaltroutegoals++; // /*#ifdef DEBUG botimport.Print(PRT_MESSAGE, "alternative route goal area %d, numclusterareas = %d\n", bestareanum, numclusterareas); if (color) { AAS_DrawPermanentCross((*aasworld).areas[bestareanum].center, 10, color); } //end if //AAS_ShowArea(bestarea, qtrue); #endif*/ //don't return more than the maximum alternative route goals if (numaltroutegoals >= maxaltroutegoals) { break; } } //end for //botimport.Print(PRT_MESSAGE, "%d alternative route goals\n", numaltroutegoals); #ifdef DEBUG // botimport.Print(PRT_MESSAGE, "alternative route goals in %d msec\n", Sys_MilliSeconds() - startmillisecs); #endif return numaltroutegoals; #endif } //end of the function AAS_AlternativeRouteGoals
// predicts the movement // assumes regular bounding box sizes // NOTE: out of water jumping is not included // NOTE: grappling hook is not included // origin origin to start with // presencetype presence type to start with // velocity velocity to start with // cmdmove client command movement // cmdframes number of frame cmdmove is valid // maxframes maximum number of predicted frames // frametime duration of one predicted frame // stopevent events that stop the prediction // stopareanum stop as soon as entered this area int AAS_ClientMovementPrediction(struct aas_clientmove_s *move, int entnum, vector3 *origin, int presencetype, int onground, vector3 *velocity, vector3 *cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, vector3 *mins, vector3 *maxs, int visualize) { float phys_friction, phys_stopspeed, phys_gravity, phys_waterfriction; float phys_watergravity; float phys_walkaccelerate, phys_airaccelerate, phys_swimaccelerate; float phys_maxwalkvelocity, phys_maxcrouchvelocity, phys_maxswimvelocity; float phys_maxstep, phys_maxsteepness, phys_jumpvel, friction; float gravity, delta, maxvel, wishspeed, accelerate; //float velchange, newvel; //int ax; int n, i, j, pc, step, swimming, crouch, event, jump_frame, areanum; int areas[20], numareas; vector3 points[20]; vector3 org, end, feet, start, stepend, lastorg, wishdir; vector3 frame_test_vel, old_frame_test_vel, left_test_vel; vector3 up = {0, 0, 1}; aas_plane_t *plane, *plane2; aas_trace_t trace, steptrace; if (frametime <= 0) frametime = 0.1f; // phys_friction = aassettings.phys_friction; phys_stopspeed = aassettings.phys_stopspeed; phys_gravity = aassettings.phys_gravity; phys_waterfriction = aassettings.phys_waterfriction; phys_watergravity = aassettings.phys_watergravity; phys_maxwalkvelocity = aassettings.phys_maxwalkvelocity;// * frametime; phys_maxcrouchvelocity = aassettings.phys_maxcrouchvelocity;// * frametime; phys_maxswimvelocity = aassettings.phys_maxswimvelocity;// * frametime; phys_walkaccelerate = aassettings.phys_walkaccelerate; phys_airaccelerate = aassettings.phys_airaccelerate; phys_swimaccelerate = aassettings.phys_swimaccelerate; phys_maxstep = aassettings.phys_maxstep; phys_maxsteepness = aassettings.phys_maxsteepness; phys_jumpvel = aassettings.phys_jumpvel * frametime; // memset(move, 0, sizeof(aas_clientmove_t)); memset(&trace, 0, sizeof(aas_trace_t)); //start at the current origin VectorCopy(origin, &org); org.z += 0.25f; //velocity to test for the first frame VectorScale(velocity, frametime, &frame_test_vel); // jump_frame = -1; //predict a maximum of 'maxframes' ahead for (n = 0; n < maxframes; n++) { swimming = AAS_Swimming(&org); //get gravity depending on swimming or not gravity = swimming ? phys_watergravity : phys_gravity; //apply gravity at the START of the frame frame_test_vel.z = frame_test_vel.z - (gravity * 0.1f * frametime); //if on the ground or swimming if (onground || swimming) { friction = swimming ? phys_friction : phys_waterfriction; //apply friction VectorScale(&frame_test_vel, 1/frametime, &frame_test_vel); AAS_ApplyFriction(&frame_test_vel, friction, phys_stopspeed, frametime); VectorScale(&frame_test_vel, frametime, &frame_test_vel); } crouch = qfalse; //apply command movement if (n < cmdframes) { //ax = 0; maxvel = phys_maxwalkvelocity; accelerate = phys_airaccelerate; VectorCopy(cmdmove, &wishdir); if (onground) { if (cmdmove->z < -300) { crouch = qtrue; maxvel = phys_maxcrouchvelocity; } //if not swimming and upmove is positive then jump if (!swimming && cmdmove->z > 1) { //jump velocity minus the gravity for one frame + 5 for safety frame_test_vel.z = phys_jumpvel - (gravity * 0.1f * frametime) + 5; jump_frame = n; //jumping so air accelerate accelerate = phys_airaccelerate; } else { accelerate = phys_walkaccelerate; } //ax = 2; } if (swimming) { maxvel = phys_maxswimvelocity; accelerate = phys_swimaccelerate; //ax = 3; } else { wishdir.z = 0; } // wishspeed = VectorNormalize(&wishdir); if (wishspeed > maxvel) wishspeed = maxvel; VectorScale(&frame_test_vel, 1/frametime, &frame_test_vel); AAS_Accelerate(&frame_test_vel, frametime, &wishdir, wishspeed, accelerate); VectorScale(&frame_test_vel, frametime, &frame_test_vel); /* for (i = 0; i < ax; i++) { velchange = (cmdmove[i] * frametime) - frame_test_vel[i]; if (velchange > phys_maxacceleration) velchange = phys_maxacceleration; else if (velchange < -phys_maxacceleration) velchange = -phys_maxacceleration; newvel = frame_test_vel[i] + velchange; // if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel; else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel; else frame_test_vel[i] = newvel; } */ } if (crouch) { presencetype = PRESENCE_CROUCH; } else if (presencetype == PRESENCE_CROUCH) { if (AAS_PointPresenceType(&org) & PRESENCE_NORMAL) { presencetype = PRESENCE_NORMAL; } } //save the current origin VectorCopy(&org, &lastorg); //move linear during one frame VectorCopy(&frame_test_vel, &left_test_vel); j = 0; do { VectorAdd(&org, &left_test_vel, &end); //trace a bounding box trace = AAS_TraceClientBBox(&org, &end, presencetype, entnum); // //#ifdef AAS_MOVE_DEBUG if (visualize) { if (trace.startsolid) botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n"); AAS_DebugLine(&org, &trace.endpos, LINECOLOR_RED); } //#endif //AAS_MOVE_DEBUG // if (stopevent & (SE_ENTERAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_TOUCHCLUSTERPORTAL)) { numareas = AAS_TraceAreas(&org, &trace.endpos, areas, points, 20); for (i = 0; i < numareas; i++) { if (stopevent & SE_ENTERAREA) { if (areas[i] == stopareanum) { VectorCopy(&points[i], &move->endpos); VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->endarea = areas[i]; move->trace = trace; move->stopevent = SE_ENTERAREA; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } //NOTE: if not the first frame if ((stopevent & SE_TOUCHJUMPPAD) && n) { if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_JUMPPAD) { VectorCopy(&points[i], &move->endpos); VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->endarea = areas[i]; move->trace = trace; move->stopevent = SE_TOUCHJUMPPAD; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } if (stopevent & SE_TOUCHTELEPORTER) { if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_TELEPORTER) { VectorCopy(&points[i], &move->endpos); move->endarea = areas[i]; VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->trace = trace; move->stopevent = SE_TOUCHTELEPORTER; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } if (stopevent & SE_TOUCHCLUSTERPORTAL) { if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_CLUSTERPORTAL) { VectorCopy(&points[i], &move->endpos); move->endarea = areas[i]; VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->trace = trace; move->stopevent = SE_TOUCHCLUSTERPORTAL; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } } } // if (stopevent & SE_HITBOUNDINGBOX) { if (AAS_ClipToBBox(&trace, &org, &trace.endpos, presencetype, mins, maxs)) { VectorCopy(&trace.endpos, &move->endpos); move->endarea = AAS_PointAreaNum(&move->endpos); VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->trace = trace; move->stopevent = SE_HITBOUNDINGBOX; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } //move the entity to the trace end point VectorCopy(&trace.endpos, &org); //if there was a collision if (trace.fraction < 1.0f) { //get the plane the bounding box collided with plane = AAS_PlaneFromNum(trace.planenum); // if (stopevent & SE_HITGROUNDAREA) { if (DotProduct(&plane->normal, &up) > phys_maxsteepness) { VectorCopy(&org, &start); start.z += 0.5f; if (AAS_PointAreaNum(&start) == stopareanum) { VectorCopy(&start, &move->endpos); move->endarea = stopareanum; VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->trace = trace; move->stopevent = SE_HITGROUNDAREA; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } } //assume there's no step step = qfalse; //if it is a vertical plane and the bot didn't jump recently if (plane->normal.z == 0 && (jump_frame < 0 || n - jump_frame > 2)) { //check for a step VectorMA(&org, -0.25f, &plane->normal, &start); VectorCopy(&start, &stepend); start.z += phys_maxstep; steptrace = AAS_TraceClientBBox(&start, &stepend, presencetype, entnum); // if (!steptrace.startsolid) { plane2 = AAS_PlaneFromNum(steptrace.planenum); if (DotProduct(&plane2->normal, &up) > phys_maxsteepness) { VectorSubtract(&end, &steptrace.endpos, &left_test_vel); left_test_vel.z = 0; frame_test_vel.z = 0; //#ifdef AAS_MOVE_DEBUG if (visualize) { if (steptrace.endpos.z - org.z > 0.125f) { VectorCopy(&org, &start); start.z = steptrace.endpos.z; AAS_DebugLine(&org, &start, LINECOLOR_BLUE); } } //#endif //AAS_MOVE_DEBUG org.z = steptrace.endpos.z; step = qtrue; } } } // if (!step) { //velocity left to test for this frame is the projection //of the current test velocity into the hit plane VectorMA(&left_test_vel, -DotProduct(&left_test_vel, &plane->normal), &plane->normal, &left_test_vel); //store the old velocity for landing check VectorCopy(&frame_test_vel, &old_frame_test_vel); //test velocity for the next frame is the projection //of the velocity of the current frame into the hit plane VectorMA(&frame_test_vel, -DotProduct(&frame_test_vel, &plane->normal), &plane->normal, &frame_test_vel); //check for a landing on an almost horizontal floor if (DotProduct(&plane->normal, &up) > phys_maxsteepness) { onground = qtrue; } if (stopevent & SE_HITGROUNDDAMAGE) { delta = 0; if (old_frame_test_vel.z < 0 && frame_test_vel.z > old_frame_test_vel.z && !onground) { delta = old_frame_test_vel.z; } else if (onground) { delta = frame_test_vel.z - old_frame_test_vel.z; } if (delta) { delta = delta * 10; delta = delta * delta * 0.0001f; if (swimming) delta = 0; // never take falling damage if completely underwater /* if (ent->waterlevel == 3) return; if (ent->waterlevel == 2) delta *= 0.25f; if (ent->waterlevel == 1) delta *= 0.5f; */ if (delta > 40) { VectorCopy(&org, &move->endpos); move->endarea = AAS_PointAreaNum(&org); VectorCopy(&frame_test_vel, &move->velocity); move->trace = trace; move->stopevent = SE_HITGROUNDDAMAGE; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } } } } //extra check to prevent endless loop if (++j > 20) return qfalse; //while there is a plane hit } while(trace.fraction < 1.0f); //if going down if (frame_test_vel.z <= 10) { //check for a liquid at the feet of the bot VectorCopy(&org, &feet); feet.z -= 22; pc = AAS_PointContents(&feet); //get event from pc event = SE_NONE; if (pc & CONTENTS_LAVA) event |= SE_ENTERLAVA; if (pc & CONTENTS_SLIME) event |= SE_ENTERSLIME; if (pc & CONTENTS_WATER) event |= SE_ENTERWATER; // areanum = AAS_PointAreaNum(&org); if (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA) event |= SE_ENTERLAVA; if (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME) event |= SE_ENTERSLIME; if (aasworld.areasettings[areanum].contents & AREACONTENTS_WATER) event |= SE_ENTERWATER; //if in lava or slime if (event & stopevent) { VectorCopy(&org, &move->endpos); move->endarea = areanum; VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->stopevent = event & stopevent; move->presencetype = presencetype; move->endcontents = pc; move->time = n * frametime; move->frames = n; return qtrue; } } // onground = AAS_OnGround(&org, presencetype, entnum); //if onground and on the ground for at least one whole frame if (onground) { if (stopevent & SE_HITGROUND) { VectorCopy(&org, &move->endpos); move->endarea = AAS_PointAreaNum(&org); VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->trace = trace; move->stopevent = SE_HITGROUND; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } else if (stopevent & SE_LEAVEGROUND) { VectorCopy(&org, &move->endpos); move->endarea = AAS_PointAreaNum(&org); VectorScale(&frame_test_vel, 1/frametime, &move->velocity); move->trace = trace; move->stopevent = SE_LEAVEGROUND; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } else if (stopevent & SE_GAP) { aas_trace_t gaptrace; VectorCopy(&org, &start); VectorCopy(&start, &end); end.z -= 48 + aassettings.phys_maxbarrier; gaptrace = AAS_TraceClientBBox(&start, &end, PRESENCE_CROUCH, -1); //if solid is found the bot cannot walk any further and will not fall into a gap if (!gaptrace.startsolid) { //if it is a gap (lower than one step height) if (gaptrace.endpos.z < org.z - aassettings.phys_maxstep - 1) { if (!(AAS_PointContents(&end) & CONTENTS_WATER)) { VectorCopy(&lastorg, &move->endpos); move->endarea = AAS_PointAreaNum(&lastorg); VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->trace = trace; move->stopevent = SE_GAP; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } } } } // VectorCopy(&org, &move->endpos); move->endarea = AAS_PointAreaNum(&org); VectorScale(&frame_test_vel, 1.0f/frametime, &move->velocity); move->stopevent = SE_NONE; move->presencetype = presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; // return qtrue; }
int BotExportTest( int parm0, char *parm1, vec3_t parm2, vec3_t parm3 ) { #if !defined RTCW_ET // return AAS_PointLight(parm2, NULL, NULL, NULL); #ifdef DEBUG static int area = -1; static int line[2]; #if defined RTCW_SP int newarea, i, highlightarea, bot_testhidepos, hideposarea, bot_testroutevispos; #elif defined RTCW_MP int newarea, i, highlightarea, bot_testhidepos, hideposarea; #endif // RTCW_XX // int reachnum; vec3_t eye, forward, right, end, origin; // vec3_t bottomcenter; // aas_trace_t trace; // aas_face_t *face; // aas_entity_t *ent; // bsp_trace_t bsptrace; // aas_reachability_t reach; // bot_goal_t goal; // clock_t start_time, end_time; vec3_t mins = {-16, -16, -24}; vec3_t maxs = {16, 16, 32}; // int areas[10], numareas; //return 0; if ( !( *aasworld ).loaded ) { return 0; } AAS_SetCurrentWorld( 0 ); for ( i = 0; i < 2; i++ ) if ( !line[i] ) { line[i] = botimport.DebugLineCreate(); } // AAS_ClearShownDebugLines(); bot_testhidepos = LibVarGetValue( "bot_testhidepos" ); if ( bot_testhidepos ) { VectorCopy( parm2, origin ); newarea = BotFuzzyPointReachabilityArea( origin ); if ( parm0 & 1 ) { botlibglobals.goalareanum = newarea; VectorCopy( origin, botlibglobals.goalorigin ); botimport.Print( PRT_MESSAGE, "new enemy position %2.1f %2.1f %2.1f area %d\n", origin[0], origin[1], origin[2], newarea ); } //end if AAS_ClearShownPolygons(); AAS_ClearShownDebugLines(); #if defined RTCW_SP hideposarea = AAS_NearestHideArea( -1, origin, AAS_PointAreaNum( origin ), 0, #elif defined RTCW_MP hideposarea = AAS_NearestHideArea( 0, origin, AAS_PointAreaNum( origin ), 0, #endif // RTCW_XX botlibglobals.goalorigin, botlibglobals.goalareanum, TFL_DEFAULT ); #if defined RTCW_SP if ( bot_testhidepos > 1 ) { if ( hideposarea ) { botimport.Print( PRT_MESSAGE, "hidepos (%i) %2.1f %2.1f %2.1f\n", hideposarea, ( *aasworld ).areawaypoints[hideposarea][0], ( *aasworld ).areawaypoints[hideposarea][1], ( *aasworld ).areawaypoints[hideposarea][2] ); } else { botimport.Print( PRT_MESSAGE, "no hidepos found\n" ); } } #endif // RTCW_XX //area we are currently in AAS_ShowAreaPolygons( newarea, 1, qtrue ); //enemy position AAS_ShowAreaPolygons( botlibglobals.goalareanum, 2, qtrue ); //area we should go hide AAS_ShowAreaPolygons( hideposarea, 4, qtrue ); return 0; } #if defined RTCW_SP bot_testroutevispos = LibVarGetValue( "bot_testroutevispos" ); if ( bot_testroutevispos ) { VectorCopy( parm2, origin ); newarea = BotFuzzyPointReachabilityArea( origin ); if ( parm0 & 1 ) { botlibglobals.goalareanum = newarea; VectorCopy( origin, botlibglobals.goalorigin ); botimport.Print( PRT_MESSAGE, "new enemy position %2.1f %2.1f %2.1f area %d\n", origin[0], origin[1], origin[2], newarea ); } //end if AAS_ClearShownPolygons(); AAS_ClearShownDebugLines(); AAS_GetRouteFirstVisPos( botlibglobals.goalorigin, origin, TFL_DEFAULT, eye ); //area we are currently in AAS_ShowAreaPolygons( newarea, 1, qtrue ); //enemy position AAS_ShowAreaPolygons( botlibglobals.goalareanum, 2, qtrue ); //area that is visible in path from enemy pos hideposarea = BotFuzzyPointReachabilityArea( eye ); AAS_ShowAreaPolygons( hideposarea, 4, qtrue ); return 0; } #endif // RTCW_XX //if (AAS_AgainstLadder(parm2)) botimport.Print(PRT_MESSAGE, "against ladder\n"); //BotOnGround(parm2, PRESENCE_NORMAL, 1, &newarea, &newarea); //botimport.Print(PRT_MESSAGE, "%f %f %f\n", parm2[0], parm2[1], parm2[2]); //* highlightarea = LibVarGetValue( "bot_highlightarea" ); if ( highlightarea > 0 ) { newarea = highlightarea; } //end if else { VectorCopy( parm2, origin ); origin[2] += 0.5; //newarea = AAS_PointAreaNum(origin); newarea = BotFuzzyPointReachabilityArea( origin ); } //end else botimport.Print( PRT_MESSAGE, "\rtravel time to goal (%d) = %d ", botlibglobals.goalareanum, AAS_AreaTravelTimeToGoalArea( newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT ) ); //newarea = BotReachabilityArea(origin, qtrue); if ( newarea != area ) { botimport.Print( PRT_MESSAGE, "origin = %f, %f, %f\n", origin[0], origin[1], origin[2] ); area = newarea; botimport.Print( PRT_MESSAGE, "new area %d, cluster %d, presence type %d\n", area, AAS_AreaCluster( area ), AAS_PointPresenceType( origin ) ); if ( ( *aasworld ).areasettings[area].areaflags & AREA_LIQUID ) { botimport.Print( PRT_MESSAGE, "liquid area\n" ); } //end if botimport.Print( PRT_MESSAGE, "area contents: " ); if ( ( *aasworld ).areasettings[area].contents & AREACONTENTS_WATER ) { botimport.Print( PRT_MESSAGE, "water " ); } //end if if ( ( *aasworld ).areasettings[area].contents & AREACONTENTS_LAVA ) { botimport.Print( PRT_MESSAGE, "lava " ); } //end if if ( ( *aasworld ).areasettings[area].contents & AREACONTENTS_SLIME ) { // botimport.Print(PRT_MESSAGE, "slime "); botimport.Print( PRT_MESSAGE, "slag " ); } //end if if ( ( *aasworld ).areasettings[area].contents & AREACONTENTS_JUMPPAD ) { botimport.Print( PRT_MESSAGE, "jump pad " ); } //end if if ( ( *aasworld ).areasettings[area].contents & AREACONTENTS_CLUSTERPORTAL ) { botimport.Print( PRT_MESSAGE, "cluster portal " ); } //end if if ( ( *aasworld ).areasettings[area].contents & AREACONTENTS_DONOTENTER ) { botimport.Print( PRT_MESSAGE, "do not enter " ); } //end if if ( ( *aasworld ).areasettings[area].contents & AREACONTENTS_DONOTENTER_LARGE ) { botimport.Print( PRT_MESSAGE, "do not enter large " ); } //end if if ( !( *aasworld ).areasettings[area].contents ) { botimport.Print( PRT_MESSAGE, "empty " ); } //end if if ( ( *aasworld ).areasettings[area].areaflags & AREA_DISABLED ) { botimport.Print( PRT_MESSAGE, "DISABLED" ); } //end if botimport.Print( PRT_MESSAGE, "\n" ); botimport.Print( PRT_MESSAGE, "travel time to goal (%d) = %d\n", botlibglobals.goalareanum, AAS_AreaTravelTimeToGoalArea( newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT | TFL_ROCKETJUMP ) ); /* VectorCopy(origin, end); end[2] += 5; numareas = AAS_TraceAreas(origin, end, areas, NULL, 10); AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1); botimport.Print(PRT_MESSAGE, "num areas = %d, area = %d\n", numareas, areas[0]); */ /* botlibglobals.goalareanum = newarea; VectorCopy(parm2, botlibglobals.goalorigin); botimport.Print(PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", origin[0], origin[1], origin[2], newarea); */ } //end if //* if ( parm0 & 1 ) { botlibglobals.goalareanum = newarea; VectorCopy( parm2, botlibglobals.goalorigin ); botimport.Print( PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", origin[0], origin[1], origin[2], newarea ); } //end if*/ // if (parm0 & BUTTON_USE) // { // botlibglobals.runai = !botlibglobals.runai; // if (botlibglobals.runai) botimport.Print(PRT_MESSAGE, "started AI\n"); // else botimport.Print(PRT_MESSAGE, "stopped AI\n"); //* / /* goal.areanum = botlibglobals.goalareanum; reachnum = BotGetReachabilityToGoal(parm2, newarea, 1, ms.avoidreach, ms.avoidreachtimes, &goal, TFL_DEFAULT); if (!reachnum) { botimport.Print(PRT_MESSAGE, "goal not reachable\n"); } //end if else { AAS_ReachabilityFromNum(reachnum, &reach); AAS_ClearShownDebugLines(); AAS_ShowArea(area, qtrue); AAS_ShowArea(reach.areanum, qtrue); AAS_DrawCross(reach.start, 6, LINECOLOR_BLUE); AAS_DrawCross(reach.end, 6, LINECOLOR_RED); // if (reach.traveltype == TRAVEL_ELEVATOR) { ElevatorBottomCenter(&reach, bottomcenter); AAS_DrawCross(bottomcenter, 10, LINECOLOR_GREEN); } //end if } //end else*/ // botimport.Print(PRT_MESSAGE, "travel time to goal = %d\n", // AAS_AreaTravelTimeToGoalArea(area, origin, botlibglobals.goalareanum, TFL_DEFAULT)); // botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n"); // AAS_Reachability_WeaponJump(703, 716); // } //end if*/ /* face = AAS_AreaGroundFace(newarea, parm2); if (face) { AAS_ShowFace(face - (*aasworld).faces); } //end if*/ /* AAS_ClearShownDebugLines(); AAS_ShowArea(newarea, parm0 & BUTTON_USE); AAS_ShowReachableAreas(area); */ AAS_ClearShownPolygons(); AAS_ClearShownDebugLines(); AAS_ShowAreaPolygons( newarea, 1, parm0 & 4 ); if ( parm0 & 2 ) { AAS_ShowReachableAreas( area ); } else { static int lastgoalareanum, lastareanum; static int avoidreach[MAX_AVOIDREACH]; static float avoidreachtimes[MAX_AVOIDREACH]; static int avoidreachtries[MAX_AVOIDREACH]; int reachnum; bot_goal_t goal; aas_reachability_t reach; goal.areanum = botlibglobals.goalareanum; VectorCopy( botlibglobals.goalorigin, goal.origin ); reachnum = BotGetReachabilityToGoal( origin, newarea, -1, lastgoalareanum, lastareanum, avoidreach, avoidreachtimes, avoidreachtries, &goal, TFL_DEFAULT | TFL_FUNCBOB, TFL_DEFAULT | TFL_FUNCBOB ); AAS_ReachabilityFromNum( reachnum, &reach ); AAS_ShowReachability( &reach ); } //end else VectorClear( forward ); //BotGapDistance(origin, forward, 0); /* if (parm0 & BUTTON_USE) { botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n"); AAS_Reachability_WeaponJump(703, 716); } //end if*/ AngleVectors( parm3, forward, right, NULL ); //get the eye 16 units to the right of the origin VectorMA( parm2, 8, right, eye ); //get the eye 24 units up eye[2] += 24; //get the end point for the line to be traced VectorMA( eye, 800, forward, end ); // AAS_TestMovementPrediction(1, parm2, forward); /* //trace the line to find the hit point trace = AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1); if (!line[0]) line[0] = botimport.DebugLineCreate(); botimport.DebugLineShow(line[0], eye, trace.endpos, LINECOLOR_BLUE); // AAS_ClearShownDebugLines(); if (trace.ent) { ent = &(*aasworld).entities[trace.ent]; AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); } //end if*/ /* start_time = clock(); for (i = 0; i < 2000; i++) { AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); // AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1); } //end for end_time = clock(); botimport.Print(PRT_MESSAGE, "me %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC); start_time = clock(); for (i = 0; i < 2000; i++) { AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); } //end for end_time = clock(); botimport.Print(PRT_MESSAGE, "id %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC); */ /* AAS_ClearShownDebugLines(); //bsptrace = AAS_Trace(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID); bsptrace = AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); if (!line[0]) line[0] = botimport.DebugLineCreate(); botimport.DebugLineShow(line[0], eye, bsptrace.endpos, LINECOLOR_YELLOW); if (bsptrace.fraction < 1.0) { face = AAS_TraceEndFace(&trace); if (face) { AAS_ShowFace(face - (*aasworld).faces); } //end if AAS_DrawPlaneCross(bsptrace.endpos, bsptrace.plane.normal, bsptrace.plane.dist + bsptrace.exp_dist, bsptrace.plane.type, LINECOLOR_GREEN); if (trace.ent) { ent = &(*aasworld).entities[trace.ent]; AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); } //end if } //end if*/ /*/ //bsptrace = AAS_Trace2(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID); bsptrace = AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); botimport.DebugLineShow(line[1], eye, bsptrace.endpos, LINECOLOR_BLUE); if (bsptrace.fraction < 1.0) { AAS_DrawPlaneCross(bsptrace.endpos, bsptrace.plane.normal, bsptrace.plane.dist,// + bsptrace.exp_dist, bsptrace.plane.type, LINECOLOR_RED); if (bsptrace.ent) { ent = &(*aasworld).entities[bsptrace.ent]; AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); } //end if } //end if */ #endif #else static int area = -1; static int line[2]; int newarea, i, highlightarea, bot_testhidepos, hideposarea, bot_debug; vec3_t forward, origin; // vec3_t mins = {-16, -16, -24}; // vec3_t maxs = {16, 16, 32}; if ( !aasworld->loaded ) { return 0; } AAS_SetCurrentWorld( 0 ); for ( i = 0; i < 2; i++ ) { if ( !line[i] ) { line[i] = botimport.DebugLineCreate(); } } // AAS_ClearShownDebugLines(); bot_testhidepos = LibVarGetValue( "bot_testhidepos" ); if ( bot_testhidepos ) { VectorCopy( parm2, origin ); newarea = BotFuzzyPointReachabilityArea( origin ); if ( parm0 & 1 ) { botlibglobals.goalareanum = newarea; VectorCopy( origin, botlibglobals.goalorigin ); botimport.Print( PRT_MESSAGE, "new enemy position %2.1f %2.1f %2.1f area %d\n", origin[0], origin[1], origin[2], newarea ); } //end if AAS_ClearShownPolygons(); AAS_ClearShownDebugLines(); hideposarea = AAS_NearestHideArea( 0, origin, AAS_PointAreaNum( origin ), 0, botlibglobals.goalorigin, botlibglobals.goalareanum, TFL_DEFAULT, 99999, NULL ); //area we are currently in AAS_ShowAreaPolygons( newarea, 1, qtrue ); //enemy position AAS_ShowAreaPolygons( botlibglobals.goalareanum, 2, qtrue ); //area we should go hide AAS_ShowAreaPolygons( hideposarea, 4, qtrue ); return 0; } highlightarea = LibVarGetValue( "bot_highlightarea" ); if ( highlightarea > 0 ) { newarea = highlightarea; } else { VectorCopy( parm2, origin ); //origin[2] += 0.5; newarea = BotFuzzyPointReachabilityArea( origin ); } //end else bot_debug = LibVarGetValue( "bot_debug" ); if ( bot_debug == 9 ) { aas_clientmove_t move; vec3_t dest; qboolean this_success; if ( parm0 & 1 ) { botlibglobals.goalareanum = newarea; VectorCopy( parm2, botlibglobals.goalorigin ); botimport.Print( PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", origin[0], origin[1], origin[2], newarea ); } VectorCopy( parm2, origin ); VectorCopy( botlibglobals.goalorigin, dest ); // debug direct movement VectorSubtract( dest, origin, forward ); VectorNormalize( forward ); VectorScale( forward, 300, forward ); this_success = AAS_PredictClientMovement( &move, 0, origin, -1, qfalse, forward, dest, -1, 40, 0.05, SE_ENTERAREA | SE_HITGROUNDDAMAGE | SE_HITENT | SE_HITGROUNDAREA | SE_STUCK | SE_GAP, botlibglobals.goalareanum, qtrue ); if ( this_success ) { switch ( move.stopevent ) { case SE_ENTERAREA: case SE_HITENT: case SE_HITGROUNDAREA: break; default: this_success = qfalse; } } if ( this_success != botlibglobals.lastsuccess ) { botimport.Print( PRT_MESSAGE, "DirectMove: %s\n", this_success ? "SUCCESS" : "FAILURE" ); botlibglobals.lastsuccess = this_success; } return 0; } botimport.Print( PRT_MESSAGE, "\rtravel time to goal (%d) = %d ", botlibglobals.goalareanum, AAS_AreaTravelTimeToGoalArea( newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT ) ); if ( newarea != area ) { botimport.Print( PRT_MESSAGE, "origin = %f, %f, %f\n", origin[0], origin[1], origin[2] ); area = newarea; botimport.Print( PRT_MESSAGE, "new area %d, cluster %d, presence type %d\n", area, AAS_AreaCluster( area ), AAS_PointPresenceType( origin ) ); if ( aasworld->areasettings[area].areaflags & AREA_LIQUID ) { botimport.Print( PRT_MESSAGE, "liquid area\n" ); } //end if botimport.Print( PRT_MESSAGE, "area contents: " ); if ( aasworld->areasettings[area].contents & AREACONTENTS_MOVER ) { botimport.Print( PRT_MESSAGE, "mover " ); } //end if if ( aasworld->areasettings[area].contents & AREACONTENTS_WATER ) { botimport.Print( PRT_MESSAGE, "water " ); } //end if if ( aasworld->areasettings[area].contents & AREACONTENTS_LAVA ) { botimport.Print( PRT_MESSAGE, "lava " ); } //end if if ( aasworld->areasettings[area].contents & AREACONTENTS_SLIME ) { botimport.Print( PRT_MESSAGE, "slag " ); } //end if if ( aasworld->areasettings[area].contents & AREACONTENTS_JUMPPAD ) { botimport.Print( PRT_MESSAGE, "jump pad " ); } //end if if ( aasworld->areasettings[area].contents & AREACONTENTS_CLUSTERPORTAL ) { botimport.Print( PRT_MESSAGE, "cluster portal " ); } //end if if ( aasworld->areasettings[area].contents & AREACONTENTS_DONOTENTER ) { botimport.Print( PRT_MESSAGE, "do not enter " ); } //end if if ( aasworld->areasettings[area].contents & AREACONTENTS_DONOTENTER_LARGE ) { botimport.Print( PRT_MESSAGE, "do not enter large " ); } //end if if ( !aasworld->areasettings[area].contents ) { botimport.Print( PRT_MESSAGE, "empty " ); } //end if botimport.Print( PRT_MESSAGE, "\n" ); botimport.Print( PRT_MESSAGE, "area flags: " ); if ( aasworld->areasettings[area].areaflags & AREA_LADDER ) { botimport.Print( PRT_MESSAGE, "ladder " ); } if ( aasworld->areasettings[area].areaflags & AREA_GROUNDED ) { botimport.Print( PRT_MESSAGE, "grounded " ); } if ( aasworld->areasettings[area].areaflags & AREA_LIQUID ) { botimport.Print( PRT_MESSAGE, "liquid " ); } if ( aasworld->areasettings[area].areaflags & AREA_DISABLED ) { botimport.Print( PRT_MESSAGE, "DISABLED " ); } if ( aasworld->areasettings[area].areaflags & AREA_AVOID ) { botimport.Print( PRT_MESSAGE, "AVOID " ); } botimport.Print( PRT_MESSAGE, "\n" ); botimport.Print( PRT_MESSAGE, "travel time to goal (%d) = %d\n", botlibglobals.goalareanum, AAS_AreaTravelTimeToGoalArea( newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT | TFL_ROCKETJUMP ) ); } if ( parm0 & 1 ) { botlibglobals.goalareanum = newarea; VectorCopy( parm2, botlibglobals.goalorigin ); botimport.Print( PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", origin[0], origin[1], origin[2], newarea ); } AAS_ClearShownPolygons(); AAS_ClearShownDebugLines(); if ( parm0 & 8 ) { int jk = 0; if ( parm0 & 16 ) { for ( ; jk < aasworld->numareas; jk++ ) { if ( !( aasworld->areasettings[jk].areaflags & AREA_DISABLED ) ) { AAS_ShowAreaPolygons( jk, 1, parm0 & 4 ); } } } else { for ( ; jk < aasworld->numareas; jk++ ) { AAS_ShowAreaPolygons( jk, 1, parm0 & 4 ); } } } else { AAS_ShowAreaPolygons( newarea, 1, parm0 & 4 ); } if ( parm0 & 2 ) { AAS_ShowReachableAreas( area ); } else { static int lastgoalareanum, lastareanum; static int avoidreach[MAX_AVOIDREACH]; static float avoidreachtimes[MAX_AVOIDREACH]; static int avoidreachtries[MAX_AVOIDREACH]; int reachnum; bot_goal_t goal; aas_reachability_t reach; static int lastreach; goal.areanum = botlibglobals.goalareanum; VectorCopy( botlibglobals.goalorigin, goal.origin ); reachnum = BotGetReachabilityToGoal( origin, newarea, -1, lastgoalareanum, lastareanum, avoidreach, avoidreachtimes, avoidreachtries, &goal, TFL_DEFAULT | TFL_FUNCBOB, TFL_DEFAULT ); AAS_ReachabilityFromNum( reachnum, &reach ); if ( lastreach != reachnum ) { botimport.Print( PRT_MESSAGE, "Travel Type: " ); AAS_PrintTravelType( reach.traveltype ); botimport.Print( PRT_MESSAGE, "\n" ); } lastreach = reachnum; AAS_ShowReachability( &reach ); } //end else VectorClear( forward ); #endif // RTCW_XX return 0; } //end of the function BotExportTest
void AAS_AddTeleporterPortals(void) { int j, area2num, facenum, otherareanum; char *target, *targetname, *classname; bsp_entity_t *entities, *ent, *dest; vec3_t origin, destorigin, mins, maxs, end; vec3_t bbmins, bbmaxs; aas_area_t *area; aas_face_t *face; aas_trace_t trace; aas_link_t *areas, *link; entities = AAS_ParseBSPEntities(); for (ent = entities; ent; ent = ent->next) { classname = AAS_ValueForBSPEpairKey(ent, "classname"); if (classname && !strcmp(classname, "misc_teleporter")) { if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) { botimport.Print(PRT_ERROR, "teleporter (%s) without origin\n", target); continue; } //end if // target = AAS_ValueForBSPEpairKey(ent, "target"); if (!target) { botimport.Print(PRT_ERROR, "teleporter (%s) without target\n", target); continue; } //end if for (dest = entities; dest; dest = dest->next) { classname = AAS_ValueForBSPEpairKey(dest, "classname"); if (classname && !strcmp(classname, "misc_teleporter_dest")) { targetname = AAS_ValueForBSPEpairKey(dest, "targetname"); if (targetname && !strcmp(targetname, target)) { break; } //end if } //end if } //end for if (!dest) { botimport.Print(PRT_ERROR, "teleporter without destination (%s)\n", target); continue; } //end if if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin)) { botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target); continue; } //end if destorigin[2] += 24; //just for q2e1m2, the dork has put the telepads in the ground VectorCopy(destorigin, end); end[2] -= 100; trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1); if (trace.startsolid) { botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target); continue; } //end if VectorCopy(trace.endpos, destorigin); area2num = AAS_PointAreaNum(destorigin); //reset all cluster fields for (j = 0; j < aasworld.numareas; j++) { aasworld.areasettings[j].cluster = 0; } //end for // VectorSet(mins, -8, -8, 8); VectorSet(maxs, 8, 8, 24); // AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs); // VectorAdd(origin, mins, mins); VectorAdd(origin, maxs, maxs); //add bounding box size VectorSubtract(mins, bbmaxs, mins); VectorSubtract(maxs, bbmins, maxs); //link an invalid (-1) entity areas = AAS_AASLinkEntity(mins, maxs, -1); // for (link = areas; link; link = link->next_area) { if (!AAS_AreaGrounded(link->areanum)) continue; //add the teleporter portal mark aasworld.areasettings[link->areanum].contents |= AREACONTENTS_CLUSTERPORTAL | AREACONTENTS_TELEPORTAL; } //end for // for (link = areas; link; link = link->next_area) { if (!AAS_AreaGrounded(link->areanum)) continue; //find a non-portal area adjacent to the portal area and flood //the cluster from there area = &aasworld.areas[link->areanum]; for (j = 0; j < area->numfaces; j++) { facenum = abs(aasworld.faceindex[area->firstface + j]); face = &aasworld.faces[facenum]; // if (face->frontarea != link->areanum) otherareanum = face->frontarea; else otherareanum = face->backarea; // if (!otherareanum) continue; // if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) { continue; } //end if // AAS_FloodCluster_r(otherareanum, 1); } //end for } //end for //if the teleport destination IS in the same cluster if (aasworld.areasettings[area2num].cluster) { for (link = areas; link; link = link->next_area) { if (!AAS_AreaGrounded(link->areanum)) continue; //add the teleporter portal mark aasworld.areasettings[link->areanum].contents &= ~(AREACONTENTS_CLUSTERPORTAL | AREACONTENTS_TELEPORTAL); } //end for } //end if } //end if } //end for AAS_FreeBSPEntities(entities); } //end of the function AAS_AddTeleporterPortals
//=========================================================================== // predicts the movement // assumes regular bounding box sizes // NOTE: out of water jumping is not included // NOTE: grappling hook is not included // // Parameter: origin : origin to start with // presencetype : presence type to start with // velocity : velocity to start with // cmdmove : client command movement // cmdframes : number of frame cmdmove is valid // maxframes : maximum number of predicted frames // frametime : duration of one predicted frame // stopevent : events that stop the prediction // stopareanum : stop as soon as entered this area // Returns: aas_clientmove_t // Changes Globals: - //=========================================================================== int AAS_PredictClientMovement( struct aas_clientmove_s *move, int entnum, vec3_t origin, #if !defined RTCW_ET int presencetype, int onground, #else int hitent, int onground, #endif // RTCW_XX vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize ) { float sv_friction, sv_stopspeed, sv_gravity, sv_waterfriction; float sv_watergravity; float sv_walkaccelerate, sv_airaccelerate, sv_swimaccelerate; float sv_maxwalkvelocity, sv_maxcrouchvelocity, sv_maxswimvelocity; float sv_maxstep, sv_maxsteepness, sv_jumpvel, friction; float gravity, delta, maxvel, wishspeed, accelerate; //float velchange, newvel; int n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum; int areas[20], numareas; #if !defined RTCW_ET vec3_t points[20]; vec3_t org, end, feet, start, stepend, lastorg, wishdir; vec3_t frame_test_vel, old_frame_test_vel, left_test_vel; vec3_t up = {0, 0, 1}; aas_plane_t *plane, *plane2; aas_trace_t trace, steptrace; #else vec3_t points[20], mins, maxs; vec3_t org, end, feet, start, stepend, lastorg, wishdir; vec3_t frame_test_vel, old_frame_test_vel, left_test_vel, savevel; vec3_t up = {0, 0, 1}; cplane_t *plane, *plane2, *lplane; //aas_trace_t trace, steptrace; bsp_trace_t trace, steptrace; if ( visualize ) { // These debugging tools are not currently available in bspc. Mad Doctor I, 1/27/2003. #ifndef BSPC AAS_ClearShownPolygons(); AAS_ClearShownDebugLines(); #endif } // don't let us succeed on interaction with area 0 if ( stopareanum == 0 ) { stopevent &= ~( SE_ENTERAREA | SE_HITGROUNDAREA ); } #endif // RTCW_XX if ( frametime <= 0 ) { frametime = 0.1; } // sv_friction = aassettings.sv_friction; sv_stopspeed = aassettings.sv_stopspeed; sv_gravity = aassettings.sv_gravity; sv_waterfriction = aassettings.sv_waterfriction; sv_watergravity = aassettings.sv_watergravity; sv_maxwalkvelocity = aassettings.sv_maxwalkvelocity; // * frametime; sv_maxcrouchvelocity = aassettings.sv_maxcrouchvelocity; // * frametime; sv_maxswimvelocity = aassettings.sv_maxswimvelocity; // * frametime; sv_walkaccelerate = aassettings.sv_walkaccelerate; sv_airaccelerate = aassettings.sv_airaccelerate; sv_swimaccelerate = aassettings.sv_swimaccelerate; sv_maxstep = aassettings.sv_maxstep; sv_maxsteepness = aassettings.sv_maxsteepness; sv_jumpvel = aassettings.sv_jumpvel * frametime; // memset( move, 0, sizeof( aas_clientmove_t ) ); #if !defined RTCW_ET memset( &trace, 0, sizeof( aas_trace_t ) ); #else memset( &trace, 0, sizeof( bsp_trace_t ) ); AAS_PresenceTypeBoundingBox( PRESENCE_NORMAL, mins, maxs ); #endif // RTCW_XX //start at the current origin VectorCopy( origin, org ); org[2] += 0.25; #if defined RTCW_ET // test this position, if it's in solid, move it up to adjust for capsules //trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum); trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY ); while ( trace.startsolid ) { org[2] += 8; //trace = AAS_TraceClientBBox(org, org, PRESENCE_NORMAL, entnum); trace = AAS_Trace( org, mins, maxs, org, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY ); if ( trace.startsolid && ( org[2] - origin[2] > 16 ) ) { move->stopevent = SE_NONE; return qfalse; } } #endif // RTCW_XX //velocity to test for the first frame VectorScale( velocity, frametime, frame_test_vel ); // jump_frame = -1; #if defined RTCW_ET lplane = NULL; #endif // RTCW_XX //predict a maximum of 'maxframes' ahead for ( n = 0; n < maxframes; n++ ) { swimming = AAS_Swimming( org ); //get gravity depending on swimming or not gravity = swimming ? sv_watergravity : sv_gravity; //apply gravity at the START of the frame frame_test_vel[2] = frame_test_vel[2] - ( gravity * 0.1 * frametime ); //if on the ground or swimming if ( onground || swimming ) { friction = swimming ? sv_friction : sv_waterfriction; //apply friction VectorScale( frame_test_vel, 1 / frametime, frame_test_vel ); AAS_ApplyFriction( frame_test_vel, friction, sv_stopspeed, frametime ); VectorScale( frame_test_vel, frametime, frame_test_vel ); } //end if crouch = qfalse; //apply command movement #if !defined RTCW_ET if ( n < cmdframes ) { #else if ( cmdframes < 0 ) { // cmdmove is the destination, we should keep moving towards it VectorSubtract( cmdmove, org, wishdir ); VectorNormalize( wishdir ); VectorScale( wishdir, sv_maxwalkvelocity, wishdir ); VectorCopy( frame_test_vel, savevel ); VectorScale( wishdir, frametime, frame_test_vel ); if ( !swimming ) { frame_test_vel[2] = savevel[2]; } } else if ( n < cmdframes ) { #endif // RTCW_XX ax = 0; maxvel = sv_maxwalkvelocity; accelerate = sv_airaccelerate; VectorCopy( cmdmove, wishdir ); if ( onground ) { if ( cmdmove[2] < -300 ) { crouch = qtrue; maxvel = sv_maxcrouchvelocity; } //end if //if not swimming and upmove is positive then jump if ( !swimming && cmdmove[2] > 1 ) { //jump velocity minus the gravity for one frame + 5 for safety frame_test_vel[2] = sv_jumpvel - ( gravity * 0.1 * frametime ) + 5; jump_frame = n; //jumping so air accelerate accelerate = sv_airaccelerate; } //end if else { accelerate = sv_walkaccelerate; } //end else ax = 2; } //end if if ( swimming ) { maxvel = sv_maxswimvelocity; accelerate = sv_swimaccelerate; ax = 3; } //end if else { wishdir[2] = 0; } //end else // wishspeed = VectorNormalize( wishdir ); if ( wishspeed > maxvel ) { wishspeed = maxvel; } VectorScale( frame_test_vel, 1 / frametime, frame_test_vel ); AAS_Accelerate( frame_test_vel, frametime, wishdir, wishspeed, accelerate ); VectorScale( frame_test_vel, frametime, frame_test_vel ); /* for (i = 0; i < ax; i++) { velchange = (cmdmove[i] * frametime) - frame_test_vel[i]; if (velchange > sv_maxacceleration) velchange = sv_maxacceleration; else if (velchange < -sv_maxacceleration) velchange = -sv_maxacceleration; newvel = frame_test_vel[i] + velchange; // if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel; else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel; else frame_test_vel[i] = newvel; } //end for */ } //end if #if !defined RTCW_ET if ( crouch ) { presencetype = PRESENCE_CROUCH; } //end if else if ( presencetype == PRESENCE_CROUCH ) { if ( AAS_PointPresenceType( org ) & PRESENCE_NORMAL ) { presencetype = PRESENCE_NORMAL; } //end if } //end else #else //if (crouch) //{ // presencetype = PRESENCE_CROUCH; //} //end if //else if (presencetype == PRESENCE_CROUCH) //{ // if (AAS_PointPresenceType(org) & PRESENCE_NORMAL) // { // presencetype = PRESENCE_NORMAL; // } //end if //} //end else #endif // RTCW_XX //save the current origin VectorCopy( org, lastorg ); //move linear during one frame VectorCopy( frame_test_vel, left_test_vel ); j = 0; do { VectorAdd( org, left_test_vel, end ); //trace a bounding box #if !defined RTCW_ET trace = AAS_TraceClientBBox( org, end, presencetype, entnum ); #else //trace = AAS_TraceClientBBox(org, end, PRESENCE_NORMAL, entnum); trace = AAS_Trace( org, mins, maxs, end, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY ); #endif // RTCW_XX // //#ifdef AAS_MOVE_DEBUG if ( visualize ) { #if !defined RTCW_ET if ( trace.startsolid ) { botimport.Print( PRT_MESSAGE, "PredictMovement: start solid\n" ); } #else //if (trace.startsolid) //botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n"); #endif // RTCW_XX AAS_DebugLine( org, trace.endpos, LINECOLOR_RED ); } //end if //#endif //AAS_MOVE_DEBUG // #if defined RTCW_ET if ( stopevent & SE_HITENT ) { if ( trace.fraction < 1.0 && trace.ent == hitent ) { areanum = AAS_PointAreaNum( org ); VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_HITENT; move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } #endif // RTCW_XX if ( stopevent & SE_ENTERAREA ) { numareas = AAS_TraceAreas( org, trace.endpos, areas, points, 20 ); for ( i = 0; i < numareas; i++ ) { if ( areas[i] == stopareanum ) { VectorCopy( points[i], move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_ENTERAREA; #if !defined RTCW_ET move->presencetype = presencetype; #else move->presencetype = ( *aasworld ).areasettings[areas[i]].presencetype; #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end for } //end if #if defined RTCW_ET if ( stopevent & SE_STUCK ) { if ( trace.fraction < 1.0 ) { plane = &trace.plane; //if (Q_fabs(plane->normal[2]) <= sv_maxsteepness) { VectorNormalize2( frame_test_vel, wishdir ); if ( DotProduct( plane->normal, wishdir ) < -0.8 ) { areanum = AAS_PointAreaNum( org ); VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_STUCK; move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } } } #endif // RTCW_XX //move the entity to the trace end point VectorCopy( trace.endpos, org ); //if there was a collision if ( trace.fraction < 1.0 ) { //get the plane the bounding box collided with #if !defined RTCW_ET plane = AAS_PlaneFromNum( trace.planenum ); #else plane = &trace.plane; #endif // RTCW_XX // if ( stopevent & SE_HITGROUNDAREA ) { if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) { VectorCopy( org, start ); start[2] += 0.5; #if !defined RTCW_ET if ( AAS_PointAreaNum( start ) == stopareanum ) { #else if ( ( stopareanum < 0 && AAS_PointAreaNum( start ) ) || ( AAS_PointAreaNum( start ) == stopareanum ) ) { #endif // RTCW_XX VectorCopy( start, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_HITGROUNDAREA; #if !defined RTCW_ET move->presencetype = presencetype; #else move->presencetype = ( *aasworld ).areasettings[stopareanum].presencetype; #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end if } //end if //assume there's no step step = qfalse; //if it is a vertical plane and the bot didn't jump recently if ( plane->normal[2] == 0 && ( jump_frame < 0 || n - jump_frame > 2 ) ) { //check for a step VectorMA( org, -0.25, plane->normal, start ); VectorCopy( start, stepend ); start[2] += sv_maxstep; #if !defined RTCW_ET steptrace = AAS_TraceClientBBox( start, stepend, presencetype, entnum ); #else //steptrace = AAS_TraceClientBBox(start, stepend, PRESENCE_NORMAL, entnum); steptrace = AAS_Trace( start, mins, maxs, stepend, entnum, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY ); #endif // RTCW_XX // if ( !steptrace.startsolid ) { #if !defined RTCW_ET plane2 = AAS_PlaneFromNum( steptrace.planenum ); #else plane2 = &steptrace.plane; #endif // RTCW_XX if ( DotProduct( plane2->normal, up ) > sv_maxsteepness ) { VectorSubtract( end, steptrace.endpos, left_test_vel ); left_test_vel[2] = 0; frame_test_vel[2] = 0; //#ifdef AAS_MOVE_DEBUG if ( visualize ) { if ( steptrace.endpos[2] - org[2] > 0.125 ) { VectorCopy( org, start ); start[2] = steptrace.endpos[2]; AAS_DebugLine( org, start, LINECOLOR_BLUE ); } //end if } //end if //#endif //AAS_MOVE_DEBUG org[2] = steptrace.endpos[2]; step = qtrue; } //end if } //end if } //end if // if ( !step ) { //velocity left to test for this frame is the projection //of the current test velocity into the hit plane VectorMA( left_test_vel, -DotProduct( left_test_vel, plane->normal ), plane->normal, left_test_vel ); #if defined RTCW_ET // RF: from PM_SlideMove() // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes if ( lplane && DotProduct( lplane->normal, plane->normal ) > 0.99 ) { VectorAdd( plane->normal, left_test_vel, left_test_vel ); } lplane = plane; #endif // RTCW_XX //store the old velocity for landing check VectorCopy( frame_test_vel, old_frame_test_vel ); //test velocity for the next frame is the projection //of the velocity of the current frame into the hit plane VectorMA( frame_test_vel, -DotProduct( frame_test_vel, plane->normal ), plane->normal, frame_test_vel ); //check for a landing on an almost horizontal floor if ( DotProduct( plane->normal, up ) > sv_maxsteepness ) { onground = qtrue; } //end if if ( stopevent & SE_HITGROUNDDAMAGE ) { delta = 0; if ( old_frame_test_vel[2] < 0 && frame_test_vel[2] > old_frame_test_vel[2] && !onground ) { delta = old_frame_test_vel[2]; } //end if else if ( onground ) { delta = frame_test_vel[2] - old_frame_test_vel[2]; } //end else if ( delta ) { delta = delta * 10; delta = delta * delta * 0.0001; if ( swimming ) { delta = 0; } // never take falling damage if completely underwater /* if (ent->waterlevel == 3) return; if (ent->waterlevel == 2) delta *= 0.25; if (ent->waterlevel == 1) delta *= 0.5; */ if ( delta > 40 ) { VectorCopy( org, move->endpos ); VectorCopy( frame_test_vel, move->velocity ); move->trace = trace; move->stopevent = SE_HITGROUNDDAMAGE; #if !defined RTCW_ET move->presencetype = presencetype; #else areanum = AAS_PointAreaNum( org ); if ( areanum ) { move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; } #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end if } //end if } //end if } //end if //extra check to prevent endless loop if ( ++j > 20 ) { return qfalse; } //while there is a plane hit } while ( trace.fraction < 1.0 ); //if going down if ( frame_test_vel[2] <= 10 ) { //check for a liquid at the feet of the bot VectorCopy( org, feet ); feet[2] -= 22; pc = AAS_PointContents( feet ); //get event from pc event = SE_NONE; if ( pc & CONTENTS_LAVA ) { event |= SE_ENTERLAVA; } if ( pc & CONTENTS_SLIME ) { event |= SE_ENTERSLIME; } if ( pc & CONTENTS_WATER ) { event |= SE_ENTERWATER; } // areanum = AAS_PointAreaNum( org ); if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_LAVA ) { event |= SE_ENTERLAVA; } if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_SLIME ) { event |= SE_ENTERSLIME; } if ( ( *aasworld ).areasettings[areanum].contents & AREACONTENTS_WATER ) { event |= SE_ENTERWATER; } //if in lava or slime if ( event & stopevent ) { VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->stopevent = event & stopevent; #if !defined RTCW_ET move->presencetype = presencetype; #else move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; #endif // RTCW_XX move->endcontents = pc; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end if // #if !defined RTCW_ET onground = AAS_OnGround( org, presencetype, entnum ); #else onground = AAS_OnGround( org, PRESENCE_NORMAL, entnum ); #endif // RTCW_XX //if onground and on the ground for at least one whole frame if ( onground ) { if ( stopevent & SE_HITGROUND ) { VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_HITGROUND; #if !defined RTCW_ET move->presencetype = presencetype; #else areanum = AAS_PointAreaNum( org ); if ( areanum ) { move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; } #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end if else if ( stopevent & SE_LEAVEGROUND ) { VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_LEAVEGROUND; #if !defined RTCW_ET move->presencetype = presencetype; #else areanum = AAS_PointAreaNum( org ); if ( areanum ) { move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; } #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end else if else if ( stopevent & SE_GAP ) { #if !defined RTCW_ET aas_trace_t gaptrace; #else bsp_trace_t gaptrace; #endif // RTCW_XX VectorCopy( org, start ); VectorCopy( start, end ); end[2] -= 48 + aassettings.sv_maxbarrier; #if !defined RTCW_ET gaptrace = AAS_TraceClientBBox( start, end, PRESENCE_CROUCH, -1 ); #else //gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); gaptrace = AAS_Trace( start, mins, maxs, end, -1, ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) & ~CONTENTS_BODY ); #endif // RTCW_XX //if solid is found the bot cannot walk any further and will not fall into a gap if ( !gaptrace.startsolid ) { //if it is a gap (lower than one step height) if ( gaptrace.endpos[2] < org[2] - aassettings.sv_maxstep - 1 ) { if ( !( AAS_PointContents( end ) & ( CONTENTS_WATER | CONTENTS_SLIME ) ) ) { //----(SA) modified since slime is no longer deadly // if (!(AAS_PointContents(end) & CONTENTS_WATER)) VectorCopy( lastorg, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_GAP; #if !defined RTCW_ET move->presencetype = presencetype; #else areanum = AAS_PointAreaNum( org ); if ( areanum ) { move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; } #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end if } //end if } //end else if if ( stopevent & SE_TOUCHJUMPPAD ) { if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_JUMPPAD ) { VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_TOUCHJUMPPAD; #if !defined RTCW_ET move->presencetype = presencetype; #else areanum = AAS_PointAreaNum( org ); if ( areanum ) { move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; } #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end if if ( stopevent & SE_TOUCHTELEPORTER ) { if ( ( *aasworld ).areasettings[AAS_PointAreaNum( org )].contents & AREACONTENTS_TELEPORTER ) { VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->trace = trace; move->stopevent = SE_TOUCHTELEPORTER; #if !defined RTCW_ET move->presencetype = presencetype; #else areanum = AAS_PointAreaNum( org ); if ( areanum ) { move->presencetype = ( *aasworld ).areasettings[areanum].presencetype; } #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; return qtrue; } //end if } //end if } //end for // #if defined RTCW_ET areanum = AAS_PointAreaNum( org ); #endif // RTCW_XX VectorCopy( org, move->endpos ); VectorScale( frame_test_vel, 1 / frametime, move->velocity ); move->stopevent = SE_NONE; #if !defined RTCW_ET move->presencetype = presencetype; #else move->presencetype = aasworld->areasettings ? aasworld->areasettings[areanum].presencetype : 0; #endif // RTCW_XX move->endcontents = 0; move->time = n * frametime; move->frames = n; // return qtrue; } //end of the function AAS_PredictClientMovement //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_TestMovementPrediction( int entnum, vec3_t origin, vec3_t dir ) { vec3_t velocity, cmdmove; aas_clientmove_t move; VectorClear( velocity ); if ( !AAS_Swimming( origin ) ) { dir[2] = 0; } VectorNormalize( dir ); VectorScale( dir, 400, cmdmove ); cmdmove[2] = 224; AAS_ClearShownDebugLines(); AAS_PredictClientMovement( &move, entnum, origin, PRESENCE_NORMAL, qtrue, velocity, cmdmove, 13, 13, 0.1, SE_HITGROUND, 0, qtrue ); //SE_LEAVEGROUND); if ( move.stopevent & SE_LEAVEGROUND ) { botimport.Print( PRT_MESSAGE, "leave ground\n" ); } //end if } //end of the function TestMovementPrediction //=========================================================================== // calculates the horizontal velocity needed to perform a jump from start // to end // // Parameter: zvel : z velocity for jump // start : start position of jump // end : end position of jump // *speed : returned speed for jump // Returns: qfalse if too high or too far from start to end // Changes Globals: - //=========================================================================== int AAS_HorizontalVelocityForJump( float zvel, vec3_t start, vec3_t end, float *velocity ) { float sv_gravity, sv_maxvelocity; float maxjump, height2fall, t, top; vec3_t dir; sv_gravity = aassettings.sv_gravity; sv_maxvelocity = aassettings.sv_maxvelocity; //maximum height a player can jump with the given initial z velocity maxjump = 0.5 * sv_gravity * ( zvel / sv_gravity ) * ( zvel / sv_gravity ); //top of the parabolic jump top = start[2] + maxjump; //height the bot will fall from the top height2fall = top - end[2]; //if the goal is to high to jump to if ( height2fall < 0 ) { *velocity = sv_maxvelocity; return 0; } //end if //time a player takes to fall the height t = c::sqrt( height2fall / ( 0.5 * sv_gravity ) ); //direction from start to end VectorSubtract( end, start, dir ); //calculate horizontal speed *velocity = c::sqrt( dir[0] * dir[0] + dir[1] * dir[1] ) / ( t + zvel / sv_gravity ); //the horizontal speed must be lower than the max speed if ( *velocity > sv_maxvelocity ) { *velocity = sv_maxvelocity; return 0; } //end if return 1; } //end of the function AAS_HorizontalVelocityForJump
//=========================================================================== // returns qtrue if the bot is against a ladder // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_AgainstLadder( vec3_t origin, int ms_areanum ) { int areanum, i, facenum, side; vec3_t org; aas_plane_t *plane; aas_face_t *face; aas_area_t *area; VectorCopy( origin, org ); areanum = AAS_PointAreaNum( org ); if ( !areanum ) { org[0] += 1; areanum = AAS_PointAreaNum( org ); if ( !areanum ) { org[1] += 1; areanum = AAS_PointAreaNum( org ); if ( !areanum ) { org[0] -= 2; areanum = AAS_PointAreaNum( org ); if ( !areanum ) { org[1] -= 2; areanum = AAS_PointAreaNum( org ); } //end if } //end if } //end if } //end if //if in solid... wrrr shouldn't happen //if (!areanum) return qfalse; // RF, it does if they're in a monsterclip brush if ( !areanum ) { areanum = ms_areanum; } //if not in a ladder area if ( !( ( *aasworld ).areasettings[areanum].areaflags & AREA_LADDER ) ) { return qfalse; } //if a crouch only area if ( !( ( *aasworld ).areasettings[areanum].presencetype & PRESENCE_NORMAL ) ) { return qfalse; } // area = &( *aasworld ).areas[areanum]; for ( i = 0; i < area->numfaces; i++ ) { facenum = ( *aasworld ).faceindex[area->firstface + i]; side = facenum < 0; face = &( *aasworld ).faces[c::abs( facenum )]; //if the face isn't a ladder face if ( !( face->faceflags & FACE_LADDER ) ) { continue; } //get the plane the face is in plane = &( *aasworld ).planes[face->planenum ^ side]; //if the origin is pretty close to the plane #if !defined RTCW_ET if ( c::abs( DotProduct( plane->normal, origin ) - plane->dist ) < 3 ) { if ( AAS_PointInsideFace( c::abs( facenum ), origin, 0.1 ) ) { #else if ( c::abs( DotProduct( plane->normal, origin ) - plane->dist ) < 7 ) { // RF, if hanging on to the edge of a ladder, we have to account for bounding box touching //if (AAS_PointInsideFace(c::abs(facenum), origin, 0.1)) return qtrue; if ( AAS_PointInsideFace( c::abs( facenum ), origin, 2.0 ) ) { #endif // RTCW_XX return qtrue; } } //end if } //end for return qfalse; } //end of the function AAS_AgainstLadder //=========================================================================== // returns qtrue if the bot is on the ground // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_OnGround( vec3_t origin, int presencetype, int passent ) { #if !defined RTCW_ET aas_trace_t trace; #else //aas_trace_t trace; bsp_trace_t trace; #endif // RTCW_XX vec3_t end, up = {0, 0, 1}; #if !defined RTCW_ET aas_plane_t *plane; #else //aas_plane_t *plane; vec3_t mins, maxs; #endif // RTCW_XX VectorCopy( origin, end ); end[2] -= 10; #if !defined RTCW_ET trace = AAS_TraceClientBBox( origin, end, presencetype, passent ); #else //trace = AAS_TraceClientBBox(origin, end, presencetype, passent); AAS_PresenceTypeBoundingBox( presencetype, mins, maxs ); trace = AAS_Trace( origin, mins, maxs, end, passent, CONTENTS_SOLID | CONTENTS_PLAYERCLIP ); #endif // RTCW_XX //if in solid if ( trace.startsolid ) { #if !defined RTCW_MP return qtrue; //qfalse; #else return qfalse; #endif // RTCW_XX } //if nothing hit at all if ( trace.fraction >= 1.0 ) { return qfalse; } //if too far from the hit plane if ( origin[2] - trace.endpos[2] > 10 ) { return qfalse; } //check if the plane isn't too steep #if !defined RTCW_ET plane = AAS_PlaneFromNum( trace.planenum ); if ( DotProduct( plane->normal, up ) < aassettings.sv_maxsteepness ) { #else //plane = AAS_PlaneFromNum(trace.planenum); if ( DotProduct( trace.plane.normal, up ) < aassettings.sv_maxsteepness ) { #endif // RTCW_XX return qfalse; } //the bot is on the ground return qtrue; } //end of the function AAS_OnGround //=========================================================================== // returns qtrue if a bot at the given position is swimming // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_Swimming( vec3_t origin ) { vec3_t testorg; VectorCopy( origin, testorg ); testorg[2] -= 2; if ( AAS_PointContents( testorg ) & ( CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER ) ) { return qtrue; } return qfalse; } //end of the function AAS_Swimming //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== vec3_t VEC_UP = {0, -1, 0}; vec3_t MOVEDIR_UP = {0, 0, 1}; vec3_t VEC_DOWN = {0, -2, 0}; vec3_t MOVEDIR_DOWN = {0, 0, -1}; void AAS_SetMovedir( vec3_t angles, vec3_t movedir ) { if ( VectorCompare( angles, VEC_UP ) ) { VectorCopy( MOVEDIR_UP, movedir ); } //end if else if ( VectorCompare( angles, VEC_DOWN ) ) { VectorCopy( MOVEDIR_DOWN, movedir ); } //end else if else { AngleVectors( angles, movedir, NULL, NULL ); } //end else } //end of the function AAS_SetMovedir //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_JumpReachRunStart( aas_reachability_t *reach, vec3_t runstart ) { vec3_t hordir, start, cmdmove; aas_clientmove_t move; // hordir[0] = reach->start[0] - reach->end[0]; hordir[1] = reach->start[1] - reach->end[1]; hordir[2] = 0; VectorNormalize( hordir ); //start point VectorCopy( reach->start, start ); start[2] += 1; //get command movement VectorScale( hordir, 400, cmdmove ); // AAS_PredictClientMovement( &move, -1, start, PRESENCE_NORMAL, qtrue, vec3_origin, cmdmove, 1, 2, 0.1, SE_ENTERWATER | SE_ENTERSLIME | SE_ENTERLAVA | SE_HITGROUNDDAMAGE | SE_GAP, 0, qfalse ); VectorCopy( move.endpos, runstart ); //don't enter slime or lava and don't fall from too high if ( move.stopevent & ( SE_ENTERLAVA | SE_HITGROUNDDAMAGE ) ) { //----(SA) modified since slime is no longer deadly // if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) VectorCopy( start, runstart ); } //end if } //end of the function AAS_JumpReachRunStart
//=========================================================================== // returns qtrue if the bot is against a ladder // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_AgainstLadder(vec3_t origin, int ms_areanum) { int areanum, i, facenum, side; vec3_t org; aas_plane_t *plane; aas_face_t *face; aas_area_t *area; VectorCopy(origin, org); areanum = AAS_PointAreaNum(org); if (!areanum) { org[0] += 1; areanum = AAS_PointAreaNum(org); if (!areanum) { org[1] += 1; areanum = AAS_PointAreaNum(org); if (!areanum) { org[0] -= 2; areanum = AAS_PointAreaNum(org); if (!areanum) { org[1] -= 2; areanum = AAS_PointAreaNum(org); } //end if } //end if } //end if } //end if //if in solid... wrrr shouldn't happen //if (!areanum) return qfalse; // RF, it does if they're in a monsterclip brush if (!areanum) { areanum = ms_areanum; } //if not in a ladder area if (!((*aasworld).areasettings[areanum].areaflags & AREA_LADDER)) { return qfalse; } //if a crouch only area if (!((*aasworld).areasettings[areanum].presencetype & PRESENCE_NORMAL)) { return qfalse; } // area = &(*aasworld).areas[areanum]; for (i = 0; i < area->numfaces; i++) { facenum = (*aasworld).faceindex[area->firstface + i]; side = facenum < 0; face = &(*aasworld).faces[abs(facenum)]; //if the face isn't a ladder face if (!(face->faceflags & FACE_LADDER)) { continue; } //get the plane the face is in plane = &(*aasworld).planes[face->planenum ^ side]; //if the origin is pretty close to the plane if (abs(DotProduct(plane->normal, origin) - plane->dist) < 7) { // RF, if hanging on to the edge of a ladder, we have to account for bounding box touching //if (AAS_PointInsideFace(abs(facenum), origin, 0.1)) return qtrue; if (AAS_PointInsideFace(abs(facenum), origin, 2.0)) { return qtrue; } } //end if } //end for return qfalse; } //end of the function AAS_AgainstLadder