//=============================================================================
// KFWeapAttach_DualBase
//=============================================================================
// Attachment with a second set of meshes/FX for dual weapons
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_DualBase extends KFWeaponAttachment;

/*********************************************************************************************
 * Left-hand weapon components
********************************************************************************************* */

/** Left hand skeletal mesh. If none is specified, the right hand skeletal mesh will be duplicated. */
var() const SkeletalMesh 						LeftHandSkelMesh;
/** Anim set to use for 3rd person weapon anims */
var() AnimSet 									LeftWeaponAnimSet;
var protected transient SkeletalMeshComponent	LeftWeapMesh;
var protected transient KFMuzzleFlash			LeftMuzzleFlash;
/** A reference to the left muzzle flash template (to specify left shell eject socket) */
var() protected const KFMuzzleFlash 			LeftMuzzleFlashTemplate;
var protected transient AnimNodeSequence		LeftWeapAnimNode;

/** Toggled when switching from right to left hand weapons */
var transient bool bPlayFXOnSecondWeapon;
/** Last world time bPlayFXOnSecondWeapon was set */
var transient float LastChooseWeaponTime;

/** Additive shoot anims */
const ShootLeftAnim		= 'ADD_Shoot_LW';
const ShootRightAnim	= 'ADD_Shoot_RW';
const CrouchShootLeftAnim	= 'ADD_CH_Shoot_LW';
const CrouchShootRightAnim	= 'ADD_CH_Shoot_RW';
const IronShootLeftAnim		= 'ADD_Iron_Shoot_LW';
const IronShootRightAnim	= 'ADD_Iron_Shoot_RW';

/** Weapon shoots */
// @todo: these should just be "Shoot", but the animsets for each gun have both anims
const WeaponFireAnim_R		= 'Shoot_RW';
const WeaponFireAnim_L		= 'Shoot_LW';
const WeaponAltFireAnim_R	= 'Shoot_RW';
const WeaponAltFireAnim_L	= 'Shoot_LW';

const LeftWeaponSocket	= 'LW_Weapon';

event PreBeginPlay()
{
	// set up left hand skel mesh just like we do the right in super
	if ( LeftWeapMesh != None && !bWeapMeshIsPawnMesh )
	{
		if ( LeftWeaponAnimSet != None )
		{
			LeftWeapMesh.AnimSets[0] = LeftWeaponAnimSet;
		}
		else if( WeaponAnimSet != None )
		{
			// default to right weapon anim set
			LeftWeapMesh.AnimSets[0] = WeaponAnimSet;
		}

		if ( LeftHandSkelMesh != none )
		{
			// set the skeletal mesh from our archetype to the WeaponAttachment
			LeftWeapMesh.SkeletalMesh = LeftHandSkelMesh;
		}

		LeftWeapAnimNode = AnimNodeSequence(LeftWeapMesh.Animations);
	}

 	super.PreBeginPlay();
}

/** Weapon Mesh Attachment */
event ChangeVisibility( bool bIsVisible )
{
	super.ChangeVisibility( bIsVisible );

	if( LeftWeapMesh != none && !bWeapMeshIsPawnMesh )
	{
		LeftWeapMesh.SetHidden( !bIsVisible );
	}
}

/*********************************************************************************************
 * Attach / Detach
********************************************************************************************* */

/** Added second weapon */
simulated function AttachTo(KFPawn P)
{
    Super.AttachTo(P);

    if ( bWeapMeshIsPawnMesh )
    {
        LeftWeapMesh = P.Mesh;
    }
    else if ( LeftWeapMesh != None )
    {
        if( LeftHandSkelMesh == none )
        {
            // Create a duplicate of the right-hand weapn mesh
            LeftWeapMesh = new(self) Class'SkeletalMeshComponent'(WeapMesh);
        }

        // Attach Weapon mesh to player skel mesh
        LeftWeapMesh.SetShadowParent(P.Mesh);
        P.Mesh.AttachComponent(LeftWeapMesh, LeftWeaponSocket);
    }

    //Do a first chance weapon skin switch (EX: changed weapon w/o ID changing by throwing a dualie)
    if (KFPawn_Human(P) != None && KFPawn_Human(P).WeaponSkinItemId > 0)
    {
        SetWeaponSkin(KFPawn_Human(P).WeaponSkinItemId);
    }
}

