An Ammo Change Script (based on Realm Wars)
by Harold "LabRat" Brown · in Torque Game Engine · 03/31/2002 (8:43 pm) · 15 replies
This script provides a way for you to have a weapon with multiple ammo types.
If you download the zip file you will need to extract it to your C:\GarageGames\RealmWars\rw directory with paths.
In the server/scripts/ folder:
Edit weapon.cs:
change the following line in the weapon::onUse function:
messageClient(%obj.client, 'MsgWeaponUsed', '\c0Weapon selected');
to:
messageClient(%obj.client, 'MsgWeaponUsed', '\c0Weapon selected',%data);
Edit player.cs add the following to the PlayerData datablock:
maxInv[CrossbowAmmo1] = 50;
maxInv[CrossbowAmmo2] = 50;
maxInv[CrossbowAmmo3] = 50;
Edit item.cs in Item::onPickup replace the following line:
%user.incInventory(%this,%count);
with this:
if (%this.className $= "Ammo") {
%weapon = %user.getMountedImage(0);
%user.incInventory($ammo[ %weapon.item, %user.cycleId[ %weapon.item ] ] ,%count);
%user.incInventory(%this,%count);
}
else {
%user.incInventory(%this,%count);
}
Edit inventory.cs add this line, in the shapebase::setInventory function:
messageClient(%this.client,'MsgInventory',"",%data.className,%data,%value);
before this line:
// Set the inventory amount for this datablock and invoke
edit game.cs in the GameConnection::onDeath after the following lines:
// Clear out the name on the corpse
%this.player.setShapeName("");
add this:
messageClient(%this,'MsgPlayerDied',"");
at the end of GameConnection::createPlayer add the following lines:
%player.setInventory(Crossbow,1);
%player.setInventory(CrossbowAmmo1,20);
%player.setInventory(CrossbowAmmo2,20);
%player.setInventory(CrossbowAmmo3,20);
%player.setInventory(CrossbowAmmo,20);
%player.use(Crossbow);
Edit crossbow.cs replace the following lines in CrossbowImage::onFire:
%projectile = %this.projectile;
// Decrement inventory ammo. The image's ammo state is update
// automatically by the ammo inventory hooks.
%obj.decInventory(%this.ammo,1);
with this:
%ammo=%obj.ammo[ %this.item ];
%projectile = %obj.projectile[%this.item];
// Decrement inventory ammo. The image's ammo state is update
// automatically by the ammo inventory hooks.
%obj.decInventory(%ammo,1);
%obj.decInventory(%this.ammo,1);
At the end of crossbow.cs add the following:
$projectile["crossbow",1] = CrossbowProjectile;
$projectile["crossbow",2] = CrossbowProjectile2;
$projectile["crossbow",3] = CrossbowProjectile3;
$ammo["crossbow",0] = CrossbowAmmo;
$ammo["crossbow",1] = CrossbowAmmo1;
$ammo["crossbow",2] = CrossbowAmmo2;
$ammo["crossbow",3] = CrossbowAmmo3;
function CrossbowImage::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.cycleId[%this.item]) {
%obj.projectile[%this.item] = $projectile[%this.item,1];
%obj.ammo[%this.item] = $ammo[%this.item,1];
%obj.cycleId[%this.item] = 1;
}
%obj.setInventory( $ammo[%weapon.item,0] , %obj.getInventory( $ammo[ %weapon.item, %obj.cycleId[ %weapon.item ] ] ) );
if (%obj.getInventory(%this.ammo))
%obj.setImageAmmo(%slot,true);
}
function serverCmdchangeammo(%client)
{
%weapon = %client.player.getMountedImage(0);
%client.player.cycleId[%weapon.item] = %client.player.cycleId[%weapon.item]+1;
if (%client.player.cycleId[%weapon.item] > 3) {
%client.player.cycleId[%weapon.item] = 1;
}
%client.player.setInventory( $ammo[%weapon.item,0] , %client.player.getInventory( $ammo[ %weapon.item, %client.player.cycleId[ %weapon.item ] ] ) );
%client.player.projectile[%weapon.item] = $projectile[%weapon.item,%client.player.cycleId[%weapon.item]];
%client.player.ammo[%weapon.item] = $ammo[%weapon.item,%client.player.cycleId[%weapon.item]];
messageClient(%client,'MsgAmmoChange',"",%client.player.ammo[%weapon.item]);
}
You will also need to create 3 new ammo definitions and 3 new projectile definitions (see samle file)
Next you will need to add a new file in the client/scripts/ folder named inventory.cs
addMessageCallback('MsgAmmoChange', handleAmmoChange);
addMessageCallback('MsgWeaponUsed', handleWeaponUsed);
addMessageCallback('MsgInventory', handleInventory);
addMessageCallback('MsgPlayerDied', handlePlayerDied);
function handleAmmoChange(%msgType, %msgString, %ammoType)
{
inventory.currentammo=%ammotype;
ammoInvBitmap.setBitmap("rw/client/ui/" @ %ammoType @ ".png");
ammoInvText.setText(inventory.itemAmmo_[%ammoType]);
}
function handleWeaponUsed(%msgType, %msgString, %weaponType)
{
inventory.currentweapon=%weapontype;
weaponInvBitmap.setBitmap("rw/client/ui/" @ %weaponType @ ".png");
weaponInvText.setText(inventory.currentweapon);
}
function handleInventory(%msgType, %msgString,%className, %item, %amount)
{
inventory.item[%className,%item]=%amount;
if (%classname $= "Ammo") {
if (inventory.currentammo $= "none") {
inventory.currentammo=%item;
}
ammoInvBitmap.setBitmap("rw/client/ui/" @ inventory.currentammo @ ".png");
ammoInvText.setText(inventory.itemAmmo_[inventory.currentammo]);
}
else if (%classname $= "Weapon") {
if (inventory.currentweapon $= "none") {
inventory.currentweapon=%item;
}
ammoInvBitmap.setBitmap("rw/client/ui/" @ inventory.currentweapon @ ".png");
ammoInvText.setText(inventory.itemWeapon_[inventory.currentweapon]);
}
}
function handlePlayerDied(%msgType, %msgString)
{
inventory.delete();
inventory::init();
}
function inventory::init() {
%inventory = new ScriptObject(inventory)
{
className = "Inventory";
};
inventory.currentammo = "none";
inventory.currentweapon = "none";
echo("Inventory: " SPC %inventory);
}
function changeammo(%val)
{
if(%val)
commandToServer('changeammo');
}
moveMap.bind(keyboard, "q", changeammo);
inventory::init();
Then create a file in the clien/ui/ folder named ammoInv.gui:
//--- OBJECT WRITE BEGIN ---
new GuiControl(ammoInv) {
profile = "GuiDefaultProfile";
horizSizing = "left";
vertSizing = "top";
position = "576 376";
extent = "64 104";
minExtent = "8 8";
visible = "1";
helpTag = "0";
new GuiBitmapCtrl(ammoInvBitmap) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 6";
extent = "64 64";
minExtent = "8 8";
visible = "1";
helpTag = "0";
bitmap = "";
wrap = "0";
};
new GuiTextCtrl(ammoInvText) {
profile = "HudTextProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "21 73";
extent = "25 23";
minExtent = "8 8";
visible = "1";
helpTag = "0";
text = "0";
maxLength = "4";
};
};
new GuiControl(weaponInv) {
profile = "GuiDefaultProfile";
horizSizing = "left";
vertSizing = "top";
position = "512 376";
extent = "64 104";
minExtent = "8 8";
visible = "1";
helpTag = "0";
new GuiBitmapCtrl(weaponInvBitmap) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 6";
extent = "64 64";
minExtent = "8 8";
visible = "1";
helpTag = "0";
bitmap = "";
wrap = "0";
};
new GuiTextCtrl(weaponInvText) {
profile = "HudTextProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 73";
extent = "64 23";
minExtent = "8 8";
visible = "1";
helpTag = "0";
text = "0";
maxLength = "4";
};
};
//--- OBJECT WRITE END ---
playgui.add(ammoInv);
playgui.add(weaponInv);
Edit client/init.cd add the following lines to the end of the initClient function:
exec("./ui/ammoInv.gui");
exec("./scripts/inventory.cs");
Finally you will need to add 4 images to your client/ui/ folder:
crossbow.png
crossbowammo1.png
crossbowammo2.png
crossbowammo3.png
To get the implementation of this download the realmwars.feylab.com/downloads/ammoswitch.zip file that includes this text and the files already edited.
If you download the zip file you will need to extract it to your C:\GarageGames\RealmWars\rw directory with paths.
In the server/scripts/ folder:
Edit weapon.cs:
change the following line in the weapon::onUse function:
messageClient(%obj.client, 'MsgWeaponUsed', '\c0Weapon selected');
to:
messageClient(%obj.client, 'MsgWeaponUsed', '\c0Weapon selected',%data);
Edit player.cs add the following to the PlayerData datablock:
maxInv[CrossbowAmmo1] = 50;
maxInv[CrossbowAmmo2] = 50;
maxInv[CrossbowAmmo3] = 50;
Edit item.cs in Item::onPickup replace the following line:
%user.incInventory(%this,%count);
with this:
if (%this.className $= "Ammo") {
%weapon = %user.getMountedImage(0);
%user.incInventory($ammo[ %weapon.item, %user.cycleId[ %weapon.item ] ] ,%count);
%user.incInventory(%this,%count);
}
else {
%user.incInventory(%this,%count);
}
Edit inventory.cs add this line, in the shapebase::setInventory function:
messageClient(%this.client,'MsgInventory',"",%data.className,%data,%value);
before this line:
// Set the inventory amount for this datablock and invoke
edit game.cs in the GameConnection::onDeath after the following lines:
// Clear out the name on the corpse
%this.player.setShapeName("");
add this:
messageClient(%this,'MsgPlayerDied',"");
at the end of GameConnection::createPlayer add the following lines:
%player.setInventory(Crossbow,1);
%player.setInventory(CrossbowAmmo1,20);
%player.setInventory(CrossbowAmmo2,20);
%player.setInventory(CrossbowAmmo3,20);
%player.setInventory(CrossbowAmmo,20);
%player.use(Crossbow);
Edit crossbow.cs replace the following lines in CrossbowImage::onFire:
%projectile = %this.projectile;
// Decrement inventory ammo. The image's ammo state is update
// automatically by the ammo inventory hooks.
%obj.decInventory(%this.ammo,1);
with this:
%ammo=%obj.ammo[ %this.item ];
%projectile = %obj.projectile[%this.item];
// Decrement inventory ammo. The image's ammo state is update
// automatically by the ammo inventory hooks.
%obj.decInventory(%ammo,1);
%obj.decInventory(%this.ammo,1);
At the end of crossbow.cs add the following:
$projectile["crossbow",1] = CrossbowProjectile;
$projectile["crossbow",2] = CrossbowProjectile2;
$projectile["crossbow",3] = CrossbowProjectile3;
$ammo["crossbow",0] = CrossbowAmmo;
$ammo["crossbow",1] = CrossbowAmmo1;
$ammo["crossbow",2] = CrossbowAmmo2;
$ammo["crossbow",3] = CrossbowAmmo3;
function CrossbowImage::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.cycleId[%this.item]) {
%obj.projectile[%this.item] = $projectile[%this.item,1];
%obj.ammo[%this.item] = $ammo[%this.item,1];
%obj.cycleId[%this.item] = 1;
}
%obj.setInventory( $ammo[%weapon.item,0] , %obj.getInventory( $ammo[ %weapon.item, %obj.cycleId[ %weapon.item ] ] ) );
if (%obj.getInventory(%this.ammo))
%obj.setImageAmmo(%slot,true);
}
function serverCmdchangeammo(%client)
{
%weapon = %client.player.getMountedImage(0);
%client.player.cycleId[%weapon.item] = %client.player.cycleId[%weapon.item]+1;
if (%client.player.cycleId[%weapon.item] > 3) {
%client.player.cycleId[%weapon.item] = 1;
}
%client.player.setInventory( $ammo[%weapon.item,0] , %client.player.getInventory( $ammo[ %weapon.item, %client.player.cycleId[ %weapon.item ] ] ) );
%client.player.projectile[%weapon.item] = $projectile[%weapon.item,%client.player.cycleId[%weapon.item]];
%client.player.ammo[%weapon.item] = $ammo[%weapon.item,%client.player.cycleId[%weapon.item]];
messageClient(%client,'MsgAmmoChange',"",%client.player.ammo[%weapon.item]);
}
You will also need to create 3 new ammo definitions and 3 new projectile definitions (see samle file)
Next you will need to add a new file in the client/scripts/ folder named inventory.cs
addMessageCallback('MsgAmmoChange', handleAmmoChange);
addMessageCallback('MsgWeaponUsed', handleWeaponUsed);
addMessageCallback('MsgInventory', handleInventory);
addMessageCallback('MsgPlayerDied', handlePlayerDied);
function handleAmmoChange(%msgType, %msgString, %ammoType)
{
inventory.currentammo=%ammotype;
ammoInvBitmap.setBitmap("rw/client/ui/" @ %ammoType @ ".png");
ammoInvText.setText(inventory.itemAmmo_[%ammoType]);
}
function handleWeaponUsed(%msgType, %msgString, %weaponType)
{
inventory.currentweapon=%weapontype;
weaponInvBitmap.setBitmap("rw/client/ui/" @ %weaponType @ ".png");
weaponInvText.setText(inventory.currentweapon);
}
function handleInventory(%msgType, %msgString,%className, %item, %amount)
{
inventory.item[%className,%item]=%amount;
if (%classname $= "Ammo") {
if (inventory.currentammo $= "none") {
inventory.currentammo=%item;
}
ammoInvBitmap.setBitmap("rw/client/ui/" @ inventory.currentammo @ ".png");
ammoInvText.setText(inventory.itemAmmo_[inventory.currentammo]);
}
else if (%classname $= "Weapon") {
if (inventory.currentweapon $= "none") {
inventory.currentweapon=%item;
}
ammoInvBitmap.setBitmap("rw/client/ui/" @ inventory.currentweapon @ ".png");
ammoInvText.setText(inventory.itemWeapon_[inventory.currentweapon]);
}
}
function handlePlayerDied(%msgType, %msgString)
{
inventory.delete();
inventory::init();
}
function inventory::init() {
%inventory = new ScriptObject(inventory)
{
className = "Inventory";
};
inventory.currentammo = "none";
inventory.currentweapon = "none";
echo("Inventory: " SPC %inventory);
}
function changeammo(%val)
{
if(%val)
commandToServer('changeammo');
}
moveMap.bind(keyboard, "q", changeammo);
inventory::init();
Then create a file in the clien/ui/ folder named ammoInv.gui:
//--- OBJECT WRITE BEGIN ---
new GuiControl(ammoInv) {
profile = "GuiDefaultProfile";
horizSizing = "left";
vertSizing = "top";
position = "576 376";
extent = "64 104";
minExtent = "8 8";
visible = "1";
helpTag = "0";
new GuiBitmapCtrl(ammoInvBitmap) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 6";
extent = "64 64";
minExtent = "8 8";
visible = "1";
helpTag = "0";
bitmap = "";
wrap = "0";
};
new GuiTextCtrl(ammoInvText) {
profile = "HudTextProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "21 73";
extent = "25 23";
minExtent = "8 8";
visible = "1";
helpTag = "0";
text = "0";
maxLength = "4";
};
};
new GuiControl(weaponInv) {
profile = "GuiDefaultProfile";
horizSizing = "left";
vertSizing = "top";
position = "512 376";
extent = "64 104";
minExtent = "8 8";
visible = "1";
helpTag = "0";
new GuiBitmapCtrl(weaponInvBitmap) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 6";
extent = "64 64";
minExtent = "8 8";
visible = "1";
helpTag = "0";
bitmap = "";
wrap = "0";
};
new GuiTextCtrl(weaponInvText) {
profile = "HudTextProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "0 73";
extent = "64 23";
minExtent = "8 8";
visible = "1";
helpTag = "0";
text = "0";
maxLength = "4";
};
};
//--- OBJECT WRITE END ---
playgui.add(ammoInv);
playgui.add(weaponInv);
Edit client/init.cd add the following lines to the end of the initClient function:
exec("./ui/ammoInv.gui");
exec("./scripts/inventory.cs");
Finally you will need to add 4 images to your client/ui/ folder:
crossbow.png
crossbowammo1.png
crossbowammo2.png
crossbowammo3.png
To get the implementation of this download the realmwars.feylab.com/downloads/ammoswitch.zip file that includes this text and the files already edited.
#2
04/01/2002 (1:57 pm)
Very
#3
I see there is a change ammo key "q".
How about using an alternate fire button for the different ammo types?
Like Unreal, Red Faction, etc (I know they only have two fire modes).
04/03/2002 (7:28 am)
First off - very cool.I see there is a change ammo key "q".
How about using an alternate fire button for the different ammo types?
Like Unreal, Red Faction, etc (I know they only have two fire modes).
#4
Not sure exactly what different modes of fire a crossbow could have... but in a traditional weapon like a rifle with a grenade launcher you could have:
single shot
three round burst
grenade launcher
Add in the ammo switch code and you have a weapon that can do all three fire modes plus you could have Armor Piercing rounds, change to tracers, explosive rounds, etc.
04/03/2002 (9:18 am)
Like you said that's for fire modes... which can also be added with a bit of scripting.Not sure exactly what different modes of fire a crossbow could have... but in a traditional weapon like a rifle with a grenade launcher you could have:
single shot
three round burst
grenade launcher
Add in the ammo switch code and you have a weapon that can do all three fire modes plus you could have Armor Piercing rounds, change to tracers, explosive rounds, etc.
#5
have it fire 3 bolts at a time.
have a (harder to find this ammo maybe?) bolt that can pierce harder???
04/07/2002 (9:27 pm)
alt fire ideas for crossbow:have it fire 3 bolts at a time.
have a (harder to find this ammo maybe?) bolt that can pierce harder???
#6
Your code works really well.
Just one question. Have you tried this with a second weapon? I added a second weapon and almost everything still works fine with switching between the two, using 3 projectile types for each one, and keeping track of the individual ammo counts, but I can't get the projectile display to update after the weapon switch during the onMount action. If I then switch ammo types ("q") it updates the projectile display to the correct new one, otherwise it leaves the last used projectile .png/ammo count of the previous weapon on the screen.
Any ideas?
04/08/2002 (6:01 am)
Harold,Your code works really well.
Just one question. Have you tried this with a second weapon? I added a second weapon and almost everything still works fine with switching between the two, using 3 projectile types for each one, and keeping track of the individual ammo counts, but I can't get the projectile display to update after the weapon switch during the onMount action. If I then switch ammo types ("q") it updates the projectile display to the correct new one, otherwise it leaves the last used projectile .png/ammo count of the previous weapon on the screen.
Any ideas?
#7
04/08/2002 (9:19 am)
I hadn't tried with a second weapon yet. I'll look into it sometime this week
#8
Below is a corrected version:
Basically the code had 2 problems. The first was in the setInventory line. I was using %weapon instead of %this. The second was I did not have a AmmoChange messege being sent to the client on weapon mount. This tends to make the whole thing less effective for multiple weapons with multiple ammoTypes.
04/09/2002 (12:19 am)
I found the problem area. It was in the onMount section of the code.Below is a corrected version:
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.cycleId[%this.item]) {
%obj.projectile[%this.item] = $projectile[%this.item,1];
%obj.ammo[%this.item] = $ammo[%this.item,1];
%obj.cycleId[%this.item] = 1;
}
%obj.setInventory( $ammo[%this.item,0] , %obj.getInventory( $ammo[ %this.item, %obj.cycleId[ %this.item ] ] ) );
messageClient(%obj.client,'MsgAmmoChange',"",%obj.ammo[%this.item]);
if (%obj.getInventory(%this.ammo))
%obj.setImageAmmo(%slot,true);
}Basically the code had 2 problems. The first was in the setInventory line. I was using %weapon instead of %this. The second was I did not have a AmmoChange messege being sent to the client on weapon mount. This tends to make the whole thing less effective for multiple weapons with multiple ammoTypes.
#9
I thought it had to do with the onMount function, but I still couldn't get it to work.
I tried adding the setInventory section, but didn't catch the %this and %weapon part. Makes sense now.
Thanks for the update.
04/09/2002 (5:30 am)
That was quick :)I thought it had to do with the onMount function, but I still couldn't get it to work.
I tried adding the setInventory section, but didn't catch the %this and %weapon part. Makes sense now.
Thanks for the update.
#10
04/11/2002 (9:08 am)
Ya know, there's a lot of times where multiple people are doin' the same thing here in the forums! Why do I mention this? Well, I was just gettin' ready to make a post about the multiple ammo types system I was workin' on for Trajectory. And I discovered this... sheesh! Someone already beat me to it! :-) Good work :-)
#11
It's always good to have different ideas posted :)
04/11/2002 (9:33 am)
Maybe yours is a little different.It's always good to have different ideas posted :)
#12
04/11/2002 (10:47 am)
True. But, after lookin' at his, I think his is better :-)
#13
04/11/2002 (11:12 am)
I have an advantage... I'm recreating things I'd done for Tribes and Tribes 2 as MOD's that I never released. I have a large number of "odd" things I had done after I stopped releasing MOD's.
#15
04/11/2002 (12:27 pm)
Heheh - well, I never even bought Tribes or Tribes 2. Played it a few times on someone else's machine. I licensed Torque because I thought both were pretty solid - but it means I'm learnin' the engine and scripting from scratch ;-) Heck, I've even gotta learn new mapping tools! (Always used UnrealED before :-P
Torque Owner Edward Gardner