Raised This Month: $32 Target: $400
 8% 

[TF2] Plugin to have BOTH grappling hook AND spell book


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
DarkPyro
Member
Join Date: Aug 2013
Old 12-04-2020 , 16:58   [TF2] Plugin to have BOTH grappling hook AND spell book
Reply With Quote #1

Hey guys! I was avoiding coming here asking for help, but I'm at a crossroads with this idea lol. I've looked for days, researching how this would be possible, and I've narrowed down the main aspects of it: using a gamedata file (I think there are multiple ways of doing this, but the gamedata way I understand more than the other methods), and also learning that the grappling hook/spell book is not an ordinary weapon, it is considered a "wearable", and I need to use functions such as "SDKCall( hRemoveWearable, client, entity );" to even remove the spell book/grappling hook. I think I'm really close to figuring this thing out, but I need some help. I'm going to post my code, but fair warning, it is quite literally a copy and paste of multiple pieces of code I've found on this forum, since this is really only a private plugin for me, I don't really care how it's written, as long as it works but if someone helps me out with this, I'd be willing to post the 100% working version of this to whomever wants to have the grappling hook AND the spell book enabled simultaneously. This plugin also has me confused because I want to use cookies to save the user's preference if they never want the spell book and only want the grappling hook, so they don't have to always enter the command to override it every time they join. I'm very new to cookies, so I don't really understand them all that well either

Basically: I just want the plugin to override the spell book with the grappling hook, since one of my servers map files forces the spell book to be enabled no matter what, and if the user wishes, they can turn off the override command and it'll allow them to use the spell book normally, using cookies to save their preference. Thank you for reading, and hopefully you guys can help me figure this out, cause I'm lost, procrastinating, all the above, even though I feel like I'm extremely close to figuring this out

Code:
#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <clientprefs>

#include <sdktools>
#include <sdkhooks>

#include <tf2>
#include <tf2_stocks>

#define PLUGIN_VERSION "13.37"

bool g_gIsEnabled[ MAXPLAYERS + 1 ];

Handle g_hClientGCookie = INVALID_HANDLE;
Handle hRemoveWearable;
Handle hEquipWearable;
Handle hGameConf;

public Plugin myinfo =
{
	name = "[TF2] Grappling Hook Overrider",
	author = "pyro",
	description = "Allows the grappling hook to override the spell book",
	version = PLUGIN_VERSION,
	url = "https://dpg.tf/"
};

public void OnPluginStart()
{
	CreateConVar( "sm_grappler_overrider_version", "Version for grappler override.", PLUGIN_VERSION, FCVAR_SPONLY|FCVAR_DONTRECORD|FCVAR_NOTIFY );
	RegConsoleCmd( "sm_grappling_enable", Event_EquipItem, "Toggle between grappling hook or spell book" );

	g_hClientGCookie = RegClientCookie( "G_OverrideCookie", "Cookie to save toggling between spells or grappler", CookieAccess_Private );

	hGameConf = LoadGameConfigFile( "tf2.grappleoverride" );

	HookEvent( "post_inventory_application", Event_EquipItem,  EventHookMode_Post );

	StartPrepSDKCall( SDKCall_Player );
	PrepSDKCall_SetFromConf( hGameConf, SDKConf_Virtual, "RemoveWearable" );
	PrepSDKCall_AddParameter( SDKType_CBaseEntity, SDKPass_Pointer );
	hRemoveWearable = EndPrepSDKCall();

	StartPrepSDKCall( SDKCall_Player );
	PrepSDKCall_SetFromConf( hGameConf, SDKConf_Virtual, "EquipWearable" );
	PrepSDKCall_AddParameter( SDKType_CBaseEntity, SDKPass_Pointer );
	hEquipWearable = EndPrepSDKCall();

	ExecuteLateLoad();
}

void ExecuteLateLoad()
{
	for ( int i = 1; i <= MaxClients; i++ )
	{
		if ( !AreClientCookiesCached( i ) )
			continue;

		OnClientCookiesCached( i );
	}
}

