Game Development Community

dev|Pro Game Development Curriculum

Certain Weapon Zoom with Individual Scope HUDs

by Chris Byars · 08/07/2005 (1:05 am) · 46 comments

Today you get to learn how to make only certain weapons be able to zoom, and to cause a unique scope HUD to be visible for each. This resource was made possible by the contributions of Matt Sanders, Harold "LabRat" Brown, and hours of banging heads on desks getting the code to function exactly as we wished.

To begin, create a new script file called zoom.cs and place it in yourgame/server/scripts/. Put the following code in it:

function serverCmdCallZoomFunction( %client, %val )
{
   %zoomer = %client.getControlObject();
   %curWeapon = %zoomer.getMountedImage($WeaponSlot).item.getName();
   commandToClient(%client,'ZoomInDaBiatch',%val,%curWeapon);
}

Open up /server/scripts/game.cs and add this in with the rest of the execute script commands:

exec("./zoom.cs");

We're done with the server side part of things. Now open up /client/scripts/default.bind.cs and under "Zoom and FOV functions", replace everything there with the following.

if($Pref::player::CurrentFOV $= "")
   $Pref::player::CurrentFOV = 45;

function clientCmdZoomInDaBiatch( %val, %curWeapon )
{
   if ( %val && %curWeapon $= "XM8" )
   {
      $ZoomOn = true;
      setFov( $Pref::player::CurrentFOV );
      ScopeGuiGroup1.Visible = 1; // Show XM8 Scope HUD
      Crosshair.Visible = 0; // Hide Crosshair
   }
   else if ( %val && %curWeapon $= "sniperrifle" )
   {
      $ZoomOn = true;
      setFov( $Pref::player::CurrentFOV );
      ScopeGuiGroup2.Visible = 1; // Show Sniper Rifle Scope HUD
      Crosshair.Visible = 0; // Hide Crosshair
   }
   else
   {
      $ZoomOn = false;
      setFov( $Pref::player::DefaultFov );
      ScopeGuiGroup1.Visible = 0; // Make XM8 Scope HUD Invisible
      ScopeGuiGroup2.Visible = 0; //Make Sniper Rifle Scope HUD Invisible
      Crosshair.Visible = 1; // Show crosshair
   }
}

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

moveMap.bind(mouse, mouse2, toggleZoom);

Be sure to change "XM8" and "sniperrifle" to the weapon names you want to zoom. What the above script does, is when you press the right-mouse button (mouse2, which you can change to whatever you wish in your options GUI), it calls the zoom function, which then makes sure you are in 1st person, checks what the client's current weapon is, and performs the zoom function and set's the scope HUD group visible that is specified for the current weapon. If you only want to have one weapon be able to zoom, simply remove this part of the script:

else if ( %val && %curWeapon $= "sniperrifle" )
   {
      $ZoomOn = true;
      setFov( $Pref::player::CurrentFOV );
      ScopeGuiGroup2.Visible = 1; // Show Sniper Rifle Scope HUD
      Crosshair.Visible = 0; // Hide Crosshair
   }

Likewise, if you want more than two weapons to zoom, add another of the above code block, and change the %curWeapon $= "" to the weapon of addition. If you want it to use another HUD, change the ScopeGuiGroup1 to your new GUI group's name. Where are all these GUI groups, you say? We'll get to that in a few moments.

You will want to now go into /client/prefs.cs and change the CurrentFOV preference to the zoom distance you want, it is the zoom in power. I happen to like 8x, so mine is set to 11.25.

$Pref::player::CurrentFOV = 11.25;

2x = 45
3x = 30
4x = 22.5
5x = 18
6x = 15
7x = 12.86
8x = 11.25

Now on to the GUI groups, the Scope HUDs. First, download the Sniper Scope image and place it in /client/ui/.

