Game Development Community

dev|Pro Game Development Curriculum

Complete Dynamic Weapon Hud

by Brian Jansen · 07/03/2006 (11:32 am) · 9 comments

This is a Weapon HUD element I have had in my game for a while now so I thought I would post it and also it includes improvements over other resources such as the Ammo Hud GUI, Sniper Head Movement, and individualized zoom.
First the Hud itself!

Step 1)
Open Up fps/client/scripts/playgui.cs and add this:
function clientCmdSetAmmoAmountHud(%valued) // time is specified in seconds
{
     AmmoAmount.setText("Ammo: " @ %valued);
}
function clientCmdSetweaponnameHud(%values) // time is specified in seconds
{
     weapname.setText(%values);
}
function clientCmdSetweaponpreviewHud(%valuea) // time is specified in seconds
{
     Weapimage.setbitmap(%valuea);
}
function clientCmdSetcrosshairHud(%valueaa) // time is specified in seconds
{
     crosshair.setbitmap(%valueaa);
} 
function clientCmdSetmoneyHud(%valuesa) // time is specified in seconds
{
     money.setText("$" @ %valuesa);
}

Step 2)
Next open up fps/client/ui/playgui.gui and add this:
new GuiButtonCtrl(Weapname) {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "top";
      position = "174 394";
      extent = "138 15";
      minExtent = "8 2";
      visible = "1";
      text = "Weapon Name";
      groupNum = "-1";
      buttonType = "PushButton";
   };
   new GuiBitmapCtrl(Weapimage) {
      profile = "GuiDefaultProfile";
      horizSizing = "right";
      vertSizing = "top";
      position = "230 326";
      extent = "72 55";
      minExtent = "8 2";
      visible = "1";
      bitmap = "~/data/shapes/beam/preview.png";
      wrap = "0";
   };
   new GuiButtonCtrl(AmmoAmount) {
      profile = "GuiButtonProfile";
      horizSizing = "right";
      vertSizing = "top";
      position = "174 408";
      extent = "138 15";
      minExtent = "8 2";
      visible = "1";
      text = "Ammo: 0";
      groupNum = "-1";
      buttonType = "PushButton";
   };
new GuiTextCtrl(CDTime) {

         profile = "GuiDefaultProfile";
         horizSizing = "left";
         vertSizing = "bottom";
         position = "4 2";
         extent = "142 24";
         minExtent = "8 2";
         visible = "1";
         text = "00:00";
         maxLength = "255";
            helpTag = "0";
      };

Then open up fps/client/ui/defaultgameprofiles.cs and add:
new GuiControlProfile ("AmmoPrintProfile")
{
   opaque = false;
   fillColor = "128 128 128";
   fontColor = "255 255 255";
   border = true;
   borderColor = "0 255 0";
};

Step 3)

Open up fps/server/scripts/game.cs and make these changes:
function GameConnection::onClientEnterGame(%this)
{
...
+%this.setAmmoAmountHud("0");
+%this.setweapHud("");
+%this.setweappHud("");
...
}

function GameConnection::onDeath(%this, %sourceObject, %sourceClient, %damageType, %damLoc)
{
...
%this.setAmmoAmountHud("0");
%this.setweapHud("");
%this.setweappHud("");
// Clear out the name on the corpse
%this.player.setShapeName("");
...
}

Step 5)
Open Up fps/server/scripts/weapon.cs and add this:
function GameConnection::setweapHud(%client, %name)
{
    commandToClient(%client, 'SetweaponnameHud', %name);
}
function GameConnection::setweappHud(%client, %image)
{
  commandToClient(%client, 'SetweaponpreviewHud', %image);
}
function GameConnection::setcrosshairHud(%client, %image)
{
  commandToClient(%client, 'SetcrosshairHud', %image);
}
function GameConnection::setAmmoAmountHud(%client, %amount)
{
    commandToClient(%client, 'SetAmmoAmountHud', %amount);
}

