/****************************************************************************/
/*                                                                          */
/*    project    : CGF                  (c) 1999 William van der Sterren    */
/*                               parts  (c) 1998 id software                */
/*                                                                          */
/*      file     : cgf_sfx_glass.h    "special effects for glass entities"  */
/*      author(s): William van der Sterren                                  */
/*      version  : 0.5                                                      */
/*                                                                          */
/*      date (last revision):  Jun 12, 99                                   */
/*      date (creation)     :  Jun 04, 99                                   */
/*                                                                          */
/*                                                                          */
/*      revision history                                                    */
/*      -- date ---- | -- revision ---------------------- | -- revisor --   */
/*      Jun 12, 1999 | fixed knife slash breaks glass     | William         */
/*                                                                          */
/******* http://www.botepidemic.com/aid/cgf for CGF for Action Quake2 *******/


#ifndef __CGF_SFX_GLASS_H_
#define __CGF_SFX_GLASS_H_


// defines (should be consistent with other weapon defs in g_local.h)
#define MOD_BREAKINGGLASS 46

/*
// forward definitions
typedef struct edict_s edict_t;
*/


// export a number of functions to g_func.c:
//
//

void CGF_SFX_InstallGlassSupport();
// registers cvar breakableglass (default 0)
// registers cvar glassfragmentlimit (default 30)


void CGF_SFX_RebuildAllBrokenGlass();
// upon starting a new team play game, reconstruct any
// broken glass because we like to break it again


int  CGF_SFX_IsBreakableGlassEnabled();
// returns whether breakable glass is enabled (cvar breakableglass)


void CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think(edict_t* aPossibleGlassEntity);
// initial think function for all func_explosives
// because we cannot verify the contents of the entity unless the entity
// has been spawned, we need to first introduce the entity, and remove
// it later (level.time == 0.1) if required


void CGF_SFX_ShootBreakableGlass(edict_t* aGlassPane, 
                                 edict_t* anAttacker,
                                 /*trace_t*/ void* tr,
                                 int      mod
                                );
// shoot thru glass - depending on bullet types and
// random effects, glass just emits fragments, or breaks


void CGF_SFX_AttachDecalToGlass(edict_t* aGlassPane, edict_t* aDecal);
// a glass that breaks will remove all decals (blood splashes, bullet
// holes) if they are attached


#endif