/** Added second weapon */
simulated function DetachFrom(KFPawn P)
{
	Super.DetachFrom(P);

	// first, detach FX
	if ( LeftMuzzleFlash != None )
	{
        LeftMuzzleFlash.DetachMuzzleFlash(LeftWeapMesh);
	}

	// detach weapon mesh from player skelmesh
	if ( bWeapMeshIsPawnMesh )
	{
		LeftWeapMesh = None;
	}
	else if ( LeftWeapMesh != None )
	{
		LeftWeapMesh.SetShadowParent(None);
		P.Mesh.DetachComponent(LeftWeapMesh);
	}
}

/** Added second weapon */
simulated function AttachMuzzleFlash()
{
	Super.AttachMuzzleFlash();

	if ( WeapMesh != none && LeftMuzzleFlash == None )
	{
		LeftMuzzleFlash = new(self) Class'KFMuzzleFlash'(LeftMuzzleFlashTemplate);
        LeftMuzzleFlash.AttachMuzzleFlash(LeftWeapMesh);
	}
}

/**
 * Assign weapon skin to 3rd person mesh
 */
event SetWeaponSkin(int ItemId, optional bool bFinishedLoading = false)
{
	local array<MaterialInterface> SkinMICs;

	if ( WeapMesh != none && LeftWeapMesh != none && ItemId > 0 && WorldInfo.NetMode != NM_DedicatedServer && !bWaitingForWeaponSkinLoad)
	{
		if (!bFinishedLoading && StartLoadWeaponSkin(ItemId))
		{
			return;
		}

		SkinMICs = class'KFWeaponSkinList'.static.GetWeaponSkin(ItemId, WST_ThirdPerson);
		if ( SkinMICs.Length > 0 )
		{
			WeapMesh.SetMaterial(0, SkinMICs[0]);
			LeftWeapMesh.SetMaterial(0, SkinMICs[0]);
		}
	}
}

/*********************************************************************************************
* Fire Effects
********************************************************************************************* */

/** Updates bPlayFXOnSecondWeapon each time weapon is fired */
function bool ChooseActiveWeapon(byte FlashCount)
{
	// If this was already called in this frame do nothing.  See GetProjectileStartLoc() for details.
	if ( LastChooseWeaponTime == WorldInfo.TimeSeconds )
	{
		return bPlayFXOnSecondWeapon;
	}

	if ( FlashCount > 0 )
	{
		// If we have a flash count (e.g. projectile) use that to synchronize with 1st P
		bPlayFXOnSecondWeapon = (FlashCount & 1) == 0;
	}
	else
	{
		// Otherwise just toggle it
		bPlayFXOnSecondWeapon = !bPlayFXOnSecondWeapon;
	}

	LastChooseWeaponTime = WorldInfo.TimeSeconds;
	return bPlayFXOnSecondWeapon;
}

/** Added second weapon */
simulated function bool ThirdPersonFireEffects( vector HitLocation, KFPawn P, byte ThirdPersonAnimRateByte )
{
	ChooseActiveWeapon(P.FlashCount);
    return super.ThirdPersonFireEffects( HitLocation, P, ThirdPersonAnimRateByte );
}

/** Plays fire animation on weapon mesh.
  * Overloaded to switch between right and left.
  */
simulated function PlayWeaponFireAnim()
{
	local float Duration;

	if( Instigator.FiringMode == 1 && WeaponAltFireAnim != 'None' )
	{
		if( bPlayFXOnSecondWeapon )
		{
			Duration = LeftWeapMesh.GetAnimLength( WeaponAltFireAnim_L );
			LeftWeapMesh.PlayAnim( WeaponAltFireAnim_L, Duration / ThirdPersonAnimRate,, true );
		}
		else
		{
			Duration = WeapMesh.GetAnimLength( WeaponAltFireAnim_R );
			WeapMesh.PlayAnim( WeaponAltFireAnim_R, Duration / ThirdPersonAnimRate,, true );
		}
	}
	else if( WeaponFireAnim != 'None' )
	{
		if( bPlayFXOnSecondWeapon )
		{
			Duration = LeftWeapMesh.GetAnimLength( WeaponFireAnim_L );
			LeftWeapMesh.PlayAnim( WeaponFireAnim_L, Duration / ThirdPersonAnimRate,, true );
		}
		else
		{
			Duration = WeapMesh.GetAnimLength( WeaponFireAnim_R );
			WeapMesh.PlayAnim( WeaponFireAnim_R, Duration / ThirdPersonAnimRate,, true );
		}
	}
}

/** Plays fire animation on pawn
  * Overloaded to switch between right and left.
  */