To get this to appear when you zoom in, we will be opening /client/ui/playGui.gui for modification. Add the following scripts somewhere under the new GameTSCtrl(PlayGui) { block of code, and be sure they are indented correctly, to reflect the GUI tree.

new GuiControl(ScopeGuiGroup1) {
      profile = "GuiDefaultProfile";
      horizSizing = "width";
      vertSizing = "height";
      position = "0 0";
      extent = "1024 768";
      minExtent = "8 8";
      visible = "0";

      new GuiBitmapCtrl() {
         profile = "GuiDefaultProfile";
         horizSizing = "relative";
         vertSizing = "relative";
         position = "0 0";
         extent = "1024 768";
         minExtent = "8 8";
         visible = "1";
         bitmap = "./sniperscope";
         wrap = "0";
            helpTag = "0";
      };
   };
   new GuiControl(ScopeGuiGroup2) {
      profile = "GuiDefaultProfile";
      horizSizing = "width";
      vertSizing = "height";
      position = "0 0";
      extent = "1024 768";
      minExtent = "8 8";
      visible = "0";

      new GuiBitmapCtrl() {
         profile = "GuiDefaultProfile";
         horizSizing = "relative";
         vertSizing = "relative";
         position = "0 0";
         extent = "1024 768";
         minExtent = "8 8";
         visible = "1";
         bitmap = "./sniperscope";
         wrap = "0";
            helpTag = "0";
      };
   };

Those two GuiBitmapCtrls control the bitmap that will be displayed for each GUI Group. Both are set to the sniperscope.png image currently, but if you will probably want to change one of them; after all, you're supposed to be able to have each weapon have unique scoping HUDs, with this resource. After doing the above additions/changes, the weapons you set to zoom, should now zoom correctly.

Now you don't want a player to be able to switch to 3rd person while zooming, so open up /client/scripts/default.bind.cs again and look for the toggleFirstPerson(%val) function, and replace it with the following.

function toggleFirstPerson(%val)
{
   if (%val && $ZoomOn != true)
   {
      $firstPerson = !$firstPerson;
   }
}

For some more exploit protection, you don't want a player to be able to switch weapons while they are zooming, otherwise they'll be able to use the zoom and scope for weapons unspecified. So if you are using the Weapon Cycling resource and/or have weapons set to be used when you hit a number on the keyboard, you'll want to do the following.

Open up /server/scripts/inventory.cs and replace the function ShapeBase::use(%this,%data) with the code below:

function ShapeBase::use(%this,%data)
{
   if ( $ZoomOn $= false )
   {
   // Use an object in the inventory.
      if (%this.getInventory(%data) > 0)
         return %data.onUse(%this);
      return false;
   }
}

And now, if you are using the Weapon Cycling resource (which I highly suggest using), you will want to also want to find your serverCmdCycleWeapon function in inventory.cs, and replace it with the following:

function serverCmdCycleWeapon( %client, %data )
{
   if ( $ZoomOn $= false )
      {
         %client.getControlObject().cycleWeapon( %data );
      }
}

There. So now you have a way to make certain weapons able to use a zoom function, and each weapon can have its own HUD plastered on the screen while you zoom. And it cannot be exploited by using items/weapons or cycling weapons while the zoom is on. If you have any problems (hope not), go ahead and post a comment.

Enjoy the power of zoom.
#21
01/21/2006 (7:30 am)
Thanks. :)
#22
03/19/2006 (11:12 am)
I made a slight change to this that I thought people might find useful. It goes along with Tim's ability to scroll through zoom levels. I use 'q' to start my zoom and 'e' to change my zoom level. The changes needed are quite simple.

I added a variable- $zoomLevel, to hold the current level of zoom.

from there I changed this:
setFov( $Pref::player::CurrentFOV );

to this:
setFov( $pref::Player::defaultFov / $zoomLevel );

I then wrote the following function and bound it to the 'e' key:
function zoomLev(%val)
{
	if(%val){
		if ($zoomLevel == "8") 
		{
			$zoomLevel = "2";
		}
		else
		{
			$zoomLevel++;
		}
		echo("Zoom Level: " @ $zoomLevel);
	
		if ($ZoomOn == "true")
		{
			setFov( $pref::Player::defaultFov / $zoomLevel );
		}
	}

}

