/*
@Copyright Looking Glass Studios, Inc.
1996,1997,1998,1999,2000 Unpublished Work.
*/

#include <math.h>
#include <kbcook.h>
#include <keydefs.h>

#include <mouse.h>
#include <2d.h>
#include <config.h>
#include <matrix.h>
#include <objpos.h>
#include <portal.h>
#include <camera.h>

#include <physapi.h>
#include <playrobj.h>

#include <dpcctrl.h>
#include <dpcplayr.h>

// these are stolen from gamemode.c and why not?
#define KEYS_WALK      case 's': case KEY_UP:                  case KEY_PAD_CENTER
#define KEYS_RUN       case 'w': case KEY_UP|KB_FLAG_SHIFT:    case KEY_PAD_UP:                 case KEY_PAD_UP|KB_FLAG_SHIFT:  case KEY_PAD_CENTER|KB_FLAG_SHIFT
#define KEYS_BACK      case 'x': case KEY_DOWN:                case KEY_PAD_DOWN
#define KEYS_SIDELEFT  case 'z': case ',':                     case KEY_LEFT|KB_FLAG_ALT:       case KEY_PAD_LEFT|KB_FLAG_ALT:  case KEY_PAD_END
#define KEYS_SIDERIGHT case 'c': case '.':                     case KEY_RIGHT|KB_FLAG_ALT:      case KEY_PAD_RIGHT|KB_FLAG_ALT: case KEY_PAD_PGDN
#define KEYS_TURNLEFT  case 'a': case KEY_LEFT:                case KEY_PAD_LEFT
#define KEYS_TURNRIGHT case 'd': case KEY_RIGHT:               case KEY_PAD_RIGHT
#define KEYS_FASTLEFT  case 'A': case KEY_LEFT|KB_FLAG_SHIFT:  case KEY_PAD_LEFT|KB_FLAG_SHIFT
#define KEYS_FASTRIGHT case 'D': case KEY_RIGHT|KB_FLAG_SHIFT: case KEY_PAD_RIGHT|KB_FLAG_SHIFT
#define KEYS_LOOKUP    case 'r': case KEY_END:                 case KEY_GREY_MINUS
#define KEYS_LOOKDOWN  case 'v': case KEY_PGDN:                case KEY_GREY_PLUS
#define KEYS_LOOKCNTR  case 'f': case KEY_DEL:                 case KEY_PAD_DEL

// misc magic numbers
#define RAW_SLEW_SPEED 15.0
#define RAW_ROTATE_SPEED 3.14    // 180 degrees/sec

static float g_PlayerSlewSpeedScale =1.0;
static float g_PlayerRotateSpeedScale =1.0;

#define SLEW_SPEED (RAW_SLEW_SPEED*g_PlayerSlewSpeedScale)
#define ROTATE_SPEED (RAW_ROTATE_SPEED*g_PlayerRotateSpeedScale)

#define NET_ROTATE_SPEED      (ROTATE_SPEED / PlayerCamera()->zoom)
#define NET_FAST_ROTATE_SPEED ((3 * ROTATE_SPEED) / (2 * PlayerCamera()->zoom))

bool DPCControlKeyParse(int keycode, ObjID controlObj, float speed)
{
    mxs_vector rotVec = {0, 0, 0};

    if (keycode & KB_FLAG_DOWN)
    {
        switch (keycode & ~KB_FLAG_DOWN)
        {
        KEYS_RUN:       PhysAxisControlVelocity(controlObj, 0, speed*SLEW_SPEED);      break;
        KEYS_WALK:      PhysAxisControlVelocity(controlObj, 0, speed*SLEW_SPEED / 2);  break;
        KEYS_BACK:      PhysAxisControlVelocity(controlObj, 0, -speed*SLEW_SPEED / 2); break;

        KEYS_SIDELEFT:  PhysAxisControlVelocity(controlObj, 1,  speed*SLEW_SPEED);     break;
        KEYS_SIDERIGHT: PhysAxisControlVelocity(controlObj, 1, -speed*SLEW_SPEED);     break;

        KEYS_TURNLEFT:  
        {
            rotVec.z = speed*NET_ROTATE_SPEED;
            PhysControlRotationalVelocity(controlObj, &rotVec); 
        }
        break;
        KEYS_TURNRIGHT: 
        {
            rotVec.z = -speed*NET_ROTATE_SPEED;
            PhysControlRotationalVelocity(controlObj, &rotVec); 
        }
        break;
        KEYS_FASTLEFT:  PhysAxisControlRotationalVelocity(controlObj, 2,  speed*NET_FAST_ROTATE_SPEED); break;
        {
            rotVec.z = speed*NET_FAST_ROTATE_SPEED;
            PhysControlRotationalVelocity(controlObj, &rotVec); 
        }
        break;
        KEYS_FASTRIGHT: PhysAxisControlRotationalVelocity(controlObj, 2, -speed*NET_FAST_ROTATE_SPEED); break;
        {
            rotVec.z = -speed*NET_FAST_ROTATE_SPEED;
            PhysControlRotationalVelocity(controlObj, &rotVec); 
        }
        break;
        KEYS_LOOKUP:    PhysAxisControlRotationalVelocity(controlObj, 1, -speed*NET_ROTATE_SPEED); break;
        KEYS_LOOKDOWN:  PhysAxisControlRotationalVelocity(controlObj, 1,  speed*NET_ROTATE_SPEED); break;
        KEYS_LOOKCNTR:
        {
            mxs_vector angvel;

            mx_zero_vec(&angvel);
            PhysSetRotationalVelocity(controlObj, &angvel);

            break;
        }
        case 'q':
            {
                PhysAxisControlVelocity(controlObj, 2, speed*SLEW_SPEED);
                break;
            }
        case 'e':
            {
                PhysAxisControlVelocity(controlObj, 2, -speed*SLEW_SPEED);
                break;
            }
        default: 
            return FALSE;
        }
    }

    else
    {
        switch (keycode)     // if not down, then up, no flag to mask out
        {
        KEYS_RUN:
        KEYS_WALK:
        KEYS_BACK:      PhysStopAxisControlVelocity(controlObj, 0); break;

        KEYS_SIDELEFT:
        KEYS_SIDERIGHT: PhysStopAxisControlVelocity(controlObj, 1); break;

        KEYS_TURNLEFT:
        KEYS_TURNRIGHT:

        KEYS_FASTLEFT:
        KEYS_FASTRIGHT:

        KEYS_LOOKUP:
        KEYS_LOOKDOWN:  PhysStopControlRotationalVelocity(controlObj); break;
        case 'q':
            {
                PhysStopAxisControlVelocity(controlObj, 2);
                break;
            }
        case 'e':
            {
                PhysStopAxisControlVelocity(controlObj, 2);
                break;
            }
        default: 
            return FALSE;
        }
    }
    return TRUE;
}

const float kPlayerJumpSpeed = 10;

void DPCPlayerJump(void)
{
    ObjID playerObjID = PlayerObject();

    mxs_vector velocity;

    if (PhysObjOnGround(playerObjID))
    {
        PhysGetVelocity(playerObjID, &velocity);
        velocity.z = kPlayerJumpSpeed;
        PhysSetVelocity(playerObjID, &velocity);
    }
    else if (PhysObjInWater(playerObjID))
    {
        PhysGetVelocity(playerObjID, &velocity);
        velocity.z = kPlayerJumpSpeed/ 4;
        PhysSetVelocity(playerObjID, &velocity);
    }
}
