enum ArcadeMinigame
{
	Quadracer = 0,
	RoachRace = 1,
	Shooter = 2,
	Tank = 3,
	Retros = 4,
	INVALID = 5,
}

enum ArcadeMachineType
{
	Default = 0,
	Pachinko = 1,
}

class ArcadeMachine extends InteractiveDevice
{
	default m_controllerTypeName = 'ArcadeMachineController';
	protected var m_arcadeMachineType : ArcadeMachineType;
	default m_arcadeMachineType = ArcadeMachineType.Default;
	private var m_isShortGlitchActive : Bool;
	private var m_shortGlitchDelayID : DelayID;
	private var m_currentGameVideo : ResRef;
	protected var m_currentGameAudio : CName;
	protected var m_currentGameAudioStop : CName;
	private var m_meshAppearanceOn : CName;
	default m_meshAppearanceOn = 'default';
	private var m_meshAppearanceOff : CName;
	default m_meshAppearanceOff = 'default';
	private var m_arcadeMinigameComponent : WorkspotResourceComponent;
	protected instanceeditable var m_minigame : ArcadeMinigame;
	default m_minigame = ArcadeMinigame.INVALID;
	private var m_combatStateListener : CallbackHandle;

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		EntityRequestComponentsInterface.RequestComponent( ri, 'ui', 'worlduiWidgetComponent', false );
		EntityRequestComponentsInterface.RequestComponent( ri, 'arcadeMinigamePlayerWorkspot', 'workWorkspotResourceComponent', false );
		super.OnRequestComponents( ri );
	}

	protected event OnPersitentStateInitialized( evt : GameAttachedEvent )
	{
		super.OnPersitentStateInitialized( evt );
		Setup();
	}

	public override function ResavePersistentData( ps : PersistentState ) : Bool
	{
		return false;
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		m_uiComponent = ( ( worlduiWidgetComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'ui' ) ) );
		m_arcadeMinigameComponent = ( ( WorkspotResourceComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'arcadeMinigamePlayerWorkspot' ) ) );
		super.OnTakeControl( ri );
		m_controller = ( ( ArcadeMachineController )( EntityResolveComponentsInterface.GetComponent( ri, 'controller' ) ) );
	}

	protected override function ResolveGameplayState()
	{
		super.ResolveGameplayState();
		if( IsUIdirty() && m_isInsideLogicArea )
		{
			RefreshUI();
		}
	}

	protected override function CreateBlackboard()
	{
		m_blackboard = IBlackboard.Create( GetAllBlackboardDefs().ArcadeMachineBlackBoard );
	}

	public const override function GetBlackboardDef() : ArcadeMachineBlackboardDef
	{
		return GetDevicePS().GetBlackboardDef();
	}

	protected const override function GetController() : ArcadeMachineController
	{
		return ( ( ArcadeMachineController )( m_controller ) );
	}

	public const override function GetDevicePS() : ArcadeMachineControllerPS
	{
		return GetController().GetPS();
	}

	protected override function StartGlitching( glitchState : EGlitchState, optional intensity : Float )
	{
		var glitchData : GlitchData;
		var evt : AdvertGlitchEvent;
		glitchData.state = glitchState;
		glitchData.intensity = intensity;
		if( intensity == 0.0 )
		{
			intensity = 1.0;
		}
		evt = new AdvertGlitchEvent;
		evt.SetShouldGlitch( intensity );
		QueueEvent( evt );
		GetBlackboard().SetVariant( GetBlackboardDef().GlitchData, glitchData, true );
		GetBlackboard().FireCallbacks();
		GameObjectEffectHelper.ActivateEffectAction( this, gamedataFxActionType.Start, 'hack_fx' );
	}

	protected override function StopGlitching()
	{
		var glitchData : GlitchData;
		var evt : AdvertGlitchEvent;
		evt = new AdvertGlitchEvent;
		evt.SetShouldGlitch( 0.0 );
		QueueEvent( evt );
		glitchData.state = EGlitchState.NONE;
		GetBlackboard().SetVariant( GetBlackboardDef().GlitchData, glitchData );
		GetBlackboard().FireCallbacks();
		GameObjectEffectHelper.ActivateEffectAction( this, gamedataFxActionType.BreakLoop, 'hack_fx' );
	}

	protected event OnHitEvent( hit : gameHitEvent )
	{
		super.OnHitEvent( hit );
		StartShortGlitch();
	}

	private function StartShortGlitch()
	{
		var evt : StopShortGlitchEvent;
		if( GetDevicePS().IsGlitching() || GetDevicePS().IsDistracting() )
		{
			return;
		}
		if( !( m_isShortGlitchActive ) )
		{
			evt = new StopShortGlitchEvent;
			StartGlitching( EGlitchState.DEFAULT, 1.0 );
			m_shortGlitchDelayID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, evt, 0.25 );
			m_isShortGlitchActive = true;
		}
	}

	protected event OnStopShortGlitch( evt : StopShortGlitchEvent )
	{
		m_isShortGlitchActive = false;
		if( !( GetDevicePS().IsGlitching() ) && !( GetDevicePS().IsDistracting() ) )
		{
			StopGlitching();
		}
	}

	protected override function TurnOnDevice()
	{
		super.TurnOnDevice();
		TurnOnScreen();
	}

	protected override function TurnOffDevice()
	{
		super.TurnOffDevice();
		TurnOffScreen();
	}

	protected override function CutPower()
	{
		super.CutPower();
		TurnOffScreen();
	}

	protected virtual function TurnOffScreen()
	{
		m_uiComponent.Toggle( false );
		PlaySound( this, m_currentGameAudioStop );
		SetMeshAppearance( m_meshAppearanceOff );
	}

	protected virtual function TurnOnScreen()
	{
		m_uiComponent.Toggle( true );
		PlaySound( this, m_currentGameAudio );
		SetMeshAppearance( m_meshAppearanceOn );
	}

	protected override function OnDirectInteractionActive( evt : InteractionActivationEvent, isInteractionActive : Bool )
	{
		var psmBlackboard : IBlackboard;
		psmBlackboard = GameInstance.GetBlackboardSystem( GetGame() ).GetLocalInstanced( evt.activator.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		if( isInteractionActive )
		{
			m_combatStateListener = psmBlackboard.RegisterListenerInt( GetAllBlackboardDefs().PlayerStateMachine.Combat, this, 'OnCombatStateChanged' );
		}
		else
		{
			psmBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().PlayerStateMachine.Combat, m_combatStateListener );
		}
	}

	protected event OnCombatStateChanged( value : Int32 )
	{
		DetermineInteractionStateByTask();
	}

	protected event OnBeginArcadeMinigameUI( evt : BeginArcadeMinigameUI )
	{
		var workspotGameSystem : WorkspotGameSystem;
		var psmBlackboard : IBlackboard;
		var isInteractingWithDevice : Bool;
		workspotGameSystem = GameInstance.GetWorkspotSystem( GetGame() );
		if( workspotGameSystem.IsActorInWorkspot( evt.GetExecutor() ) )
		{
			workspotGameSystem.StopInDevice( evt.GetExecutor() );
			isInteractingWithDevice = false;
		}
		else
		{
			workspotGameSystem.PlayInDevice( this, evt.GetExecutor(), 'lockedCamera', 'arcadeMinigamePlayerWorkspot', 'arcadeMinigameDeviceWorkspot' );
			isInteractingWithDevice = true;
		}
		psmBlackboard = GameInstance.GetBlackboardSystem( GetGame() ).GetLocalInstanced( evt.GetExecutor().GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
		psmBlackboard.SetBool( GetAllBlackboardDefs().PlayerStateMachine.IsInteractingWithDevice, isInteractingWithDevice );
	}

	public const override function DeterminGameplayRole() : EGameplayRole
	{
		return EGameplayRole.Distract;
	}

	protected override function ApplyActiveStatusEffect( target : EntityID, statusEffect : TweakDBID )
	{
		if( IsActiveStatusEffectValid() && GetDevicePS().IsGlitching() )
		{
			GameInstance.GetStatusEffectSystem( GetGame() ).ApplyStatusEffect( target, statusEffect );
		}
	}

	protected override function UploadActiveProgramOnNPC( targetID : EntityID )
	{
		var evt : ExecutePuppetActionEvent;
		if( IsActiveProgramToUploadOnNPCValid() && GetDevicePS().IsGlitching() )
		{
			evt = new ExecutePuppetActionEvent;
			evt.actionID = GetActiveProgramToUploadOnNPC();
			QueueEventForEntityID( targetID, evt );
		}
	}

	private function Setup()
	{
		m_currentGameVideo = GetDevicePS().GetGameVideoPath();
		if( m_arcadeMachineType == ArcadeMachineType.Default )
		{
			SetupMinigame();
		}
	}

	private function SetupMinigame()
	{
		var randValue : Int32;
		var roachraceMovie1 : ResRef;
		var roachraceMovie2 : ResRef;
		var roachraceMovie3 : ResRef;
		var shooterMovie1 : ResRef;
		var shooterMovie2 : ResRef;
		var tankMovie : ResRef;
		var quadracerMovie : ResRef;
		randValue = -1;
		roachraceMovie1 = R"base\movies\misc\arcade\roach_race.bk2";
		roachraceMovie2 = R"base\movies\misc\arcade\roachrace.bk2";
		roachraceMovie3 = R"base\movies\misc\arcade\roach_race_game.bk2";
		shooterMovie1 = R"base\movies\misc\arcade\td_title_screen_press_start.bk2";
		shooterMovie2 = R"base\movies\misc\arcade\retros.bk2";
		tankMovie = R"base\movies\misc\arcade\hishousai_panzer.bk2";
		quadracerMovie = R"base\movies\misc\arcade\quadracer.bk2";
		if( m_arcadeMachineType == ArcadeMachineType.Pachinko )
		{
			return;
		}
		if( m_minigame == ArcadeMinigame.INVALID )
		{
			if( !( ResRef.IsValid( m_currentGameVideo ) ) )
			{
				randValue = RandRange( 0, 10 );
			}
			if( ( randValue == 9 ) || m_currentGameVideo == quadracerMovie )
			{
				m_minigame = ArcadeMinigame.Quadracer;
			}
			if( ( randValue == 8 ) || m_currentGameVideo == tankMovie )
			{
				m_minigame = ArcadeMinigame.Tank;
			}
			else if( ( ( ( randValue >= 4 ) || m_currentGameVideo == roachraceMovie1 ) || m_currentGameVideo == roachraceMovie2 ) || m_currentGameVideo == roachraceMovie3 )
			{
				m_minigame = ArcadeMinigame.RoachRace;
			}
			else if( ( ( randValue >= 0 ) || m_currentGameVideo == shooterMovie1 ) || m_currentGameVideo == shooterMovie2 )
			{
				m_minigame = ArcadeMinigame.Shooter;
			}
		}
		if( m_minigame == ArcadeMinigame.Quadracer )
		{
			m_currentGameVideo = quadracerMovie;
			m_currentGameAudio = 'mus_cp_arcade_quadra_START_menu';
			m_currentGameAudioStop = 'mus_cp_arcade_quadra_STOP';
			m_meshAppearanceOn = 'ap1';
			m_meshAppearanceOff = 'ap1_off';
		}
		else if( m_minigame == ArcadeMinigame.RoachRace )
		{
			m_currentGameVideo = roachraceMovie3;
			m_currentGameAudio = 'mus_cp_arcade_roach_START_menu';
			m_currentGameAudioStop = 'mus_cp_arcade_roach_STOP';
			m_meshAppearanceOn = 'ap2';
			m_meshAppearanceOff = 'ap2_off';
		}
		else if( m_minigame == ArcadeMinigame.Shooter )
		{
			m_currentGameVideo = shooterMovie1;
			m_currentGameAudio = 'mus_cp_arcade_shooter_START_menu';
			m_currentGameAudioStop = 'mus_cp_arcade_shooter_STOP';
			m_meshAppearanceOn = 'ap3';
			m_meshAppearanceOff = 'ap3_off';
		}
		else if( m_minigame == ArcadeMinigame.Tank )
		{
			m_currentGameVideo = tankMovie;
			m_currentGameAudio = 'mus_cp_arcade_panzer_START_menu';
			m_currentGameAudioStop = 'mus_cp_arcade_panzer_STOP';
			m_meshAppearanceOn = 'ap4';
			m_meshAppearanceOff = 'ap4_off';
		}
		GetDevicePS().SetArcadeMinigame( m_minigame );
	}

	public const function GetArcadeGameVideo() : ResRef
	{
		return m_currentGameVideo;
	}

	public const function GetArcadeGameAudio() : CName
	{
		return m_currentGameAudio;
	}

	public const function GetArcadeGameAudioStop() : CName
	{
		return m_currentGameAudioStop;
	}

}