public Action GrapplerToggle( int client, int args )
{
	char sValue[ 8 ];

	g_gIsEnabled[ client ] = !g_gIsEnabled[ client ]; // toggle value
	IntToString( g_gIsEnabled[ client ], sValue, sizeof( sValue ) ); // convert to string
	SetClientCookie( client, g_hClientGCookie, sValue ); // save to cookie
}

public Action Event_EquipItem( Handle event, const String:name[], bool dontBroadcast )
{
	new client = GetClientOfUserId( GetEventInt( event, "userid" ) );
	if ( client == 0 )
	{
		return;
	}

	new entity = -1;
	while ( ( entity = FindEntityByClassname( entity, "tf_wearable" ) ) != -1 )
	{
		new owner = GetEntPropEnt( entity, Prop_Send, "m_hOwnerEntity" );
		if ( owner != client )
		{
			continue;
		}

		new itemIndex = GetEntProp( entity, Prop_Send, "m_iItemDefinitionIndex" );
		if ( itemIndex == 1070  )
		{
			SDKCall( hRemoveWearable, client, entity );
		}
	}
	return Plugin_Continue;
}

public void OnClientCookiesCached( int client )
{
	char sValue[ 8 ];

	GetClientCookie( client, g_hClientGCookie, sValue, sizeof( sValue ) ); // Gets stored value for specific client and stores in sValue
	g_gIsEnabled[ client ] = ( sValue[ 0 ] != '\0' && StringToInt( sValue ) ); // If the string isn't empty and is >0, it'll be set to true
}
The gamedata file:
Code:
"Games"
{
	"tf"
	{
		"Offsets"
		{
			"EquipWearable"
			{
				"windows"	"430"
				"linux"		"431"
				"mac"		"431"
			}

			"RemoveWearable"
			{
				"windows"	"431"
				"linux"		"432"
				"mac"		"432"
			}
		}
	}
}
__________________



Last edited by DarkPyro; 12-04-2020 at 16:59.
DarkPyro is offline
PC Gamer
Veteran Member
Join Date: Mar 2014
Old 12-04-2020 , 22:21   Re: [TF2] Plugin to have BOTH grappling hook AND spell book
Reply With Quote #2

I do this to enable grappling hooks on my server: tf_grapplinghook_enable 1
I do this to disable grappling hooks on my server: tf_grapplinghook_enable 0

Are you trying to limit the player to EITHER the spellbook OR the grappling hook? Or do you want them to have both? May I ask what you want them to do with the spellbook?

If you want spellbooks to appear in the player's display you'll need to add this: sm_cvar tf_spells_enabled 1

Here's an example of what I do to give players 10 Fireball spells:
PHP Code:
#include <sourcemod> 
#include <tf2> 
#include <tf2_stocks> 
#include <tf2items> 

#define PLUGIN_VERSION "1.0" 

#define MAGIC    "vo/halloween_merasmus/sf12_staff_magic13.mp3" 

public Plugin:myinfo =  

    
name "Spellbook"
    
author "PC Gamer"
    
description "Give Spellbook with Spells"
    
version PLUGIN_VERSION
    
url "www.sourcemod.com" 


public 
OnPluginStart() 

    
LoadTranslations("common.phrases"); 
    
RegAdminCmd("sm_spellbook"Command_nobookADMFLAG_SLAY"Give Spells"); 


public 
OnMapStart()
{
    
PrecacheSound(MAGICtrue); 
}

