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 #include "FreeBooter.h"
23 #include "structs.h"
24 #include "SimpleParticle.h"
25 #include "GunParticle.h"
26
CShip(void)27 CShip::CShip(void)
28 {
29 extern CFreebooter FB;
30 CGalaxy *gal = (CGalaxy*)FB.scene;
31 cargoQuants.SetSize(gal->cargoTypes.Size());
32 for(int c_i = 0; c_i < cargoQuants.Size(); c_i++)
33 cargoQuants[c_i] = 0;
34 cargoLoad = 0;
35 cargoVol = 0;
36 shieldDamage_f = 0;
37 damage_i = 0;
38 // no shields to start with
39 mk1Shield_i = 0;
40 mk2Shield_i = 0;
41 mk3Shield_i = 0;
42 inContact_b = false;
43 dead_b = false;
44 faction_i = 0;
45 kills_i = 0;
46 SetVelocity(0,0,0);
47 SetRotation(0,0,0);
48 aiMode_i = AIMD_ROAM;
49 aiSubMode_i = 0;
50 }
51
~CShip(void)52 CShip::~CShip(void)
53 {
54 }
55
56
57 // control functions
RotateCW()58 void CShip::RotateCW()
59 {
60 extern CFreebooter FB;
61 CGalaxy *gal;
62 gal = (CGalaxy*) FB.scene;
63 float turnSpd = gal->shipTypes[shipType_i]->rotationSpeed_f;
64 float zRot = this->ZRot();
65 SetRotation( 0, 0, zRot - turnSpd);
66 }
67
RotateCCW()68 void CShip::RotateCCW()
69 {
70 extern CFreebooter FB;
71 CGalaxy *gal;
72 gal = (CGalaxy*) FB.scene;
73 float turnSpd = -gal->shipTypes[shipType_i]->rotationSpeed_f;
74 float zRot = this->ZRot();
75 SetRotation(0,0, zRot - turnSpd);
76 }
77
FwdThrust()78 void CShip::FwdThrust()
79 {
80 extern CFreebooter FB;
81 CGalaxy *gal;
82 gal = (CGalaxy*) FB.scene;
83 CVec4f acc_v4f; // acceleration vector
84 float accMag = gal->shipTypes[shipType_i]->fwdThrustPow_f;
85 acc_v4f.SetXYZW(0, accMag, 0, 0);
86
87 // transform to world space
88 CMatrix4f tfm;
89 tfm.SetIdentity();
90 glMatrixMode(GL_MODELVIEW);
91 glPushMatrix();
92 glLoadIdentity();
93 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
94 glRotatef(rot_v3f.X(), 1, 0, 0);
95 glRotatef(rot_v3f.Y(), 0, 1, 0);
96 glRotatef(rot_v3f.Z(), 0, 0, 1);
97 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
98 glPopMatrix();
99 tfm.Transpose();
100 acc_v4f = acc_v4f.Transform(tfm);
101 if(inContact_b == false) vel_v4f = vel_v4f + acc_v4f;
102
103 // add thruster particles
104 CVec4f newvel, randVec;
105 newvel.SetXYZW(0,0,0,0);
106 float xoff, yoff;
107 xoff = ((float)(rand()%120))/100;
108 yoff = ((float)(rand()%120))/100;
109 randVec.SetXYZW(acc_v4f.X() * xoff, acc_v4f.Y() * yoff, acc_v4f.Z(), 0);
110 newvel = vel_v4f - (acc_v4f + randVec) * 5;
111 float red, green, blue;
112 red = 0.5f;
113 red += ((float)(rand()%20))/100;
114 green = 0.4f;
115 green += ((float)(rand()%20))/100;
116 blue = 0;
117
118 for(int thrc_i = 0; thrc_i < gal->shipTypes[this->shipType_i]->thrPositions.Size(); thrc_i++)
119 {
120 CVec4f thrpos;
121 thrpos = gal->shipTypes[this->shipType_i]->thrPositions[thrc_i].Transform(tfm);
122 thrpos = thrpos + pos_v4f;
123
124 CSimpleParticle *newPart = NULL;
125 try
126 {
127 newPart = new(CSimpleParticle);
128 if(newPart != NULL)
129 {
130 newPart->SetPos(thrpos.X(), thrpos.Y(), thrpos.Z());
131 newPart->SetVelocity(newvel.X(), newvel.Y(), newvel.Z());
132 newPart->SetRotVel(0,0,0);
133 newPart->life = 20;
134 // newPart->SetColour(red, green, blue, 0.25);
135 newPart->r_f = red;
136 newPart->g_f = green;
137 newPart->b_f = blue;
138 newPart->a_f = 0.3;
139 newPart->hasTexture_b = false;
140 thrPartGen.AddParticle(newPart);
141 }
142 }
143 catch(bad_alloc)
144 {
145 cout << "couldn't allocate particle. - Fwd Thrust" << endl;
146 }
147
148 }
149
150
151 }
152
RvsThrust()153 void CShip::RvsThrust()
154 {
155 extern CFreebooter FB;
156 CGalaxy *gal;
157 gal = (CGalaxy*) FB.scene;
158 CVec4f acc_v4f; // acceleration vector
159 float accMag = -gal->shipTypes[shipType_i]->rvsTrustPow_f;
160 acc_v4f.SetXYZW(0, accMag, 0, 0);
161
162 // transform to world space
163 CMatrix4f tfm;
164 tfm.SetIdentity();
165 glMatrixMode(GL_MODELVIEW);
166 glPushMatrix();
167 glLoadIdentity();
168 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
169 glRotatef(rot_v3f.X(), 1, 0, 0);
170 glRotatef(rot_v3f.Y(), 0, 1, 0);
171 glRotatef(rot_v3f.Z(), 0, 0, 1);
172 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
173 glPopMatrix();
174 tfm.Transpose();
175 acc_v4f = acc_v4f.Transform(tfm);
176 vel_v4f = vel_v4f + acc_v4f;
177 }
178
Update()179 void CShip::Update()
180 {
181 extern CFreebooter FB;
182 CGalaxy *gal = (CGalaxy*) FB.scene;
183
184 vel_v4f.SetW(0);
185 if(vel_v4f.Magnitude() > gal->shipTypes[this->shipType_i]->fwdThrustPow_f * 50)
186 {
187 vel_v4f.Normalise();
188 vel_v4f = vel_v4f * gal->shipTypes[this->shipType_i]->fwdThrustPow_f * 50;
189 }
190 if(vel_v4f.Magnitude() > 100)
191 {
192 SetVelocity(0,0,0);
193 }
194
195 if(this->dead_b == true)
196 {
197 Die();
198 return;
199 }
200 if(this->damage_i > gal->shipTypes[this->shipType_i]->maxHullHealth_i)
201 {
202 this->Die();
203 return;
204 }
205 vel_v4f.SetZ(0.0f);
206 pos_v4f.SetZ(0.0f);
207 pos_v4f = pos_v4f + vel_v4f;
208
209 // check state of current collision, if any
210 if(inContact_b == true)
211 {
212 // this is fuck arsed. Keep getting entities sent through that don't exist, which
213 // is quite a bitch, so let's just fuck it.
214 BSBSCollision(contactThis);
215 //inContact_b = false;
216
217 }
218 // check for a collision with another ship
219 else if(inContact_b == false)
220 {
221 for(int sc_i = 0; sc_i < gal->ships.Size(); sc_i++)
222 {
223 if((gal->ents[gal->ships[sc_i]] != this) && (((CShip*)(gal->ents[gal->ships[sc_i]]))->dead_b == false))
224 if(this->BSBSCollision((CModelEntity*)gal->ents[gal->ships[sc_i]]) == true)
225 {
226 CVec4f tempVel1;
227 CVec4f tempVel2;
228 tempVel1 = GetVelocity();
229 tempVel2 = gal->ents[gal->ships[sc_i]]->GetVelocity();
230
231 tempVel1.SetW(0);
232 tempVel2.SetW(0);
233
234 CVec4f entEnt_v4f, negEntEnt;
235 entEnt_v4f = gal->ents[gal->ships[sc_i]]->GetPos() - pos_v4f;
236 entEnt_v4f.SetW(0);
237
238 CVec4f w;
239 if(tempVel1.MagSquare() > 0.01)
240 {
241 //w = tempVel1 * ((tempVel1.Dot(entEnt_v4f)) / tempVel1.MagSquare());
242 w = entEnt_v4f * ((tempVel1.Dot(entEnt_v4f)) / entEnt_v4f.MagSquare());
243 }
244 else w.SetXYZW(0,0,0,0);
245
246 tempVel2 = tempVel2 + (w*2.0f);
247 tempVel1 = tempVel1 - (w*2.0f);
248
249 // how much will this impact hurt? Magnitude of the difference of velocities
250 CVec4f pain_v4f = GetVelocity() - gal->ents[gal->ships[sc_i]]->GetVelocity();
251 int pain = pain_v4f.Magnitude() / 2;
252 this->damage_i += pain;
253 ((CShip*)(gal->ents[gal->ships[sc_i]]))->damage_i += pain;
254
255
256 this->SetVelocity(tempVel1.X(), tempVel1.Y(), 0);
257 gal->ents[gal->ships[sc_i]]->SetVelocity(tempVel2.X(), tempVel2.Y(), 0);
258 }
259 }
260 // check for a collision with an inert
261 for(int sc_i = 0; sc_i < gal->inerts.Size(); sc_i++)
262 {
263 //if(gal->ents[gal->inerts[sc_i]] != this)
264 if(this->BSBSCollision((CModelEntity*)gal->ents[gal->inerts[sc_i]]) == true)
265 {
266 CVec4f tempVel1;
267 CVec4f tempVel2;
268 tempVel1 = GetVelocity();
269 tempVel2 = gal->ents[gal->inerts[sc_i]]->GetVelocity();
270
271 tempVel1.SetW(0);
272 tempVel2.SetW(0);
273
274 CVec4f entEnt_v4f, negEntEnt;
275 entEnt_v4f = gal->ents[gal->inerts[sc_i]]->GetPos() - pos_v4f;
276 entEnt_v4f.SetW(0);
277
278 CVec4f w;
279 if(tempVel1.MagSquare() > 0.01)
280 {
281 //w = tempVel1 * ((tempVel1.Dot(entEnt_v4f)) / tempVel1.MagSquare());
282 w = entEnt_v4f * ((tempVel1.Dot(entEnt_v4f)) / entEnt_v4f.MagSquare());
283 }
284 else w.SetXYZW(0,0,0,0);
285
286 tempVel2 = tempVel2 + w;
287 tempVel1 = tempVel1 - w;
288
289
290 // how much will this impact hurt? Magnitude of the difference of velocities
291 CVec4f pain_v4f = GetVelocity() - gal->ents[gal->inerts[sc_i]]->GetVelocity();
292 float pain = pain_v4f.Magnitude() / 2;
293 this->shieldDamage_f += pain;
294
295
296 this->SetVelocity(tempVel1.X(), tempVel1.Y(), 0);
297 gal->ents[gal->inerts[sc_i]]->SetVelocity(tempVel2.X(), tempVel2.Y(), 0);
298 }
299 }
300 }
301
302
303
304 thrPartGen.Update();
305 gunPartGen.Update();
306
307 for(int gc_i = 0; gc_i < guns.Size(); gc_i++)
308 {
309 if(guns[gc_i].gunType_i != -1)
310 {
311 guns[gc_i].currentCharge_f += gal->gunTypes[guns[gc_i].gunType_i]->chargeRate_f;
312 if(guns[gc_i].currentCharge_f > gal->gunTypes[guns[gc_i].gunType_i]->maxCharge_f)
313 guns[gc_i].currentCharge_f = gal->gunTypes[guns[gc_i].gunType_i]->maxCharge_f;
314 guns[gc_i].reloadTime_i -= 1;
315 }
316 }
317
318 if((pos_v4f.X() > gal->width_f) && (vel_v4f.X() > 0)) vel_v4f.SetX(-vel_v4f.X());
319 if((pos_v4f.X() < 0) && (vel_v4f.X() < 0)) vel_v4f.SetX(-vel_v4f.X());
320
321 if((pos_v4f.Y() > gal->height_f) && (vel_v4f.Y() > 0)) vel_v4f.SetY(-vel_v4f.Y());
322 if((pos_v4f.Y() < 0) && (vel_v4f.Y() < 0)) vel_v4f.SetY(-vel_v4f.Y());
323
324 //charge shields
325 if((this->shieldDamage_f > 0)) this->shieldDamage_f -= 0.25;
326
327 // probably more to this (recharge shields, guns, whatever...)
328
329
330 }
331
FireGun()332 void CShip::FireGun()
333 {
334
335 extern CFreebooter FB;
336 CGalaxy *gal = (CGalaxy*)FB.scene;
337
338 CVec4f face_v4f;
339 face_v4f.SetXYZW(0,1,0,0);
340
341 CMatrix4f tfm;
342 tfm.SetIdentity();
343 glMatrixMode(GL_MODELVIEW);
344 glPushMatrix();
345 glLoadIdentity();
346 // glTranslatef(-pos_v4f.X(), -pos_v4f.Y(), -pos_v4f.Z());
347 glRotatef(rot_v3f.X(), 1, 0, 0);
348 glRotatef(rot_v3f.Y(), 0, 1, 0);
349 glRotatef(rot_v3f.Z(), 0, 0, 1);
350 glGetFloatv(GL_MODELVIEW_MATRIX, tfm.m_af);
351 glPopMatrix();
352 tfm.Transpose();
353
354 face_v4f = face_v4f.Transform(tfm);
355
356 for(int gc_i = 0; gc_i < this->guns.Size(); gc_i++)
357 {
358 bool readyToFire_b;
359 readyToFire_b = ((guns[gc_i].isActive_b == true) &&
360 (guns[gc_i].currentCharge_f > gal->gunTypes[guns[gc_i].gunType_i]->chargeCost_f) &&
361 (guns[gc_i].reloadTime_i < 1));
362
363 // if this is a burst firing cannon
364 if(gal->gunTypes[guns[gc_i].gunType_i]->isBurst_b)
365 {
366 // has the burst come to an end?
367 if(guns[gc_i].isBursting_b && !readyToFire_b) guns[gc_i].isBursting_b = false;
368
369 // are we ready to burst again?
370 if(!guns[gc_i].isBursting_b && readyToFire_b && (guns[gc_i].currentCharge_f >= gal->gunTypes[guns[gc_i].gunType_i]->minCharge_f))
371 guns[gc_i].isBursting_b = true;
372
373 // if gun is not bursting, then it's not firing
374 if(!guns[gc_i].isBursting_b) readyToFire_b = false;
375 }
376
377
378
379
380 if(readyToFire_b)
381
382 {
383
384
385 CVec4f gunPos = gal->shipTypes[this->shipType_i]->gunPositions[gc_i];
386 gunPos = gunPos.Transform(tfm);
387
388 gunPos = gunPos + (face_v4f * this->boundSphRadius_f);
389
390 CGunParticle *new_part = NULL;
391 try
392 {
393 new_part = new(CGunParticle);
394 if(new_part != NULL)
395 {
396 new_part->r_f = gal->gunTypes[guns[gc_i].gunType_i]->r_f;
397 new_part->g_f = gal->gunTypes[guns[gc_i].gunType_i]->g_f;
398 new_part->b_f = gal->gunTypes[guns[gc_i].gunType_i]->b_f;
399 new_part->a_f = gal->gunTypes[guns[gc_i].gunType_i]->a_f;
400 // new_part->SetColour(r,g,b,a);
401 new_part->SetPos(pos_v4f.X() + gunPos.X(), pos_v4f.Y() + gunPos.Y(), 0);
402 float spd = gal->gunTypes[guns[gc_i].gunType_i]->speed_f;
403 new_part->SetVelocity((face_v4f.X() * spd) + vel_v4f.X(),
404 face_v4f.Y() * spd + vel_v4f.Y(), 0);
405 // new_part->life = gal->gunTypes[guns[gc_i].gunType_i]->life;
406 new_part->SetRotVel(0,0,3);
407 new_part->life = 70;
408 new_part->gunType_i = this->guns[gc_i].gunType_i;
409
410 new_part->owner = this;
411
412 new_part->size_f = gal->gunTypes[guns[gc_i].gunType_i]->partSize_f;
413 new_part->boundSphRadius_f = gal->gunTypes[guns[gc_i].gunType_i]->partSize_f;
414 new_part->hasBoundSph_b = true;
415
416 this->gunPartGen.AddParticle(new_part);
417 }
418 }
419 catch(bad_alloc)
420 {
421 cout << "couldn't allocate particle (gun-fire)" << endl;
422 }
423
424 this->guns[gc_i].reloadTime_i = gal->gunTypes[guns[gc_i].gunType_i]->fireRate_i;
425 this->guns[gc_i].currentCharge_f -= gal->gunTypes[guns[gc_i].gunType_i]->chargeCost_f;
426
427 }
428 }
429 }
430
Die()431 void CShip::Die()
432 {
433 // for now, just shift the ship to a new random position in the galaxy
434 extern CFreebooter FB;
435 CGalaxy *gal = (CGalaxy*) FB.scene;
436 // and let's have some particles as an explosion, just for fun of course...
437
438 if(aiSubMode_i == 1000)
439 {
440
441 extern CTextureManager texMan;
442 int texInd = texMan.LoadTexture("data/shot.bmp",WIN_BMP);
443
444 dead_b = true;
445 int numNewParts = rand()%100 + 100;
446 for(int npc_i = 0; npc_i < numNewParts; npc_i++)
447 {
448 CSimpleParticle *newPart;
449 try
450 {
451 newPart = new(CSimpleParticle);
452
453 newPart->SetPos(X(), Y(), Z());
454 newPart->SetVelocity(((float) (rand()%1000)/1000)-0.5,
455 ((float) (rand()%1000)/1000)-0.5,
456 0.0f);
457 newPart->life = rand()%70 +12;
458 float r = 1.0f;
459 //newPart->SetColour(r,r,r,0.7);
460 newPart->tex_i = texInd;
461 newPart->hasTexture_b = true;
462 newPart->r_f = 1.0f;
463 newPart->g_f = 1.0f;
464 newPart->b_f = 1.0f;
465 newPart->a_f = 0.6f;
466 newPart->size_f = rand()%3+1;
467 gal->galPartGen.AddParticle(newPart);
468 }
469 catch(bad_alloc)
470 {
471 cout << "Couldn't allocate particle - AI death" << endl;
472 }
473
474 aiSubMode_i++;
475 }
476
477 aiStartTime_i = SDL_GetTicks();
478 }
479 else
480 {
481 if((SDL_GetTicks() - aiStartTime_i) > 2000)
482 {
483 this->SetPos(-400, -400, 0);
484 this->SetVelocity(0,0,0);
485 this->damage_i = 0;
486 this->shieldDamage_f = 0;
487 // respawn as a different faction
488 // this->faction_i = rand()%gal->factions.Size();
489 dead_b = true;
490 // also, make sure anything that thinks it's in contact with us
491 // no longer has that opinion.
492 if(inContact_b)
493 {
494 contactThis->inContact_b == false;
495 contactThis->contactThis = NULL;
496 contactThis = NULL;
497 inContact_b = false;
498 }
499 }
500 }
501 }
502