If you want to help us maintaining this wiki, check out our discord server: https://discord.gg/3u69jMa 

GameObject

From SWRC Wiki
Jump to navigation Jump to search
class GameObject extends Actor
    abstract notplaceable;

var bool            bHome;
var bool            bHeld;

var MPPawn          Holder;
var MPPlayerReplicationInfo HolderPRI;

var GameObjective   HomeBase;
var float           TakenTime;
var float           MaxDropTime;
var bool            bDisabled;

var MPTeam          OldTeam;
var MPPawn          OldHolder;
var float			OldHolderTime;
var float			HoldTime;

var byte 			TeamNum;

var vector			HomeLocation;

var(GameObject) int ExitSpeed;

replication
{
	// TODO: Couple of things that can be optimized here. such as TeamNum
	reliable if (bNetInitial && (Role == ROLE_Authority))
		HomeBase, HomeLocation, TeamNum;

	// TODO: Couple of things that can be optimized here. such as TeamNum
    reliable if (bNetDirty && (Role == ROLE_Authority))
        bHome, bHeld, HolderPRI, Holder;		
}

// Initialization
function PostBeginPlay()
{
	Super.PostBeginPlay();

	HomeBase = GameObjective(Owner);
	if ( HomeBase == None )
	{
		log("Error: Flag has no home base:"$self);
		Destroy();
		return;
	}
    
    SetOwner(None);

	TeamNum = HomeBase.GetTeamIndex();

	// Go straight to home location on creation.
	SetLocation(HomeBase.Location);
	SetRotation(HomeBase.Rotation);

	HomeLocation = HomeBase.Location;

 }

// State transitions
function SetHolder(Controller C)
{
	if ( !C.IsA('MPPlayer') )
	{
		log("Error"@C@"is not a MPPlayer");
		return;
	}

	if ((OldHolder == MPPawn(C.Pawn)) && ( OldHolderTime > Level.TimeSeconds ))
		return;
	
	LogTaken(c);
	Holder = MPPawn(C.Pawn);
	Holder.SpawnTime = -100000;
	
	HolderPRI = MPPlayerReplicationInfo(Holder.PlayerReplicationInfo);
	HolderPRI.SetFlag(self);

	GotoState('Held');
}


function Score()
{
    //log(self$" score holder="$holder, 'GameObject');
    Disable('Touch');
    SetLocation(HomeBase.Location);
    SetRotation(HomeBase.Rotation);
    GotoState('Home');
}

function Drop(vector newVel)
{	
	local vector HolderDir;
	OldHolder = Holder;	
	OldHolderTime = Level.TimeSeconds + HoldTime;

	if ( Holder.Controller != None )
	{
		HolderDir = vector(Holder.Controller.Rotation);
		SetLocation(Holder.Location + Holder.EyePosition() + (HolderDir * Holder.CollisionRadius));
		Velocity = Holder.Velocity;
		Velocity += HolderDir * ExitSpeed;
	}
	else
		SetLocation(Holder.Location);
	
	LogDropped();
	
	GotoState('Dropped');
	
}

function SendHome()
{	
    CalcSetHome();
    GotoState('Home');			
}

function SendHomeDisabled(float TimeOut);

// Helper funcs
protected function CalcSetHome()
{
	LogReturned();
}

function ClearHolder()
{
	local int i;
	local GameReplicationInfo GRI;
	local MPPlayerReplicationInfo MPPRI;

	if (Holder == None && HolderPRI == None)
		return;

	if ( HolderPRI == None )
	{
		GRI = Level.Game.GameReplicationInfo;
		for (i=0; i<GRI.PRIArray.Length; i++)
		{
			MPPRI = MPPlayerReplicationInfo(GRI.PRIArray[i]);
			if ( (MPPRI != None) && (MPPRI.HasFlag == self) )
				MPPRI.SetFlag(None);
		}
	}
	else
		HolderPRI.SetFlag(None);

	Holder = None;
	HolderPRI = None;
}


protected function SetDisable(bool disable)
{
    bDisabled = disable;
    bHidden = disable;
	
	UpdateHolograms();
}

function Actor Position()
{
    if (bHeld)
        return Holder;

    if (bHome)
        return HomeBase;

    return self;
}

function bool IsHome()
{
    return false;
}

// Helper funcs

// stub function
function SameTeamTouch(Controller c);

