1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5
6 #include "servership.h"
7 #include "serverdata.h"
8 #include "netconfig.h"
9 #include "scorevals.h"
10 #include "sounddefs.h"
11 #include "mainplayerthread.h"
12 #include "thread.h"
13 #include "timeutils.h"
14 #include "sizes.h"
15 #include "collision.h"
16
17
18 void *StartGame(void *threadid);
19 void InitServerGame();
20 void DeletePlayer(int playernum);
21 void CheckForCollisions();
22 int CheckForCollision(struct Point point1, float size1,
23 struct Point point2, float size2);
24 int ShipHit(int playernum, int objnum);
25 void CreateRandomRock();
26 void CreateExplosionRandomRock(int objnum);
27 void CreateExplosion(int objnum, int type);
28 void AddSound(int playernum, struct Point *SoundPos, char type);
29 void AddSoundAll(struct Point *SoundPos, char type);
30 int BounceObjects(ServerObject *obj1, ServerObject *obj2);
31 float CalcDistance(struct Point *point1, struct Point *point2);
32 void CreateRandomPosition(struct Point *Position);
33
34
35 SoundStruct Sounds[MAX_PLAYERS][MAX_SOUNDS];
36 ServerObject *ServerObjects[MAX_OBJECTS];
37 ServerShip *ServerShips[MAX_PLAYERS];
38 float MaxRockSize=0.7;
39 float MinRockSize=0.15;
40 int NumAsteroids;
41 float TotalAsteroidSize;
42 int ServerGameRunning;
43 float BotRatio;
44
45
46 // Main function to run the game
StartGame(void * threadid)47 void *StartGame(void *threadid)
48 {
49 #ifdef CYGWIN
50 int sleepcount=0;
51 #endif
52 int i, j=0, k=0, l=0;
53 int update, keyupdate;
54 int secondupdate;
55 int threadnum, RunTime;
56 unsigned long TimeElapsed, OldTimeElapsed=0;
57 int TimeCounter=0;
58 int SleepTimesElapsed;
59 int AsteroidTime=NewAsteroidTime;
60 int MakeAsteroidTime=NewAsteroidTime;
61 int SleepTime;
62 float Size;
63 int GameWaitTime=500;
64 char BotName[80];
65 struct Point Position, Velocity, Rotation;
66
67 ServerGameRunning=1;
68
69 threadnum=(size_t)threadid;
70
71 pthread_mutex_lock(&ServerLock);
72
73 NumAsteroids=0;
74 TotalAsteroidSize=0.0;
75
76 BotRatio=StartBotRatio;
77
78 for (i=0; i<MAX_PLAYERS; i++) {
79 ServerShips[i]=NULL;
80 }
81
82 for (i=0; i<MAX_OBJECTS; i++) {
83 ServerObjects[i]=NULL;
84 }
85
86 if (MaxPlayers==1) {
87 ServerGameType=SINGLE_PLAYER;
88 }
89
90 #ifndef CYGWIN
91 InitTime();
92 #endif
93
94 SleepTime=2000*GameSleep;
95
96 update=FALSE;
97 keyupdate=FALSE;
98 secondupdate=FALSE;
99
100 InitServerGame();
101
102 for (i=0; i<NumBots; i++) {
103 for (j=0; j<MAX_PLAYERS; j++) {
104 if (!ServerShips[j]) {
105 sprintf(BotName, "Bot %d", i+1);
106 CreateRandomPosition(&Position);
107 Rotation.x=0.0;
108 Rotation.y=0.0;
109 Rotation.z=0.0;
110 Velocity.x=0.0;
111 Velocity.y=0.0;
112 Velocity.z=0.0;
113 ServerShips[j]=new ServerShip(Position, Velocity, Rotation, SHIP_TYPE,
114 ShipSize, 1.0, j, BotName, 1);
115 break;
116 }
117 }
118 }
119
120 while(!StopServer) {
121 // Allow other threads to access shared data while we're sleeping
122 #ifdef DEBUG
123 printf("Server Game Thread Sleeping\n");
124 #endif
125 pthread_mutex_unlock(&ServerLock);
126
127 #ifdef CYGWIN
128 if (sleepcount != 3) {
129 usleep(SleepTime);
130 sleepcount++;
131 } else {
132 sleepcount=0;
133 }
134 #else
135 TimeElapsed=GetTimeElapsed();
136 if (TimeElapsed < OldTimeElapsed) {
137 OldTimeElapsed=TimeElapsed;
138 }
139 /*
140 We need this because usleep is somewhat inaccurate and we may be
141 slighly under or over the necessary sleep time
142 */
143 SleepTimesElapsed=(int)(TimeElapsed/SleepTime)-
144 (int)(OldTimeElapsed/SleepTime);
145
146 if (SleepTimesElapsed < 0 || SleepTimesElapsed > 10) {
147 SleepTimesElapsed=0;
148 }
149
150 TimeCounter+=1-SleepTimesElapsed;
151
152 if (TimeCounter>0) {
153 usleep(SleepTime*TimeCounter);
154 }
155 OldTimeElapsed=TimeElapsed;
156
157 #endif
158 pthread_mutex_lock(&ServerLock);
159 #ifdef DEBUG
160 printf("Server Game Thread Awake\n");
161 #endif
162
163 if (NumConnectedPlayers && ServerGameRunning) {
164 // Update the game at a constant rate no matter how long we sleep
165 k+=GameSleep;
166 if (k >= 10) {
167 update=TRUE;
168 k-=10;
169 } else {
170 update=FALSE;
171 }
172
173 // Updates for key input
174 l+=GameSleep;
175 if (l >= 20) {
176 keyupdate=TRUE;
177 l-=20;
178 } else {
179 keyupdate=FALSE;
180 }
181
182 // Updates that we have to do once a second
183 j+=GameSleep;
184 if (j >= 1000) {
185 secondupdate=TRUE;
186 j-=1000;
187 } else {
188 secondupdate=FALSE;
189 }
190
191 MakeAsteroidTime-=GameSleep;
192 if (MakeAsteroidTime <= 0) {
193 CreateRandomRock();
194 MakeAsteroidTime=AsteroidTime;
195 }
196
197 // Age all the objects
198 if (update) {
199 for (i=0; i<MAX_OBJECTS; i++) {
200 if (ServerObjects[i]) {
201 ServerObjects[i]->UpdatePosition();
202 ServerObjects[i]->UpdateRotation();
203 if (ServerObjects[i]->AliveTime > 0) {
204 if (ServerObjects[i]->ObjectType==NUKE_EXPLOSION_TYPE) {
205 ServerObjects[i]->ObjectSize+=NukeExplosionGrowthSpeed;
206 }
207 ServerObjects[i]->AliveTime--;
208 if (ServerObjects[i]->AliveTime==0) {
209 delete ServerObjects[i];
210 ServerObjects[i]=NULL;
211 }
212 }
213 }
214 }
215 for (i=0; i<MAX_PLAYERS; i++) {
216 if (ServerShips[i]) {
217 ServerShips[i]->DoUpdates();
218 if (ServerGameType==DEATHMATCH) {
219 if (ServerShips[i]->Score>=MaxKills) {
220 ServerGameRunning=0;
221 continue;
222 }
223 }
224 }
225 }
226 CheckForCollisions();
227 }
228
229 if (secondupdate) {
230 if (ServerGameType==SINGLE_PLAYER) {
231 AsteroidTime-=AsteroidTimeSpeedup;
232 if (AsteroidTime < MinAsteroidTime) {
233 AsteroidTime=MinAsteroidTime;
234 }
235 BotRatio+=BotRatioIncrease;
236 if (BotRatio > MaxBotRatio) {
237 BotRatio=MaxBotRatio;
238 }
239 }
240 }
241 }
242 if (NumConnectedPlayers && !ServerGameRunning) {
243 GameWaitTime--;
244 if (!GameWaitTime) {
245 GameWaitTime=500;
246 ServerGameRunning=1;
247 InitServerGame();
248 }
249 }
250 }
251 for (i=0; i<MAX_OBJECTS; i++) {
252 if (ServerObjects[i]) {
253 delete(ServerObjects[i]);
254 ServerObjects[i]=NULL;
255 }
256 }
257
258 for (i=0; i<MAX_PLAYERS; i++) {
259 if (ServerShips[i]) {
260 delete(ServerShips[i]);
261 ServerShips[i]=NULL;
262 }
263 }
264
265 pthread_mutex_unlock(&ServerLock);
266
267 pthread_exit(NULL);
268 }
269
270
InitServerGame()271 void InitServerGame()
272 {
273 int i;
274
275 for (i=0; i<MAX_OBJECTS; i++) {
276 if (ServerObjects[i]) {
277 delete(ServerObjects[i]);
278 ServerObjects[i]=NULL;
279 }
280 }
281
282 for (i=0; i<MAX_PLAYERS; i++) {
283 if (ServerShips[i]) {
284 ServerShips[i]->InitPlayer();
285 }
286 }
287
288 for (i=0; i<StartAsteroids; i++) {
289 CreateRandomRock();
290 }
291 }
292
293
DeletePlayer(int playernum)294 void DeletePlayer(int playernum)
295 {
296 delete ServerShips[playernum];
297 ServerShips[playernum]=NULL;
298 }
299
300
CheckForCollisions()301 void CheckForCollisions()
302 {
303 int i, j, rc;
304
305 // Check for Object to Object Collisions
306 for (i=0; i<MAX_OBJECTS; i++) {
307 if (ServerObjects[i]) {
308 for (j=i+1; j<MAX_OBJECTS; j++) {
309 if (ServerObjects[j]) {
310 if (CheckForCollision(ServerObjects[i]->Position,
311 ServerObjects[i]->ObjectSize,
312 ServerObjects[j]->Position,
313 ServerObjects[j]->ObjectSize)) {
314 if (ServerObjects[i]->ObjectType <= ServerObjects[j]->ObjectType) {
315 if (ObjectToObjectCollisionFunctions[ServerObjects[i]->ObjectType][ServerObjects[j]->ObjectType]) {
316 rc=ObjectToObjectCollisionFunctions[ServerObjects[i]->ObjectType][ServerObjects[j]->ObjectType](i, j);
317 if (rc==1 || rc==3) {
318 break;
319 }
320 }
321 } else {
322 if (ObjectToObjectCollisionFunctions[ServerObjects[j]->ObjectType][ServerObjects[i]->ObjectType]) {
323 rc=ObjectToObjectCollisionFunctions[ServerObjects[j]->ObjectType][ServerObjects[i]->ObjectType](j, i);
324 if (rc==2 || rc==3) {
325 break;
326 }
327 }
328 }
329 }
330 }
331 }
332 }
333 }
334
335 // Check for Ship to Object Collisions
336 for (i=0; i<MAX_PLAYERS; i++) {
337 if (ServerShips[i]) {
338 if (ServerShips[i]->AliveTime==-1 && !ServerShips[i]->WarpTime) {
339 for (j=0; j<MAX_OBJECTS; j++) {
340 if (ServerObjects[j]) {
341 if (CheckForCollision(ServerObjects[j]->Position,
342 ServerObjects[j]->ObjectSize,
343 ServerShips[i]->Position,
344 ServerShips[i]->ObjectSize)) {
345 if (ObjectToShipCollisionFunctions[ServerObjects[j]->ObjectType]) {
346 if (ObjectToShipCollisionFunctions[ServerObjects[j]->ObjectType](j, i)) {
347 break;
348 }
349 }
350 }
351 }
352 }
353 }
354 }
355 }
356
357 // Check for Ship to Ship Collisions
358 for (i=0; i<MAX_PLAYERS; i++) {
359 if (ServerShips[i]) {
360 if (ServerShips[i]->AliveTime==-1 && !ServerShips[i]->WarpTime) {
361 for (j=i+1; j<MAX_PLAYERS; j++) {
362 if (ServerShips[j]) {
363 if (ServerShips[j]->AliveTime==-1 && !ServerShips[j]->WarpTime) {
364 if (CheckForCollision(ServerShips[i]->Position, ServerShips[i]->ObjectSize,
365 ServerShips[j]->Position, ServerShips[j]->ObjectSize)) {
366 if (ShipToShipCollision(i, j)) {
367 break;
368 }
369 }
370 }
371 }
372 }
373 }
374 }
375 }
376 }
377
378
379 // Check if the two spheres overlap
CheckForCollision(struct Point point1,float size1,struct Point point2,float size2)380 int CheckForCollision(struct Point point1, float size1,
381 struct Point point2, float size2)
382 {
383 if (CalcDistance(&point1, &point2) < size1+size2) {
384 return(1);
385 } else {
386 return(0);
387 }
388 }
389
390
CreateRandomRock()391 void CreateRandomRock()
392 {
393 int i;
394 struct Point Position, Rotation, Velocity;
395 float Size;
396
397 if (NumAsteroids==MAX_ASTEROIDS || TotalAsteroidSize > MaxTotalAsteroidSize) {
398 return;
399 }
400
401 for (i=0; i<MAX_OBJECTS; i++) {
402 if (!ServerObjects[i]) {
403 CreateRandomPosition(&Position);
404 Rotation.x=float(rand()%50-25)/50.0;
405 Rotation.y=float(rand()%50-25)/50.0;
406 Rotation.z=float(rand()%50-25)/50.0;
407 Velocity.x=float(rand()%50-25)/6000.0;
408 Velocity.y=float(rand()%50-25)/6000.0;
409 Velocity.z=float(rand()%50-25)/6000.0;
410 Size=((float(rand()%50+1)/50)*(MaxRockSize-MinRockSize))+MinRockSize;
411 ServerObjects[i]=new ServerObject(Position, Velocity, Rotation, ASTEROID_TYPE, Size, Size*Size*Size*400.0);
412 break;
413 }
414 }
415 }
416
417
CreateExplosionRandomRock(int objnum)418 void CreateExplosionRandomRock(int objnum)
419 {
420 int i, j, numRocks;
421 struct Point Position, Rotation, Velocity, Momentum;
422 float Size;
423
424 numRocks=rand()%2+2;
425 Momentum.x=0.0;
426 Momentum.y=0.0;
427 Momentum.z=0.0;
428
429 for (j=0; j<numRocks; j++) {
430 if (NumAsteroids==MAX_ASTEROIDS) {
431 return;
432 }
433 for (i=0; i<MAX_OBJECTS; i++) {
434 if (!ServerObjects[i]) {
435 Position.x=ServerObjects[objnum]->Position.x;
436 Position.y=ServerObjects[objnum]->Position.y;
437 Position.z=ServerObjects[objnum]->Position.z;
438 Rotation.x=float(rand()%50-25)/50.0;
439 Rotation.y=float(rand()%50-25)/50.0;
440 Rotation.z=float(rand()%50-25)/50.0;
441 Velocity.x=float(rand()%50-25)/6000.0+ServerObjects[objnum]->Velocity.x;
442 Velocity.y=float(rand()%50-25)/6000.0+ServerObjects[objnum]->Velocity.y;
443 Velocity.z=float(rand()%50-25)/6000.0+ServerObjects[objnum]->Velocity.z;
444 Size=(ServerObjects[objnum]->ObjectSize*0.8*
445 (1.0/sqrt((float)numRocks))*
446 (1.0-(float)(rand()%20)/50.0));
447 Velocity.x-=Momentum.x/Size;
448 Velocity.y-=Momentum.y/Size;
449 Velocity.z-=Momentum.z/Size;
450 Momentum.x+=(Velocity.x-ServerObjects[objnum]->Velocity.x)*Size;
451 Momentum.y+=(Velocity.y-ServerObjects[objnum]->Velocity.y)*Size;
452 Momentum.z+=(Velocity.z-ServerObjects[objnum]->Velocity.z)*Size;
453
454 ServerObjects[i]=new ServerObject(Position, Velocity, Rotation,
455 ASTEROID_TYPE, Size, Size*Size*Size*400.0);
456 break;
457 }
458 }
459 }
460 }
461
462
CreateExplosion(int objnum,int type)463 void CreateExplosion(int objnum, int type)
464 {
465 int i;
466 struct Point Rotation, Velocity;
467
468 Rotation.x=0.0;
469 Rotation.y=0.0;
470 Rotation.z=0.0;
471 Velocity.x=0.0;
472 Velocity.y=0.0;
473 Velocity.z=0.0;
474
475 for (i=0; i<MAX_OBJECTS; i++) {
476 if (!ServerObjects[i]) {
477 if (type==0) {
478 ServerObjects[i]=new ServerObject(ServerObjects[objnum]->Position,
479 Velocity, Rotation,
480 EXPLOSION_TYPE, 1.0, 0.0, 1);
481 } else if (type==1) {
482 ServerObjects[i]=new ServerObject(ServerShips[objnum]->Position,
483 Velocity, Rotation,
484 BIG_EXPLOSION_TYPE, 1.0, 0.0, 1);
485 }
486 break;
487 }
488 }
489 }
490
491
AddSound(int playernum,struct Point * SoundPos,char type)492 void AddSound(int playernum, struct Point *SoundPos, char type)
493 {
494 int i;
495
496 if (ServerShips[playernum]) {
497 if (!ServerShips[playernum]->Bot) {
498 for (i=0; i<NUM_SOUNDS; i++) {
499 if (Sounds[playernum][i].type==-1) {
500 Sounds[playernum][i].Position.x=SoundPos->x;
501 Sounds[playernum][i].Position.y=SoundPos->y;
502 Sounds[playernum][i].Position.z=SoundPos->z;
503 Sounds[playernum][i].type=type;
504 break;
505 }
506 }
507 }
508 }
509 }
510
511
AddSoundAll(struct Point * SoundPos,char type)512 void AddSoundAll(struct Point *SoundPos, char type)
513 {
514 int i;
515
516 for (i=0; i<MAX_PLAYERS; i++) {
517 AddSound(i, SoundPos, type);
518 }
519 }
520
521
BounceObjects(ServerObject * obj1,ServerObject * obj2)522 int BounceObjects(ServerObject *obj1, ServerObject *obj2)
523 {
524 struct Point npos1, npos2;
525 struct Point RelPosition, RelVelocity, ForcePoint, Force;
526 float dist1, dist2, dist3;
527 float Angle;
528 float ForceAngle;
529
530 npos1.x=obj1->Position.x+obj1->Velocity.x/100.0;
531 npos1.y=obj1->Position.y+obj1->Velocity.y/100.0;
532 npos1.z=obj1->Position.z+obj1->Velocity.z/100.0;
533 npos2.x=obj2->Position.x+obj2->Velocity.x/100.0;
534 npos2.y=obj2->Position.y+obj2->Velocity.y/100.0;
535 npos2.z=obj2->Position.z+obj2->Velocity.z/100.0;
536
537 dist1=CalcDistance(&obj1->Position, &obj2->Position);
538 dist2=CalcDistance(&npos1, &npos2);
539
540 if (dist2 >= dist1) {
541 return(0);
542 }
543
544 RelPosition.x=obj1->Position.x-obj2->Position.x;
545 RelPosition.y=obj1->Position.y-obj2->Position.y;
546 RelPosition.z=obj1->Position.z-obj2->Position.z;
547 RelVelocity.x=obj1->Velocity.x-obj2->Velocity.x;
548 RelVelocity.y=obj1->Velocity.y-obj2->Velocity.y;
549 RelVelocity.z=obj1->Velocity.z-obj2->Velocity.z;
550 ForcePoint.x=RelVelocity.x+RelPosition.x;
551 ForcePoint.y=RelVelocity.y+RelPosition.y;
552 ForcePoint.z=RelVelocity.z+RelPosition.z;
553 dist1=sqrt(RelPosition.x*RelPosition.x+RelPosition.y*RelPosition.y+RelPosition.z*RelPosition.z);
554 dist2=sqrt(RelVelocity.x*RelVelocity.x+RelVelocity.y*RelVelocity.y+RelVelocity.z*RelVelocity.z);
555 dist3=sqrt(ForcePoint.x*ForcePoint.x+ForcePoint.y*ForcePoint.y+ForcePoint.z*ForcePoint.z);
556
557 ForceAngle=(dist1*dist1+dist2*dist2-dist3*dist3)/(2*dist1*dist2);
558 Force.x=(RelPosition.x/dist1)*ForceAngle*dist2;
559 Force.y=(RelPosition.y/dist1)*ForceAngle*dist2;
560 Force.z=(RelPosition.z/dist1)*ForceAngle*dist2;
561
562 obj1->Velocity.x+=(Force.x*2.0)/(1.0+(obj1->ObjectMass/obj2->ObjectMass));
563 obj1->Velocity.y+=(Force.y*2.0)/(1.0+(obj1->ObjectMass/obj2->ObjectMass));
564 obj1->Velocity.z+=(Force.z*2.0)/(1.0+(obj1->ObjectMass/obj2->ObjectMass));
565 obj2->Velocity.x-=(Force.x*2.0)/(1.0+(obj2->ObjectMass/obj1->ObjectMass));
566 obj2->Velocity.y-=(Force.y*2.0)/(1.0+(obj2->ObjectMass/obj1->ObjectMass));
567 obj2->Velocity.z-=(Force.z*2.0)/(1.0+(obj2->ObjectMass/obj1->ObjectMass));
568
569 return((int)(sqrt(Force.x*Force.x+Force.y*Force.y+Force.z*Force.z)*100.0*(float)CollisionDamage));
570 }
571
572
CalcDistance(struct Point * point1,struct Point * point2)573 float CalcDistance(struct Point *point1, struct Point *point2)
574 {
575 float xdist, ydist, zdist;
576
577 if (point1->x > point2->x) {
578 xdist=point1->x-point2->x;
579 } else {
580 xdist=point2->x-point1->x;
581 }
582 if (xdist > 2*ServerWorldWidth-xdist) {
583 xdist=2*ServerWorldWidth-xdist;
584 }
585 if (point1->y > point2->y) {
586 ydist=point1->y-point2->y;
587 } else {
588 ydist=point2->y-point1->y;
589 }
590 if (ydist > 2*ServerWorldWidth-ydist) {
591 ydist=2*ServerWorldWidth-ydist;
592 }
593 if (point1->z > point2->z) {
594 zdist=point1->z-point2->z;
595 } else {
596 zdist=point2->z-point1->z;
597 }
598 if (zdist > 2*ServerWorldWidth-zdist) {
599 zdist=2*ServerWorldWidth-zdist;
600 }
601
602 return(sqrt(xdist*xdist+ydist*ydist+zdist*zdist));
603 }
604
605
CreateRandomPosition(struct Point * Position)606 void CreateRandomPosition(struct Point *Position)
607 {
608 int i, j;
609 int found;
610
611 for (i=0; i<20; i++) {
612 Position->x=(float(rand()%50-25)/25.0)*ServerWorldWidth;
613 Position->y=(float(rand()%50-25)/25.0)*ServerWorldWidth;
614 Position->z=(float(rand()%50-25)/25.0)*ServerWorldWidth;
615
616 found=1;
617 for (j=0; j<MAX_OBJECTS; j++) {
618 if (ServerObjects[j]) {
619 if (CheckForCollision(ServerObjects[j]->Position,
620 ServerObjects[j]->ObjectSize,
621 *Position, 0.3)) {
622 found=0;
623 break;
624 }
625 }
626 }
627 if (!found) {
628 continue;
629 }
630 for (j=0; j<MAX_PLAYERS; j++) {
631 if (ServerShips[j] && ServerShips[j]->AliveTime==-1) {
632 if (CheckForCollision(ServerShips[j]->Position,
633 ServerShips[j]->ObjectSize,
634 *Position, 1.0)) {
635 found=0;
636 break;
637 }
638 }
639 }
640 if (found) {
641 break;
642 }
643 }
644 }
645