//=============================================================================
// DawnsEDischargeMover.
// Version: 1.0
// $DateTime: Wed, 01/21/2009 03:28:58 pm$
// Author: Dawn Knight
// UT Version Coded/Tested: 4.36.
//
// A special Mover intended to simulate the flickering, wandering electrical
// discharge of a high voltage static generator such as a Van DeGraff or Tesla
// coil.
// It steps through KeyFrames, perhaps randomly, but always returns to KeyFrame 0
// between all other moves, making instantaneous moves from one KeyFrame to
// another.  KeyFrame 0 should be a hidden position to represent the absence of
// any discharge.
// The Mover Brush itself should normally consist of a 2 Sheet Volumetric using
// an animated Texture such as XFX.xtreme.Elektroshok.
//
// If bRandomKey is false, the pattern of movement is 0 1 0 2 0 3 etc.  If it is
// set True, the pattern is 0 RandomKey 0 RandomKey 0 RandomKey etc.
//
// If bRandomTiming is False, the time between moves is held constant by
// StayOpenTime.  If it is set True, StayOpenTime will be modified by a random
// time element for each move.
//
// If bFlicker is set True, The Mover will randomly alternate bHidden to give the
// effect of a flickering discharge.
//
// This is an effect only, so Collision will be off by default, MoverEncroachType
// will default to ME_IgnoreWhenEncroach, and TakeDamage() will be ignored.
//
// It's not clear if there is any need to synchronize movements between the
// Server and Clients but a significant code and network bandwidth improvement
// is realized by replicating KeyNum to Clients, so use new var KeyNumC
// throughout all this Class's code instead of KeyNum.  Assign KeyNumC = KeyNum
// once during initialization and use KeyNumC thereafter.
//=============================================================================


class DawnsEDischargeMover extends Mover;

#exec obj load file=..\Textures\XFX.utx package=XFX

#exec mesh import mesh=DawnsEDischargeMover anivfile=Models\DawnsEDischargeMover_a.3d datafile=Models\DawnsEDischargeMover_d.3d x=0 y=0 z=0 mlod=0
#exec mesh origin mesh=DawnsEDischargeMover x=0 y=0 z=0
#exec mesh sequence mesh=DawnsEDischargeMover seq=All startframe=0 numframes=1

#exec meshmap new meshmap=DawnsEDischargeMover mesh=DawnsEDischargeMover
#exec meshmap scale meshmap=DawnsEDischargeMover x=0.18750 y=0.18750 z=0.37500

var(Mover) bool  bRandomKey;
var(Mover) bool  bRandomTiming;
var(Mover) bool  bFlicker;

var        byte  KeyNumC;

var        float ZeroTime;
var        float FlkrOn;
var        float FlkrOff;
var        float FlkrTime;

replication
{
	// Things the server should send to the client.
	reliable if( Role==ROLE_Authority )
		KeyNumC;
}

function Trigger( Actor other, Pawn EventInstigator ) {}

function UnTrigger( Actor other, Pawn EventInstigator ) {}

function FindTriggerActor() {}

function bool HandleTriggerDoor(pawn Other)
{
	return False;
}

function Actor SpecialHandling(Pawn Other)
{
	return None;
}

function InterpolateEnd( actor Other ) {}

function FinishNotify() {}

function FinishedClosing() {}

function FinishedOpening() {}

function DoOpen() {}

function DoClose() {}

function MakeGroupStop() {}

function MakeGroupReturn() {}

// Return true to abort, false to continue.
function bool EncroachingOn( actor Other )
{
	return False; // Always ME_IgnoreWhenEncroach
}

function Bump( actor Other ) {}

function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
						Vector momentum, name damageType) {}


