]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cgame.c
Cleaned up alot more memory leaks. (still get 720 leaks just running demo1.dem)
[xonotic/darkplaces.git] / cgame.c
diff --git a/cgame.c b/cgame.c
index a8715c414904c03a42d335f24c0fd92cdc1ab05d..86da9a53d8074849f5d6ee6981eb276349164949 100644 (file)
--- a/cgame.c
+++ b/cgame.c
@@ -1,19 +1,13 @@
 
+#include <string.h>
 #include "cgame_api.h"
 #include "cg_math.h"
 
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
 static double gametime, frametime;
 
 struct localentity_s;
 typedef struct localentity_s
 {
-       int active; // true if the entity is alive (not freed)
-       float freetime; // time this entity was freed
        float dietime;
        vec3_t velocity;
        vec3_t avelocity;
@@ -21,19 +15,22 @@ typedef struct localentity_s
        vec3_t worldmaxs;
        vec3_t entitymins;
        vec3_t entitymaxs;
+       vec3_t lastimpactorigin; // updated by physics code, used by gib blood stains
        float bouncescale;
        float airfrictionscale;
        float gravityscale;
        void (*framethink)(struct localentity_s *e);
-       //int solid;
-       //void (*touch)(struct localentity_s *self, struct localentity_s *other);
-       //void (*touchnetwork)(struct *localentity_s *self);
+       void (*touchnetwork)(struct localentity_s *self);
        cgdrawentity_t draw;
 }
 localentity_t;
 
 #define MAX_LOCALENTITIES 1024
 static localentity_t *localentity;
+// true if the entity is alive (not freed)
+static unsigned char *localentityactive;
+// time the entity was freed
+static float *localentityfreetime;
 
 static cgphysentity_t *phys_entity;
 static int phys_entities;
@@ -49,35 +46,38 @@ static void readvector(vec3_t v)
 
 static localentity_t *entspawn(void)
 {
-       int i;
-       localentity_t *l;
+       int i, best;
+       float bestfreetime;
+       bestfreetime = (float) (gametime + 100.0);
+       best = -1;
        for (i = 0;i < MAX_LOCALENTITIES;i++)
        {
-               l = localentity + i;
-               if (!l->active && l->freetime < gametime)
+               if (!localentityactive[i] && bestfreetime > localentityfreetime[i])
                {
-                       memset(l, 0, sizeof(*l));
-                       l->active = true;
-                       return l;
+                       bestfreetime = localentityfreetime[i];
+                       best = i;
+                       if (bestfreetime < gametime)
+                               break;
                }
        }
-       for (i = 0;i < MAX_LOCALENTITIES;i++)
+       if (best >= 0)
        {
-               l = localentity + i;
-               if (!l->active)
-               {
-                       memset(l, 0, sizeof(*l));
-                       l->active = true;
-                       return l;
-               }
+               memset(localentity + best, 0, sizeof(*localentity));
+               localentityactive[best] = true;
+               return localentity + best;
        }
        return NULL;
 }
 
 static void entremove(localentity_t *e)
 {
-       memset(e, 0, sizeof(*e));
-       e->freetime = gametime + 1;
+       int i;
+       i = (e - localentity) / sizeof(localentity_t);
+       if (i < 0 || i >= MAX_LOCALENTITIES)
+               return; // this should be an error
+       //memset(e, 0, sizeof(*e));
+       localentityactive[i] = false;
+       localentityfreetime[i] = (float)gametime + 1.0f;
 }
 
 static void phys_setupphysentities(void)
@@ -86,9 +86,9 @@ static void phys_setupphysentities(void)
        /*
        for (i = 0;i < MAX_LOCALENTITIES;i++)
        {
-               l = localentities + i;
-               if (l->active && l->solid)
+               if (localentityactive[i] && localentities[i].solid)
                {
+                       l = localentities + i;
                }
        }
        */
@@ -100,12 +100,16 @@ static void phys_moveentities(void)
        localentity_t *l;
        for (i = 0;i < MAX_LOCALENTITIES;i++)
        {
-               l = localentity + i;
-               if (l->active)
+               if (localentityactive[i])
                {
+                       l = localentity + i;
                        if (l->framethink)
+                       {
                                l->framethink(l);
-                       if (l->active && l->draw.model)
+                               if (!localentityactive[i])
+                                       continue;
+                       }
+                       if (l->draw.model)
                                CGVM_Draw_Entity(&l->draw);
                }
        }
@@ -122,7 +126,7 @@ static void phys_update(localentity_t *e)
        vec3_t impactpos, impactnormal, end;
        int impactentnum;
        float t, f, frac, bounce;
-       t = frametime;
+       t = (float)frametime;
        if (t == 0)
                return;
        VectorMA(e->draw.angles, t, e->avelocity, e->draw.angles);
@@ -133,13 +137,17 @@ static void phys_update(localentity_t *e)
        {
                bounce = DotProduct(e->velocity, impactnormal) * -e->bouncescale;
                VectorMA(e->velocity, bounce, impactnormal, e->velocity);
-               // FIXME: do some kind of touch code here if physentities get implemented
-
                if (impactnormal[2] >= 0.7 && DotProduct(e->velocity, e->velocity) < 100*100)
                {
                        VectorClear(e->velocity);
                        VectorClear(e->avelocity);
                }
+
+               if (e->touchnetwork)
+                       e->touchnetwork(e);
+               // FIXME: do some kind of touch code here if physentities get implemented
+
+               VectorCopy(impactpos, e->lastimpactorigin);
        }
 
        if (e->airfrictionscale)