And replace the whole function WeaponImage::onMount(%this,%obj,%slot) with this:
function WeaponImage::onMount(%this,%obj,%slot)
{
   // Images assume a false ammo state on load.  We need to
   // set the state according to the current inventory.
if (%obj.getInventory(%this.ammo)) {

  %obj.setImageAmmo(%slot,true);
  %currentAmmo = %obj.getInventory(%this.ammo);
} else {
  %currentAmmo = 0;
}
%obj.client.setAmmoAmountHud(%currentAmmo);
}

Then Replace function Ammo::onInventory(%this,%obj,%amount) with this:
function Ammo::onInventory(%this,%obj,%amount)
{
   // The ammo inventory state has changed, we need to update any
   // mounted images using this ammo to reflect the new state.
   for (%i = 0; %i < 8; %i++) {
      if ((%image = %obj.getMountedImage(%i)) > 0)
         if (isObject(%image.ammo) && %image.ammo.getId() == %this.getId()) {
            %obj.setImageAmmo(%i,%amount != 0);
            %currentAmmo = %obj.getInventory(%this);
            %obj.client.setAmmoAmountHud(%currentAmmo);
         }
   }
}

Last replace function Weapon::onUse(%data,%obj) with this:
function Weapon::onUse(%data,%obj)
{
   // Default behavoir for all weapons is to mount it into the
   // this object's weapon slot, which is currently assumed
   // to be slot 0
   if (%obj.getMountedImage($WeaponSlot) != %data.image.getId()) {
      serverPlay3D(WeaponUseSound,%obj.getTransform());
      %obj.mountImage(%data.image, $WeaponSlot);

      if (%obj.client)
      %obj.client.setweapHud(%data.name);
      %obj.client.setweappHud(%data.weapimage);
      %obj.client.setcrosshairHud(%data.crosshair);
      %obj.client.fov = %data.fov;
     }
}

Step 6)
Now open up any weapon and look at the Item Datablock and add these variables to it:
Name = "Put full weapon name here";
Weapimage = "fps/data/shapes/[weapon folder goes here]/preview.png";
crosshair = "fps/data/shapes/[weapon folder goes here]/crosshair.png";
fov = "Feild of Vision for Custom Zoom";
Change any of those to your likeing

!**READ THIS**!
Make saure you make 512x512 preview images for your weapons and call them preview.png and also be sure they are located in the folder that you can find the weapon's shapes. If you desire you can also include a different crosshair for every weapon just put a crosshair in the same folder as the preview image

Now for the custom Zoom

Step 7)
Install this resource Drunk or Sniper-Breathing movement then open up fps/client/scripts/default.bind.cs and add:
function clientCmdZoomInDaBiatch( %val, %curWeapon, %client )
{
   if (%val && %curWeapon <= $pref::player::defaultfov)
   {
      commandtoserver('sniper',%client);
      $ZoomOn = true;
      //ScopeGuiGroup1.Visible = 1; // Show Sniper Rifle Scope HUD
      //Crosshair.Visible = 0;	
      setFov( %curweapon );
   }
   else
   {
      $ZoomOn = false;
      //ScopeGuiGroup1.Visible = 0; // Show Sniper Rifle Scope HUD
      //Crosshair.Visible = 1;	
      setFov( $Pref::player::DefaultFov );
      commandtoserver('weaponzoomout',%client);
   }
}


moveMap.bind(mouse, mouse2, toggleZoom);

function doSomething(%val)
{
   if (%val == "1" && $ZoomOn == "true")
   commandtoserver('holdbreath',%val);
   else if(%val == "0" && $ZoomOn == "true")
      commandtoserver('holdbreath',%val);
}

moveMap.Bind(keyboard, "r", doSomething);

function clientCmdweaponzoomout(%client){
$ZoomOn = false;
setFov( $Pref::player::DefaultFov );
commandtoserver('weaponzoomout',%client);
}

replace function toggleFirstPerson(%val) with:
function toggleFirstPerson(%val)
{
   if (%val && $ZoomOn != true)
   {
      $firstPerson = !$firstPerson;
      ServerConnection.setFirstPerson($firstPerson);
   }
}

