I've seen many users ask how to create dynamic classes or items with sub-plugins like in Zombie Plague.
This tutorial will teach you just how to do that.
This tutorial is not for new users to AMXX scripting!
In this tutorial, you will need knowledge of:
new menu style
cellarrays
data structures (enum)
callfunc_* natives (aren't used in this but could be for more advanced API)
creating custom forwards
creating dynamic natives
For this tutorial, I'm going to use a "shop" for an example.
It will show a menu on spawn which contains the items.
Integration File (.inc):
Let's call it shop.inc:
Code: Select all
#if defined _shop_included
#endinput
#endif
#define _shop_includedFirst, you will need a custom library for this.
Let's call it "shop"
Code: Select all
#if AMXX_VERSION_NUM >= 175
#pragma reqlib shop
#if !defined AMXMODX_NOAUTOLOAD
#pragma loadlib shop
#endif
#else
#pragma library shop
#endifA function executed in the sub-plugin that sends data to the main plugin so the item is recognized.
A forward executed from the main plugin and is hooked in the sub-plugin to know when the item is selected.
If the sub-plugin is going to be an item, then you will need to pass all the information about the item into the function.
To keep it simple, we will only need:
item name
item cost
So, here is how our function would look.
Code: Select all
native shop_item_add( const szName[ ], const iCost );In the forward when the player selects the item, it will need to pass the player's index and the unique item index.
So, here is how the forward would look.
Code: Select all
forward shop_item_selected( iPlayer, iItemIndex );Code: Select all
#if defined _shop_included
#endinput
#endif
#define _shop_included
#if AMXX_VERSION_NUM >= 175
#pragma reqlib shop
#if !defined AMXMODX_NOAUTOLOAD
#pragma loadlib shop
#endif
#else
#pragma library shop
#endif
native shop_item_add( const szName[ ], const iCost );
forward shop_item_selected( iPlayer, iItemIndex );I commented the plugin very well.
If you have knowledge that was listed above, you should be able to understand everything with just the comments.
Code: Select all
#include < amxmodx >
#include < cstrike >
#include < hamsandwich >
// create the structure for each item
// we need the item name and cost
enum _:ItemData
{
ItemName[ 32 ],
ItemCost
};
// create a dynamic array to hold all the items
new Array:g_aItems;
// this will tell how many are in the array instead of using ArraySize()
new g_iTotalItems;
// create a forward for when player selects an item
new g_hSelectItemForward;
public plugin_init( )
{
// register player spawn to show the shop menu
RegisterHam( Ham_Spawn, "player", "FwdPlayerSpawnPost", 1 );
// create our array with the size of the item structure
g_aItems = ArrayCreate( ItemData );
// create our forward
g_hSelectItemForward = CreateMultiForward( "shop_item_selected", ET_IGNORE, FP_CELL, FP_CELL );
}
public plugin_natives( )
{
// register our custom library
register_library( "shop" );
// create a native to allow other plugins to add items
register_native( "shop_item_add", "_item_add" );
}
public _item_add( iPlugin, iParams )
{
// create an array to hold our item data
new eItemData[ ItemData ];
// get item name from function
get_string( 1, eItemData[ ItemName ], charsmax( eItemData[ ItemName ] ) );
// get item cost from function
eItemData[ ItemCost ] = get_param( 2 );
// add item to array and increase size
ArrayPushArray( g_aItems, eItemData );
g_iTotalItems++;
// return the index of this item in the array
// this creates the unique item index
return ( g_iTotalItems - 1 );
}
public FwdPlayerSpawnPost( iPlayer )
{
// check if player spawned properly
if( is_user_alive( iPlayer ) )
{
// show the shop menu starting with the first page
// don't understand this function call?
// <a href="http://forums.alliedmods.net/showthread.php?t=90480" target="_blank" rel="nofollow noopener">http://forums.alliedmods.net/showthread.php?t=90480</a>
ShowShopMenu( iPlayer, .iPage = 0 );
}
}
ShowShopMenu( iPlayer, iPage )
{
// check if there are no items
if( !g_iTotalItems )
{
return;
}
// clamp page to valid range of pages
iPage = clamp( iPage, 0, ( g_iTotalItems - 1 ) / 7 );
// create menu
new hMenu = menu_create( "Shop Menu", "MenuShop" );
// used to display item in the menu
new eItemData[ ItemData ];
new szItem[ 64 ];
// used for array index to menu
new szNum[ 3 ];
// loop through each item
for( new i = 0; i < g_iTotalItems; i++ )
{
// get item data from array
ArrayGetArray( g_aItems, i, eItemData );
// format item for menu
formatex( szItem, charsmax( szItem ), "%s\R\y%i", eItemData[ ItemName ], eItemData[ ItemCost ] );
// pass array index to menu to find information about it later
num_to_str( i, szNum, charsmax( szNum ) );
// add item to menu
menu_additem( hMenu, szItem, szNum );
}
// display menu to player
menu_display( iPlayer, hMenu, iPage );
}
public MenuShop( iPlayer, hMenu, iItem )
{
if( iItem == MENU_EXIT )
{
menu_destroy( hMenu );
return;
}
new iAccess, szNum[ 3 ], hCallback;
menu_item_getinfo( hMenu, iItem, iAccess, szNum, charsmax( szNum ), _, _, hCallback );
menu_destroy( hMenu );
// get item index from menu
new iItemIndex = str_to_num( szNum );
// get item data from array
new eItemData[ ItemData ];
ArrayGetArray( g_aItems, iItemIndex, eItemData );
// get player money and subtract the cost
new iMoney = cs_get_user_money( iPlayer ) - eItemData[ ItemCost ];
// result money will be < 0 if not enough money
if( iMoney < 0 )
{
// notify player
client_print( iPlayer, print_chat, "* You need $%i more to buy this item!", ( iMoney * -1 ) );
}
else
{
// set player money
cs_set_user_money( iPlayer, iMoney );
// notify plugins that the player bought this item
new iReturn;
ExecuteForward( g_hSelectItemForward, iReturn, iPlayer, iItemIndex );
}
ShowShopMenu( iPlayer, .iPage = ( iItemIndex / 7 ) );
}Code: Select all
#include < amxmodx >
#include < fun >
#include < shop >
// save item index
new g_iItemIndex;
public plugin_init( )
{
// register item with main plugin and store item index
g_iItemIndex = shop_item_add( "Low Gravity", 2000 );
}
// catch when items are bought
public shop_item_selected( iPlayer, iItemIndex )
{
// check if bought item is the one from this plugin
if( g_iItemIndex == iItemIndex )
{
// set gravity
set_user_gravity( iPlayer, 0.25 );
}
}