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