public 
Action:Command_nobook(clientargs

    
decl String:arg1[32]; 
    if (
args 1
    { 
        
arg1 "@me"
    } 
    else 
GetCmdArg(1arg1sizeof(arg1)); 
    new 
String:target_name[MAX_TARGET_LENGTH]; 
    new 
target_list[MAXPLAYERS], target_count
    new 
bool:tn_is_ml

    if ((
target_count ProcessTargetString
                    
arg1
                    
client
                    
target_list
                    
MAXPLAYERS
                    
COMMAND_FILTER_ALIVE|(args COMMAND_FILTER_NO_IMMUNITY 0), 
                    
target_name
                    
sizeof(target_name), 
                    
tn_is_ml)) <= 0
    { 
        
ReplyToTargetError(clienttarget_count); 
        return 
Plugin_Handled
    } 
 
    for (new 
0target_counti++) 
    { 
        
forceSpellbook(target_list[i]); 
        
SetSpell2(target_list[i], 010); 
        
EmitSoundToClient(target_list[i],MAGIC);          
        
PrintToChat(target_list[i], "You received 10 Fireball Spells.  Use 'H' key to cast.");        
    } 
    
    return 
Plugin_Handled



stock forceSpellbook(client)
{
    
TF2_RemoveWeaponSlot(client10);

    new 
Handle:hWeapon TF2Items_CreateItem(OVERRIDE_ALL|FORCE_GENERATION);
    
TF2Items_SetClassname(hWeapon"tf_weapon_spellbook");
    
TF2Items_SetItemIndex(hWeapon1132);
    
TF2Items_SetLevel(hWeapon100);
    
TF2Items_SetQuality(hWeapon6);
    
TF2Items_SetNumAttributes(hWeapon1);
    
TF2Items_SetAttribute(hWeapon05470.5);

    new 
entity TF2Items_GiveNamedItem(clienthWeapon);
    
CloseHandle(hWeapon);
    
EquipPlayerWeapon(cliententity);
    return 
entity;
}

SetSpell2(clientspelluses)
{
    new 
ent GetSpellBook(client);
    if(!
IsValidEntity(ent)) return;
    
SetEntProp(entProp_Send"m_iSelectedSpellIndex"spell);
    
SetEntProp(entProp_Send"m_iSpellCharges"uses);
}  

GetSpellBook(client)
{
    new 
entity = -1;
    while((
entity FindEntityByClassname(entity"tf_weapon_spellbook")) != INVALID_ENT_REFERENCE)
    {
        if(
GetEntPropEnt(entityProp_Send"m_hOwnerEntity") == client) return entity;
    }
    return -
1;

PC Gamer is offline
DarkPyro
Member
Join Date: Aug 2013
Old 12-04-2020 , 23:35   Re: [TF2] Plugin to have BOTH grappling hook AND spell book
Reply With Quote #3

Quote:
Originally Posted by PC Gamer View Post
I do this to enable grappling hooks on my server: tf_grapplinghook_enable 1
I do this to disable grappling hooks on my server: tf_grapplinghook_enable 0

Are you trying to limit the player to EITHER the spellbook OR the grappling hook? Or do you want them to have both? May I ask what you want them to do with the spellbook?

If you want spellbooks to appear in the player's display you'll need to add this: sm_cvar tf_spells_enabled 1

Here's an example of what I do to give players 10 Fireball spells:
PHP Code:
#include <sourcemod> 
#include <tf2> 
#include <tf2_stocks> 
#include <tf2items> 

#define PLUGIN_VERSION "1.0" 

#define MAGIC    "vo/halloween_merasmus/sf12_staff_magic13.mp3" 

public Plugin:myinfo =  

    
name "Spellbook"
    
author "PC Gamer"
    
description "Give Spellbook with Spells"
    
version PLUGIN_VERSION
    
url "www.sourcemod.com" 


public 
OnPluginStart() 

    
LoadTranslations("common.phrases"); 
    
RegAdminCmd("sm_spellbook"Command_nobookADMFLAG_SLAY"Give Spells"); 


public 
OnMapStart()
{
    
PrecacheSound(MAGICtrue); 
}

public 
Action:Command_nobook(clientargs

    
decl String:arg1[32]; 
    if (
args 1
    { 
        
arg1 "@me"
    } 
    else 
GetCmdArg(1arg1sizeof(arg1)); 
    new 
String:target_name[MAX_TARGET_LENGTH]; 
    new 
target_list[MAXPLAYERS], target_count
    new 
bool:tn_is_ml

    if ((
target_count ProcessTargetString
                    
arg1
                    
client
                    
target_list
                    
MAXPLAYERS
                    
COMMAND_FILTER_ALIVE|(args COMMAND_FILTER_NO_IMMUNITY 0), 
                    
target_name
                    
sizeof(target_name), 
                    
tn_is_ml)) <= 0
    { 
        
ReplyToTargetError(clienttarget_count); 
        return 
Plugin_Handled
    } 
 
    for (new 
0target_counti++) 
    { 
        
forceSpellbook(target_list[i]); 
        
SetSpell2(target_list[i], 010); 
        
EmitSoundToClient(target_list[i],MAGIC);          
        
PrintToChat(target_list[i], "You received 10 Fireball Spells.  Use 'H' key to cast.");        
    } 
    
    return 
Plugin_Handled



stock forceSpellbook(client)
{
    
TF2_RemoveWeaponSlot(client10);

    new 
Handle:hWeapon TF2Items_CreateItem(OVERRIDE_ALL|FORCE_GENERATION);
    
TF2Items_SetClassname(hWeapon"tf_weapon_spellbook");
    
TF2Items_SetItemIndex(hWeapon1132);
    
TF2Items_SetLevel(hWeapon100);
    
TF2Items_SetQuality(hWeapon6);
    
TF2Items_SetNumAttributes(hWeapon1);
    
TF2Items_SetAttribute(hWeapon05470.5);

    new 
entity TF2Items_GiveNamedItem(clienthWeapon);
    
CloseHandle(hWeapon);
    
EquipPlayerWeapon(cliententity);
    return 
entity;
}

SetSpell2(clientspelluses)
{
    new 
ent GetSpellBook(client);
    if(!
IsValidEntity(ent)) return;
    
SetEntProp(entProp_Send"m_iSelectedSpellIndex"spell);
    
SetEntProp(entProp_Send"m_iSpellCharges"uses);
}  

GetSpellBook(client)
{
    new 
entity = -1;
    while((
entity FindEntityByClassname(entity"tf_weapon_spellbook")) != INVALID_ENT_REFERENCE)
    {
        if(
GetEntPropEnt(entityProp_Send"m_hOwnerEntity") == client) return entity;
    }
    return -
1;

Lol okay so basically if you have the spellbook cvar set to 1, you cannot set the grappling hook cvar to 1 and use the grappling hook. You have to disable the spellbook first in order to get the grappling hook, meaning you can't just enable both and get to choose from both the spell book and the grappling hook. I believe that works vice versa, or maybe the spell book is just always dominant over the grappling hook, either way I've been wanting a plugin that just allows the user to choose between either at any given time through a command for years and haven't found any, but I think your plugin just gave me the answer to my question. Will keep you posted, and sorry, I type a lot and it can get confusing lmao
__________________



Last edited by DarkPyro; 12-04-2020 at 23:36.
DarkPyro is offline
Isiah Scott
New Member
Join Date: Sep 2021
Old 09-28-2021 , 15:35   Re: [TF2] Plugin to have BOTH grappling hook AND spell book
Reply With Quote #4

Quote:
Originally Posted by PC Gamer View Post
I do this to enable grappling hooks on my server: tf_grapplinghook_enable 1
I do this to disable grappling hooks on my server: tf_grapplinghook_enable 0

Are you trying to limit the player to EITHER the spellbook OR the grappling hook? Or do you want them to have both? May I ask what you want them to do with the spellbook?

If you want spellbooks to appear in the player's display you'll need to add this: sm_cvar tf_spells_enabled 1

Here's an example of what I do to give players 10 Fireball spells:
PHP Code:
#include <sourcemod> 
#include <tf2> 
#include <tf2_stocks> 
#include <tf2items> 

#define PLUGIN_VERSION "1.0" 

#define MAGIC    "vo/halloween_merasmus/sf12_staff_magic13.mp3" 

public Plugin:myinfo =  

    
name "Spellbook"
    
author "PC Gamer"
    
description "Give Spellbook with Spells"
    
version PLUGIN_VERSION
    
url "www.sourcemod.com" 


public 
OnPluginStart() 

    
LoadTranslations("common.phrases"); 
    
RegAdminCmd("sm_spellbook"Command_nobookADMFLAG_SLAY"Give Spells"); 


public 
OnMapStart()
{
    
PrecacheSound(MAGICtrue); 
}

public 
Action:Command_nobook(clientargs

    
decl String:arg1[32]; 
    if (
args 1
    { 
        
arg1 "@me"
    } 
    else 
GetCmdArg(1arg1sizeof(arg1)); 
    new 
String:target_name[MAX_TARGET_LENGTH]; 
    new 
target_list[MAXPLAYERS], target_count
    new 
bool:tn_is_ml

    if ((
target_count ProcessTargetString
                    
arg1
                    
client
                    
target_list
                    
MAXPLAYERS
                    
COMMAND_FILTER_ALIVE|(args COMMAND_FILTER_NO_IMMUNITY 0), 
                    
target_name
                    
sizeof(target_name), 
                    
tn_is_ml)) <= 0
    { 
        
ReplyToTargetError(clienttarget_count); 
        return 
Plugin_Handled
    } 
 
    for (new 
0target_counti++) 
    { 
        
forceSpellbook(target_list[i]); 
        
SetSpell2(target_list[i], 010); 
        
EmitSoundToClient(target_list[i],MAGIC);          
        
PrintToChat(target_list[i], "You received 10 Fireball Spells.  Use 'H' key to cast.");        
    } 
    
    return 
Plugin_Handled


{
    
TF2_RemoveWeaponSlot(client10);

    new 
Handle:hWeapon TF2Items_CreateItem(OVERRIDE_ALL|FORCE_GENERATION);
    
TF2Items_SetClassname(hWeapon"tf_weapon_spellbook");
    
TF2Items_SetItemIndex(hWeapon1132);
    
TF2Items_SetLevel(hWeapon100);
    
TF2Items_SetQuality(hWeapon6);
    
TF2Items_SetNumAttributes(hWeapon1);
    
TF2Items_SetAttribute(hWeapon05470.5);

    new 
entity TF2Items_GiveNamedItem(clienthWeapon);
    
CloseHandle(hWeapon);
    
EquipPlayerWeapon(cliententity);
    return 
entity;
}

SetSpell2(clientspelluses)
{
    new 
ent GetSpellBook(client);
    if(!
IsValidEntity(ent)) return;
    
SetEntProp(entProp_Send"m_iSelectedSpellIndex"spell);
    
SetEntProp(entProp_Send"m_iSpellCharges"uses);
}  

GetSpellBook(client)
{
    new 
entity = -1;
    while((
entity FindEntityByClassname(entity"tf_weapon_spellbook")) != INVALID_ENT_REFERENCE)
    {
        if(
GetEntPropEnt(entityProp_Send"m_hOwnerEntity") == client) return entity;
    }
    return -
1;

An excellent site, I read books here most often. I strongly advise you to read the book Of Mice And Men. I learned about it from my acquaintances, who read a lot of books and are connoisseurs of literature. After that, I went to the site https://artscolumbia.org/free-essays/of-mice-and-men/ and read very cool articles about this book, which convinced me to finally read this book. I highly recommend it.
Thank you so much for sharing.

Last edited by Isiah Scott; 09-29-2021 at 07:59.
Isiah Scott is offline
PC Gamer
Veteran Member
Join Date: Mar 2014
Old 09-28-2021 , 23:33   Re: [TF2] Plugin to have BOTH grappling hook AND spell book
Reply With Quote #5

Quote:
Originally Posted by Isiah Scott View Post
Thank you so much for sharing.
You're welcome! Here's a slightly different version that doesn't require TF2Items.

PHP Code:
#pragma semicolon 1
#include <sourcemod>
#include <tf2_stocks>

#define PLUGIN_VERSION "1.1" 

#define MAGIC    "vo/halloween_merasmus/sf12_staff_magic13.mp3" 

public Plugin:myinfo =  

    
name "Spellbook"
    
author "PC Gamer"
    
description "Give Spellbook with Spells"
    
version PLUGIN_VERSION
    
url "www.sourcemod.com" 


Handle g_hWearableEquip;

public 
OnPluginStart() 

    
LoadTranslations("common.phrases"); 
    
RegAdminCmd("sm_spellbook"Command_nobookADMFLAG_SLAY"Give Spells"); 

    
GameData hTF2 = new GameData("sm-tf2.games"); // sourcemod's tf2 gamedata

    
if (!hTF2)
    
SetFailState("This plugin is designed for a TF2 dedicated server only.");

    
StartPrepSDKCall(SDKCall_Player);
    
PrepSDKCall_SetVirtual(hTF2.GetOffset("RemoveWearable") - 1);    // EquipWearable offset is always behind RemoveWearable, subtract its value by 1
    
PrepSDKCall_AddParameter(SDKType_CBaseEntitySDKPass_Pointer);
    
g_hWearableEquip EndPrepSDKCall();

    if (!
g_hWearableEquip)
    
SetFailState("Failed to create call: CBasePlayer::EquipWearable");

    
delete hTF2


public 
OnMapStart()
{
    
PrecacheSound(MAGICtrue); 
}

public 
Action:Command_nobook(clientargs

    
decl String:arg1[32]; 
    if (
args 1
    { 
        
arg1 "@me"
    } 
    else 
GetCmdArg(1arg1sizeof(arg1)); 
    new 
String:target_name[MAX_TARGET_LENGTH]; 
    new 
target_list[MAXPLAYERS], target_count
    new 
bool:tn_is_ml

    if ((
target_count ProcessTargetString
                    
arg1
                    
client
                    
target_list
                    
MAXPLAYERS
                    
COMMAND_FILTER_ALIVE|(args COMMAND_FILTER_NO_IMMUNITY 0), 
                    
target_name
                    
sizeof(target_name), 
                    
tn_is_ml)) <= 0
    { 
        
ReplyToTargetError(clienttarget_count); 
        return 
Plugin_Handled
    } 

    for (new 
0target_counti++) 
    { 
        
forceSpellbook(target_list[i]); 
        
SetSpell2(target_list[i], 010); 
        
EmitSoundToClient(target_list[i],MAGIC);          
        
PrintToChat(target_list[i], "You received 10 Fireball Spells.  Use 'H' key to cast.");        
    } 
    
    return 
Plugin_Handled



stock forceSpellbook(client)
{
    
TF2_RemoveWeaponSlot(client10);

    
CreateHat(client11321006); //Spellbook    
    
    
TF2_RegeneratePlayer(client);
}

SetSpell2(clientspelluses)
{
    new 
ent GetSpellBook(client);
    if(!
IsValidEntity(ent)) return;
    
SetEntProp(entProp_Send"m_iSelectedSpellIndex"spell);
    
SetEntProp(entProp_Send"m_iSpellCharges"uses);
}  

GetSpellBook(client)
{
    new 
entity = -1;
    while((
entity FindEntityByClassname(entity"tf_weapon_spellbook")) != INVALID_ENT_REFERENCE)
    {
        if(
GetEntPropEnt(entityProp_Send"m_hOwnerEntity") == client) return entity;
    }
    return -
1;
}

bool CreateHat(int clientint itemindexint levelint quality)
{
    
int hat CreateEntityByName("tf_wearable");
    
    if (!
IsValidEntity(hat))
    {
        return 
false;
    }
    
    
char entclass[64];
    
GetEntityNetClass(hatentclasssizeof(entclass));
    
SetEntData(hatFindSendPropInfo(entclass"m_iItemDefinitionIndex"), itemindex);
    
SetEntData(hatFindSendPropInfo(entclass"m_bInitialized"), 1);     
    
SetEntData(hatFindSendPropInfo(entclass"m_iEntityLevel"), level);
    
SetEntData(hatFindSendPropInfo(entclass"m_iEntityQuality"), quality);

    if (
level)
    {
        
SetEntData(hatFindSendPropInfo(entclass"m_iEntityLevel"), level);
    }
    else
    {
        
SetEntData(hatFindSendPropInfo(entclass"m_iEntityLevel"), GetRandomInt(1,100));
    }

    
DispatchSpawn(hat);
    
SDKCall(g_hWearableEquipclienthat);
    return 
true;

PC Gamer is offline
Reply



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 21:42.


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