/*
================================================================
MOVEMENT CAPTURING ENTITY
================================================================

Copyright (C) 1998 by 2015, Inc.
All rights reserved.

This source is may not be distributed and/or modified without
expressly written permission by 2015, Inc.
*/

#include "movecapture.h"
#include "player.h"

// the list of flags used to put together the output value
#define MCF_OFF		0 // indicates that the movement capturer is not being used
#define MCF_ACTIVE	1 // indicates that the movement capturer is being used
#define MCF_ATTACK	2 // player is pressing the attack key
#define MCF_FORWARD	4 // player is pressing forward
#define MCF_BACK	8 // player is pressing backward
#define MCF_RIGHT	16 // player is pressing right strafe key
#define MCF_LEFT	32 // player is pressing left strafe key
#define MCF_UP		64 // player is pressing jump key
#define MCF_DOWN	128 // player is pressing duck key

CLASS_DECLARATION(TriggerUse, MoveCapture, "trigger_movecapture");

ResponseDef MoveCapture::Responses[] =
{
	{&EV_Trigger_Effect, (Response)&MoveCapture::Activate},
	{&EV_Use, (Response)&MoveCapture::Use},
	{NULL, NULL}
};

/*****************************************************************************/
/*SINED trigger_movecapture (0 .5 .8) ? NOUSE

"outputvar" is the name of the script variable to output the controls info to (required)

NOUSE means that a user can't use it directly to activate it
 *****************************************************************************/

MoveCapture::MoveCapture()
{
	setMoveType(MOVETYPE_NONE);
	setSolidType(SOLID_TRIGGER);
	hideModel();

	if(!LoadingSavegame)
	{
		// make sure that there's a variable name specified
		outputvar = G_GetSpawnArg("outputvar", "");
		if(!outputvar.length())
		{
			error("MoveCapture",  "no outputvar specified\n");
		}

		if(!Target())
		{
			error("MoveCapture",  "no camera specified\n");
		}

		// init script variable
		SetMCVariable(MCF_OFF);
	}

	// so the function will set the variable
	lastvalue = MCF_ACTIVE;

	usedebounce = 0;
}

void MoveCapture::Use(Event *ev)
{
	// Don't respond to users using me
	if (spawnflags & 1)
		return;

	// can't use if already being used
	if(usingplayer)
		return;

	TriggerStuff(ev);
}

void MoveCapture::Activate(Event *ev)
{
	Entity   *other;
	Event    *ev2;
	Camera   *cam;
	int      num;
	Player *player;

	// can't activate if already being used
	if(usingplayer)
		return;

	other = ev->GetEntity(1);

	// only clients can use this
	if(!other->isClient())
		return;

	player = (Player *)other;

	// check for the player already being in a movement capturer
	if(player == usingplayer)
		return;

	if(player->movecapturer)
		player->movecapturer->Deactivate();

	num = G_FindTarget(0, Target());
	
	if(!num)
		return;

	cam = (Camera *)G_GetEntity(num);
	assert(cam);
	player->SetCamera(cam);
	ev2 = new Event(EV_Player_HideStats);
	player->ProcessEvent(ev2);
	player->movecapturer = this;

	usingplayer = player;
	usedebounce = level.time + 1;
}

void MoveCapture::Deactivate(void)
{
	Player *player;
	Event *ev2;

	if(!usingplayer)
		return;

	player = (Player *)usingplayer.Ptr();

	ev2 = new Event(EV_Player_DrawStats);
	player->ProcessEvent(ev2);

	player->SetCamera(NULL);

	player->movecapturer = NULL;

	usingplayer = NULL;
	SetMCVariable(MCF_OFF);
}

void MoveCapture::CaptureMovement(usercmd_t *ucmd)
{
	Player *player;
	int i;

	player = (Player *)usingplayer.Ptr();

	// check for the player wanting out
	if	(
		(player->new_buttons & BUTTON_USE) &&
		(usedebounce < level.time)
		)
	{
		Deactivate();
		player->new_buttons &= ~BUTTON_USE;
		return;
	}

	// construct the new output value
	i = MCF_ACTIVE;

	if(player->buttons & BUTTON_ATTACK)
		i |= MCF_ATTACK;

	if(ucmd->forwardmove > 0)
		i |= MCF_FORWARD;
	else if(ucmd->forwardmove < 0)
		i |= MCF_BACK;

	if(ucmd->sidemove > 0)
		i |= MCF_RIGHT;
	else if(ucmd->sidemove < 0)
		i |= MCF_LEFT;

	if(ucmd->upmove > 0)
		i |= MCF_UP;
	else if(ucmd->upmove < 0)
		i |= MCF_DOWN;


	// output the new value
	SetMCVariable(i);

	// clear out the ucmd so that the player doesn't move around
	memset(ucmd, 0, sizeof(*ucmd));
	player->new_buttons = 0;
	player->buttons = 0;
}

void MoveCapture::SetMCVariable(int newvalue)
{
	char valuestring[10];

	// don't set the variable if the new
	// value is the same as the old value
	if(newvalue == lastvalue)
		return;

	sprintf(valuestring, "%i",newvalue);
	Director.ConsoleVariable(outputvar.c_str(), valuestring);

	lastvalue = newvalue;
}
