1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 
23 #include "g_headers.h"
24 
25 #include "b_local.h"
26 #include "Q3_Interface.h"
27 
28 extern qboolean FlyingCreature( gentity_t *ent );
29 /*
30 SetGoal
31 */
32 
SetGoal(gentity_t * goal,float rating)33 void SetGoal( gentity_t *goal, float rating )
34 {
35 	NPCInfo->goalEntity = goal;
36 //	NPCInfo->goalEntityNeed = rating;
37 	NPCInfo->goalTime = level.time;
38 //	NAV_ClearLastRoute(NPC);
39 	if ( goal )
40 	{
41 //		Debug_NPCPrintf( NPC, debugNPCAI, DEBUG_LEVEL_INFO, "NPC_SetGoal: %s @ %s (%f)\n", goal->classname, vtos( goal->currentOrigin), rating );
42 	}
43 	else
44 	{
45 //		Debug_NPCPrintf( NPC, debugNPCAI, DEBUG_LEVEL_INFO, "NPC_SetGoal: NONE\n" );
46 	}
47 }
48 
49 
50 /*
51 NPC_SetGoal
52 */
53 
NPC_SetGoal(gentity_t * goal,float rating)54 void NPC_SetGoal( gentity_t *goal, float rating )
55 {
56 	if ( goal == NPCInfo->goalEntity )
57 	{
58 		return;
59 	}
60 
61 	if ( !goal )
62 	{
63 //		Debug_NPCPrintf( NPC, debugNPCAI, DEBUG_LEVEL_ERROR, "NPC_SetGoal: NULL goal\n" );
64 		return;
65 	}
66 
67 	if ( goal->client )
68 	{
69 //		Debug_NPCPrintf( NPC, debugNPCAI, DEBUG_LEVEL_ERROR, "NPC_SetGoal: goal is a client\n" );
70 		return;
71 	}
72 
73 	if ( NPCInfo->goalEntity )
74 	{
75 //		Debug_NPCPrintf( NPC, debugNPCAI, DEBUG_LEVEL_INFO, "NPC_SetGoal: push %s\n", NPCInfo->goalEntity->classname );
76 		NPCInfo->lastGoalEntity = NPCInfo->goalEntity;
77 //		NPCInfo->lastGoalEntityNeed = NPCInfo->goalEntityNeed;
78 	}
79 
80 	SetGoal( goal, rating );
81 }
82 
83 
84 /*
85 NPC_ClearGoal
86 */
87 
NPC_ClearGoal(void)88 void NPC_ClearGoal( void )
89 {
90 	gentity_t	*goal;
91 
92 	if ( !NPCInfo->lastGoalEntity )
93 	{
94 		SetGoal( NULL, 0.0 );
95 		return;
96 	}
97 
98 	goal = NPCInfo->lastGoalEntity;
99 	NPCInfo->lastGoalEntity = NULL;
100 //	NAV_ClearLastRoute(NPC);
101 	if ( goal->inuse && !(goal->s.eFlags & EF_NODRAW) )
102 	{
103 //		Debug_NPCPrintf( NPC, debugNPCAI, DEBUG_LEVEL_INFO, "NPC_ClearGoal: pop %s\n", goal->classname );
104 		SetGoal( goal, 0 );//, NPCInfo->lastGoalEntityNeed
105 		return;
106 	}
107 
108 	SetGoal( NULL, 0.0 );
109 }
110 
111 /*
112 -------------------------
113 G_BoundsOverlap
114 -------------------------
115 */
116 
G_BoundsOverlap(const vec3_t mins1,const vec3_t maxs1,const vec3_t mins2,const vec3_t maxs2)117 qboolean G_BoundsOverlap(const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2)
118 {//NOTE: flush up against counts as overlapping
119 	if(mins1[0]>maxs2[0])
120 		return qfalse;
121 
122 	if(mins1[1]>maxs2[1])
123 		return qfalse;
124 
125 	if(mins1[2]>maxs2[2])
126 		return qfalse;
127 
128 	if(maxs1[0]<mins2[0])
129 		return qfalse;
130 
131 	if(maxs1[1]<mins2[1])
132 		return qfalse;
133 
134 	if(maxs1[2]<mins2[2])
135 		return qfalse;
136 
137 	return qtrue;
138 }
139 
NPC_ReachedGoal(void)140 void NPC_ReachedGoal( void )
141 {
142 //	Debug_NPCPrintf( NPC, debugNPCAI, DEBUG_LEVEL_INFO, "UpdateGoal: reached goal entity\n" );
143 	NPC_ClearGoal();
144 	NPCInfo->goalTime = level.time;
145 
146 //MCG - Begin
147 	NPCInfo->aiFlags &= ~NPCAI_MOVING;
148 	ucmd.forwardmove = 0;
149 	//Return that the goal was reached
150 	Q3_TaskIDComplete( NPC, TID_MOVE_NAV );
151 //MCG - End
152 }
153 /*
154 ReachedGoal
155 
156 id removed checks against waypoints and is now checking surfaces
157 */
158 //qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, gentity_t *goal, qboolean flying );
ReachedGoal(gentity_t * goal)159 qboolean ReachedGoal( gentity_t *goal )
160 {
161 	//FIXME: For script waypoints, need a special check
162 /*
163 	int		goalWpNum;
164 	vec3_t	vec;
165 	//vec3_t	angles;
166 	float	delta;
167 
168 	if ( goal->svFlags & SVF_NAVGOAL )
169 	{//waypoint_navgoal
170 		return NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, goal, FlyingCreature( NPC ) );
171 	}
172 
173 	if ( goal == NPCInfo->tempGoal && !(goal->svFlags & SVF_NAVGOAL))
174 	{//MUST touch waypoints, even if moving to it
175 		//This is odd, it just checks to see if they are on the same
176 		//surface and the tempGoal in in the FOV - does NOT check distance!
177 		// are we on same surface?
178 
179 		//FIXME: NPC->waypoint reset every frame, need to find it first
180 		//Should we do that here?  (Still will do it only once per frame)
181 		if ( NPC->waypoint >= 0 && NPC->waypoint < num_waypoints )
182 		{
183 			goalWpNum = NAV_FindWaypointAt ( goal->currentOrigin );
184 			if ( NPC->waypoint != goalWpNum )
185 			{
186 				return qfalse;
187 			}
188 		}
189 
190 		VectorSubtract ( NPCInfo->tempGoal->currentOrigin, NPC->currentOrigin, vec);
191 		//Who cares if it's in our FOV?!
192 		/*
193 		// is it in our FOV
194 		vectoangles ( vec, angles );
195 		delta = AngleDelta ( NPC->client->ps.viewangles[YAW], angles[YAW] );
196 		if ( fabs ( delta ) > NPCInfo->stats.hfov )
197 		{
198 			return qfalse;
199 		}
200 		*/
201 
202 		/*
203 		//If in the same waypoint as tempGoal, we're there, right?
204 		if ( goal->waypoint >= 0 && goal->waypoint < num_waypoints )
205 		{
206 			if ( NPC->waypoint == goal->waypoint )
207 			{
208 				return qtrue;
209 			}
210 		}
211 		*/
212 
213 /*
214 		if ( VectorLengthSquared( vec ) < (64*64) )
215 		{//Close enough
216 			return qtrue;
217 		}
218 
219 		return qfalse;
220 	}
221 */
222 	if ( NPCInfo->aiFlags & NPCAI_TOUCHED_GOAL )
223 	{
224 		NPCInfo->aiFlags &= ~NPCAI_TOUCHED_GOAL;
225 		return qtrue;
226 	}
227 /*
228 	if ( goal->s.eFlags & EF_NODRAW )
229 	{
230 		goalWpNum = NAV_FindWaypointAt( goal->currentOrigin );
231 		if ( NPC->waypoint == goalWpNum )
232 		{
233 			return qtrue;
234 		}
235 		return qfalse;
236 	}
237 
238 	if(goal->client && goal->health <= 0)
239 	{//trying to get to dead guy
240 		goalWpNum = NAV_FindWaypointAt( goal->currentOrigin );
241 		if ( NPC->waypoint == goalWpNum )
242 		{
243 			VectorSubtract(NPC->currentOrigin, goal->currentOrigin, vec);
244 			vec[2] = 0;
245 			delta = VectorLengthSquared(vec);
246 			if(delta <= 800)
247 			{//with 20-30 of other guy's origin
248 				return qtrue;
249 			}
250 		}
251 	}
252 */
253 	return NAV_HitNavGoal( NPC->currentOrigin, NPC->mins, NPC->maxs, goal->currentOrigin, NPCInfo->goalRadius, FlyingCreature( NPC ) );
254 }
255 
256 /*
257 static gentity_t *UpdateGoal( void )
258 
259 Id removed a lot of shit here... doesn't seem to handle waypoints independantly of goalentity
260 
261 In fact, doesn't seem to be any waypoint info on entities at all any more?
262 
263 MCG - Since goal is ALWAYS goalEntity, took out a lot of sending goal entity pointers around for no reason
264 */
265 
UpdateGoal(void)266 gentity_t *UpdateGoal( void )
267 {
268 	gentity_t	*goal;
269 
270 	if ( !NPCInfo->goalEntity )
271 	{
272 		return NULL;
273 	}
274 
275 	if ( !NPCInfo->goalEntity->inuse )
276 	{//Somehow freed it, but didn't clear it
277 		NPC_ClearGoal();
278 		return NULL;
279 	}
280 
281 	goal = NPCInfo->goalEntity;
282 
283 	if ( ReachedGoal( goal ) )
284 	{
285 		NPC_ReachedGoal();
286 		goal = NULL;//so they don't keep trying to move to it
287 	}//else if fail, need to tell script so?
288 
289 	return goal;
290 }
291 
292