Life as an unresolved external symbol.
HTWeapon: Part 1 – Adding Ammo
Contents
Video Version
Subject: HTWeapon: Part 1 – Adding Ammo
Skill Level: Beginner
Run-Time: 30 minutes
Author: Michael Allar
Notes: How to implement a very basic ammo system in our custom weapon class, taking code from UTWeapon.
Download: Low-Res (66MB) Hi-Res (200MB)
Written Version
Subject: HTWeapon: Part 1 – Adding Ammo
Skill Level: Beginner
Author: Michael Allar
Notes: How to implement a very basic ammo system in our custom weapon class, taking code from UTWeapon.
See video for an in-depth explanation. Sorry about the indentation, it seems like my indentation will not survive copy paste… D:
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
}
HTWP_M16
/*******************************************************************************
HTWP_M16
Creation date: 08/03/2010 06:48
Copyright (c) 2010, Allar
*******************************************************************************/
class HTWP_M16 extends HTWeapon;
defaultproperties
{
// Weapon SkeletalMesh
Begin Object Name=FirstPersonMesh
SkeletalMesh=SkeletalMesh'ALWP_M16.Mesh.SK_WP_M16_1P'
AnimSets(0)=AnimSet'ALWP_M16.Anims.K_WP_M16_1P'
Scale=1.0
FOV=60.0
End Object
// Pickup staticmesh
Begin Object Name=PickupMesh
SkeletalMesh=SkeletalMesh'ALWP_M16.Mesh.SK_WP_M16_3P'
End Object
PlayerViewOffset=(X=17,Y=10.0,Z=-8.0)
}
Michael Allar
March 18, 2010 - 5:40 pm
Hey dude, I really love your tutorials, and I think you are doing a great job. However I am having trouble compiling the files and making errors in the codes when I copy and paste. Is it alright if you post a zip file with all the class files? No content is needed, haha.
March 18, 2010 - 11:22 pm
I was thinking about doing this as well. You suggested it, so I will do so with all future tutorials. Because the working code I am using for these tutorials has evolved, I no longer have this iteration of code. Forcing me to create .zip files of these iterations will allow me to go back to specific versions in the future, so its a good idea all around. If you are using the March build with this tutorial, you will get errors about variables being already declared in their super classes as Epic decided to move some variables up to parent classes. If thats the case, I recommend following and reading until you get to the February to March tutorial, and use that code in these classes. You should get no errors and be able to compile just fine after that. Later tonight or this week I will work on reformatting this code along with posting a .zip
Can you reply with specific errors? Just so I know its a pure code formatting thing instead of the actual code… The last thing I want to post is not functional code
April 4, 2010 - 12:18 am
I have followed the tutorials from the beginning but somewhere from “Beginning your game part” 3 to “HTWeapon: Part 1″ some thing has goes wrong. Everything is working fine except i am unable to contiune with the tutorial because my First Person mesh does not load when i type the command “giveweapon UDKGame.SMWP_Cannon” (which would be my script name). Everything recompiles nicely, but even when i change the skeletalmesh and anims to the proper shockrifle files it does not work. Hopefully you will have an idea as to what i am talkin about and some thoughts as to how to fix it. besides this litte issue Thank You for Awsome Tutorials!!
April 4, 2010 - 2:16 am
Thats odd, trying placing a
`log(“Weapon attached”);
in the AttachWeaponTo and see if it spits out Weapon attached in your log files when you use giveweapon
EDIT:
I totally just remembered that the ShockRifle is facing down the wrong axis and in Epic’s code it is rotated in its default properties. Check the defaultproperties block of UTWeap_ShockRifle for this.
You can either fix it by rotating it the same way they did, or copying the shockrifle asset, save it into your own package, and then adjust its Rot Origin.
April 4, 2010 - 5:07 pm
I believe that mine is already suppose to be spiting out the weapon state, since iv been following both the written and video versions so it should be already telling me that the weapon is attached, has this function been removed in the Written Version?
It just doesnt seem to load the mesh. I am using a weapon that has the X axis facing facing the same as your M-16 so i shouldn’t have to rotate the origin.
April 4, 2010 - 5:22 pm
Interesting. I’ll perform the rare occasion of looking at your code + package if you send me your UDKGame directory and the package containing your weapon if you are willing to email it to me. Email is on my about page.
April 4, 2010 - 5:57 pm
Your code is working, however you put that `log function in the wrong spot, it belongs inside the curly brackets and somewhere after the local variable declarations.
Heres the issue: You named the folder with all your code RedRain, which means your code package is RedRain, not UDKGame.
Which means as you follow this tutorial, things like UDKGame.UDKGame will be RedRain.UDKGame. Things like UDKGame.HTWeapon will be RedRain.HTWeapon. And in your case, UDKGame.SMWP_Cannon will become RedRain.SMWP_Cannon.
Try using the command giveweapon RedRain.SMWP_Cannon
April 4, 2010 - 6:09 pm
That makes sense but where did you see UDKGame where it was suppose to be RedRain? The console command I was typing in wrong, but still seems to not work even with RedRain.SMWP_Cannon.
April 4, 2010 - 6:33 pm
Beautiful, Ok the problem seemed to be just the “config (UDKGame)” which was suppose to be “config (RedRain)”. Thanks for the help!
I can continue with ur tutorials now : ). I dont wanna bug you all day but in the tutorial will it go into using the animset for the gun, with Reload and Alternate fire and what not?
April 4, 2010 - 7:10 pm
I have not covered how to implement custom characters or animations yet, but a few tutorials about that should be going up within the next few eeks about it.
April 6, 2010 - 8:11 am
emergency
now I do a Make for game there are errors:
Warning/Error Summary
———————
D:\UDK\UDK-2010-03\Development\Src\UDKGame\Classes\HTWeapon.uc(326) : Error, BEGIN OBJECT: No base template named FirstPersonMesh found in parent class UDKWeapon: Begin Object Name=FirstPersonMesh
D:\UDK\UDK-2010-03\Development\Src\UDKGame\Classes\HTWP_M16.uc(14) : Error, BEGIN OBJECT: No base template named FirstPersonMesh found in parent class HTWeapon: Begin Object Name=FirstPersonMesh
D:\UDK\UDK-2010-03\Development\Src\UDKGame\Classes\HTWeapon.uc(11) : Warning, Variable declaration: ‘AmmoCount’ conflicts with previously defined field in ‘UDKWeapon’
here is the link for my code:
http://www.4shared.com/file/258310476/9bc308a5/UDKGame.html
April 6, 2010 - 8:27 am
Too busy to look at your code, but I don’t need to either.
Code listing for HTWeapon updated and fixed.
You can also rip out line 11 of your code to get rid of that warning. The code above works with the Feb build but causes that warning on the March build, as you’ll see in the next few tutorials.
April 6, 2010 - 12:16 pm
i’ll try help U soon…
I’ll check the code now
April 6, 2010 - 1:04 pm
sorry I can’t …
maybe allar help U
April 8, 2010 - 2:30 am
U seem to buuussssssy…
April 28, 2010 - 1:46 am
Getting a warning when I compile in:
warning : ObjectProperty Engine.SkeletalMeshComponent:SkeletalMesh: unresolved reference to ‘SkeletalMesh ‘AvaWeapons.Mesh.SK_WP_Thompson”
I copied everything from both of the weapon files and just changed the names to match the ones in my project. Not to sure why I’m getting these warnings.
Also the part where it says “AvaWeapons.Mesh.SK_WP_Thompson” is the AvaWeapons part the .upk in the contents package?
April 28, 2010 - 2:12 am
Launch the editor and find the skeletal mesh in your package that you want to use (SK_WP_Thompson).
Right click it, and click copy full name to clipboard.
Now paste that over your SkeletalMesh’AvaWeapons…’ line.
April 28, 2010 - 2:27 am
I’m not to sure if you went over it in a previous Tutorial. My problem just had to do with: AvaWeapons.Mesh.SK_WP_Thompson
I didn’t name my group Mesh so I had to change that. Also I noticed you said to make it so the gun is on the X axis does that mean I have to have the PlayerViewOffset still or no?
April 28, 2010 - 2:42 am
oops totally didn’t see your post. So I got that to work but I can’t seem to get it in the game. A few things I am doing differently is I’m not deriving from the same Game info class just cause for my project it’s easier to use unreal code thats already there. Anyway I went into my GameInfo class and added:
DefaultInventory(0)=class’AvaWeapon_Thompson’
But I keep loading up my map with the link gun. Any thoughts as to why?
April 28, 2010 - 4:10 am
Hmm, that should do it… You might need to look in-depth at some of their default inventory code and see if they are using this array or some other means to give inventory items in the mode you are deriving from. I don’t know of any reason for that to not work but… I suppose you can always override the function that gives players their default inventory directly.
April 28, 2010 - 1:05 pm
I think what I will try to do is go back and just do my Game info class the same as yours and see if I can get it to work like that. I was doing some testing last night with my pawn class and changed my character so it was the Human male. When I ran the game the character stayed as that robot character. Which to me is a little confusing because I know I am running my Game info class because when I changed my class to derive from just GameInfo I didn’t have a gun or anything opposed to the UTGameinfo class.
Also you have a character in your game right?
April 28, 2010 - 1:52 pm
So I went back and changed everything but all I get is a floating camera when I load up my Game. I feel like it isn’t using my pawn or anything but I have double checked my code to make sure that my GameInfo class is using my default pawn and player controller. Is there any way for me to check if my pawn class is even being called on level start up? and same when I use the give weapon?
April 28, 2010 - 10:14 pm
in your Pawn class you can hook the PostBeginPlay or Spawned events and use `log(“Im a Pawn!”) within these functions to log some text to your log files. Then you can check your latest log file in UTGame\Logs and see if that text shows up. If not, then your Pawn class isn’t being used.
April 28, 2010 - 10:35 pm
Just to make sure I am calling the function the postbegin play looks like this:
function PostBeginPlay()
{
Super.PostBeginPlay();
`Log(“I’m in the pawn class”);
}
Trying that right now. let me know If I did anything wrong
April 28, 2010 - 10:45 pm
I’m assuming that right when I load up the game somewhere in my log file it should say I am in my pawn class, but I don’t see it there. It does say in there though:
Log: Game class is ‘AvaGameInfo’
So why isn’t it calling my pawn class?
April 28, 2010 - 11:00 pm
So I tried putting the script log in my Player controller class and it worked so I guess that narrows a few things down.
Sorry about all the posts just really confused as to why this wouldn’t be working if the script log comes up for my player controller
May 30, 2010 - 6:19 am
I’m in the same boat as GregC. I have redone the tutorial twice, and both times at this stage I simply end up with a floating camera and any time I call “giveweapon” nothing happens. My code is identical to the code you provide, Allar, so I’ve no idea why it isn’t working. It’s like it isn’t recognising my UDKGame classes. Do you have any idea what might be causing this?
May 30, 2010 - 8:09 am
Which build yall using?
June 6, 2010 - 6:36 pm
Good tutorial. Still, I think you need to focus a little more on the udk aspect of things instead of having us copy-paste, but your getting better and this tutorial has less filler and more info than your previous. Congrats.
June 6, 2010 - 7:16 pm
Actually you explained variables and some of the statements such as repnotify so you actually improved ALOT from the last video. I’m quite impressed and to be brutally honest…your more helpful than hourence’s although I still use his map making tuts. You really should check out the site. We’ve got are game in acceleration now and we have an interview series for all my homies.
June 6, 2010 - 7:22 pm
Already watched all your latest vids on both channels an hour or so ago.
June 6, 2010 - 7:26 pm
Sorry for the tripple post, but I’m giving you cred. on the next video we do (For the “Official” channel (not the behind-the-scenes one)). It’ll be about our progress in the engine and even though part 4 was actually the hardest of your tutorials I stuck through it, you still did wonders to explain Unreal Script. Even though I ranted I still thought it was better for me to get my hands dirty and take a look at the code my self, instead of complaining that someone else should do it for me. Although it would be nice to see some more explanation of Unreal Scripts syntax, these are still VERY good tutorials and I’d keep watching regardless. Props man.
June 6, 2010 - 7:29 pm
This entire series is far sub-par in quality as to where I want them to be.
I’m already in the process of recreating this whole series, just got my brand new microphone, and kind of know what I’m talking about now.
The series is meant to also go along with my book, so we’ll see how that goes. Its going to go pretty in-depth, most likely so in-depth its annoying but whatever.
June 11, 2010 - 12:18 pm
Hey allar that interview with the developers part 3 is going to be remade. That was Tree_gnome and he kinda fails at videos so after class Im making him redo his video
June 13, 2010 - 11:18 am
Hey just got a quick question my gun is showing up black when I run the game and I tried just bringing in the unreal Link gun and it was black to. I’m not to sure where to look to solve this problem. I was thinking it had to do with the dynamic light for the gun but everything seems to be the same as your code. Do you have any places that I could look for this problem.
June 13, 2010 - 12:07 pm
http://forecourse.com/2010/04/fixing-character-lighting/
Apply that to your weapon
June 13, 2010 - 2:56 pm
Awesome thanks for the quick response.