Raised This Month: $12 Target: $400
 3% 

Dynamic Items in Menu and Plugin API


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 04-05-2010 , 12:44   Dynamic Items in Menu and Plugin API
Reply With Quote #1

Introduction:

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:
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:
#if defined _shop_included     #endinput #endif #define _shop_included

That code will make sure if included more than once in a single plugin, it won't duplicate its contents.

First, you will need a custom library for this.
Let's call it "shop"
Code:
#if AMXX_VERSION_NUM >= 175     #pragma reqlib shop     #if !defined AMXMODX_NOAUTOLOAD         #pragma loadlib shop     #endif #else     #pragma library shop #endif

Next, you will need 2 functions that will integrate your plugins:
  1. A function executed in the sub-plugin that sends data to the main plugin so the item is recognized.
  2. 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:
native shop_item_add( const szName[ ], const iCost );

The function should return a unique item index so it can be separate from other plugins.
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:
forward shop_item_selected( iPlayer, iItemIndex );

Here is our complete shop.inc file:
Code:
#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 );

Main Plugin:

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:
#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 ) ); }

Sub-Plugin:

Code:
#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 );     } }
___________________________




Here is how it would be done with specific callback functions.

Introduction:

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:
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:
#if defined _shop_included     #endinput #endif #define _shop_included

That code will make sure if included more than once in a single plugin, it won't duplicate its contents.

First, you will need a custom library for this.
Let's call it "shop"
Code:
#if AMXX_VERSION_NUM >= 175     #pragma reqlib shop     #if !defined AMXMODX_NOAUTOLOAD         #pragma loadlib shop     #endif #else     #pragma library shop #endif

Next, you will need 2 functions that will integrate your plugins:
  1. A function executed in the sub-plugin that sends data to the main plugin so the item is recognized.
  2. 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
  • callback function

So, here is how our function would look.
Code:
native shop_item_add( const szName[ ], const iCost, const szHandler[ ] );

The function should uses a callback handler so it can be separate from other plugins.

Here is our complete shop.inc file:
Code:
#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, const szHandler[ ] );

Main Plugin:

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:
#include < amxmodx > #include < cstrike > #include < hamsandwich > // create the structure for each item // we need the item name, cost, plugin adding it, and the callback function enum _:ItemData {     ItemName[ 32 ],     ItemCost,     ItemPlugin,     ItemFuncID }; // 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; 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 ); } 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 );         // save the plugin adding the item     eItemData[ ItemPlugin ] = iPlugin;         // get item callback function     new szHandler[ 32 ];     get_string( 3, szHandler, charsmax( szHandler ) );     eItemData[ ItemFuncID ] = get_func_id( szHandler, iPlugin );         // 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 the plugin that the player bought this item         callfunc_begin_i( eItemData[ ItemFuncID ], eItemData[ ItemPlugin ] );         callfunc_push_int( iPlayer );         callfunc_end( );     }         ShowShopMenu( iPlayer, .iPage = ( iItemIndex / 7 ) ); }

Sub-Plugin:

Code:
#include < amxmodx > #include < fun > #include < shop > public plugin_init( ) {     // register item with main plugin and store item index     shop_item_add( "Low Gravity", 2000, "ShopLowGravity" ); } // player bought low gravity public ShopLowGravity( iPlayer ) {     // set gravity     set_user_gravity( iPlayer, 0.25 ); }

___________________________




Last Notes:

Don't post here asking how to fix your mod.
Feel free to post if you don't understand something about this or if you have suggestions to better this information.
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!

Last edited by Exolent[jNr]; 12-10-2010 at 14:29.
Exolent[jNr] is offline
Seta00
The Seta00 user has crashed.
Join Date: Jan 2010
Location: Berlin
Old 04-05-2010 , 14:10   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #2

Nice! A guy requested me this last week, but I haven't got time to do this, so thank you Exolent.
Seta00 is offline
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 04-05-2010 , 14:22   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #3

I'm glad you find it useful.
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!
Exolent[jNr] is offline
fezh
Veteran Member
Join Date: Dec 2008
Location: BANNED
Old 04-05-2010 , 18:02   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #4

Nice
__________________
"There is no knowledge, that is not power"
fezh is offline
wrecked_
Veteran Member
Join Date: Jan 2010
Location: New York (GMT-5)
Old 04-05-2010 , 23:04   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #5

I had a few people ask me how this type of thing would work (natives to interact with the base plugin) and they were using ZP as an example, which confused them. A lot. This is certainly a better example.

Awesome job.
__________________
[ Paid Requests ]
DO NOT PM ME ABOUT BLOCKMAKER
NO PRIVATE SUPPORT

Last edited by wrecked_; 04-05-2010 at 23:05. Reason: must have moving smiley
wrecked_ is offline
abdul-rehman
Veteran Member
Join Date: Jan 2010
Location: Khi, Pakistan
Old 04-06-2010 , 05:34   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #6

Coool i needed this for my ZP New Modes
abdul-rehman is offline
Send a message via Yahoo to abdul-rehman Send a message via Skype™ to abdul-rehman
Seta00
The Seta00 user has crashed.
Join Date: Jan 2010
Location: Berlin
Old 04-06-2010 , 11:05   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #7

@Exolent
How about making specific forwards for each menu item?
Code:
shop_add_item("Durgs", 1337, "MyCoolAndShinyHandler"); public MyCoolAndShinyHandler() {     // la la la la }
Seta00 is offline
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 04-06-2010 , 12:44   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #8

Quote:
Originally Posted by Seta00 View Post
@Exolent
How about making specific forwards for each menu item?
Code:
shop_add_item("Durgs", 1337, "MyCoolAndShinyHandler"); public MyCoolAndShinyHandler() {     // la la la la }
The purpose was to show how it would be done like Zombie Plague.
I can add more features to this like what you're suggesting, but people can figure those features out themselves.
They normally have problems just figuring out how to do this basic API.
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!
Exolent[jNr] is offline
padilha007
Senior Member
Join Date: Jul 2008
Old 04-14-2010 , 11:38   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #9

Quote:
// format item for menu
formatex( szItem, charsmax(szItem), "%s\R\y%i", eItemData[ ItemName ], eItemData[ ItemCost ] );
__________________


Last edited by padilha007; 04-14-2010 at 11:40.
padilha007 is offline
drekes
Veteran Member
Join Date: Jul 2009
Location: Vault 11
Old 04-14-2010 , 13:17   Re: Dynamic Items in Menu and Plugin API
Reply With Quote #10

nice tutorial.
I just don't understand the #pragma thing.

And don't we include the shop in the plugin? Can you explain that?
__________________

Quote:
Originally Posted by nikhilgupta345 View Post
You're retarded.
drekes is offline
Send a message via MSN to drekes
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 11:45.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode