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