Then Replace function toggleZoom(%val) with:
function toggleZoom(%val)
{
   if ($firstPerson == 1) // No Zoom When in 3rd Person View
   {
   commandToServer( 'CallZoomFunction', %val );
   }
}

Get rid of fetfov()

Step 8)
Open up fps/client/scripts/client.cs and add this:
function clientCmdunpausecounter()
{
                 counter();
}
function clientCmdpausecounter()
{
                 cancel($cou);
}
function clientCmdstopcounter()
{
	cancel($cou);
	//CDTime.visible = 0;
	timer.visible = 0;
	//CDBG.visible = 0;
	//CDBGR.visible = 0;
}
function clientCmdstartcounter()
{
	cancel($cou);
	timer.visible = 1;
	//CDBG.visible = 1;
	CDTime.setValue("0");
	//$Min = %min;
	$Sec = "a";
	$secs = 0;
	counter();
}

function counter()
{
if($Sec $= "a")
{
$Secs++;
if($secs > "10")
{
//$Secs++;
$timea = $secs - "10";
$dmg = $timea * "5";
cdTime.setValue("\c2(" @ $secs @ " - 10) * 5 = " @ $dmg @ " Damage");
//%couschedule = Schedule(1000,0,"counter");
//$cou = %couschedule;
}
else
{
//$Secs++;
cdTime.setValue($secs);
}	
%couschedule = Schedule(1000,0,"counter");
$cou = %couschedule;
}
}

Step 9)
Open Up fps/server/scripts/weapon.cs and add:
function serverCmdCallZoomFunction( %client, %val )
{
   %zoomer = %client.getControlObject();
   %curWeapon = %zoomer.getMountedImage($WeaponSlot).item.fov;
if(%curweapon != "") 
   commandToClient(%client,'ZoomInDaBiatch',%val,%curWeapon,%client);
   //%zoomer.setTranquilized(0.01);
return;
}
function serverCmdsniper(%client)
{
   %zoomer = %client.getControlObject();
 %zoomer.setTranquilized(0.008);
return;
}

$startTime = 0;
$endTime = 0;
$breathTime = 0;
$maxbreathTime = 10; // 2 sec
$breath = 0;
$damage = 0;
$damagemultiplier = 5;
function serverCmdholdbreath(%client,%val)
{
%zoomer = %client.getControlObject();
//if %val = 0 the button is released (OnkeyUp); 1 if pressed (onKeydown)
if (%val)
{
$startTime = $Sim::Time;
%zoomer.setTranquilized(0.0);
echo("Start (" @ $starttime @ ")");
//commandtoclient(%client,"startcounter");
clientCmdstartcounter();
}
else if(!%val)
{
//commandtoclient(%client,"stopcounter"); 
clientCmdstopcounter();
$endTime = $Sim::Time;
echo("End (" @ $endtime @ ")");
//Subtract the 2 to find out how long we held the key
$breath = $endTime - $startTime;
//echo($breath);   
//echo("Charge Time : " @ $breath);
%zoomer.setTranquilized(0.008);
if ($breath > $maxbreathtime)
echo("Over");
$damage = $breath - $maxbreathtime;
//echo($damage);
%damage = $damage * $damagemultiplier;
error("( " @ $breath @ " - " @ $maxbreathtime @ " ) X " @ $damagemultiplier @ " = " @ %damage); 
%zoomer.damage(%zoomer,%pos,%damage,"breath");
}
}

Step 10)
Open up fps/server/scripts/inventory.cs and replace function ShapeBase::use(%this,%data) with this:
function ShapeBase::use(%this,%data)
{
commandToclient(%this.client,'weaponzoomout');
   // Use an object in the inventory.
      if (%this.getInventory(%data) > 0)
         return %data.onUse(%this);
      return false;
   }

Then add:
function serverCmdweaponzoomout(%client){
%zoomer = %client.getControlObject();
%zoomer.setTranquilized(0);
clientCmdstopcounter();
//commandToClient(%client,'weaponZoomout');
}

