D:\cygwin\wf_fusion_src_r8\CVSROOT\cgame\cg_debris.c

/*
==============================================================================
The Weapons Factory - 
  
Modified code by Keith Pase

Copyright (C) 1997-2003 Weapons Factory Software
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  $Id$
  client-game side debris
  
==============================================================================
*/

#include "cg_local.h"

#define FRAMETIME 0.01

/*
=================
CG_ClearCGDebrischunks
=================
*/
void CG_ClearCGDebrischunks (void)
{
    memset ( cg_debrischunks, 0, sizeof(cg_debrischunks) );
    cg_numDebrischunks = 0;
}



/*
=================

=================
*/
void CG_UpdateDebris ( int owner, int type, vec3_t origin )
{
    int number = cg_numDebrischunks + 1;

    //remove all in this case
    if (type == DEBRIS_ALL)
    {
        int i;

        for(i=0; i<cg_numDebrischunks; i++)
            debrischunks_drawlist[i] = NULL;

        cg_numDebrischunks = 0;

        for(i=0; i<MAX_CG_DEBRISCHUNKS; i++)
            cg_debrischunks[i].inuse = qfalse;

        return;
    }

    if (cg_numDebrischunks > MAX_CG_DEBRISCHUNKS)
    {
        Com_Printf("MAX DEBRIS HIT (1024)\n");
        return;
    }

    //add this debris to draw list
    cg_debrischunks[number].type = type;
    VectorCopy( origin, cg_debrischunks[number].origin );

    if (cg_debrischunks[number].inuse != qtrue)
    {
        //Com_Printf("Got new debris (%i): origin: %f %f %f\n", debris, origin[0],origin[1],origin[2]);
        cg_debrischunks[number].inuse = qtrue;
        cg_debrischunks[number].time = cg.frame.serverTime + 15500; //2500 is 2.5 seconds
        cg_debrischunks[number].number = number;
        cg_debrischunks[number].origin[2] +=12;
        
        // todo types
/*
        if (cg_debrischunks[number].type == DEBRIS_CHUNK_BOUNCE)
        {
            vec3_t  v = {0,0,0};

//          v[0] = 75 * crandom();  
//          v[1] = 75 * crandom();  
//          v[2] = 75 + 75 * crandom();
//          VectorMA (cg_debrischunks[number].velocity, 20, v, cg_debrischunks[number].velocity);
            cg_debrischunks[number].velocity[2] = 100;

            VectorSet(cg_debrischunks[number].mins, -10,-10,-10);
            VectorSet(cg_debrischunks[number].maxs, 5, 5, 5);


//          cg_debrischunks[number].velocity[0] = random()*600; 
//          cg_debrischunks[number].velocity[1] = random()*600;
//          cg_debrischunks[number].velocity[2] = random()*600;
            cg_debrischunks[number].gravity = 1;
        }
*/
        //drawlist
        cg_debrischunks[number].velocity[0] = 400 * crandom();
        cg_debrischunks[number].velocity[1] = 400 * crandom();
        cg_debrischunks[number].velocity[2] = 400 * crandom();

        cg_debrischunks[number].avelocity[0] = 100 * random();
        cg_debrischunks[number].avelocity[1] = 100 * random();
        cg_debrischunks[number].avelocity[2] = 100 * random();

        cg_debrischunks[number].gravity = 1;
        cg_debrischunks[number].originalgravity = 1;

        debrischunks_drawlist[cg_numDebrischunks] = &cg_debrischunks[number];
        cg_numDebrischunks++;

        Com_Printf("CreatingChunk: %i\n",cg_numDebrischunks);
    }
}


void CG_UpdateDebrischunks (void)
{
    int                 pnum;
    entity_state_t      *state;
    int                 i,k = 0;

    for ( pnum = 0; pnum < cg.frame.numEntities; pnum++ )
    {
        state = &cg_parseEntities[(cg.frame.parseEntities+pnum)&(MAX_PARSE_ENTITIES-1)];

        if ( state->type != ET_EVENT )
            continue;

        for ( i = 0; i < 2; i++ ) {
            if ( state->events[i] == EV_DRAWDEBRIS )
            {
                for (k=0; k<10; k++)
                CG_UpdateDebris ( state->ownerNum, state->eventParms[i], state->origin2 );
            }
        }
    }
}

void CG_CheckVelocity (cg_debris_t *chunk)
{
    float   scale;

//
// bound velocity
//
    scale = VectorLength ( chunk->velocity );
    if ( (scale > 2000) && (scale) ) // sv_maxvelocity
    {
        scale = 2000 / scale;
        VectorScale ( chunk->velocity, scale, chunk->velocity );
    }
}

