1 /***************************************************************************
2 * Copyright (C) 2004 by Murray Evans *
3 * m.evans@rdg.ac.uk *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include "Ship.h"
21 #include "Galaxy.h"
22
DoAI()23 void CShip::DoAI()
24 {
25 if(this->dead_b == true) return;
26 SelectMode(); // select a new mode if appropriate
27 if(aiMode_i == AIMD_AVOID) Avoid(NULL); // avoid obstacles in the way
28 if(aiMode_i == AIMD_ROAM) Roam(); // roam randomly around galaxy
29 if(aiMode_i == AIMD_FIGHT) Fight(); // engage current target
30 if(aiMode_i == AIMD_FORMATE) Formate(); // join formation with current target
31 // ? More ?
32 }
33
SelectMode()34 void CShip::SelectMode()
35 {
36 // in all cases, check if there is something in the way and avoid hitting it...
37 // this is quite a shabby way of doing it, and I already see its flaws even before
38 // implementing it. But let's just see eh?
39 // calculate a point some distance infront of this ship
40 // in world space.
41 //*
42 extern CFreebooter FB;
43 CGalaxy *gal = (CGalaxy*)FB.scene;
44
45 CVec4f face_v4f;
46 face_v4f.SetXYZW(0,1,0,0);
47
48 CMatrix4f tfm;
49 tfm.SetIdentity();
50 glMatrixMode(GL_MODELVIEW);
51 glPushMatrix();
52 glLoadIdentity();
53 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
54 glRotatef(rot_v3f.X(), 1, 0, 0);
55 glRotatef(rot_v3f.Y(), 0, 1, 0);
56 glRotatef(rot_v3f.Z(), 0, 0, 1);
57 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
58 glPopMatrix();
59 tfm.Transpose();
60
61 face_v4f = face_v4f.Transform(tfm);
62
63 CVec4f pif = face_v4f + pos_v4f;
64 if(aiMode_i != AIMD_AVOID)
65 {
66 // see if there are any obstacles in the way
67 bool clear_b = true;
68 int sc_i = 0;
69 while((clear_b == true) && (sc_i < gal->ments.Size()))
70 {
71 CVec4f shipToEnt;
72 shipToEnt = gal->ents[gal->ments[sc_i]]->GetPos() - pos_v4f;
73 shipToEnt.SetW(0);
74 if(shipToEnt.MagSquare() < 300)
75 {
76 if(gal->ents[gal->ments[sc_i]] != this)
77 clear_b = !((CModelEntity*)gal->ents[gal->ments[sc_i]])->BSVectCollision(pos_v4f, pif);
78 }
79 if(clear_b)sc_i++;
80 }
81 if(clear_b == false)
82 {
83 aiPrevMode_i = aiMode_i;
84 aiMode_i = AIMD_AVOID;
85 aiSubMode_i = 0;
86 Avoid((CModelEntity*)gal->ents[gal->ments[sc_i]]);
87
88 }
89 }//*/
90 if(aiMode_i == AIMD_FIGHT)
91 {
92 if(((abs(X() - target->X()) > 150) &&
93 (abs(Y() - target->Y()) > 150)) || ((CShip*)target)->dead_b == true) // stop fighting (range too large || target dead)
94 {
95 // before roaming, see if an ally is alive that has an index nearer to zero.
96 // if so, formate with it.
97 //*
98 extern CFreebooter FB;
99 CGalaxy *gal = (CGalaxy*)FB.scene;
100 int c_i = 0;
101 bool newTarget_b = false;
102 while((gal->ents[gal->ships[c_i]] != this) && (newTarget_b == false))
103 {
104 // is this ship an ally?
105 CShip *ship = (CShip*) gal->ents[gal->ships[c_i]];
106 if((ship->faction_i == this->faction_i) && (ship->dead_b == false))
107 {
108 this->target = ship;
109 newTarget_b = true;
110 aiMode_i = AIMD_FORMATE;
111 }
112 c_i++;
113 }
114
115 // Otherwise, roam.
116 if(newTarget_b == false)
117 {
118 aiMode_i = AIMD_ROAM;
119 GenerateRoute();
120 }
121 //*/
122 aiMode_i = AIMD_ROAM;
123 GenerateRoute();
124 }
125
126 }
127 // if(aiMode_i == AIMD_AVOID);
128 else if(aiMode_i == AIMD_FORMATE)
129 {
130 this->Formate();
131 }
132 else // probably roaming or formating
133 {
134 // before roaming, see if an ally is alive that has an index nearer to zero.
135 // if so, formate with it.
136
137 extern CFreebooter FB;
138 CGalaxy *gal = (CGalaxy*)FB.scene;
139 //*
140 int c_i = 0;
141 bool newTarget_b = false;
142 while((gal->ents[gal->ships[c_i]] != this) && (newTarget_b == false))
143 {
144 // is this ship an ally?
145 CShip *ship = (CShip*) gal->ents[gal->ships[c_i]];
146 if((ship->faction_i == this->faction_i) && (ship->dead_b == false))
147 {
148 this->target = ship;
149 newTarget_b = true;
150 aiMode_i = AIMD_FORMATE;
151 }
152 c_i++;
153 }
154
155 // Otherwise, roam.
156 if(newTarget_b == false)
157 {
158 aiMode_i = AIMD_ROAM;
159 GenerateRoute();
160 }
161 //*/
162 {
163 if(waypoints.Size() == 0) GenerateRoute();
164 aiMode_i = AIMD_ROAM;
165
166 // if a ship get's within a certain range, attack it until its range is twice that
167 for(int sc_i = 0; sc_i < gal->ships.Size(); sc_i++)
168 {
169 if((abs(X() - gal->ents[gal->ships[sc_i]]->X()) < 50) &&
170 (abs(Y() - gal->ents[gal->ships[sc_i]]->Y()) < 50) &&
171 (gal->factions[faction_i]->relations[((CShip*)gal->ents[gal->ships[sc_i]])->faction_i] < 4) &&
172 this != gal->ents[gal->ships[sc_i]] )
173 {
174 this->target = gal->ents[gal->ships[sc_i]];
175 aiMode_i = AIMD_FIGHT;
176 aiSubMode_i = 0;
177 }
178 }
179 }
180 }
181 }
182
GenerateRoute()183 void CShip::GenerateRoute()
184 {
185 // for now, just one random waypoint
186 extern CFreebooter FB;
187 CGalaxy *gal = (CGalaxy*) FB.scene;
188 waypoints.SetSize(1);
189 waypoints[0].SetXYZW(rand()%(int)gal->width_f, rand()%(int)gal->height_f, 0, 1);
190 }
191
Fight()192 void CShip::Fight()
193 {
194 // a bad but simple implementation based on the roaming behaviour
195 CVec4f posToWay; // vector to target - can you see the copy and paste... ;P
196 posToWay = target->GetPos() - pos_v4f;
197 posToWay.SetW(0);
198 if(posToWay.Magnitude() < 10) GenerateRoute();
199
200 // turn towards waypoint
201 CVec4f faceVector;
202 faceVector.SetXYZW(0,1,0,1);
203 CMatrix4f tfm;
204 tfm.SetIdentity();
205 glMatrixMode(GL_MODELVIEW);
206 glPushMatrix();
207 glLoadIdentity();
208 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
209 glRotatef(rot_v3f.X(), 1, 0, 0);
210 glRotatef(rot_v3f.Y(), 0, 1, 0);
211 glRotatef(rot_v3f.Z(), 0, 0, 1);
212 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
213 glPopMatrix();
214 tfm.Transpose();
215 faceVector = faceVector.Transform(tfm);
216
217 faceVector.SetW(0);
218 posToWay.SetW(0);
219
220 float dist = posToWay.MagSquare();
221
222 faceVector.Normalise();
223 posToWay.Normalise();
224
225 CVec4f vel;
226 vel.SetXYZW(-vel_v4f.X(), -vel_v4f.Y(),-vel_v4f.Z(),0);
227 vel.Normalise();
228 float degAngle;
229 CVec4f decisionVec;
230 decisionVec = posToWay.Cross(faceVector);
231 float z = decisionVec.Z();
232 float cosangle = faceVector.Dot(posToWay);
233 float angle = acos(cosangle);
234 degAngle = (angle*180) / 3.14;
235 if(aiSubMode_i == 0)
236 {
237 waypoints.Clear();
238 if(dist > rand()%4000 + 6000) // if reasonably far away
239 {
240 if(z > 0)
241 RotateCW();
242 if(z < -0)
243 RotateCCW();
244 if((degAngle < 20) || (degAngle > 340))
245 {
246 FwdThrust();
247
248 // check for line of sight. don't want to shoot a friendly!
249
250 // calculate a point some distance infront of this ship
251 // in world space.
252
253 extern CFreebooter FB;
254 CGalaxy *gal = (CGalaxy*)FB.scene;
255
256 CVec4f face_v4f;
257 face_v4f.SetXYZW(0,1,0,0);
258
259 CMatrix4f tfm;
260 tfm.SetIdentity();
261 glMatrixMode(GL_MODELVIEW);
262 glPushMatrix();
263 glLoadIdentity();
264 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
265 glRotatef(rot_v3f.X(), 1, 0, 0);
266 glRotatef(rot_v3f.Y(), 0, 1, 0);
267 glRotatef(rot_v3f.Z(), 0, 0, 1);
268 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
269 glPopMatrix();
270 tfm.Transpose();
271
272 face_v4f = face_v4f.Transform(tfm);
273
274 CVec4f pif = face_v4f + pos_v4f;
275
276 // see if there are any allied ships in the way
277 bool clear_b = true;
278 int sc_i = 0;
279 while((clear_b == true) && (sc_i < gal->ships.Size()))
280 {
281 if(((CShip*)gal->ents[gal->ships[sc_i]])->faction_i == this->faction_i)
282 {
283 clear_b = ((CShip*)gal->ents[gal->ships[sc_i]])->BSVectCollision(this->GetPos(), pif);
284 }
285 sc_i++;
286 }
287
288 if(clear_b)FireGun();
289 }
290 }
291 else if(dist < 400)
292 {
293 // BACK OFF! YOU'RE TOO CLOSE!!! AHHHH!!!
294
295 if(z > 0)
296 RotateCW();
297 if(z < -0)
298 RotateCCW();
299 if((degAngle < 20) || (degAngle > 340))
300 {
301 RvsThrust();
302 // check for line of sight. don't want to shoot a friendly!
303
304 // calculate a point some distance infront of this ship
305 // in world space.
306
307 extern CFreebooter FB;
308 CGalaxy *gal = (CGalaxy*)FB.scene;
309
310 CVec4f face_v4f;
311 face_v4f.SetXYZW(0,1,0,0);
312
313 CMatrix4f tfm;
314 tfm.SetIdentity();
315 glMatrixMode(GL_MODELVIEW);
316 glPushMatrix();
317 glLoadIdentity();
318 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
319 glRotatef(rot_v3f.X(), 1, 0, 0);
320 glRotatef(rot_v3f.Y(), 0, 1, 0);
321 glRotatef(rot_v3f.Z(), 0, 0, 1);
322 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
323 glPopMatrix();
324 tfm.Transpose();
325
326 face_v4f = face_v4f.Transform(tfm);
327
328 CVec4f pif = face_v4f + pos_v4f;
329
330 // see if there are any allied ships in the way
331 bool clear_b = true;
332 int sc_i = 0;
333 while((clear_b == true) && (sc_i < gal->ships.Size()))
334 {
335 if(((CShip*)gal->ents[gal->ships[sc_i]])->faction_i == this->faction_i)
336 {
337 clear_b = ((CShip*)gal->ents[gal->ships[sc_i]])->BSVectCollision(this->GetPos(), pif);
338 }
339 sc_i++;
340 }
341
342 if(clear_b)FireGun();
343 }
344 }
345 else
346 {
347 aiSubMode_i = 1;
348 waypoints.Clear();
349 glMatrixMode(GL_MODELVIEW);
350 glPushMatrix();
351 glLoadIdentity();
352 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
353 glRotatef(target->XRot(), 1, 0, 0);
354 glRotatef(target->YRot(), 0, 1, 0);
355 glRotatef(target->ZRot(), 0, 0, 1);
356 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
357 glPopMatrix();
358 tfm.Transpose();
359 CVec4f targsSix;
360 int r = rand()%50;
361 if(r > 25)targsSix.SetXYZW((float) -(rand()%50+50),(float)-(rand()%50+100),0,0);
362 else targsSix.SetXYZW((float)(rand()%50+50),(float)-(rand()%50+100),0,0);
363 targsSix = targsSix.Transform(tfm);
364 targsSix = targsSix + target->GetPos();
365 waypoints.AddToEnd(targsSix);
366 aiStartTime_i == SDL_GetTicks();
367 }
368 }
369 if(aiSubMode_i == 1) // otherwise fly straight past target until reasonably far away
370 {
371
372
373 Roam();
374 if((degAngle < 20) || (degAngle > 340))
375 {
376 FireGun();
377 }
378
379 if(dist > 8000) aiSubMode_i = 0;
380 if((SDL_GetTicks() - aiStartTime_i > 2000) && ((degAngle > 90) && (degAngle < 270)))
381 aiSubMode_i = 0;
382
383 }
384
385
386 }
387
Roam()388 int CShip::Roam()
389 {
390 CVec4f posToWay; // vector to waypoint
391 if(waypoints.Size() < 1)
392 {
393 GenerateRoute();
394 }
395 posToWay = waypoints[waypoints.Size()-1] - pos_v4f;
396 posToWay.SetW(0);
397 if(posToWay.Magnitude() < 10)
398 {
399 if(waypoints.Size() <= 1) waypoints.Clear();
400 else waypoints.SetSize(waypoints.Size() - 1);
401 }
402
403 // turn towards waypoint
404 CVec4f faceVector;
405 faceVector.SetXYZW(0,1,0,1);
406 CMatrix4f tfm;
407 tfm.SetIdentity();
408 glMatrixMode(GL_MODELVIEW);
409 glPushMatrix();
410 glLoadIdentity();
411 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
412 glRotatef(rot_v3f.X(), 1, 0, 0);
413 glRotatef(rot_v3f.Y(), 0, 1, 0);
414 glRotatef(rot_v3f.Z(), 0, 0, 1);
415 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
416 glPopMatrix();
417 tfm.Transpose();
418 faceVector = faceVector.Transform(tfm);
419
420 faceVector.SetW(0);
421 posToWay.SetW(0);
422 faceVector.Normalise();
423 posToWay.Normalise();
424
425 CVec4f vel;
426 vel.SetXYZW(-vel_v4f.X(), -vel_v4f.Y(),-vel_v4f.Z(),0);
427 vel.Normalise();
428 float degAngle;
429 extern CFreebooter FB;
430 CGalaxy *gal = (CGalaxy*)FB.scene;
431 if(vel_v4f.Magnitude() < (0.2 * gal->shipTypes[this->shipType_i]->fwdThrustPow_f * 50))
432 {
433 CVec4f decisionVec;
434 decisionVec = posToWay.Cross(faceVector);
435 float z = decisionVec.Z();
436 float cosangle = faceVector.Dot(posToWay);
437 float angle = acos(cosangle);
438
439 degAngle = (angle*180) / 3.14;
440 if(z > 0)
441 RotateCW();
442 if(z < -0)
443 RotateCCW();
444 if((degAngle < 20) || (degAngle > 340))
445 {
446 FwdThrust();
447 }
448 }
449 else
450 {
451 CVec4f decisionVec;
452 decisionVec = posToWay.Cross(faceVector-vel);
453 float z = decisionVec.Z();
454 if(z > 0)
455 RotateCW();
456 if(z < 0)
457 RotateCCW();
458
459 float cosangle = posToWay.Dot(faceVector);
460 float angle = acos(cosangle);
461 degAngle = (angle*180) / 3.14;
462 FwdThrust();
463
464 }
465 return degAngle;
466
467
468 }
469
470 // avoid the given entity
Avoid(CModelEntity * in_Obstacle)471 void CShip::Avoid(CModelEntity *in_Obstacle)
472 {
473
474 // there is an object in our way.
475 // generate some suitable waypoint to go around the object, then return to previous
476 // ai mode.
477 if((aiSubMode_i == 0) && (in_Obstacle != NULL)) // first time through loop
478 {
479 // get obstacle coords in local space
480 CMatrix4f tfm, invTfm;
481 glMatrixMode(GL_MODELVIEW);
482 glPushMatrix();
483 glLoadIdentity();
484 glTranslatef(pos_v4f.X(), pos_v4f.Y(), pos_v4f.Z());
485 glRotatef(XRot(), 1, 0, 0);
486 glRotatef(YRot(), 0, 1, 0);
487 glRotatef(ZRot(), 0, 0, 1);
488 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
489 glPopMatrix();
490
491 tfm.Transpose();
492 invTfm = tfm;
493 invTfm.Invert();
494
495
496 CVec4f obsLoc = in_Obstacle->GetPos();
497 obsLoc = obsLoc.Transform(invTfm);
498
499 CVec4f avoid;
500 avoid.SetXYZW(in_Obstacle->boundSphRadius_f + (this->boundSphRadius_f *1.5), 0, 0, 0);
501 CVec4f newWyPntLoc = obsLoc + avoid;
502
503 CVec4f newWyPnt;
504 newWyPnt = newWyPntLoc.Transform(tfm);
505 newWyPnt.SetZ(0);
506 waypoints.AddToEnd(newWyPnt);
507 aiSubMode_i = 1;
508 }
509
510 else
511 {
512 // if the ship reaches the avoidance waypoint, that waypoint will be removed.
513
514 int nwp = waypoints.Size();
515 Roam();
516 if((nwp - waypoints.Size()) > 0)
517 {
518 aiMode_i = aiPrevMode_i;
519 aiPrevMode_i = AIMD_AVOID;
520 }
521 }
522
523
524
525 }
526
Formate()527 void CShip::Formate()
528 {
529 if(waypoints.Size() > 0)
530 waypoints.Clear();
531 CVec4f nwp;
532 nwp.SetXYZW(target->X(), target->Y(), target->Z(), 1);
533 waypoints.AddToEnd(nwp);
534 Roam();
535 if(((CShip*)target)->aiMode_i == AIMD_FIGHT)
536 {
537 target = ((CShip*)target)->target;
538 aiMode_i = AIMD_FIGHT;
539 aiSubMode_i = 0;
540 }
541 }
542