/* a_doorkick.c
 * Door kicking code by hal[9k] 
 * originally for AQ:Espionage (http://aqdt.fear.net/)
 * email: hal9000@telefragged.com
 * Assembled here by Homer (homer@fear.net)
 */

#include "g_local.h"

#define STATE_TOP               0
#define STATE_BOTTOM            1
#define STATE_UP                2
#define STATE_DOWN              3

#define DOOR_START_OPEN         1
#define DOOR_REVERSE            2

extern void door_use (edict_t *self, edict_t *other, edict_t *activator);

// needed for KickDoor
void VectorRotate(vec3_t in, vec3_t angles, vec3_t out) 
{
	float cv, sv, angle, tv;
	
	VectorCopy(in, out);
	
	angle = (-angles[PITCH]) * M_PI / 180;
	cv = cos(angle);
	sv = sin(angle);
	tv = (out[0] * cv) - (out[2] * sv);

	out[2] = (out[2] * cv) + (out[0] * sv);
	out[0] = tv;
	
	angle = (angles[YAW]) * M_PI / 180;

	cv = cos(angle);
	sv = sin(angle);
	tv = (out[0] * cv) - (out[1] * sv);

	out[1] = (out[1] * cv) + (out[0] * sv);
	out[0] = tv;
	angle = (angles[ROLL]) * M_PI / 180;

	cv = cos(angle);
	sv = sin(angle);
	tv = (out[1] * cv) - (out[2] * sv);
	out[2] = (out[2] * cv) + (out[1] * sv);
	out[1] = tv;
}

int KickDoor( trace_t *tr_old, edict_t *ent, vec3_t forward )
{
  trace_t tr;
  
  vec3_t d_forward, right, end;
  float d;
  if ( !Q_strcasecmp( tr_old->ent->classname, "func_door_rotating" ) )
  {
    // Make that the door is closed
    
    tr = *tr_old;
#if 1
    if ( (!(tr.ent->spawnflags & DOOR_START_OPEN) &&
          !(tr.ent->moveinfo.state == STATE_TOP)) ||
          ( (tr.ent->spawnflags & DOOR_START_OPEN) &&
           !(tr.ent->moveinfo.state == STATE_BOTTOM)) )
#else
    if ( (!(tr.ent->spawnflags & DOOR_START_OPEN) &&
      ((tr.ent->moveinfo.state == STATE_BOTTOM) ||
      (tr.ent->moveinfo.state == STATE_DOWN))) ||
      ((tr.ent->spawnflags & DOOR_START_OPEN) &&
      ((tr.ent->moveinfo.state == STATE_TOP) ||
      (tr.ent->moveinfo.state == STATE_UP))) )
#endif
    {
      //gi.dprintf( "Kicking a closed door\n" );
      
      // Find out if we are on the "outside"
      
#if 0
      gi.WriteByte (svc_temp_entity);
      gi.WriteByte (TE_RAILTRAIL);
      gi.WritePosition (tr.ent->s.origin);
      gi.WritePosition (tr.endpos);
      gi.multicast (tr.ent->s.origin, MULTICAST_PHS);
#endif
      VectorSubtract( tr.endpos, tr.ent->s.origin, d_forward );
      
      forward[2] = 0;
      d_forward[2] = 0;
      VectorNormalize( forward );
      VectorNormalize( d_forward );
      VectorSet( right, 0, 90, 0 );
      VectorRotate( d_forward, right, d_forward );
      
      d = DotProduct( forward, d_forward );
      if ( tr.ent->spawnflags & DOOR_REVERSE )
        d = -d;
      // d = sin( acos( d ) );
      if ( d > 0.0 )
      {
        // gi.dprintf( "we think we are on the outside\n" );
        //if ( tr.ent->spawnflags & DOOR_REVERSE )
        //  gi.dprintf( "but DOOR_REVERSE is set\n" );
        // Only use the door if it's not already opening
        if ( (!( tr.ent->spawnflags & DOOR_START_OPEN ) &&  
               !( tr.ent->moveinfo.state == STATE_UP )) ||
               ((tr.ent->spawnflags & DOOR_START_OPEN ) &&
                (tr.ent->moveinfo.state == STATE_DOWN) ) )
          door_use( tr.ent, ent, ent );
        // Find out if someone else is on the other side
        VectorMA( tr.endpos, 25, forward, end );
	PRETRACE();
        tr = gi.trace (tr.endpos, NULL, NULL, end, tr.ent, MASK_SHOT);
	POSTTRACE();
        if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))    
        {
          if (tr.fraction < 1.0)        
          {            
            if (tr.ent->client)            
            {
              //gi.dprintf("we found a client on the other side\n");
              *tr_old = tr;
              return( 1 );
            }
          }
        }
      }
      
    }
  }

  return( 0 );
}