void CG_AddGravity (cg_debris_t *chunk)
{
    chunk->velocity[2] -= chunk->gravity * 800 * FRAMETIME;
}

trace_t CG_PushEntity (cg_debris_t *ent, vec3_t push)
{
    trace_t trace;
    vec3_t  start;
    vec3_t  end;
    int     mask;

    VectorCopy (ent->origin, start);
    VectorAdd (start, push, end);

//retry:
    if (ent->clipmask)
        mask = ent->clipmask;
    else
        mask = MASK_SOLID;

    CG_Trace (&trace, start, ent->mins, ent->maxs, end, ent->number, mask);
    
    VectorCopy (trace.endpos, ent->origin);

    if (trace.fraction != 1.0)
    {
//      SV_Impact (ent, &trace);

        // if the pushed entity went away and the pusher is still there
        /*
        if (!game.edicts[trace.ent].r.inuse && ent->r.inuse)
        {
            // move the pusher back and try again
            VectorCopy (start, ent->origin);
            goto retry;
        }
        */
    }

    if (trace.contents < 0)
        Com_Printf("DEBUG: VOID\n");

    return trace;
}   

/*
==================
CG_ClipChunkVelocity
copy of g_phys.c

Slide off of the impacting object
returns the blocked flags (1 = floor, 2 = step / wall)
==================
*/
#define STOP_EPSILON    0.1

int CG_ClipChunkVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
{
    float   backoff;
    float   change;
    int     i, blocked;
    
    blocked = 0;
    if (normal[2] > 0)
        blocked |= 1;       // floor
    if (!normal[2])
        blocked |= 2;       // step
    
    backoff = DotProduct (in, normal) * overbounce;

    for (i=0 ; i<3 ; i++)
    {
        change = normal[i]*backoff;
        out[i] = in[i] - change;
        if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
            out[i] = 0;
    }
    
    return blocked;
}

void CG_ReduceChunkVelocity (vec3_t in, vec3_t out, float multiplier)
{
    int     i;
    
    for (i=0 ; i<3 ; i++)
    {
        out[i] = in[i] * multiplier;
        if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
            out[i] = 0;
    }
}


void CG_DebrisToss (cg_debris_t *chunk)
{
    vec3_t      old_origin;
    trace_t     trace;
    vec3_t      move;
    float       backoff;
    qboolean    wasinwater;
    qboolean    isinwater;


    if (chunk->velocity[2] > 0)
        chunk->groundentity = 0;
/*
    if (chunk->groundentity )
    {
        VectorClear(chunk->velocity);
        return;
    }
*/
    VectorCopy (chunk->origin, old_origin);

    CG_CheckVelocity (chunk);

    CG_AddGravity (chunk);

    VectorMA (chunk->angles, FRAMETIME, chunk->avelocity, chunk->angles);

    VectorScale (chunk->velocity, FRAMETIME, move);

    trace = CG_PushEntity (chunk, move);

    if (trace.fraction < 1)
    {
//      Com_Printf("DEBUG: InSolid\n");

        if (chunk->type == DEBRIS_CHUNK_FLYRICOCHET)//WF34
            backoff = 1.8;//WF34
        else if (
            (chunk->type == DEBRIS_CHUNK_BOUNCE)
            ||
            (chunk->type == DEBRIS_CHUNK_FLYRICOCHET2)
            ||
            (chunk->type == DEBRIS_CHUNK_FLOAT)
            ||
            (chunk->type == DEBRIS_CHUNK_BOUNCEALIGN)
            )
            backoff = 1.5;
        else
            backoff = 1;

        CG_ClipChunkVelocity (chunk->velocity, trace.plane.normal, chunk->velocity, backoff);

        if ((chunk->type == DEBRIS_CHUNK_FLYRICOCHET) || (chunk->type == DEBRIS_CHUNK_FLYRICOCHET2) || (chunk->type == DEBRIS_CHUNK_BOUNCE))
            VecToAngles(chunk->velocity, chunk->angles);

    // stop if on ground
        if  ((trace.plane.normal[2] > 0.6) && chunk->type != DEBRIS_CHUNK_FLYRICOCHET && chunk->type != DEBRIS_CHUNK_BOUNCEALIGN)
        {       
            if (chunk->velocity[2] < 60 ||
                (
                chunk->type != DEBRIS_CHUNK_BOUNCE 
                && chunk->type != DEBRIS_CHUNK_FLOAT
                ) 
                )
            {
                chunk->groundentity = 1;
                VectorClear (chunk->velocity);
                VectorClear (chunk->avelocity);
            }
        }

        if  ((trace.plane.normal[2] > 0.6) && chunk->type == DEBRIS_CHUNK_BOUNCEALIGN   )
        {       
            if (chunk->velocity[2] < 30 )
            {
                chunk->groundentity = 1;
                VectorClear (chunk->velocity);
                VectorClear (chunk->avelocity);
                chunk->angles[0] = 270;
            }
        }
    }

    wasinwater = (chunk->watertype & MASK_WATER);
    chunk->watertype = trap_CM_PointContents (chunk->origin, NULL);
    isinwater = chunk->watertype & MASK_WATER;

    if ( chunk->groundentity && !chunk->CanFloat)
        return;

    if (chunk->movetype == DEBRIS_CHUNK_FLOAT)
        CG_ReduceChunkVelocity (chunk->velocity, chunk->velocity, 0.9);

    if (isinwater)
        chunk->waterlevel = 1;
    else
        chunk->waterlevel = 0;

    if (chunk->waterlevel > 1)
        chunk->gravity = 0.1;
    else 
        chunk->gravity = chunk->originalgravity;

}


