If you want to help us maintaining this wiki, check out our discord server: https://discord.gg/3u69jMa
GameObject
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
}