function bool SameTeam(Controller c)
{

	if ( (c != None) && (c.PlayerReplicationInfo != None) &&
		(c.PlayerReplicationInfo.Team != None) && (c.PlayerReplicationInfo.Team.TeamIndex == TeamNum))
		return true;
		
	return false;
}

function bool ValidHolder(Actor other)
{
	
    local Pawn p;

	// Not valid if object is disabled
    if( bDisabled )
        return false;
    
    // not valid if pawn is dead or not there or not player.
    p = Pawn(other);
    if (p == None || p.Health <= 0 || !p.IsPlayerPawn())
        return false;

    return true;
}

// Events
singular function Touch(Actor Other)
{
	local Controller c;

    if ( ValidHolder(Other) )
	{
		// Return to home base if same team
		c = Pawn(Other).Controller;
		if ( c != None ) 		
		{
			if ( SameTeam(c) ) 			
				SameTeamTouch(c);	
			else
				SetHolder( c );
		}
	}    
	return;
}

function CheckPain(); 

event FellOutOfWorld(eKillZType KillType)
{
    log(self$" FellOutOfWorld", 'GameObject');
    SendHome();
}

event Landed(vector HitNormall)
{	
	local rotator NewRot;
	
	NewRot = Rot(0,0,0);
	NewRot.Yaw = Rotation.Yaw;
	SetRotation(NewRot);
}

singular simulated function BaseChange()
{
    //log(self$" basechange", 'GameObject');
}

// Logging
function LogTaken(Controller c);
function LogDropped();
function LogReturned();

// States
auto state home
{
    ignores SendHome, Score, Drop;

	function SameTeamTouch(Controller c)
	{
		local MPPlayerReplicationInfo MPPRI;
				
		//TODO
		MPPRI = MPPlayerReplicationInfo(C.PlayerReplicationInfo);

		if (MPPRI == None || MPPRI.HasFlag == None)
			return;

		// Score!
		CTFGame(Level.Game).ScoreFlag(C, MPPRI.HasFlag);
		MPPRI.HasFlag.Score();
		TriggerEvent(HomeBase.Event,HomeBase,C.Pawn);
	}

	function Timer()
	{
		if ( VSize(Location - HomeBase.Location) > 60 && !bHidden )
		{
			MPGame(Level.Game).GameEvent("flag_returned_timeout",""$TeamNum,None);
			
			BroadcastLocalizedMessage( MessageClass, 3, None, None, Level.Game.GameReplicationInfo.Teams[TeamNum] );
			log(self$" Home.Timer: had to sendhome"$Location@HomeBase.Location, 'Error');
			SendHome();
		}
	}

	function CheckTouching()
	{
		local int i;
				
		for ( i=0; i<Touching.Length; i++ )
		{
			if ( (ValidHolder(Touching[i])) && (Touching[i].IsA('Pawn') ) &&
				( Pawn(Touching[i]).Controller != None ) &&  ( !SameTeam(Pawn(Touching[i]).Controller)) )
			{
				SetHolder(Pawn(Touching[i]).Controller);
				return;
			}
		}
	}	

    function bool IsHome()
    {
        return true;
    }

    function BeginState()
    {
		Disable('Touch');
		bHome = true;
		SetLocation(HomeBase.Location);
		SetRotation(HomeBase.Rotation);

		MPGameReplicationInfo(Level.Game.GameReplicationInfo).SetGameObjectState(TeamNum,'Home');

		HomeBase.Timer();
		SetTimer(1.0, true);
		Enable('Touch');
		UpdateHolograms();
    }

    function EndState()
    {		
		bHome = false;
		TakenTime = Level.TimeSeconds;
		
		HomeBase.PlayAlarm();
		SetTimer(0.0, false);
		UpdateHolograms();
    }
    
Begin:
	// check if an enemy was standing on the base
	Sleep(0.05);
	CheckTouching();
	bCollideWorld=false;
}