/*
  
  further documentation:

  cgf_sfx_glass.cpp can be compiled with ordinary c compilers as
  well - just change the extension from .cpp to .c

  to install breakable glass in the ActionQuake2 1.51 code base,
  do the following:

  @ file a_game.h
    + modify
        #define ACTION_VERSION  "1.51"
      to something that tells users breakable glass is supported

  @ file a_team.c
    + add #include "cgf_sfx_glass.h"
    + in void CleanLevel()
      add 
        CGF_SFX_RebuildAllBrokenGlass();
      as the last statement (thus after CleanBodies();)

  @ file g_misc.c
    + add #include "cgf_sfx_glass.h"
    + in void SP_func_explosive (edict_t *self)
      disable the statements (put them within comments):
        if (deathmatch->value)
        {       // auto-remove for deathmatch
                G_FreeEdict (self);
                return;
        }
    + in void SP_func_explosive (edict_t *self)
      add
        self->think     = CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think;
        self->nextthink = level.time + FRAMETIME;
      as the last statement (thus after gi.linkentity (self);)

  @ file g_save.c
    + add #include "cgf_sfx_glass.h"
    + in void InitGame (void)
      add
        CGF_SFX_InstallGlassSupport();
      under (splatlimit = gi.cvar ("splatlimit", "0", 0);)

  @ file g_local.h
    + replace
        void AddDecal (edict_t *self, vec3_t point, vec3_t direct);
        void AddSplat (edict_t *self, vec3_t point, vec3_t direct);
      by    
        void AddDecal (edict_t *self, trace_t* tr);
        void AddSplat (edict_t *self, vec3_t point, trace_t* tr);

  @ file a_game.c
    + add #include "cgf_sfx_glass.h"
    + replace
        void AddDecal (edict_t *self, vec3_t point, vec3_t direct)
      by    
        void AddDecal (edict_t *self, trace_t* tr)
    + replace
        void AddSplat (edict_t *self, vec3_t point, vec3_t direct);
      by    
        void AddSplat (edict_t *self, vec3_t point, trace_t* tr);
    + in void AddDecal (edict_t *self, trace_t* tr)
      replace each occurrence of 'point' by tr->endpos
    + in void AddDecal (edict_t *self, trace_t* tr)
      replace each occurrence of 'direct' by tr->plane.normal
    + in void AddDecal (edict_t *self, trace_t* tr)
      add (as the last line, thus under gi.linkentity (decal);)
        if ((tr->ent) && (0 == Q_stricmp("func_explosive", tr->ent->classname)))
          {
            CGF_SFX_AttachDecalToGlass(tr->ent, decal);
          }
    + in void AddSplat (edict_t *self, vec3_t point, trace_t* tr)
      replace each occurrence of 'direct' by tr->plane.normal
    + in void AddSplat (edict_t *self, vec3_t point, trace_t* tr)
      add (as the last line, thus under gi.linkentity (decal);)
        if ((tr->ent) && (0 == Q_stricmp("func_explosive", tr->ent->classname)))
          {
            CGF_SFX_AttachDecalToGlass(tr->ent, splat);
          }
  @ file g_weapon.c
    + add #include "cgf_sfx_glass.h"
    + in static void fire_lead (edict_t *self, ...)
      replace 
        AddDecal (self, tr.endpos, tr.plane.normal);
      by
        AddDecal (self, &tr);
    + in void fire_lead_ap (edict_t *self, ...)
      replace 
        AddDecal (self, tr.endpos, tr.plane.normal);
      by
        AddDecal (self, &tr);
    + in static void fire_lead (edict_t *self, ...)
      add
      between
        tr = do_trace (start, NULL, NULL, end, self, content_mask);
      and
        // see if we hit water
      the following
        // catch case of firing thru one or breakable glasses
        while (   (tr.fraction < 1.0) 
               && (tr.surface->flags & (SURF_TRANS33 | SURF_TRANS66))
               && (tr.ent) 
               && (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
              )
          {
            // break glass  
            CGF_SFX_ShootBreakableGlass(tr.ent, self, &tr, mod);
            // continue trace from current endpos to start
            tr = do_trace (tr.endpos, NULL, NULL, end, tr.ent, content_mask);
          }
    + in static void fire_lead_ap (edict_t *self, ...)
      add
      between
        tr = do_trace (start, NULL, NULL, end, self, content_mask);
      and
        // see if we hit water
      the following
        // catch case of firing thru one or breakable glasses
        while (   (tr.fraction < 1.0) 
               && (tr.surface->flags & (SURF_TRANS33 | SURF_TRANS66))
               && (tr.ent) 
               && (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
              )
          {
            // break glass  
            CGF_SFX_ShootBreakableGlass(tr.ent, self, &tr, mod);
            // continue trace from current endpos to start
            tr = do_trace (tr.endpos, NULL, NULL, end, tr.ent, content_mask);
          }
    + in void knife_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
      replace
        if (other->takedamage)
      by 
        if (0 == Q_stricmp(other->classname, "func_explosive"))
          {
            // ignore it, so it can bounce
            return;
          }
        else
        if (other->takedamage) 
    + in void kick_attack (edict_t * ent )
      between
        // zucc stop powerful upwards kicking
        forward[2] = 0;
      and
        T_Damage (tr.ent, ent, ent, forward, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_KICK );
      add
        if (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
          {
            CGF_SFX_ShootBreakableGlass(tr.ent, ent, &tr, MOD_KICK);
          }
    + in int knife_attack ( edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
      replace
        if (tr.ent->takedamage)
      by
        if (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
          {
            CGF_SFX_ShootBreakableGlass(tr.ent, self, &tr, MOD_KNIFE);
          }
        else
        if (tr.ent->takedamage) 

  @ file g_phys.c
    + add #include "cgf_sfx_glass.h"
    + in void SV_Physics_Toss (edict_t *ent)
      replace 
        AddSplat (self, tr.endpos, tr.plane.normal);
      by
        AddSplat (self, &tr);

  @ file g_combat.c
    + add #include "cgf_sfx_glass.h"
    + in void T_Damage (edict_t *targ, ...)
      replace
        if ( (mod == MOD_M3) || (mod == MOD_HC) || (mod == MOD_HELD_GRENADE) ||
             (mod == MOD_HG_SPLASH) || (mod == MOD_G_SPLASH) )
      by
        if (    (mod == MOD_M3) 
             || (mod == MOD_HC) 
             || (mod == MOD_HELD_GRENADE) 
             || (mod == MOD_HG_SPLASH) 
             || (mod == MOD_G_SPLASH) 
             || (mod == MOD_BREAKINGGLASS)
           )
    + in void T_RadiusDamage (...)
      add before if (CanDamage (ent, inflictor))
        if (0 == Q_stricmp(ent->classname, "func_explosive"))
          {
            CGF_SFX_ShootBreakableGlass(ent, inflictor, 0, mod);
          }
        else
       
  @ file p_client.c
    + add #include "cgf_sfx_glass.h"
    + in void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
      between
		    switch (mod)
		    {
      and
    		  case MOD_SUICIDE:
      add
      		case MOD_BREAKINGGLASS:
            message = "ate too much glass";
            break;
*/