K
#23
03/20/2006 (3:58 am)
I was able to make the zoom toggle on/off by hitting the zoom button, rather than having the need to hold it down the entire time you want to zoom:

function clientCmdZoomInDaBiatch( %val, %curWeapon )
{
   if ( %val && %curWeapon $= "XM8" )
   {
      $ZoomOn = !$ZoomOn;

      if ($ZoomOn)
         setFov(15);
      else
         setFov($Pref::player::DefaultFov);

      ScopeGuiGroup.setVisible($ZoomOn); // show crosshair for zoom
      Crosshair.setVisible(!$ZoomOn); // hide crosshair
   }
   else if ( %val && %curWeapon $= "sniperRifle" )
   {
      $ZoomOn = !$ZoomOn;

      if ($ZoomOn)
         setFov(11.25);
      else
         setFov($Pref::player::DefaultFov);

      SniperGuiGroup.setVisible($ZoomOn); // show GUI for zoom
      Crosshair.setVisible(!$ZoomOn); // hide crosshair
   }
   else
   {
      if ( !$ZoomOn )
      {
      setFov( $Pref::player::DefaultFov );
      }
      else
      {
      }
   }
}
#24
08/02/2006 (12:14 pm)
C2, after implementing the toggle thing, i cant get the sniper scope image to appear., also before it didnt proberly align with the middle, how do i correct these things?

especially the first one?

also, shouldnt this:
ScopeGuiGroup.setVisible($ZoomOn); // show crosshair for zoom
Crosshair.setVisible(!$ZoomOn); // hide crosshair

be this?
ScopeGuiGroup1.setVisible($ZoomOn); // show crosshair for zoom//scopegui group 1
Crosshair.setVisible(!$ZoomOn); // hide crosshair
#25
08/02/2006 (12:20 pm)
Yes, your correction is right. Also, just change "SniperGuiGroup" to "ScopeGuiGroup2" and it should appear.
#26
08/02/2006 (3:13 pm)
i have them correct, however i cant get the scope image to appear.

is this wrong?
//-----scope
   new GuiControl(ScopeGuiGroup2) {
      profile = "GuiDefaultProfile";
      horizSizing = "width";
      vertSizing = "height";
      position = "0 0";
      extent = "1024 768";
      minExtent = "8 8";
      visible = "0";

      new GuiBitmapCtrl() {
         profile = "GuiDefaultProfile";
         horizSizing = "relative";
         vertSizing = "relative";
         position = "0 0";
         extent = "1024 768";
        minExtent = "8 8";
         visible = "1";
         bitmap = "./sniperscope";
         wrap = "0";
            helpTag = "0";
      };
   };

and

if ( %val && %curWeapon $= "Crossbow" )
   {
      $ZoomOn = !$ZoomOn;

      if ($ZoomOn)
      {   setFov( $pref::Player::defaultFov / $zoomLevel );
      }
      else
      {
      setFov($Pref::player::DefaultFov);
      ScopeGuiGroup2.setVisible($ZoomOn); // show crosshair for zoom
      Crosshair.setVisible(!$ZoomOn); // hide crosshair
      }
   }
#27
08/02/2006 (3:55 pm)
Make the second code block like this:

if ( %val && %curWeapon $= "Crossbow" )
{
      $ZoomOn = !$ZoomOn;
      if ($ZoomOn)
      {
         setFov( $pref::Player::defaultFov / $zoomLevel );
      }
      else
      {
         setFov($Pref::player::DefaultFov);
      }
      ScopeGuiGroup2.setVisible($ZoomOn); // Show Sniper Scope HUD
      Crosshair.setVisible(!$ZoomOn); // Hide crosshair if zoom is on
}
#28
08/22/2006 (1:57 pm)
Can the original resource not be edited to fit what works? Does the original work as it stands? I am unable to get this resource working. It not only is not working but stops ALL of my weapons from firing.
#29
08/23/2006 (6:34 pm)
I keep getting these errors and I followed the above resource to a "T". The suggestions listed below the resource...are they a requirment to getting the zoom funtion to work??? here are the errors---