Step 11)
Open up fps/client/scripts/optionsdlg.cs and add this to the mappings:
$RemapName[$RemapCount] = "Hold Breath";
$RemapCmd[$RemapCount] = "dosomething";
$RemapCount++;

Then add this:
function holdbreath (%val)
{
		commandtoserver('holdbreath',%val);
}

Step 12)
TEST!!!

Enjoy this resource I hope it is helpful and if I missed anything please let me know because I am not sure if this is all of it.

#1
05/07/2006 (8:14 pm)
This looks cool, I'll have a swing at it tomorrow.
I love the idea of the dynamic crosshair for different weapons/weapon modes.
#2
05/13/2006 (4:36 pm)
In step2 above if you want to have images for your buttons than replace that code with this one. The image is 256 x 104 this give more detail. if you have any questions please me.

new GuiBitmapButtonTextCtrl(Weapname) {
Profile = "GuiButtonProfile";
HorizSizing = "right";
VertSizing = "top";
Position = "90 682";
Extent = "128 38";
MinExtent = "8 2";
Visible = "1";
text = "Weapon Name";
groupNum = "-1";
buttonType = "PushButton";
bitmap = "./myAmmo/button"; // replace the path with yours
};
new GuiBitmapCtrl(Weapimage) {
Profile = "GuiDefaultProfile";
HorizSizing = "right";
VertSizing = "top";
Position = "120 614";
Extent = "72 55";
MinExtent = "8 2";
Visible = "1";
bitmap = "~/data/shapes/AssaultRifle/preview.png"; // replace the path with yours
wrap = "0";
};
new GuiBitmapButtonTextCtrl(AmmoAmount) {
Profile = "GuiButtonProfile";
HorizSizing = "right";
VertSizing = "top";
Position = "120 706";
Extent = "128 38";
MinExtent = "8 2";
Visible = "1";
text = "Ammo: 50";
groupNum = "-1";
buttonType = "PushButton";
bitmap = "./myAmmo/button"; // replace the path with yours
};
new GuiTextCtrl(CDTime) {
Profile = "GuiDefaultProfile";
HorizSizing = "left";
VertSizing = "bottom";
Position = "614 2";
Extent = "142 24";
MinExtent = "8 2";
Visible = "1";
text = "00:00";
maxLength = "255";
helpTag = "0";
};
#3
07/04/2006 (6:32 am)
Ive been working all weekend on my own system. Going to scrap that and Try this.

Thanks so much
#4
07/04/2006 (11:44 am)
I was going to start on a system tomorrow, this has saved me a lot of time, Thanks :)
Edit: This resource is one of the buggiest I have ever come across, will be posting changes soon
Edit: Still getting these
DawnOfMen/server/scripts/weapon.cs (481): Unable to find object: '' attempting to call function 'setAmmoAmountHud'
DawnOfMen/server/scripts/weapon.cs (506): Unable to find object: '' attempting to call function 'setAmmoAmountHud'
Yet Another Edit: It works fine now but those errors still plague my log and im out of ideas
#5
07/04/2006 (12:35 pm)
Use this instead:
function doSomething(%val)
{
   if (%val == 1 && $ZoomOn $= "true")
   commandtoserver('holdbreath',%val);
   else 
   if(%val == 0 && $ZoomOn $= "true")
   commandtoserver('holdbreath',%val);
}
#6
07/04/2006 (12:48 pm)
%this.setAmmoAmountHud("0");
	%this.setweapHud("");
	%this.setweappHud("");
in function GameConnection::onClientEnterGame(%this) otherwise you get a syntax error
#7
11/21/2006 (4:16 pm)
A good resource
#8
09/11/2007 (5:54 pm)
Hello. I had some troubles using this resource in my project (see here for details).
I uploaded a patch to apply on a clean 1.4.2 TGE install on my website here, and I left this resource's code commented out.
Can you give me some hints on what I done wrong? Thanks in advance for anything.

Bye, Berserk.
.
#9
02/02/2010 (10:43 pm)
Hello everyone. I am having trouble with this.
I have gotten everything to compile and run but when I hit the zoom key, keys, it will not zoom in and I do not get any console errors.

Any tips?

Thanks