@@ -179,7 +187,7 @@ static void explosiondebris_framethink(localentity_t *self)
 {
        if (gametime > self->dietime)
        {
-               self->draw.scale -= frametime * 3;
+               self->draw.scale -= (float)(frametime * 3.0);
                if (self->draw.scale < 0.05f)
                {
                        entremove(self);
@@ -189,6 +197,33 @@ static void explosiondebris_framethink(localentity_t *self)
        phys_update(self);
 }
 
+static void gib_framethink(localentity_t *self)
+{
+       if (gametime > self->dietime)
+       {
+               self->draw.scale -= (float)frametime * 3.0f;
+               if (self->draw.scale < 0.05f)
+               {
+                       entremove(self);
+                       return;
+               }
+       }
+       /*
+       if (gametime > self->trailnexttime)
+       {
+               self->trailnexttime = gametime + 0.1f;
+               CGVM_BloodParticle(self->draw.origin, self->velocity);
+       }
+       */
+       phys_update(self);
+}
+
+static void gib_touchnetwork(localentity_t *self)
+{
+       if (VectorDistance2(self->draw.origin, self->lastimpactorigin) >= 5*5)
+               CGVM_Stain(self->draw.origin, 64, 64, 24, 24, 48, 192, 48, 48, 48);
+}
+
 static void net_explosion(unsigned char num)
 {
        int i;
@@ -213,7 +248,7 @@ static void net_explosion(unsigned char num)
                e->draw.angles[2] = CGVM_RandomRange(0, 360);
                VectorRandom(e->velocity);
                VectorScale(e->velocity, 300, e->velocity);
-               e->velocity[2] -= cg_gravity * 0.1;
+               e->velocity[2] -= (float)cg_gravity * 0.1f;
                e->avelocity[0] = CGVM_RandomRange(0, 1440);
                e->avelocity[1] = CGVM_RandomRange(0, 1440);
                e->avelocity[2] = CGVM_RandomRange(0, 1440);
@@ -234,20 +269,79 @@ static void net_explosion(unsigned char num)
                VectorSet(e->worldmaxs, 0, 0, -8);
                VectorSet(e->entitymins, -8, -8, -8);
                VectorSet(e->entitymaxs, 8, 8, 8);
-               e->bouncescale = 1.4;
+               e->bouncescale = 1.4f;
                e->gravityscale = 1;
                e->airfrictionscale = 1;
                e->framethink = explosiondebris_framethink;
-               e->dietime = time + 5;
+               e->dietime = (float)time + 5.0f;
+       }
+}
+
+static void net_gibshower(unsigned char num)
+{
+       int i, count;
+       float r, velocityscale;
+       vec3_t org;
+       double time;
+       localentity_t *e;
+       // need the time to know when the gibs should fade
+       time = CGVM_Time();
+       // read the network data
+       count = CGVM_MSG_ReadByte();
+       velocityscale = (float)(CGVM_MSG_ReadByte() * 100);
+       readvector(org);
+
+       for (i = 0;i < count;i++)
+       {
+               e = entspawn();
+               if (!e)
+                       return;
+
+               VectorCopy(org, e->draw.origin);
+               e->draw.angles[0] = CGVM_RandomRange(0, 360);
+               e->draw.angles[1] = CGVM_RandomRange(0, 360);
+               e->draw.angles[2] = CGVM_RandomRange(0, 360);
+               VectorRandom(e->velocity);
+               VectorScale(e->velocity, velocityscale, e->velocity);
+               e->velocity[2] -= (float)(cg_gravity * 0.1);
+               e->avelocity[0] = CGVM_RandomRange(0, 1440);
+               e->avelocity[1] = CGVM_RandomRange(0, 1440);
+               e->avelocity[2] = CGVM_RandomRange(0, 1440);
+               r = CGVM_RandomRange(0, 3);
+               if (r < 1)
+                       e->draw.model = CGVM_Model("progs/gib1.mdl");
+               else if (r < 2)
+                       e->draw.model = CGVM_Model("progs/gib2.mdl");
+               else
+                       e->draw.model = CGVM_Model("progs/gib3.mdl");
+               e->draw.alpha = 1;
+               e->draw.scale = 1;
+               e->draw.frame1 = 0;
+               e->draw.frame2 = 0;
+               e->draw.framelerp = 0;
+               e->draw.skinnum = 0;
+               VectorSet(e->worldmins, 0, 0, -8);
+               VectorSet(e->worldmaxs, 0, 0, -8);
+               VectorSet(e->entitymins, -8, -8, -8);
+               VectorSet(e->entitymaxs, 8, 8, 8);
+               e->bouncescale = 1.5;
+               e->gravityscale = 1;
+               e->airfrictionscale = 1;
+               e->framethink = gib_framethink;
+               e->touchnetwork = gib_touchnetwork;
+               e->dietime = (float)time + CGVM_RandomRange(3.0f, 5.0f);
        }
 }
 
 // called by engine
 void CG_Init(void)
 {
-       localentity = CGVM_Malloc(sizeof(localentity_t) * MAX_LOCALENTITIES);
-       phys_entity = CGVM_Malloc(sizeof(cgphysentity_t) * MAX_LOCALENTITIES);
+       localentity = CGVM_Malloc(sizeof(*localentity) * MAX_LOCALENTITIES);
+       localentityactive = CGVM_Malloc(sizeof(*localentityactive) * MAX_LOCALENTITIES);
+       localentityfreetime = CGVM_Malloc(sizeof(*localentityfreetime) * MAX_LOCALENTITIES);
+       phys_entity = CGVM_Malloc(sizeof(*phys_entity) * MAX_LOCALENTITIES);
        CGVM_RegisterNetworkCode(1, net_explosion);
+       CGVM_RegisterNetworkCode(2, net_gibshower);
        gametime = 0;
 }