state Held
{
    ignores SetHolder, SendHome;

	function Timer()
	{
		if (Holder == None)
		{
			log(self$" Held.Timer: had to sendhome", 'Error');
			if ( MPGame(Level.Game) != None )
				MPGame(Level.Game).GameEvent("flag_returned_timeout",""$TeamNum,None);
			BroadcastLocalizedMessage( MessageClass, 3, None, None, Level.Game.GameReplicationInfo.Teams[TeamNum] );

			// Can't call send home. so we send home old-school
			CalcSetHome();
			GotoState('Home');	
		}

		// TODO: seems to me the timer should be reset
	}

	function BeginState()
    {		
		MPGameReplicationInfo(Level.Game.GameReplicationInfo).SetGameObjectState(TeamNum,'HeldEnemy');
        bOnlyDrawIfAttached = true;
        bHeld = true;
        bCollideWorld = false;
        SetCollision(false, false, false);
        SetLocation(Holder.Location);
        Holder.HoldGameObject();
		SetBase(Holder);
		bHidden = true;
		SetTimer(10.0, true);
		UpdateHolograms();
    }

    function EndState()
    {				
        //log(self$" held.endstate", 'GameObject');
        bOnlyDrawIfAttached = false;
		Holder.DropGameObject();
		bHidden = false;
        ClearHolder();
        bHeld = false;
        bCollideWorld = true;
        SetCollision(true, false, false);
        SetBase(None);
        SetRelativeLocation(vect(0,0,0));
        SetRelativeRotation(rot(0,0,0));
		UpdateHolograms();
    }
}

state Dropped
{
    ignores Drop;

	function SameTeamTouch(Controller c)
	{				
		// returned flag score
		CTFGame(Level.Game).ScoreFlag(C, self);
		SendHome();
	}

	function CheckPain()
	{
		if (IsInPain())
			SetTimer(1.0, false);		
	}

	function float TakeDamage( float NDamage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class<DamageType> damageType, optional Name BoneName)
	{
		CheckPain();
		return 0;
	}

	function Timer()
	{
		if (Level.Game.GameStats != None)
			Level.Game.GameStats.GameEvent("flag_returned_timeout",""$TeamNum,None);

		SendHome();
	}

	singular function PhysicsVolumeChange( PhysicsVolume NewVolume )
	{
		Super.PhysicsVolumeChange(NewVolume);
		CheckPain();
	}

	function Landed(vector HitNormall)
	{
		Enable('Touch');
		bUpdateSimulatedPosition = false;
		SetPhysics(PHYS_None);

		Super.Landed(HitNormall);
	}

	function BeginState()
	{
		Disable('Touch');
		bUpdateSimulatedPosition = true;
		MPGameReplicationInfo(Level.Game.GameReplicationInfo).SetGameObjectState(TeamNum,'Down');
		SetPhysics(PHYS_Falling);
		bCollideWorld = true;
		SetCollisionSize(0.5 * default.CollisionRadius, CollisionHeight);
		CheckFit();
		CheckPain();
		SetTimer(MaxDropTime, false);
		
	}

	function EndState()
	{		
		Enable('Touch');
		bUpdateSimulatedPosition = false;
		SetPhysics(PHYS_None);
		bCollideWorld = false;
		SetCollisionSize(default.CollisionRadius, default.CollisionHeight);
	}

	function CheckFit()
	{

		//CPL NOTE: We probably want to clean this up and re-use it
/*		local vector X,Y,Z;

		GetAxes(OldHolder.Rotation, X,Y,Z);
		SetRotation(rotator(-1 * X));
		if ( !SetLocation(OldHolder.Location - 2 * OldHolder.CollisionRadius * X + OldHolder.CollisionHeight * vect(0,0,0.5)) 
			&& !SetLocation(OldHolder.Location) )
		{
			SetCollisionSize(0.8 * OldHolder.CollisionRadius, FMin(CollisionHeight, 0.8 * OldHolder.CollisionHeight));
			if ( !SetLocation(OldHolder.Location) )
			{
				
				MPGame(Level.Game).GameEvent("flag_returned_timeout",""$TeamNum,None);							
				BroadcastLocalizedMessage( MessageClass, 3, None, None, Level.Game.GameReplicationInfo.Teams[TeamNum] );				
				SendHome();
				return;
			}
		}
		*/
	}
}

simulated function UpdateHolograms();


defaultproperties
{
     bHome=True
     MaxDropTime=25
     HoldTime=1
     TeamNum=255
     ExitSpeed=600
     bAlwaysZeroBoneOffset=True
     bCollideActors=True
     bUseCylinderCollision=True
     RemoteRole=ROLE_SimulatedProxy
     NetPriority=3
     AttachmentBone="Head"
     CollisionRadius=60
     CollisionHeight=60
}