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