DEADSOFTWARE

Изменены физические константы
[netwar.git] / game.c
diff --git a/game.c b/game.c
index cbc8e156ce5ff24ec6ef70e1a9150f34052f8a3d..2370692abdad4904825a910b65828b03821394a3 100644 (file)
--- a/game.c
+++ b/game.c
@@ -6,26 +6,24 @@
 
 #include "game.h"
 
-#define SPEED  0.00006
-#define ROTATE 0.00004
+#define SPEED      (0.0005 / TICK)
+#define ROTATE     (0.03 / TICK)
+#define BULL_SPEED (0.4  / TICK)
 
-Player g_player[MAX_PLAYERS];
+#define MAX_SPEED  (0.1 / TICK)
+#define MAX_ROTATE (0.3 / TICK)
 
-static void moveplayer(int id, float speed) {
-       g_player[id].vx += speed * cos(g_player[id].r * 2 * M_PI);
-       g_player[id].vy += speed * sin(g_player[id].r * 2 * M_PI);
-}
+// Цифры взяты с потолка, но вроде неплохо подобраны
+#define G      6.6719199e-11
+#define M_STAR 3e8
+#define M_SHIP 0.001
 
-static void checkspacebound(float * a) {
-       float x = *a;
-       if(x < -1)
-               x = abs(x);
-       else if(x > 1)
-               x = -x;
-       *a = x;
-}
+Player g_player[MAX_PLAYERS];
+Bullet g_bullet[MAX_BULLETS];
+
+static bool svmode;
 
-void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr) {
+void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr, int shoot) {
        assert(id < MAX_PLAYERS);
        g_player[id] = (Player) {
                .updated = true,
@@ -39,18 +37,92 @@ void g_player_set(unsigned int id, bool live, float x, float y, float r, float v
        };
 }
 
-void g_player_does(unsigned int id, DoesCode code) {
-       assert(id < MAX_PLAYERS);
-       g_player[id].updated = true;
-       switch(code) {
-       case DOES_UP:    moveplayer(id, SPEED); break;
-       case DOES_DOWN:  moveplayer(id, -SPEED); break;
-       case DOES_LEFT:  g_player[id].vr -= ROTATE; break;
-       case DOES_RIGHT: g_player[id].vr += ROTATE; break;
-       case DOES_FIRE:  break;
+void g_bullet_set(unsigned int id, unsigned int owner, bool live, float x, float y, float vx, float vy, int tick) {
+       assert(id < MAX_BULLETS);
+       assert(owner < MAX_PLAYERS);
+       g_bullet[id] = (Bullet) {
+               .live  = live,
+               .owner = owner,
+               .x     = x,
+               .y     = y,
+               .vx    = vx,
+               .vy    = vy,
+               .tick  = tick,
+       };
+}
+
+static int freebullet() {
+       for(int i = 0; i < MAX_BULLETS; i++)
+               if(!g_bullet[i].live)
+                       return i;
+       return -1;
+}
+
+static void moveplayer(int id, float speed) {
+       if(fabs(g_player[id].vx) < MAX_SPEED)
+               g_player[id].vx += speed * cos(g_player[id].r * 2 * M_PI);
+       if(fabs(g_player[id].vy) < MAX_SPEED)
+               g_player[id].vy += speed * sin(g_player[id].r * 2 * M_PI);
+}
+
+static void roteplayer(int id, float speed) {
+       g_player[id].vr += speed;
+       if(fabs(g_player[id].vr) > MAX_ROTATE)
+               g_player[id].vr = copysignf(MAX_ROTATE, g_player[id].vr);
+}
+
+static void fireplayer(int id) {
+       int j = freebullet();
+       if(j < 0)
+               return;
+
+       if(g_player[id].shoot < PLAYER_SHOOT)
+               return;
+
+       g_player[id].shoot = 0;
+
+       if(svmode) {
+               float vx = BULL_SPEED * cos(g_player[id].r * 2 * M_PI);
+               float vy = BULL_SPEED * sin(g_player[id].r * 2 * M_PI);
+               g_bullet_set(j, id, true, g_player[id].x, g_player[id].y, vx, vy, 0);
        }
 }
 
+static void checkspacebound(float * a) {
+       float x = *a;
+       if(x < -1 || x > 1)
+               x = copysign(fmodf(x, 1) + 1, -1 * x);
+       *a = x;
+}
+
+static float length(float x1, float y1, float x2, float y2) {
+       return sqrtf(powf(x1 - x2, 2) + powf(y1 - y2, 2));
+}
+
+static bool collide(float x1, float y1, float r1, float x2, float y2, float r2) {
+       return ((length(x1, y1, x2, y2) - r1 - r2) <= 0);
+}
+
+static void gravity(float * vx, float * vy, float x, float y) {
+       *vx += copysign(G * M_STAR * M_SHIP / length(0, 0, x, y), x * -1);
+       *vy += copysign(G * M_STAR * M_SHIP / length(0, 0, x, y), y * -1);
+}
+
+void g_player_does(unsigned int id, DoesBits code) {
+       assert(id < MAX_PLAYERS);
+
+       if(code.up)
+               moveplayer(id, SPEED);
+       if(code.down)
+               moveplayer(id, -SPEED);
+       if(code.left)
+               roteplayer(id, -ROTATE);
+       if(code.right)
+               roteplayer(id, ROTATE);
+       if(code.fire)
+               fireplayer(id);
+}
+
 void g_update() {
        for(int i = 0; i < MAX_PLAYERS; i++) {
                if(g_player[i].live) {
@@ -58,8 +130,46 @@ void g_update() {
                        g_player[i].x += g_player[i].vx;
                        g_player[i].y += g_player[i].vy;
                        g_player[i].r += g_player[i].vr;
+
+                       gravity(&g_player[i].vx, &g_player[i].vy, g_player[i].x, g_player[i].y);
+
                        checkspacebound(&g_player[i].x);
                        checkspacebound(&g_player[i].y);
+
+                       ++g_player[i].shoot;
+                       if(g_player[i].shoot > PLAYER_SHOOT)
+                               g_player[i].shoot = PLAYER_SHOOT;
+
+                       if(collide(g_player[i].x, g_player[i].y, PLAYER_SIZE, 0, 0, STAR_SIZE))
+                               g_player[i].live = false;
+               }
+       }
+
+       for(int i = 0; i < MAX_BULLETS; i++) {
+               if(g_bullet[i].live) {
+                       g_bullet[i].updated = true;
+                       g_bullet[i].tick += 1;
+                       g_bullet[i].x += g_bullet[i].vx;
+                       g_bullet[i].y += g_bullet[i].vy;
+
+                       checkspacebound(&g_bullet[i].x);
+                       checkspacebound(&g_bullet[i].y);
+
+                       gravity(&g_bullet[i].vx, &g_bullet[i].vy, g_bullet[i].x, g_bullet[i].y);
+
+                       for(int j = 0; j < MAX_PLAYERS; j++)
+                               if(g_player[j].live)
+                                       if(collide(g_bullet[i].x, g_bullet[i].y, 0.0001, g_player[j].x, g_player[j].y, PLAYER_SIZE))
+                                               if(j != g_bullet[i].owner)
+                                                       g_player[j].live = false;
+
+                       if(g_bullet[i].tick > BULLET_TIME)
+                               g_bullet[i].live = false;
                }
        }
 }
+
+void g_init(bool server_mode) {
+       svmode = server_mode;
+       // TODO memset & co
+}