//---Begine Errors-----
keyboard0 input device unacquired.
keyboard0 input device acquired.
Mapping string: CallZoomFunction to index: 5
Mapping string: ZoomInDaBiatch to index: 15
keyboard0 input device unacquired.
keyboard0 input device acquired.
serverCmduse: Unknown command.
keyboard0 input device unacquired.
keyboard0 input device acquired.
serverCmduse: Unknown command.
serverCmduse: Unknown command.
serverCmduse: Unknown command.
serverCmduse: Unknown command.
keyboard0 input device unacquired.
//---end errors------

These errors show up when I try to use the zoom funtion. The zoom.cs file compiles just fine in the log. No known errors in the log. But, it won't let me select my sniper rifle. PLEASE HELP!! If I had hair I would be pulling it out!!! :)
#30
08/29/2006 (12:12 pm)
a quick question!

can the zoom be like confint to a box? what i mean is that the entire hud is normal, and when zoomed, around the crosshair a box appears with the new zoom level., know what i mean?

how would one do this?
#31
08/29/2006 (2:58 pm)
@David: Resource works fine as written. Comments are optional.

@Andrew: Those errors are unrelated, there are no "use" commands sent to the server in this resource, that's your use weapon code.

@Tom: You'd have to render a second view at the higher FoV. Takes C++ work and doubles the rendering cost, lowering framerate.
#32
10/23/2006 (5:12 am)
I am wondering if there is a way I could hide the weapon image when I am zoomed? I have a large weapon that can be seen in the sights when I zoom.
#33
10/24/2006 (7:15 am)
Of course. How I do it is I use iron sights scripts in order to realign the weapon image so that it is not in the view through the scope (on my sniper rifle). I set it to be aligned centered so you see the muzzle effects, but far enough back so that the camera does not see it.
#34
10/30/2006 (6:52 pm)
I have a slightly different take on this, or shall we say slightly different hack. You may find it a bit more flexible.

//--------------------------------------------------------------------------
// Server

datablock ItemData(Crossbow)
{
   // Mission editor category
   category = "Weapon";

   // Hook into Item Weapon class hierarchy. The weapon namespace
   // provides common weapon handling functions in addition to hooks
   // into the inventory system.
   className = "Weapon";

   // Basic Item properties
   shapeFile = "~/data/shapes/crossbow/weapon.dts";
   mass = 1;
   elasticity = 0.2;
   friction = 0.6;
   emap = true;

   // Dynamic properties defined by the scripts
   pickUpName = "a crossbow";
   zoomReticle = 'sniperscope.png'; // Assign a reticule for zooming
   image = CrossbowImage;
};

function serverCmdgetZoomReticle(%client)
{
   %player = %client.player;
      %weapon = (%player.getMountedImage($WeaponSlot) == 0 ) ? "" : %player.getMountedImage($WeaponSlot).item;
      %reticle = %weapon $= "" ? 'Binonoculars.png' : %weapon.zoomReticle;
   commandToClient( %client, 'setZoom', %reticle );
}

//--------------------------------------------------------------------------
// Client

   new GuiCrossHairHud(reticle) { // Default crosshair, give it a name
      profile = "GuiDefaultProfile";
      horizSizing = "center";
      vertSizing = "center";
      position = "304 224";
      extent = "32 32";
      minExtent = "8 8";
      visible = "1";
      helpTag = "0";
      bitmap = "./crossHair";
      wrap = "0";
      damageFillColor = "0.000000 1.000000 0.000000 1.000000";
      damageFrameColor = "1.000000 0.600000 0.000000 1.000000";
      damageRect = "50 4";
      damageOffset = "0 10";
   };
   new GuiCrossHairHud(zoomReticle) { // Add crosshair for zoom
      profile = "GuiDefaultProfile";
      horizSizing = "center";
      vertSizing = "center";
      position = "304 224";
      extent = "32 32";
      minExtent = "8 8";
      visible = "0"; // Hidden by default
      helpTag = "0";
      bitmap = "./sniperscope";
      wrap = "0";
      damageFillColor = "0.000000 1.000000 0.000000 1.000000";
      damageFrameColor = "1.000000 0.600000 0.000000 1.000000";
      damageRect = "50 4";
      damageOffset = "0 10";
   };