void CG_RunDebris (cg_debris_t *chunk)
{
    int i;

    for (i=0; i<3; i++)
    {
        if (chunk->velocity[i] !=0)
        {
            chunk->origin[i] += ((chunk->velocity[i]/1000)*cg.normalfps);
//          Com_Printf("VELOCITY: %f %f %f\n",chunk->velocity[0],chunk->velocity[1],chunk->velocity[2]);
//          Com_Printf("ORIGIN: %f %f %f\n",chunk->origin[0],chunk->origin[1],chunk->origin[2]);
        }
    }
}

void CG_AddDebrischunks ( void )
{
    int i, j;
    entity_t    *ent;
    vec4_t shadelight = { 0, 0, 0, 0.3 };

    cg_debris_t *chunk;


//  Com_Printf("cg.time %i\n cg.Realtime %i\n server: %i\n",cg.time,cg.realTime,cg.frame.serverTime);

    if(!cg_numDebrischunks)
        return;

    for( i=0; i<cg_numDebrischunks; i++)
    {
        ent = &debrischunks_drawlist[i]->ent;

        if (debrischunks_drawlist[i]==NULL )
            continue;

        if (debrischunks_drawlist[i]->time < cg.frame.serverTime)
        {
            debrischunks_drawlist[i]->inuse = qfalse;
            debrischunks_drawlist[i] = NULL;
            cg_numDebrischunks--;
            continue;
        }

        chunk = debrischunks_drawlist[i];

        CG_RunDebris (chunk);

        CG_DebrisToss (chunk);

        VectorCopy(chunk->origin, ent->origin);
        AnglesToAxis(chunk->angles, ent->axis);

        VectorCopy(ent->origin, ent->oldorigin);
        VectorCopy(ent->origin, ent->lightingOrigin );

        //todo model types
        ent->model = trap_R_RegisterModel("models/weapons2/spike/spike.md3");

        ent->flags = RF_MINLIGHT;
        ent->rtype = RT_MODEL;
        ent->scale = 1.0;
        ent->frame = 0;
        ent->oldframe = 0;
        ent->backlerp = 0;
//      Matrix_Copy( axis_identity, ent->axis );

        ent->customSkin = NULL;
        ent->customShader = NULL;


        //------------------------
        
        if(debrischunks_drawlist[i]->type == DEBRIS_CHUNK)
        {
            shadelight[0] = 0;      //R
            shadelight[1] = 0;      //G
            shadelight[2] = 1.0;    //B
            shadelight[3] = 0.3;
        }
        /*
        else if(debrischunks_drawlist[i]->type == DEBRIS_SHRAPNEL)
        {
            shadelight[0] = 1.0;
            shadelight[1] = 0;
            shadelight[2] = 0;
            shadelight[3] = 0.3;
        }
        else if(debrischunks_drawlist[i]->type == DEBRIS_GLOWSHRAPNEL)
        {
            shadelight[0] = 0;
            shadelight[1] = 1.0;
            shadelight[2] = 1.0;
            shadelight[3] = 0.3;
        }
        else if(debrischunks_drawlist[i]->type == DEBRIS_LOTSOFSHRAPNEL)
        {
            shadelight[0] = 0;
            shadelight[1] = 0.5;
            shadelight[2] = 1.0;
            shadelight[3] = 0.3;
        }
        */
        else
        {
            shadelight[0] = 0;
            shadelight[1] = 1.0;
            shadelight[2] = 0;
            shadelight[3] = 0.3;
        }
            
        for( j = 0; j < 4; j++ )
            ent->color[j] = shadelight[j] * 255;
        
        ent->customShader = CG_MediaShader( cgs.media.shaderShellEffect );
        
        //-------------------

        CG_AddEntity( ent );
    }
}