1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”).
8 
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW SP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW SP 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 SP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 
30 /*****************************************************************************
31  * name:		be_aas_routealt.c
32  *
33  * desc:		AAS
34  *
35  *
36  *****************************************************************************/
37 
38 #include "../qcommon/q_shared.h"
39 #include "l_utils.h"
40 #include "l_memory.h"
41 #include "l_log.h"
42 #include "l_script.h"
43 #include "l_precomp.h"
44 #include "l_struct.h"
45 #include "aasfile.h"
46 #include "botlib.h"
47 #include "be_aas.h"
48 #include "be_aas_funcs.h"
49 #include "be_interface.h"
50 #include "be_aas_def.h"
51 
52 //#define ENABLE_ALTROUTING
53 
54 typedef struct midrangearea_s
55 {
56 	int valid;
57 	unsigned short starttime;
58 	unsigned short goaltime;
59 } midrangearea_t;
60 
61 midrangearea_t *midrangeareas;
62 int *clusterareas;
63 int numclusterareas;
64 
65 //===========================================================================
66 //
67 // Parameter:				-
68 // Returns:					-
69 // Changes Globals:		-
70 //===========================================================================
AAS_AltRoutingFloodCluster_r(int areanum)71 void AAS_AltRoutingFloodCluster_r( int areanum ) {
72 	int i, otherareanum;
73 	aas_area_t *area;
74 	aas_face_t *face;
75 
76 	//add the current area to the areas of the current cluster
77 	clusterareas[numclusterareas] = areanum;
78 	numclusterareas++;
79 	//remove the area from the mid range areas
80 	midrangeareas[areanum].valid = qfalse;
81 	//flood to other areas through the faces of this area
82 	area = &( *aasworld ).areas[areanum];
83 	for ( i = 0; i < area->numfaces; i++ )
84 	{
85 		face = &( *aasworld ).faces[abs( ( *aasworld ).faceindex[area->firstface + i] )];
86 		//get the area at the other side of the face
87 		if ( face->frontarea == areanum ) {
88 			otherareanum = face->backarea;
89 		} else { otherareanum = face->frontarea;}
90 		//if there is an area at the other side of this face
91 		if ( !otherareanum ) {
92 			continue;
93 		}
94 		//if the other area is not a midrange area
95 		if ( !midrangeareas[otherareanum].valid ) {
96 			continue;
97 		}
98 		//
99 		AAS_AltRoutingFloodCluster_r( otherareanum );
100 	} //end for
101 } //end of the function AAS_AltRoutingFloodCluster_r
102 //===========================================================================
103 //
104 // Parameter:				-
105 // Returns:					-
106 // Changes Globals:		-
107 //===========================================================================
AAS_AlternativeRouteGoals(vec3_t start,vec3_t goal,int travelflags,aas_altroutegoal_t * altroutegoals,int maxaltroutegoals,int color)108 int AAS_AlternativeRouteGoals( vec3_t start, vec3_t goal, int travelflags,
109 							   aas_altroutegoal_t *altroutegoals, int maxaltroutegoals,
110 							   int color ) {
111 #ifndef ENABLE_ALTROUTING
112 	return 0;
113 #else
114 	int i, j, startareanum, goalareanum, bestareanum;
115 	int numaltroutegoals, nummidrangeareas;
116 	int starttime, goaltime, goaltraveltime;
117 	float dist, bestdist;
118 	vec3_t mid, dir;
119 #ifdef DEBUG
120 	int startmillisecs;
121 
122 	startmillisecs = Sys_MilliSeconds();
123 #endif
124 
125 	startareanum = AAS_PointAreaNum( start );
126 	if ( !startareanum ) {
127 		return 0;
128 	}
129 	goalareanum = AAS_PointAreaNum( goal );
130 	if ( !goalareanum ) {
131 		return 0;
132 	}
133 	//travel time towards the goal area
134 	goaltraveltime = AAS_AreaTravelTimeToGoalArea( startareanum, start, goalareanum, travelflags );
135 	//clear the midrange areas
136 	memset( midrangeareas, 0, ( *aasworld ).numareas * sizeof( midrangearea_t ) );
137 	numaltroutegoals = 0;
138 	//
139 	nummidrangeareas = 0;
140 	//
141 	for ( i = 1; i < ( *aasworld ).numareas; i++ )
142 	{
143 		//
144 		if ( !( ( *aasworld ).areasettings[i].contents & AREACONTENTS_ROUTEPORTAL ) ) {
145 			continue;
146 		}
147 		//if the area has no reachabilities
148 		if ( !AAS_AreaReachability( i ) ) {
149 			continue;
150 		}
151 		//tavel time from the area to the start area
152 		starttime = AAS_AreaTravelTimeToGoalArea( startareanum, start, i, travelflags );
153 		if ( !starttime ) {
154 			continue;
155 		}
156 		//if the travel time from the start to the area is greater than the shortest goal travel time
157 		if ( starttime > 1.5 * goaltraveltime ) {
158 			continue;
159 		}
160 		//travel time from the area to the goal area
161 		goaltime = AAS_AreaTravelTimeToGoalArea( i, NULL, goalareanum, travelflags );
162 		if ( !goaltime ) {
163 			continue;
164 		}
165 		//if the travel time from the area to the goal is greater than the shortest goal travel time
166 		if ( goaltime > 1.5 * goaltraveltime ) {
167 			continue;
168 		}
169 		//this is a mid range area
170 		midrangeareas[i].valid = qtrue;
171 		midrangeareas[i].starttime = starttime;
172 		midrangeareas[i].goaltime = goaltime;
173 		Log_Write( "%d midrange area %d", nummidrangeareas, i );
174 		nummidrangeareas++;
175 	} //end for
176 	  //
177 	for ( i = 1; i < ( *aasworld ).numareas; i++ )
178 	{
179 		if ( !midrangeareas[i].valid ) {
180 			continue;
181 		}
182 		//get the areas in one cluster
183 		numclusterareas = 0;
184 		AAS_AltRoutingFloodCluster_r( i );
185 		//now we've got a cluster with areas through which an alternative route could go
186 		//get the 'center' of the cluster
187 		VectorClear( mid );
188 		for ( j = 0; j < numclusterareas; j++ )
189 		{
190 			VectorAdd( mid, ( *aasworld ).areas[clusterareas[j]].center, mid );
191 		} //end for
192 		VectorScale( mid, 1.0 / numclusterareas, mid );
193 		//get the area closest to the center of the cluster
194 		bestdist = 999999;
195 		bestareanum = 0;
196 		for ( j = 0; j < numclusterareas; j++ )
197 		{
198 			VectorSubtract( mid, ( *aasworld ).areas[clusterareas[j]].center, dir );
199 			dist = VectorLength( dir );
200 			if ( dist < bestdist ) {
201 				bestdist = dist;
202 				bestareanum = clusterareas[j];
203 			} //end if
204 		} //end for
205 		  //now we've got an area for an alternative route
206 		  //FIXME: add alternative goal origin
207 		VectorCopy( ( *aasworld ).areas[bestareanum].center, altroutegoals[numaltroutegoals].origin );
208 		altroutegoals[numaltroutegoals].areanum = bestareanum;
209 		altroutegoals[numaltroutegoals].starttraveltime = midrangeareas[bestareanum].starttime;
210 		altroutegoals[numaltroutegoals].goaltraveltime = midrangeareas[bestareanum].goaltime;
211 		altroutegoals[numaltroutegoals].extratraveltime =
212 			( midrangeareas[bestareanum].starttime + midrangeareas[bestareanum].goaltime ) -
213 			goaltraveltime;
214 		numaltroutegoals++;
215 		//
216 #ifdef DEBUG
217 		botimport.Print( PRT_MESSAGE, "alternative route goal area %d, numclusterareas = %d\n", bestareanum, numclusterareas );
218 		if ( color ) {
219 			AAS_DrawPermanentCross( ( *aasworld ).areas[bestareanum].center, 10, color );
220 		} //end if
221 		  //AAS_ShowArea(bestarea, qtrue);
222 #endif
223 		//don't return more than the maximum alternative route goals
224 		if ( numaltroutegoals >= maxaltroutegoals ) {
225 			break;
226 		}
227 	} //end for
228 	botimport.Print( PRT_MESSAGE, "%d alternative route goals\n", numaltroutegoals );
229 #ifdef DEBUG
230 	botimport.Print( PRT_MESSAGE, "alternative route goals in %d msec\n", Sys_MilliSeconds() - startmillisecs );
231 #endif
232 	return numaltroutegoals;
233 #endif
234 } //end of the function AAS_AlternativeRouteGoals
235 //===========================================================================
236 //
237 // Parameter:				-
238 // Returns:					-
239 // Changes Globals:		-
240 //===========================================================================
AAS_InitAlternativeRouting(void)241 void AAS_InitAlternativeRouting( void ) {
242 #ifdef ENABLE_ALTROUTING
243 	if ( midrangeareas ) {
244 		FreeMemory( midrangeareas );
245 	}
246 	midrangeareas = (midrangearea_t *) GetMemory( ( *aasworld ).numareas * sizeof( midrangearea_t ) );
247 	if ( clusterareas ) {
248 		FreeMemory( clusterareas );
249 	}
250 	clusterareas = (int *) GetMemory( aasworld.numareas * sizeof( int ) );
251 #endif
252 } //end of the function AAS_InitAlternativeRouting
253 //===========================================================================
254 //
255 // Parameter:				-
256 // Returns:					-
257 // Changes Globals:		-
258 //===========================================================================
AAS_ShutdownAlternativeRouting(void)259 void AAS_ShutdownAlternativeRouting( void ) {
260 #ifdef ENABLE_ALTROUTING
261 	if ( midrangeareas ) {
262 		FreeMemory( midrangeareas );
263 	}
264 	midrangeareas = NULL;
265 	if ( clusterareas ) {
266 		FreeMemory( clusterareas );
267 	}
268 	clusterareas = NULL;
269 	numclusterareas = 0;
270 #endif
271 }
272