if($Pref::player::CurrentFOV $= "")
   $Pref::player::CurrentFOV = 45;

function setZoomFOV(%val)
{
   if ( %val )
      toggleZoomFOV();
}

function clientCmdsetZoom(%reticle)
{
   $ZoomOn = true;
   setFov( $Pref::player::CurrentFOV );
   zoomReticle.setBitmap( "common/data/textures/zoomrets/" @ deTag( %reticle ) );
   reticle.setVisible(false);
   zoomReticle.setVisible(true);
}

function toggleZoomFOV()
{
   if ( $ZoomLevel >= 9 )
      $ZoomLevel = 2;
   else
      $ZoomLevel++;

   if ( $ZoomOn )
      setFov( $pref::Player::currentFov / $ZoomLevel );
   else
      setFov( $pref::player::Fov ); 
}

function toggleZoom(%val)
{
   if ( $pref::player::stickyZoom ) // Set this varible however you wish
   {
      if ( %val )
      {
         if ( !$ZoomOn )
            commandToServer('getZoomReticle');
         else
         {
            $ZoomOn = false;
            setFov( $Pref::player::Fov );
            reticle.setVisible(true);
            zoomReticle.setVisible(false);
         }
      }
   }
   else
   {
      if ( %val )
      {
         if ( !$ZoomOn )
            commandToServer('getZoomReticle');
      }
      else
      {
         $ZoomOn = false;
         setFov( $Pref::player::Fov );
         reticle.setVisible(true);
         zoomReticle.setVisible(false);
      }
   }
}

moveMap.bind( keyboard, r, setZoomFOV );
moveMap.bind( keyboard, e, toggleZoom );
#35
01/18/2007 (12:12 pm)
Great resource
@Zod

I ended up using your code for my version of the scope.

Thanks
#36
12/27/2007 (9:25 pm)
Couple Notes:

The keybind for the right mouse click has changed, for TGEA.
OLD:
moveMap.bind(mouse, mouse2, toggleZoom);

NEW:
moveMap.bind(mouse0, "button1", toggleZoom);

To get the scope png to show up in the center, for people playing at resolutions other than 1024x768

new GuiControl(ScopeGuiGroup1) {
profile = "GuiDefaultProfile";
horizSizing = "width"; //change to "center"
vertSizing = "height"; // change to "center"
position = "0 0";
extent = "1024 768";
minExtent = "8 8";
visible = "0";
new GuiBitmapCtrl() {
...
#37
12/27/2007 (9:33 pm)
Oh yeah, by the way, in order for keybinding changes to take effect (for certain).

rename the (starter.fps)\client\config.cs (or just delete it, if you trust your changes...hehe...)

Start the game
Launch a mission
Close the game
Re-launch game.
Launch a mission
Check keybindings.

(Why do you have to do that?)
Because the config file is loaded when you start the game.
Changes are made when the default.bind.cs is run
Changes are not saved until game is shut down (properly)
New changes don't take effect until the game engine reads the config file again (on game load).
#38
02/16/2008 (10:07 pm)
thanks for that info william i was just having problems porting into tgea
#39
12/14/2008 (11:54 am)
hi all,
got this to work in tgea 1.7.1,
but one problem:
I use the cycle weapon resource, but cant cycle weapons until I use the zoom. once I use zoom on the default weapon, I can cycle through my weapons and zoom and all,
but without using zoom one time, I cant cycle weapons at all.

any ideas why??

its becoming a frustration now.
#40
03/21/2009 (5:15 pm)
The scope .png file link appears to be broken.


I would make my own but have no idea what the parameters are...

Can any enlighten me as to what the scope PNG file should be ( ie size,dimensions etc ?)

thanks