// Initialization (Engine notifications)
// When mover enters gameplay.
simulated function BeginPlay()
{

	super(Actor).BeginPlay();

	// Init key info.
	KeyNumC = 0;

	// Set initial location.
	SetLocation( BasePos + KeyPos[KeyNumC] );

	// Set initial rotation.
	SetRotation( BaseRot + KeyRot[KeyNumC] );

	ZeroTime = StayOpenTime/4.0;
	FlkrOn = 0.6;
	FlkrOff = 0.3;
}

// Called immediately after gameplay begins.
simulated function PostBeginPlay()
{
	super(Actor).PostBeginPlay();
}

function Timer() // Runs only on ROLE_Authority
{

	if( KeyNumC == 0 )
	{
		if ( bRandomKey )
		{
			KeyNumC = 1+Rand( NumKeys-1 );
		}
		else
		{
			PrevKeyNum++;
			if( PrevKeyNum >= NumKeys )
			{
				KeyNumC = 1;
				PrevKeyNum = 0;
			}
			else
			KeyNumC = PrevKeyNum;
		}
	}
	else
	{
		PrevKeyNum = KeyNumC;
		KeyNumC = 0;
	}

	SetLocation( BasePos + KeyPos[KeyNumC] );
	SetRotation( BaseRot + KeyRot[KeyNumC] );

	if ( bRandomTiming )
	{
		if( KeyNumC == 0 )
			SetTimer( ZeroTime, False );
		else
			SetTimer( StayOpenTime*( 0.5+1.5*FRand() ), False );
	}
	else
	{
		if( KeyNumC == 0 )
			SetTimer( ZeroTime, False );
		else
			SetTimer( StayOpenTime, False );
	}
}

simulated function Tick( float DeltaTime ) // Runs on all but Servers
{
	// Do the Flicker thing (ListenServers won't have 'Flicker' effect
	if ( bFlicker )
	{
		FlkrTime+=DeltaTime;
		if ( bHidden )
		{
			if ( FlkrTime > FlkrOff )
			{
				bHidden = False;
				FlkrOff = FRand()*0.2 + 0.025;
				FlkrTime = 0;
			}
		}
		else
		{ // bHidden = False
			if ( FlkrTime > FlkrOn )
			{
				bHidden = True;
				FlkrOn = FRand()*0.6 + 0.15;
				FlkrTime = 0;
			}
		}
	}

	if ( Level.NetMode != NM_Client )
		return;

	if( KeyNumC != PrevKeyNum )
	{
		SetLocation( BasePos + KeyPos[KeyNumC] );
		SetRotation( BaseRot + KeyRot[KeyNumC] );
		PrevKeyNum = KeyNumC;
	}
}

auto state() StartUp
{
	// Runs everywhere, even though the StartUp state isn't explicitly "simulated"!
	simulated function BeginState()
	{
		if( Role < ROLE_Authority )
		{
			Disable('Timer'); // No Timer on anything but Authority
		}
		else
			SetTimer( 0.2, False );

		if( Level.NetMode == NM_DedicatedServer || Level.NetMode == NM_ListenServer )
		{
			Disable('Tick'); // No Tick on Servers (ListenServers won't have 'Flicker' effect
		}
	}
}

// Trigger states.

state TriggerOpenTimed {}

state TriggerToggle {}

state TriggerControl {}

state TriggerPound {}

// Bump states.

state BumpOpenTimed {}

state BumpButton {}

// Stand states.

state StandOpenTimed {}

defaultproperties
{
     DrawType=DT_Mesh
     Mesh=Mesh'DawnsEDischargeMover'
     CollisionRadius=32.00000
     CollisionHeight=64.00000
     MultiSkins(0)=Texture'XFX.xtreme.Elektroshok'
     MoverEncroachType=ME_IgnoreWhenEncroach
     Physics=PHYS_None
     RemoteRole=ROLE_SimulatedProxy
     InitialState=StartUp
     StayOpenTime=1.000000
     bUnlit=True
     bCollideActors=False
     bCollideWorld=False
     bBlockActors=False
     bBlockPlayers=False
}
