/* =========================================================================== Return to Castle Wolfenstein multiplayer GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”). RTCW MP Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. RTCW MP Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RTCW MP Source Code. If not, see . In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ /***************************************************************************** * name: be_aas_routealt.c * * desc: AAS * * *****************************************************************************/ #include "../game/q_shared.h" #include "l_utils.h" #include "l_memory.h" #include "l_log.h" #include "l_script.h" #include "l_precomp.h" #include "l_struct.h" #include "aasfile.h" #include "../game/botlib.h" #include "../game/be_aas.h" #include "be_aas_funcs.h" #include "be_interface.h" #include "be_aas_def.h" //#define ENABLE_ALTROUTING typedef struct midrangearea_s { int valid; unsigned short starttime; unsigned short goaltime; } midrangearea_t; midrangearea_t *midrangeareas; int *clusterareas; int numclusterareas; //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_AltRoutingFloodCluster_r( int areanum ) { int i, otherareanum; aas_area_t *area; aas_face_t *face; //add the current area to the areas of the current cluster clusterareas[numclusterareas] = areanum; numclusterareas++; //remove the area from the mid range areas midrangeareas[areanum].valid = qfalse; //flood to other areas through the faces of this area area = &( *aasworld ).areas[areanum]; for ( i = 0; i < area->numfaces; i++ ) { face = &( *aasworld ).faces[abs( ( *aasworld ).faceindex[area->firstface + i] )]; //get the area at the other side of the face if ( face->frontarea == areanum ) { otherareanum = face->backarea; } else { otherareanum = face->frontarea;} //if there is an area at the other side of this face if ( !otherareanum ) { continue; } //if the other area is not a midrange area if ( !midrangeareas[otherareanum].valid ) { continue; } // AAS_AltRoutingFloodCluster_r( otherareanum ); } //end for } //end of the function AAS_AltRoutingFloodCluster_r //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== 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; #ifdef DEBUG int startmillisecs; startmillisecs = Sys_MilliSeconds(); #endif startareanum = AAS_PointAreaNum( start ); if ( !startareanum ) { return 0; } goalareanum = AAS_PointAreaNum( goal ); 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 ) ) { 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 > 1.5 * 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 > 1.5 * 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 //now we've got an area for an alternative route //FIXME: add alternative goal origin VectorCopy( ( *aasworld ).areas[bestareanum].center, 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 //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_InitAlternativeRouting( void ) { #ifdef ENABLE_ALTROUTING if ( midrangeareas ) { FreeMemory( midrangeareas ); } midrangeareas = (midrangearea_t *) GetMemory( ( *aasworld ).numareas * sizeof( midrangearea_t ) ); if ( clusterareas ) { FreeMemory( clusterareas ); } clusterareas = (int *) GetMemory( aasworld.numareas * sizeof( int ) ); #endif } //end of the function AAS_InitAlternativeRouting //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_ShutdownAlternativeRouting( void ) { #ifdef ENABLE_ALTROUTING if ( midrangeareas ) { FreeMemory( midrangeareas ); } midrangeareas = NULL; if ( clusterareas ) { FreeMemory( clusterareas ); } clusterareas = NULL; numclusterareas = 0; #endif }