AMX Mod X Plugin Approver
|

01-06-2012
, 16:07
[TUT] Custom Weapon Hud Sprites + Slot Redirection
|
#1
|
Custom Weapon Hud Sprites + Slot Redirection
Updated January 6th, 2012

Ever wanted to show your new weapon in the hud ?
It's actually and surprisely easy to show a new sprite.
The following method have these features :
- Can change few sprites types - weapon, weapon_s (select), ammo, crosshair, zoom
- Can redirect slots - you can decide how to arrange your weapons list
- Dynamic - you don't need to restart, waiting, or something
- Per player - you can handle new weapons per player with conditions
The drawbacks are :
- Must be based on an original weapon - Meaning you replace an existing weapon, you can't add
- Therefore you can have only 29 new weapons at once - which is actually good and you could handle different set of weapons per player
- Slot redirection might not work always properly - Discovered while writing the tutorial, it doesn't work well
I wanted to wait by making an API before posting, but that's not really useful. Though, I will do it, some people may find that useful.
Such functionnality would deserve to be integrated in a plugin which manages custom weapon, like WeaponMod, so for each new weapon, an original weapon is distribuated to be used as replacement.
Purpose would be to avoid multiples plugins using different method for creating a new weapon, using the same original weapon.
Important : While writing the tutorial and testing, I've noticed the slot redirection doesn't work well for all weapons. For example, ak47 doesn't like to be redirected, or knife doesn't want to go on slot 1/2. I have no idea why, still need to be figured out. I have not tested much and don't have much time, so it will be up to you people to give feebacks and therefore improving the way of altering hud. Even without the redirection, you might encounter issues. Please understand that's something which would be needed to test. I've posted even though I'm not sure it will work properly all the time, for the sake of knowledge and because the more people looks at that, the better chance to get a more robust method.
Please keep in mind the tutorial has the purpose only for now to show the basis of the method.
Contents :
How it works ? top
The main key is the game event : WeaponList.
This message basically configures the hud weapon list.
That's something you should send with the right values when a weapon is added to the player's inventory.
Values you can find here.
The structure looks like :
Code:
string WeaponName
byte PrimaryAmmoID
byte PrimaryAmmoMaxAmount
byte SecondaryAmmoID
byte SecondaryAmmoMaxAmount
byte SlotID
byte NumberInSlot
byte WeaponID
byte Flags
The second key is WeaponName and SlotID.
The first argument is used for example when you select a weapon, it's the same as entering in the console the weapon name.
It's there you change it by your new weapon name, like weapon_flare.
To select the weapon, you will need to hook this weapon name in order to redirect it to the original weapon.
The latter argument will help you to change the slot of a weapon.
It will need some extra code to work properly. The third key is the first argument which refers also to the file named weapon_*.txt (* = name) in the /sprites directory.
It contains the sprites to use for each types.
A full list of types would be : weapon, weapon_s, ammo, ammo2, autoaim, crosshair, zoom, zoom_aim.
(Though I'm not sure ammo2, autoaim or zoom_aim could be used.)
So, in this file you can define your new sprites.
Here the format of such file :
Code:
numberOfSprites
<type> <resolution> <spriteFile> <shiftX> <shiftY> <width> <height>
...
Example with weapon_knife.txt :
Code:
10
weapon 320 320hud1 0 0 80 20
weapon_s 320 320hud1 0 20 80 20
ammo 320 320hud2 0 16 18 18
crosshair 320 crosshairs 24 0 24 24
autoaim 320 crosshairs 0 72 24 24
weapon 640 640hud10 0 135 170 45
weapon_s 640 640hud11 0 135 170 45
ammo 640 640hud7 0 72 24 24
crosshair 640 crosshairs 24 0 24 24
autoaim 640 crosshairs 0 72 24 24
I think it's self-explanatory. Just look at a sprite file and see. The fourth key is to precache the required files.
Both .txt and .spr/.tga files are needed on the client.
They can be precached without problem using precache_generic().
Don't hesitate to make elaborate name for the weapon name, so file will be somewhow unique.
Because if there is another plugin using the same weapon name, the existing file on the client won't be overwrite.
Also, for the sprites, you may want to create custom folders.
Coding example in steps top
Let's say you want to replace the knife with a flare, and you want to change its slot too.
So, you have a weapon_ArkFlare.txt file with as content :
Code:
2
weapon 640 640hud19 0 0 170 45
weapon_s 640 640hud20 0 0 170 45
It will use sprites/640hud19.spr and sprites/640hud20.spr files.

Precaching your files topAll you need is to make the client downloading the files. That's precache_generic is used.
Code:
public plugin_precache()
{
precache_generic( "sprites/weapon_ArkFlare.txt" );
precache_generic( "sprites/640hud19.spr" );
precache_generic( "sprites/640hud20.spr" );
}
Hooking when player got a weapon top
We need to hook when a player gets a knife.
So, we can send a WeaponList message to tell the client to use "weapon_ArkFlare".
We can the use forward Ham_Item_AddToPlayer for that.
Code:
RegisterHam( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", .Post = true );
Then we can send our message.
Code:
new MsgIndexWeaponList;
public plugin_init ()
{
RegisterHam ( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", . Post = true );
MsgIndexWeaponList = get_user_msgid( "WeaponList" );
}
public OnAddToPlayerKnife ( const item, const player )
{
if( pev_valid ( item ) && is_user_alive( player ) ) // just for safety.
{
message_begin( MSG_ONE, MsgIndexWeaponList, . player = player );
{
write_string( "weapon_ArkFlare" ); // WeaponName write_byte( -1 ); // PrimaryAmmoID
write_byte( -1 ); // PrimaryAmmoMaxAmount
write_byte( -1 ); // SecondaryAmmoID
write_byte( -1 ); // SecondaryAmmoMaxAmount
write_byte( 2 ); // SlotID (0...N)
write_byte( 1 ); // NumberInSlot (1...N)
write_byte( CSW_KNIFE ); // WeaponID
write_byte( 0 ); // Flags
}
message_end();
}
}
Result :

Hooking when player got a weapon and redirecting a slot top
More or less the same code. You would need to modify the slot in the message.
Also, hooking Ham_Item_ItemSlot because the values stored in CKnife::GetItemInfo() function
are not changed and when ItemSlot() will be called, it will return the original value. Therefore we
need to change the return value.
Code:
RegisterHam( Ham_Item_ItemSlot, "weapon_knife", "OnItemSlotKnife" );
Let's say we want to redirect slot to the 5th.
Be careful, slot value in the message starts from 0, while in ItemSlot from 1.
Code:
new MsgIndexWeaponList;
public plugin_init ()
{
RegisterHam ( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", . Post = true );
RegisterHam ( Ham_Item_ItemSlot, "weapon_knife", "OnItemSlotKnife" );
MsgIndexWeaponList = get_user_msgid( "WeaponList" );
}
public OnAddToPlayerKnife ( const item, const player )
{
if( pev_valid ( item ) && is_user_alive( player ) ) // just for safety.
{
message_begin( MSG_ONE, MsgIndexWeaponList, . player = player );
{
write_string( "weapon_ArkFlare" ); // WeaponName write_byte( -1 ); // PrimaryAmmoID
write_byte( -1 ); // PrimaryAmmoMaxAmount
write_byte( -1 ); // SecondaryAmmoID
write_byte( -1 ); // SecondaryAmmoMaxAmount
write_byte( 4 ); // SlotID (0...N) <== Changed here (was 2) write_byte( 1 ); // NumberInSlot (1...N)
write_byte( CSW_KNIFE ); // WeaponID
write_byte( 0 ); // Flags
}
message_end();
}
}
public OnItemSlotKnife ( const item )
{
SetHamReturnInteger( 5 ); return HAM_SUPERCEDE;
}
Result :

Hooking weapon selection top
Now, you have changed the weapon name, you would need to hook when you select it.
The reason is when you will tell the client you select this weapon, "weapon_ArkFlare" will be used.
Which means you won't be able to select it since such weapon name is not known.
Solution is simple : hooking the weapon name and redirecting to the original name.
Code:
public plugin_init()
{
register_clcmd( "weapon_ArkFlare", "ClientCommand_SelectFlare" );
}
public ClientCommand_SelectFlare( const client )
{
engclient_cmd( client, "weapon_knife" );
}
Full code of the example top
As it is, it would be really a basic example.
Purpose was to show you only the way without any elaborated code.
PHP Code:
#include <amxmodx>
#include <hamsandwich>
#include <fakemeta>
new MsgIndexWeaponList;
public plugin_precache()
{
precache_generic( "sprites/weapon_ArkFlare.txt" );
precache_generic( "sprites/640hud19.spr" );
precache_generic( "sprites/640hud20.spr" );
}
public plugin_init()
{
RegisterHam( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", .Post = true );
RegisterHam( Ham_Item_ItemSlot, "weapon_knife", "OnItemSlotKnife" );
register_clcmd( "weapon_ArkFlare", "ClientCommand_SelectFlare" );
MsgIndexWeaponList = get_user_msgid( "WeaponList" );
}
public ClientCommand_SelectFlare( const client )
{
engclient_cmd( client, "weapon_knife" );
}
public OnAddToPlayerKnife( const item, const player )
{
if( pev_valid( item ) && is_user_alive( player ) ) // just for safety.
{
message_begin( MSG_ONE, MsgIndexWeaponList, .player = player );
{
write_string( "weapon_ArkFlare" ); // WeaponName
write_byte( -1 ); // PrimaryAmmoID
write_byte( -1 ); // PrimaryAmmoMaxAmount
write_byte( -1 ); // SecondaryAmmoID
write_byte( -1 ); // SecondaryAmmoMaxAmount
write_byte( 4 ); // SlotID (0...N)
write_byte( 1 ); // NumberInSlot (1...N)
write_byte( CSW_KNIFE ); // WeaponID
write_byte( 0 ); // Flags
}
message_end();
}
}
public OnItemSlotKnife( const item )
{
SetHamReturnInteger( 5 );
return HAM_SUPERCEDE;
}
Advanced examples top
Coming... Probably. API top
Coming... Probably.
__________________
Last edited by Arkshine; 01-06-2012 at 17:20.
|
|