Life as an unresolved external symbol.
Beginning Your Game Part 4
Video Version
Subject: Beginning Your Game Part 4
Skill Level: Beginner
Run-Time: 54 Minutes
Author: Michael Allar
Notes: Setting up HTInventoryManager, HTInventory, HTWeapon
Download: Low-Res (32MB) Hi-Res (200MB)
Written Version
Subject: Beginning Your Game Part 4
Skill Level: Beginner
Author: Michael Allar
Notes: Setting up HTInventoryManager, HTInventory, HTWeapon
See the video for an in-depth explanation.
HTInventoryManager
/*******************************************************************************
HTInventoryManager
Creation date: 08/03/2010 07:03
Lots of code stolen from Epic
*******************************************************************************/
class HTInventoryManager extends InventoryManager
config(Game);
/** Holds the last weapon used */
var Weapon PreviousWeapon;
simulated function GetWeaponList(out array<HTWeapon> WeaponList, optional bool bNoEmpty)
{
local HTWeapon Weap;
ForEach InventoryActors( class'HTWeapon', Weap )
{
if ( !bNoEmpty || Weap.HasAnyAmmo())
{
WeaponList.Insert(0,1);
WeaponList[0] = Weap;
}
}
}
/**
* Accessor for the server to begin a weapon switch on the client.
*
* @param DesiredWeapon The Weapon to switch to
*/
reliable client function ClientSetCurrentWeapon(Weapon DesiredWeapon)
{
SetPendingWeapon(DesiredWeapon);
}
simulated function Inventory CreateInventory(class<Inventory> NewInventoryItemClass, optional bool bDoNotActivate)
{
if (Role==ROLE_Authority)
{
return Super.CreateInventory(NewInventoryItemClass, bDoNotActivate);
}
return none;
}
/**
* Handle AutoSwitching to a weapon
*/
simulated function bool AddInventory( Inventory NewItem, optional bool bDoNotActivate )
{
local bool bResult;
if (Role == ROLE_Authority)
{
bResult = super.AddInventory(NewItem, bDoNotActivate);
}
return bResult;
}
simulated function DiscardInventory()
{
local Vehicle V;
if (Role == ROLE_Authority)
{
Super.DiscardInventory();
V = Vehicle(Owner);
if (V != None && V.Driver != None && V.Driver.InvManager != None)
{
V.Driver.InvManager.DiscardInventory();
}
}
}
simulated function RemoveFromInventory(Inventory ItemToRemove)
{
if (Role==ROLE_Authority)
{
Super.RemoveFromInventory(ItemToRemove);
}
}
/**
* Scans the inventory looking for any of type InvClass. If it finds it it returns it, other
* it returns none.
*/
function Inventory HasInventoryOfClass(class<Inventory> InvClass)
{
local inventory inv;
inv = InventoryChain;
while(inv!=none)
{
if (Inv.Class==InvClass)
return Inv;
Inv = Inv.Inventory;
}
return none;
}
/**
* Store the last used weapon for later
*/
simulated function ChangedWeapon()
{
PreviousWeapon = Instigator.Weapon;
Super.ChangedWeapon();
}
simulated function SwitchToPreviousWeapon()
{
if ( PreviousWeapon!=none && PreviousWeapon != Pawn(Owner).Weapon )
{
PreviousWeapon.ClientWeaponSet(false);
}
}
defaultproperties
{
bMustHoldWeapon=true
PendingFire(0)=0
PendingFire(1)=0
}
HTInventory
/******************************************************************************* HTInventory Creation date: 08/03/2010 07:06 Copyright (c) 2010, Allar *******************************************************************************/ class HTInventory extends Inventory;
HTWeapon
/*******************************************************************************
HTWeapon
Creation date: 08/03/2010 06:21
Copyright (c) 2010, Allar
*******************************************************************************/
class HTWeapon extends UDKWeapon;
/** Current ammo count */
var repnotify int AmmoCount;
/** Max ammo count */
var int MaxAmmoCount;
/** Holds the amount of ammo used for a given shot */
var array<int> ShotCost;
/** Offset from view center */
var(FirstPerson) vector PlayerViewOffset;
replication
{
// Server->Client properties
if ( bNetOwner )
AmmoCount;
}
simulated event ReplicatedEvent(name VarName)
{
if ( VarName == 'AmmoCount' )
{
if ( !HasAnyAmmo() )
{
WeaponEmpty();
}
}
else
{
Super.ReplicatedEvent(VarName);
}
}
simulated function int GetAmmoCount()
{
return AmmoCount;
}
/*
* Consumes some of the ammo
*/
function ConsumeAmmo( byte FireModeNum )
{
// Subtract the Ammo
AddAmmo(-ShotCost[FireModeNum]);
}
/**
* This function is used to add ammo back to a weapon. It's called from the Inventory Manager
*/
function int AddAmmo( int Amount )
{
AmmoCount = Clamp(AmmoCount + Amount,0,MaxAmmoCount);
return AmmoCount;
}
/**
* Returns true if the ammo is maxed out
*/
simulated function bool AmmoMaxed(int mode)
{
return (AmmoCount >= MaxAmmoCount);
}
/**
* This function checks to see if the weapon has any ammo available for a given fire mode.
*
* @param FireModeNum - The Fire Mode to Test For
* @param Amount - [Optional] Check to see if this amount is available. If 0 it will default to checking
* for the ShotCost
*/
simulated function bool HasAmmo( byte FireModeNum, optional int Amount )
{
if (Amount==0)
return (AmmoCount >= ShotCost[FireModeNum]);
else
return ( AmmoCount >= Amount );
}
/**
* returns true if this weapon has any ammo
*/
simulated function bool HasAnyAmmo()
{
return ( ( AmmoCount > 0 ) || (ShotCost[0]==0 && ShotCost[1]==0) );
}
/**
* This function retuns how much of the clip is empty.
*/
simulated function float DesireAmmo(bool bDetour)
{
return (1.f - float(AmmoCount)/MaxAmmoCount);
}
/**
* Returns true if the current ammo count is less than the default ammo count
*/
simulated function bool NeedAmmo()
{
return ( AmmoCount < Default.AmmoCount );
}
/**
* Cheat Help function the loads out the weapon
*
* @param bUseWeaponMax - [Optional] If true, this function will load out the weapon
* with the actual maximum, not 999
*/
simulated function Loaded(optional bool bUseWeaponMax)
{
if (bUseWeaponMax)
AmmoCount = MaxAmmoCount;
else
AmmoCount = 999;
}
/**
* Called when the weapon runs out of ammo during firing
*/
simulated function WeaponEmpty()
{
// If we were firing, stop
if ( IsFiring() )
{
GotoState('Active');
}
if ( Instigator != none && Instigator.IsLocallyControlled() )
{
Instigator.InvManager.SwitchToBestWeapon( true );
}
}
/*********************************************************************************************
* Ammunition / Inventory
*********************************************************************************************/
function PrintScreenDebug(string debugText)
{
local PlayerController PC;
PC = PlayerController(Pawn(Owner).Controller);
if (PC != None)
PC.ClientMessage("HTWeapon: " $ debugText);
}
simulated function AttachWeaponTo( SkeletalMeshComponent MeshCpnt, optional Name SocketName )
{
local HTPawn HTP;
HTP = HTPawn(Instigator);
PrintScreenDebug("Attaching Weapon");
// Attach 1st Person Muzzle Flashes, etc,
if ( Instigator.IsFirstPerson() )
{
AttachComponent(Mesh);
EnsureWeaponOverlayComponentLast();
SetHidden(False);
Mesh.SetLightEnvironment(HTP.LightEnvironment);
PrintScreenDebug("First Person Weapon Attached");
}
else
{
SetHidden(True);
if (HTP != None)
{
Mesh.SetLightEnvironment(HTP.LightEnvironment);
}
}
//SetSkin(HTPawn(Instigator).ReplicatedBodyMaterial);
}
simulated event SetPosition(UDKPawn Holder)
{
local vector DrawOffset, ViewOffset, FinalLocation;
local rotator NewRotation, FinalRotation, SpecRotation;
local PlayerController PC;
local vector2D ViewportSize;
local bool bIsWideScreen;
local vector SpecViewLoc;
if ( !Holder.IsFirstPerson() )
return;
Mesh.SetHidden(False);
foreach LocalPlayerControllers(class'PlayerController', PC)
{
LocalPlayer(PC.Player).ViewportClient.GetViewportSize(ViewportSize);
break;
}
bIsWideScreen = (ViewportSize.Y > 0.f) && (ViewportSize.X/ViewportSize.Y > 1.7);
Mesh.SetScale3D(default.Mesh.Scale3D);
Mesh.SetRotation(default.Mesh.Rotation);
ViewOffset = PlayerViewOffset;
// Calculate the draw offset
if ( Holder.Controller == None )
{
if ( DemoRecSpectator(PC) != None )
{
PC.GetPlayerViewPoint(SpecViewLoc, SpecRotation);
DrawOffset = ViewOffset >> SpecRotation;
//DrawOffset += UTPawn(Holder).WeaponBob(BobDamping, JumpDamping);
FinalLocation = SpecViewLoc + DrawOffset;
SetLocation(FinalLocation);
SetBase(Holder);
// Add some rotation leading
//SpecRotation.Yaw = LagRot(SpecRotation.Yaw & 65535, LastRotation.Yaw & 65535, MaxYawLag, 0);
//SpecRotation.Pitch = LagRot(SpecRotation.Pitch & 65535, LastRotation.Pitch & 65535, MaxPitchLag, 1);
//LastRotUpdate = WorldInfo.TimeSeconds;
//LastRotation = SpecRotation;
if ( bIsWideScreen )
{
//SpecRotation += WidescreenRotationOffset;
}
SetRotation(SpecRotation);
return;
}
else
{
DrawOffset = (ViewOffset >> Holder.GetBaseAimRotation()) + HTPawn(Holder).GetEyeHeight() * vect(0,0,1);
PrintScreenDebug("Setting DrawOffset to Holder Info");
}
}
else
{
DrawOffset.Z = HTPawn(Holder).GetEyeHeight();
//DrawOffset += HTPawn(Holder).WeaponBob(BobDamping, JumpDamping);
if ( HTPlayerController(Holder.Controller) != None )
{
DrawOffset += HTPlayerController(Holder.Controller).ShakeOffset >> Holder.Controller.Rotation;
}
DrawOffset = DrawOffset + ( ViewOffset >> Holder.Controller.Rotation );
}
// Adjust it in the world
FinalLocation = Holder.Location + DrawOffset;
SetLocation(FinalLocation);
SetBase(Holder);
NewRotation = (Holder.Controller == None) ? Holder.GetBaseAimRotation() : Holder.Controller.Rotation;
// Add some rotation leading
//if (Holder.Controller != None)
//{
// FinalRotation.Yaw = LagRot(NewRotation.Yaw & 65535, LastRotation.Yaw & 65535, MaxYawLag, 0);
// FinalRotation.Pitch = LagRot(NewRotation.Pitch & 65535, LastRotation.Pitch & 65535, MaxPitchLag, 1);
// FinalRotation.Roll = NewRotation.Roll;
//}
//else
//{
FinalRotation = NewRotation;
//}
//LastRotUpdate = WorldInfo.TimeSeconds;
//LastRotation = NewRotation;
if ( bIsWideScreen )
{
//FinalRotation += WidescreenRotationOffset;
}
SetRotation(FinalRotation);
}
simulated state WeaponEquipping
{
simulated event BeginState(Name PreviousStateName)
{
PrintScreenDebug("Weapon Equipping");
AttachWeaponTo(Instigator.Mesh);
Super.BeginState(PreviousStateName);
}
}
simulated state Active
{
simulated event BeginState(Name PreviousStateName)
{
PrintScreenDebug("Active");
Super.BeginState(PreviousStateName);
}
}
simulated state WeaponFiring
{
simulated event BeginState(Name PreviousStateName)
{
PrintScreenDebug("Firing");
Super.BeginState(PreviousStateName);
}
/**
* We override BeginFire() so that we can check for zooming and/or empty weapons
*/
simulated function BeginFire( Byte FireModeNum )
{
// No Ammo, then do a quick exit.
if( !HasAmmo(FireModeNum) )
{
WeaponEmpty();
return;
}
Global.BeginFire(FireModeNum);
}
}
defaultproperties
{
Begin Object Class=UDKSkeletalMeshComponent Name=FirstPersonMesh
DepthPriorityGroup=SDPG_Foreground
bOnlyOwnerSee=true
bOverrideAttachmentOwnerVisibility=true
CastShadow=false
bAllowAmbientOcclusion=false
End Object
Mesh=FirstPersonMesh
Begin Object Class=SkeletalMeshComponent Name=PickupMesh
bOnlyOwnerSee=false
CastShadow=false
bForceDirectLightMap=true
bCastDynamicShadow=false
CollideActors=false
BlockRigidBody=false
bUseAsOccluder=false
MaxDrawDistance=6000
bForceRefPose=1
bUpdateSkelWhenNotRendered=false
bIgnoreControllersWhenNotRendered=true
bAcceptsStaticDecals=FALSE
bAcceptsDynamicDecals=FALSE
bAllowAmbientOcclusion=false
End Object
DroppedPickupMesh=PickupMesh
PickupFactoryMesh=PickupMesh
MessageClass=class'UTPickupMessage'
DroppedPickupClass=class'UTDroppedPickup'
FiringStatesArray(0)=WeaponFiring
FiringStatesArray(1)=WeaponFiring
WeaponFireTypes(0)=EWFT_InstantHit
WeaponFireTypes(1)=EWFT_InstantHit
WeaponProjectiles(0)=none
WeaponProjectiles(1)=none
FireInterval(0)=+0.3
FireInterval(1)=+0.3
Spread(0)=0.0
Spread(1)=0.0
ShotCost(0)=1
ShotCost(1)=1
AmmoCount=5
MaxAmmoCount=5
InstantHitDamage(0)=0.0
InstantHitDamage(1)=0.0
InstantHitMomentum(0)=0.0
InstantHitMomentum(1)=0.0
InstantHitDamageTypes(0)=class'DamageType'
InstantHitDamageTypes(1)=class'DamageType'
WeaponRange=22000
ShouldFireOnRelease(0)=0
ShouldFireOnRelease(1)=0
DefaultAnimSpeed=0.9
EquipTime=+0.45
PutDownTime=+0.33
}
Michael Allar
March 26, 2010 - 4:23 pm
Thanks for your great tutes mate.
April 2, 2010 - 12:20 pm
I am getting an error in the weapon class
Error, BEGIN OBJECT: No base template named FirstPersonMesh found in parent class UDKWeapon: Begin Object Name=FirstPersonMesh
April 2, 2010 - 12:24 pm
Code updated for the defaultproperties block of HTWeapon.
Apparently when copy+pasting from WOTgreal, the “class” part gets ripped out for whatever reason.
April 8, 2010 - 5:20 am
Could U plz put the class HTPlayerController…
because I downloal the low resoluion..
April 8, 2010 - 10:38 am
we don’t touch HTPlayerController in this tutorial I believe :0
May 23, 2010 - 3:00 am
(Using April UDK)
I’m getting this warning:
Warning, Variable declaration: ‘AmmoCount’ conflicts with previously defined field in ‘UDKWeapon’
When compiling your code. I know that AmmoCount already exists in UDKWeapon, and commenting out the line gives me a replication error.
Would it be safe to rename all AmmoCount instances in the code to something like CurAmmoCount or something, without damaging the system?
I know it’s a warning and can be ingored, but yellow text scares me :3
May 26, 2010 - 1:32 am
(((((( (Using April UDK)
I’m getting this warning:
Warning, Variable declaration: ‘AmmoCount’ conflicts with previously defined field in ‘UDKWeapon’
When compiling your code. I know that AmmoCount already exists in UDKWeapon, and commenting out the line gives me a replication error.
Would it be safe to rename all AmmoCount instances in the code to something like CurAmmoCount or something, without damaging the system?
I know it’s a warning and can be ingored, but yellow text scares me :3)))))))
Yes by switching AmmoCount to CurAmmoCount will get rid of the warnings you get. Switch it to this —var repnotify int CurAmmoCount;— and the same for any where you see AmmoCount I repeat any where!! LOL
May 26, 2010 - 1:34 am
class HTWeapon extends UDKWeapon;
/** Current ammo count, Switched name to CurAmmoCount to avoid error
* (‘AmmoCount’ conflicts with previously defined field in ‘UDKWeapon’)
*/
var repnotify int CurAmmoCount;
/** Max ammo count */
var int MaxAmmoCount;
/** Holds the amount of ammo used for a given shot */
var array ShotCost;
/** Offset from view center */
var(FirstPerson) vector PlayerViewOffset;
replication
{
// Server->Client properties
if ( bNetOwner )
CurAmmoCount;
}
simulated event ReplicatedEvent(name VarName)
{
if ( VarName == ‘CurAmmoCount’ )
{
if ( !HasAnyAmmo() )
{
WeaponEmpty();
}
}
else
{
Super.ReplicatedEvent(VarName);
}
}
simulated function int GetAmmoCount()
{
return CurAmmoCount;
}
/*
* Consumes some of the ammo
*/
function ConsumeAmmo( byte FireModeNum )
{
// Subtract the Ammo
AddAmmo(-ShotCost[FireModeNum]);
}
/**
* This function is used to add ammo back to a weapon. It’s called from the Inventory Manager
*/
function int AddAmmo( int Amount )
{
AmmoCount = Clamp(AmmoCount + Amount,0,MaxAmmoCount);
return CurAmmoCount;
}
/**
* Returns true if the ammo is maxed out
*/
simulated function bool AmmoMaxed(int mode)
{
return (CurAmmoCount >= MaxAmmoCount);
}
/**
* This function checks to see if the weapon has any ammo available for a given fire mode.
*
* @param FireModeNum – The Fire Mode to Test For
* @param Amount – [Optional] Check to see if this amount is available. If 0 it will default to checking
* for the ShotCost
*/
simulated function bool HasAmmo( byte FireModeNum, optional int Amount )
{
if (Amount==0)
return (CurAmmoCount >= ShotCost[FireModeNum]);
else
return ( CurAmmoCount >= Amount );
}
/**
* returns true if this weapon has any ammo
*/
simulated function bool HasAnyAmmo()
{
return ( ( CurAmmoCount > 0 ) || (ShotCost[0]==0 && ShotCost[1]==0) );
}
/**
* This function retuns how much of the clip is empty.
*/
simulated function float DesireAmmo(bool bDetour)
{
return (1.f – float(CurAmmoCount)/MaxAmmoCount);
}
/**
* Returns true if the current ammo count is less than the default ammo count
*/
simulated function bool NeedAmmo()
{
return ( CurAmmoCount < Default.CurAmmoCount );
}
/**
* Cheat Help function the loads out the weapon
*
* @param bUseWeaponMax – [Optional] If true, this function will load out the weapon
* with the actual maximum, not 999
*/
simulated function Loaded(optional bool bUseWeaponMax)
{
if (bUseWeaponMax)
CurAmmoCount = MaxAmmoCount;
else
CurAmmoCount = 999;
}
/**
* Called when the weapon runs out of ammo during firing
*/
simulated function WeaponEmpty()
{
// If we were firing, stop
if ( IsFiring() )
{
GotoState('Active');
}
if ( Instigator != none && Instigator.IsLocallyControlled() )
{
Instigator.InvManager.SwitchToBestWeapon( true );
}
}
May 26, 2010 - 3:11 pm
When I launch the game it has no hud or physics. I can fly around. Is that suppose to happen?
June 6, 2010 - 9:58 am
O.k. , good tutorial but consider some things:
1) When you were taking out functions you talked as if the average joe knew what the hell all that stuff did, and you should consider that some people are relatively new to programming and udk and don’t know all of Epic’s logic functions.
2) You kept referencing (verbally) to things that the user hasnt made yet and thats pretty confusing…like when you were explaining the inventory/weapon classes prior to us creating them.
3) The video tutorial was pretty dense and felt like it had alot of filler and unnecessary comments (again read number 1) about classes we haven’t made.
4) Your tutorials explain how udk organizes it’s classes and the general format for manipulating their organization structure to fit your own game but you don’t explain unreal script itself. (I code in C++ so I recognize all the logic statements if-else switch etc.) but you don’t explain variables, unique statements, or anything else.
5) You stated we we’re building from the ground up, but you just randomly copied a bunch of stuff from epic and deleted other stuff. It would be easier to actually learn what everything does and how to set it up if you started from scratch. I don’t like to copy paste I actually want to know what it does so I don’t have to revisit old code 300 times every-time I want to do something.
This is not a rant, it is just a list of problems and suggestions to fix it. If it sounds as if I’m being cruel, i’m sorry, but as you know its hard to show emotion of the internet.