1 /*
2 * This code is released under the GNU General Public License. See COPYING for
3 * details. Copyright 2003 John Spray: spray_john@users.sourceforge.net
4 */
5
6
7 #include <stdlib.h>
8 #include <math.h>
9 #include <string.h>
10
11 #include "Ufo.h"
12 #include "Game.h"
13 #include "SoundCore.h"
14 #include "Player.h"
15 #include "Particle.h"
16 #include "Visual.h"
17 #include "LList.h"
18 #include "Missile.h"
19
20
21 #ifndef M_2PI
22 #define M_2PI 6.28318
23 #endif
24
25 #ifndef M_PI
26 #define M_PI 3.14159
27 #endif
28
Ufo()29 Ufo::Ufo()
30 {
31 thrust=0.0f;
32 bear=0.0f;
33 bearv=0.0f;
34 beara=0.0f;
35 s.x=s.z=0;
36 s.y=3.0;
37 v=0.0f;
38 a=0.0f;
39 alive=0;
40 soundid=-1;
41 collideradius=5.0f;
42 collideradius2=25.0f;
43 sniffradius=250.0f;
44 spawneffect=0.0f;
45 hp=1.0f;
46 pilotstate=UFO_POTTER;
47 thinkwait=0.0f;
48 }
49
50
Live()51 void Ufo::Live()
52 {
53 TriggerShield();
54 alive=1;
55 soundid = game->sound->Play("ufo.wav",-1,&s,&v);
56 }
57
~Ufo()58 Ufo::~Ufo()
59 {
60 if(alive){
61 alive=0;
62 game->sound->StopEffect(soundid);
63 }
64 }
65
TriggerShield()66 void Ufo::TriggerShield()
67 {
68 spawneffect=maxspawneffect=400.0f;
69 }
70
Physics()71 void Ufo::Physics()
72 {
73 float afactor;
74 float maxv=1.0f;
75 float targetbear;
76
77 if(!alive) return;
78
79 if(s.y!=3.0f||a.y!=0.0f||v.y!=0.0f){
80 printf("Ufo::Physics: My y is not static! My a.y=%f,v.y=%f,s.y=%f\n",a.y,v.y,s.y);
81 }
82
83 if(spawneffect){
84 spawneffect-=game->dtf;
85 if(spawneffect<0.0f)
86 spawneffect=0.0f;
87 }
88
89 //bear isn't really used properly:
90 if(fabs(v.x)>0.001f||fabs(v.z)>0.001f){
91 targetbear=atan(a.x/a.z);
92 if(a.z<0.0f)
93 targetbear+=M_PI;
94 }
95 else
96 targetbear=0.0f;
97
98 while(bear<targetbear-M_PI)
99 bear+=M_PI*2;
100 while(bear>targetbear+M_PI)
101 bear-=M_PI*2;
102
103 bearv=(targetbear-bear)*0.01f;
104
105 bearv+=beara*game->dtf;
106 bearv*=pow(0.999f,game->dtf);
107 bear+=bearv*game->dtf;
108 if(bear>M_2PI)
109 bear-=M_2PI;
110
111 /*a=0.0f;
112 a.x=sin(bear);
113 a.z=cos(bear);
114 a*=0.001f;
115 printf("bear=%f,a.x=%f,a.z=%f\n",bear,a.x,a.z);*/
116
117 afactor=1.0-(v.Mag()/maxv);
118
119 v+=(game->dtf*afactor)*a;
120 v*=pow(0.99f,game->dtf);
121 Collide();
122 s+=v*game->dtf;
123
124
125 //Collision detection may allow ufo to escape in concave corners
126 //Cope with this by bringing it back. Player should never see this
127 //happen up close and personal.
128 if(fabs(s.x)>game->arena->halfwidth){
129 if(game->verbose) printf("Ufo::Physics: out of arena, s.x=%f\n",s.x);
130 s.x*=0.98f;
131 }
132 else if(fabs(s.z)>game->arena->halfwidth){
133 if(game->verbose) printf("Ufo::Physics: out of arena, s.z=%f\n",s.z);
134 s.z*=0.98f;
135 }
136
137 //Smoke for damaged ufos
138 if(hp<0.5f){
139 Particle newpart;
140 newpart.s=s;
141 newpart.v=v*0.5f;
142 newpart.a.y=0.0001f;
143 newpart.diffuse=0.000001f;
144 newpart.res=0.99f;
145 newpart.life=1000.0f;
146 newpart.rad=3.0f;
147 newpart.blendmode=GL_ONE_MINUS_SRC_ALPHA;
148 strcpy(newpart.texfile,"smoke1.png");
149 game->visual->NewParticle(&newpart);
150 }
151
152 }
153
154
Collide()155 void Ufo::Collide()
156 {
157 Vector dist;
158 dist=s-game->player->s;
159 if(dist.Mag2()<collideradius2+game->player->collideradius2+game->player->collideradius*collideradius && game->player->alive){
160 Die();
161 game->player->Hurt(0.21f);
162 return;
163 }
164
165 if(game->arena->Collision(s,s+v*game->dtf,collideradius)){
166 v=game->arena->GetLastQuad()->SlideVector(v);
167 }
168
169 Vector h,d;
170 LListItem<Missile>* item;
171 item=game->missilelist->head;
172 while(item){
173
174 h=PerpLinePoint(item->data.s,item->data.s+item->data.v*game->dtf,s);
175 d=h-s;
176 if(d.Mag2()<collideradius2 && PointOnLine(item->data.s,item->data.s+item->data.v*game->dtf,h)){
177 Hurt(1.1f);
178 return;
179 }
180
181 d=item->data.s-s;
182 if(d.Mag2()<collideradius2 && PointOnLine(item->data.s,item->data.s+item->data.v*game->dtf,h)){
183 Hurt(1.1f);
184 return;
185 }
186
187 d=item->data.s+item->data.v*game->dtf-s;
188 if(d.Mag2()<collideradius2 && PointOnLine(item->data.s,item->data.s+item->data.v*game->dtf,h)){
189 Hurt(1.1f);
190 return;
191 }
192
193 item=item->next;
194 }
195 }
196
197
Pilot()198 void Ufo::Pilot()
199 {
200 Vector temp;
201 Vector d;
202
203 temp=s-game->player->s;
204
205 thinkwait-=game->dtf;
206 if(thinkwait<=0){
207 if(game->player->alive && temp.Mag2() < sniffradius*sniffradius
208 && !game->arena->Collision(s,game->player->s)){
209 if(pilotstate!=UFO_SEEKPLAYER)
210 game->sound->Play("spotted.wav",0,s,v);
211 pilotstate=UFO_SEEKPLAYER;
212 }
213 else if(game->player->alive){
214 pilotstate=UFO_SEARCH;
215 }
216 else
217 pilotstate=UFO_POTTER;
218 thinkwait+=500.0f;
219 }
220
221 if(pilotstate==UFO_SEEKPLAYER){
222 temp.y=0.0f;
223 temp.Unitize();
224 a=-temp;
225 }
226 else if(pilotstate==UFO_POTTER){
227 temp.Randomize();
228 a+=temp;
229 a.Unitize();
230 a*=0.01f;
231 }
232 else if(pilotstate==UFO_SEARCH){
233 temp.Randomize();
234 a+=temp;
235 a.Unitize();
236 a*=0.01f;
237 }
238
239 Ufo* nearest=Nearest();
240
241 d=nearest->s-s;
242 temp=d;
243 temp.Unitize();
244 if(d.Mag2()!=0.0f)
245 temp*=(collideradius*2)/d.Mag(); //ie ufos avoiding each other has equal precedence to homing
246 //on player where temp.Mag=collideradius*2, ie the ufos are collideradius*2 apart.
247 a+=-temp;
248
249 a+=(nearest->v-v)*10.0f; //a more orderly formation
250
251 /* if(nearest->pilotstate==UFO_SEEKPLAYER)
252 {
253 temp=d;
254 temp.Unitize();
255 a=-temp;
256 }*/
257
258 //clear the respawn if the player's waiting to spawn
259 if(!game->player->alive){
260 d=s;//IE distance from center, assuming spawn at ccenter
261 if(d.Mag2()<sniffradius*sniffradius*1.2f){
262 temp=s;
263 temp.Unitize();
264 temp*=(sniffradius)/s.Mag();
265 a+=temp;
266 }
267 }
268
269 a.Unitize();
270 a.y=0.0;
271 a*=0.001+0.0005*(1.0f-game->spawndelay/5000.0f);
272
273 #ifdef RELEASE
274 //FIXME: Do this to cover up an unfound bug
275 s.y=3.0f;
276 #endif
277 }
278
279 //Find the closest Ufo in game->ufolist to this
280 //if game->ufolist->count==1 then return this
Nearest()281 Ufo* Ufo::Nearest()
282 {
283 Ufo* retval;
284 LListItem<Ufo> *ufoitem;
285 Vector d;
286 Vector temp;
287
288 ufoitem=game->ufolist->head;
289 temp=ufoitem->data.s-s;
290 d=temp;
291 retval=&ufoitem->data;
292 ufoitem=ufoitem->next;
293
294 while(ufoitem){
295 temp=ufoitem->data.s-s;
296 if(temp.Mag2()<d.Mag2() && &ufoitem->data!=this){
297 d=temp;
298 retval=&ufoitem->data;
299 }
300 ufoitem=ufoitem->next;
301 }
302
303 return retval;
304 }
305
Die()306 void Ufo::Die()
307 {
308 if(!alive){//general paranoia checking
309 printf("Ufo::Die: Warning, (!alive) is true!\n");
310 return;
311 }
312 game->IncScore(200);
313 Explode();
314 alive=0;
315 game->sound->StopEffect(soundid);
316 }
317
Explode()318 void Ufo::Explode()
319 {
320 Particle newpart;
321 newpart.s=s;
322 newpart.rad=collideradius;
323 newpart.diffuse=0.000003;
324 newpart.blendmode=GL_ONE;
325 strcpy(newpart.texfile,"explosion1.png");
326 newpart.life=200;
327 for(int i=0;i<3;i++)
328 game->visual->NewParticle(&newpart);
329 strcpy(newpart.texfile,"smoke1.png");
330 newpart.life=1000;
331 newpart.rad=collideradius*1.2;
332 newpart.diffuse=0.0000005;
333 newpart.res=0.999f;
334 newpart.a=game->g*0.1f;
335 newpart.blendmode=GL_ONE_MINUS_SRC_ALPHA;
336 for(int i=0;i<8;i++)
337 game->visual->NewParticle(&newpart);
338 strcpy(newpart.texfile,"explosion1.png");
339 newpart.life=1500.0f;
340 newpart.bounce=PARTICLE_BOUNCE_ONE;
341 newpart.drawmode=PARTICLE_DRAW_SIMPLE;
342 newpart.rad=0.5;
343 newpart.diffuse=0.000000;
344 newpart.res=1.0f;
345 newpart.a=game->g;
346 newpart.collide=1;
347 for(int i=0;i<8;i++){
348 newpart.v.Randomize();
349 newpart.v.y+=1.0f;
350 newpart.v*=0.05f;
351 game->visual->NewParticle(&newpart);
352 }
353 newpart.drawmode=PARTICLE_DRAW_MOTION;
354 newpart.rad=0.25;
355 newpart.life=400.0f;
356 newpart.collide=1;
357 for(int i=0;i<8;i++){
358 newpart.v.Randomize();
359 newpart.v*=1.0f;
360 game->visual->NewParticle(&newpart);
361 }
362
363
364 game->sound->Play("ufodie.wav",0,s,v);
365 }
366
Hurt(float pain)367 int Ufo::Hurt(float pain)
368 {
369 if(hp<=0) return 1;
370
371 hp-=pain;
372 if(hp<=0){
373 Die();
374 return 1;
375 }
376 else
377 return 0;
378 }
379