simulated function PlayPawnFireAnim( KFPawn P, EAnimSlotStance AnimType )
{
	if ( P.bIsCrouched )
	{
		P.PlayBodyAnim((bPlayFXOnSecondWeapon) ? CrouchShootLeftAnim : CrouchShootRightAnim, EAS_FullBody, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
	}
	else if ( P.bIsWalking )
	{
		P.PlayBodyAnim((bPlayFXOnSecondWeapon) ? IronShootLeftAnim : IronShootRightAnim, EAS_FullBody, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
	}
	else
	{
		P.PlayBodyAnim((bPlayFXOnSecondWeapon) ? ShootLeftAnim : ShootRightAnim, EAS_FullBody, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
	}
}

/** Added second weapon */
simulated function CauseMuzzleFlash(byte FiringMode)
{
	// Can use the same weapon that was used by ThirdPersonFireEffects
	if ( bPlayFXOnSecondWeapon )
	{
		if (LeftMuzzleFlash == None && MuzzleFlashTemplate != None)
		{
			AttachMuzzleFlash();
		}

		if (LeftMuzzleFlash != None )
		{
			LeftMuzzleFlash.CauseMuzzleFlash(FiringMode);
			if ( LeftMuzzleFlash.bAutoActivateShellEject )
			{
				LeftMuzzleFlash.CauseShellEject();
			}
		}
	}
	else
	{
		Super.CauseMuzzleFlash(FiringMode);
	}
}

/** Added second weapon */
simulated function vector GetMuzzleLocation(optional byte MuzzleID)
{
	local vector SocketLocation;

	if ( MuzzleID >= 1 || bPlayFXOnSecondWeapon )
	{
		if (LeftMuzzleFlash == None && MuzzleFlashTemplate != None)
		{
			AttachMuzzleFlash();
		}

		if( LeftMuzzleFlash != none )
		{
	        LeftWeapMesh.GetSocketWorldLocationAndRotation(LeftMuzzleFlash.GetSocketName(), SocketLocation);
			return SocketLocation;
		}
	}

	return Super.GetMuzzleLocation(MuzzleID);
}

/** Overrides super to play anim on both meshes. Used for reloads at the moment (will this mess up other possible anims?) */
simulated function PlayWeaponMeshAnim(name AnimName, AnimNodeSlot SyncNode, bool bLoop)
{
	local float Duration;

	super.PlayWeaponMeshAnim( AnimName, SyncNode, bLoop );

	Duration = LeftWeapMesh.GetAnimLength( AnimName );
	LeftWeapMesh.PlayAnim( AnimName, Duration / ThirdPersonAnimRate, bLoop );
}

/*********************************************************************************************
 * @name	Rendering/Lighting
********************************************************************************************* */

/** Set the lighting channels on all the appropriate weapon attachment mesh(es) */
simulated function SetMeshLightingChannels(LightingChannelContainer NewLightingChannels)
{
	super.SetMeshLightingChannels( NewLightingChannels );

	if( !bWeapMeshIsPawnMesh )
	{
		LeftWeapMesh.SetLightingChannels(NewLightingChannels);
	}
}

/** Debug */
simulated function bool HasIndoorLighting()
{
	return super.HasIndoorLighting() && LeftWeapMesh.LightingChannels.Indoor;
}

/** Debug */
simulated function bool HasOutdoorLighting()
{
	return super.HasOutdoorLighting() && LeftWeapMesh.LightingChannels.Outdoor;
}

defaultproperties
{
	// Left Weapon SkeletalMesh (copy of right weapon in super)
	Begin Object Class=SkeletalMeshComponent Name=SkeletalMeshComponent1
		bOwnerNoSee=true
		bOnlyOwnerSee=false
		CollideActors=false
		AlwaysLoadOnClient=true
		AlwaysLoadOnServer=true
		MaxDrawDistance=4000
		bUpdateSkelWhenNotRendered=false
		bIgnoreControllersWhenNotRendered=true
		bOverrideAttachmentOwnerVisibility=true
		bAcceptsDynamicDecals=FALSE
		Animations=MeshSequenceA
		CastShadow=true
		bCastDynamicShadow=true
		bPerBoneMotionBlur=true
		bForceRefPose=1
		// Default to outdoor. If indoor, this will be set when TWIndoorLightingVolume::Touch() event is received at spawn.
		LightingChannels=(Outdoor=TRUE,bInitialized=TRUE)
	End Object
	LeftWeapMesh=SkeletalMeshComponent1
}
