AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Scripting (https://forums.alliedmods.net/forumdisplay.php?f=107)
-   -   [H3LP] PlayerClass Fortress Forever (https://forums.alliedmods.net/showthread.php?t=303169)

DarthMan 11-25-2017 11:05

[H3LP] PlayerClass Fortress Forever
 
Could someone help me in getting and setting the player class id for the game Fortress Forever?

Code:
stock int GetPlayerClass(int client) {     if(!IsPlayer(client))         return 0;         if (GetEngineVersion() == Engine_DarkMessiah)         return GetEntProp(client, Prop_Send, "m_iPlayerClass");         return GetEntProp(client, Prop_Send, "m_iClass"); } stock int SetPlayerClass(int client, int class, bool persistant=false) {     if(!IsPlayer(client))         return 0;         if (GetEngineVersion() == Engine_DarkMessiah)         SetEntProp(client, Prop_Send, "m_iPlayerClass", class);     else         SetEntProp(client, Prop_Send, "m_iClass", class);         if(persistent)         SetEntProp(client, Prop_Send, "m_iDesiredPlayerClass", class);         return 1; }

I tried to print the player class when typing console command classname but it throwed an error so I guess that something might be wrong on the stock maybe?
I got the netprops and it seems that FF indded contains the m_iClass prop.

Thanks !

DarthMan 11-26-2017 05:55

Re: [H3LP] PlayerClass Fortress Forever
 
The error I'm getting : L 11/26/2017 - 12:53:50: [SM] Exception reported: Property "m_iClass" not found (entity 1/player)

I can conrifm that the property m_iClass exists on FF.

hlstriker 11-28-2017 05:02

Re: [H3LP] PlayerClass Fortress Forever
 
You will want to use "m_iClassStatus". But that won't work to set the class, so read all to the end.

GetClassSlot
PHP Code:

GetClassSlot(iClient)
{
    return (
GetEntProp(iClientProp_Send"m_iClassStatus") & 0x0000000F);


SetClassForClient
PHP Code:

SetClassForClient(iClientiSlot)
{
    
SetEntProp(iClientProp_Send"m_iClassStatus"iSlot 0x0000000F);


However, because "m_iNextClass" is not changed the server will put you back to your original class. The variable "m_iNextClass" is what ultimately decides what class you will be when you respawn. The problem is "m_iNextClass" is not accessible through netprops or datamaps. The easiest solution in your case would be to simply force the player to call the "ChangeClass" function. We do this by force using the "class" console command.

Here is a simple plugin I whipped up so you can see how to change a client's class in Fortress-Forever.
PHP Code:

#include <sourcemod>
#include <sdktools_functions>

#pragma semicolon 1

new const String:PLUGIN_NAME[] = "Testing";
new const 
String:PLUGIN_VERSION[] = "1.0";

public 
Plugin:myinfo =
{
    
name PLUGIN_NAME,
    
author "hlstriker",
    
description "Testing.",
    
version PLUGIN_VERSION,
    
url "www.swoobles.com"
}

new const 
String:g_szClasses[][] =
{
    
"none",
    
"scout",
    
"sniper",
    
"soldier",
    
"demoman",
    
"medic",
    
"hwguy",
    
"pyro",
    
"spy",
    
"engineer",
    
"civilian"
};


public 
OnPluginStart()
{
    
RegConsoleCmd("sm_class"OnClass);
}

public 
Action:OnClass(iClientiArgs)
{
    if(!
iClient)
        return;
    
    if(!
iArgs)
    {
        
ReplyToCommand(iClient"Enter a class number 1-10.");
        return;
    }
    
    
decl String:szClass[3];
    
GetCmdArg(1szClasssizeof(szClass));
    
    new 
iClass StringToInt(szClass);
    if(
iClass || iClass 10)
    {
        
ReplyToCommand(iClient"Enter a class number 1-10.");
        return;
    }
    
    
ReplyToCommand(iClient"Current class: %s. New class: %s"g_szClasses[GetClassSlot(iClient)], g_szClasses[iClass]);
    
ForceChangeClass(iClientiClass);
}

GetClassSlot(iClient)
{
    return (
GetEntProp(iClientProp_Send"m_iClassStatus") & 0x0000000F);
}

// It would be nice if we could simply use SetClassForClient, but we must use ForceChangeClass instead.
// This is here just for an example.
stock SetClassForClient(iClientiSlot)
{
    
SetEntProp(iClientProp_Send"m_iClassStatus"iSlot 0x0000000F);
}

ForceChangeClass(iClientiClass)
{
    
// Make sure the team's class limits don't override the class we are trying to force to.
    
decl iOriginalClassLimit;
    new 
iTeamManager GetTeamManager(GetEntProp(iClientProp_Data"m_iTeamNum"));
    if(
iTeamManager)
    {
        
iOriginalClassLimit GetEntProp(iTeamManagerProp_Send"m_iClasses"_iClass);
        
SetEntProp(iTeamManagerProp_Send"m_iClasses"99_iClass);
    }
    
    
// Force the client to change their class and instantly respawn them on the next frame.
    
FakeClientCommand(iClient"class %s"g_szClasses[iClass]);
    
    
// Put the team's class limits back to normal.
    
if(iTeamManager)
        
SetEntProp(iTeamManagerProp_Send"m_iClasses"iOriginalClassLimit_iClass);
}

GetTeamManager(iTeam)
{
    static 
iTeamManagers[6], bool:bHasManagers;
    
    if(
iTeam >= sizeof(iTeamManagers))
        return 
0;
    
    if(!
bHasManagers)
    {
        
decl iTeamNum;
        new 
iEnt = -1;
        while((
iEnt FindEntityByClassname(iEnt"ff_team_manager")) != -1)
        {
            
iTeamNum GetEntProp(iEntProp_Send"m_iTeamNum");
            if(
iTeamNum >= sizeof(iTeamManagers))
                continue;
            
            
iTeamManagers[iTeamNum] = iEnt;
        }
        
        
bHasManagers true;
    }
    
    return 
iTeamManagers[iTeam];



DarthMan 11-28-2017 06:08

Re: [H3LP] PlayerClass Fortress Forever
 
Quote:

Originally Posted by hlstriker (Post 2563268)
You will want to use "m_iClassStatus".

GetClassSlot
PHP Code:

GetClassSlot(iClient)
{
    return (
GetEntProp(iClientProp_Send"m_iClassStatus") & 0x0000000F);


SetClassForClient
PHP Code:

SetClassForClient(iClientiSlot)
{
    
SetEntProp(iClientProp_Send"m_iClassStatus"iSlot 0x0000000F);



Unfortunately, it still doesn't change my class, but now there are no errors.
I also tested the GetClassSlot and that seems to work fine.

hlstriker 11-28-2017 06:52

Re: [H3LP] PlayerClass Fortress Forever
 
Updated my post above.

DarthMan 11-28-2017 08:12

Re: [H3LP] PlayerClass Fortress Forever
 
Quote:

Originally Posted by hlstriker (Post 2563268)
You will want to use "m_iClassStatus". But that won't work to set the class, so read all to the end.

GetClassSlot
PHP Code:

GetClassSlot(iClient)
{
    return (
GetEntProp(iClientProp_Send"m_iClassStatus") & 0x0000000F);


SetClassForClient
PHP Code:

SetClassForClient(iClientiSlot)
{
    
SetEntProp(iClientProp_Send"m_iClassStatus"iSlot 0x0000000F);


However, because "m_iNextClass" is not changed the server will put you back to your original class. The variable "m_iNextClass" is what ultimately decides what class you will be when you respawn. The problem is "m_iNextClass" is not accessible through netprops or datamaps. The easiest solution in your case would be to simply force the player to call the "ChangeClass" function. We do this by force using the "class" console command.

Here is a simply plugin I whipped up so you can see how to change a client's class in Fortress-Forever.
PHP Code:

#include <sourcemod>
#include <sdktools_functions>

#pragma semicolon 1

new const String:PLUGIN_NAME[] = "Testing";
new const 
String:PLUGIN_VERSION[] = "1.0";

public 
Plugin:myinfo =
{
    
name PLUGIN_NAME,
    
author "hlstriker",
    
description "Testing.",
    
version PLUGIN_VERSION,
    
url "www.swoobles.com"
}

new const 
String:g_szClasses[][] =
{
    
"none",
    
"scout",
    
"sniper",
    
"soldier",
    
"demoman",
    
"medic",
    
"hwguy",
    
"pyro",
    
"spy",
    
"engineer",
    
"civilian"
};


public 
OnPluginStart()
{
    
RegConsoleCmd("sm_class"OnClass);
}

public 
Action:OnClass(iClientiArgs)
{
    if(!
iClient)
        return;
    
    if(!
iArgs)
    {
        
ReplyToCommand(iClient"Enter a class number 1-10.");
        return;
    }
    
    
decl String:szClass[3];
    
GetCmdArg(1szClasssizeof(szClass));
    
    new 
iClass StringToInt(szClass);
    if(
iClass || iClass 10)
    {
        
ReplyToCommand(iClient"Enter a class number 1-10.");
        return;
    }
    
    
ReplyToCommand(iClient"Current class: %s. New class: %s"g_szClasses[GetClassSlot(iClient)], g_szClasses[iClass]);
    
ForceChangeClass(iClientiClass);
}

GetClassSlot(iClient)
{
    return (
GetEntProp(iClientProp_Send"m_iClassStatus") & 0x0000000F);
}

// It would be nice if we could simply use SetClassForClient, but we must use ForceChangeClass instead.
// This is here just for an example.
stock SetClassForClient(iClientiSlot)
{
    
SetEntProp(iClientProp_Send"m_iClassStatus"iSlot 0x0000000F);
}

ForceChangeClass(iClientiClass)
{
    
// Make sure the team's class limits don't override the class we are trying to force to.
    
new Handle:hClassLimits CreateArray();
    new 
iTeamManager GetTeamManager(GetEntProp(iClientProp_Data"m_iTeamNum"));
    if(
iTeamManager)
    {
        new 
iArraySize GetEntPropArraySize(iTeamManagerProp_Send"m_iClasses");
        for(new 
i=0i<iArraySizei++)
        {
            
PushArrayCell(hClassLimitsGetEntProp(iTeamManagerProp_Send"m_iClasses"_i));
            
SetEntProp(iTeamManagerProp_Send"m_iClasses"0_i);
        }
    }
    
    
// Force the client to change their class and instantly respawn them on the next frame.
    
FakeClientCommand(iClient"class %s"g_szClasses[iClass]);
    
RequestFrame(RequestFrame_RespawnClientGetClientSerial(iClient));
    
    
// Put the team's class limits back to normal.
    
if(iTeamManager)
    {
        new 
iArraySize GetEntPropArraySize(iTeamManagerProp_Send"m_iClasses");
        for(new 
i=0i<iArraySizei++)
        {
            
SetEntProp(iTeamManagerProp_Send"m_iClasses"GetArrayCell(hClassLimitsi), _i);
        }
    }
    
    
CloseHandle(hClassLimits);
}

public 
RequestFrame_RespawnClient(any:iClientSerial)
{
    new 
iClient GetClientFromSerial(iClientSerial);
    if(!
iClient)
        return;
    
    
DispatchSpawn(iClient);
}

GetTeamManager(iTeam)
{
    static 
iTeamManagers[6], bool:bHasManagers;
    
    if(
iTeam >= sizeof(iTeamManagers))
        return 
0;
    
    if(!
bHasManagers)
    {
        
decl iTeamNum;
        new 
iEnt = -1;
        while((
iEnt FindEntityByClassname(iEnt"ff_team_manager")) != -1)
        {
            
iTeamNum GetEntProp(iEntProp_Send"m_iTeamNum");
            if(
iTeamNum >= sizeof(iTeamManagers))
                continue;
            
            
iTeamManagers[iTeamNum] = iEnt;
        }
        
        
bHasManagers true;
    }
    
    return 
iTeamManagers[iTeam];



When trying to spawn as a civilian, it says
#FF_ERROR_NOLONGERAVAILABLE.

hlstriker 11-28-2017 15:26

Re: [H3LP] PlayerClass Fortress Forever
 
Quote:

Originally Posted by DarthMan (Post 2563293)
When trying to spawn as a civilian, it says
#FF_ERROR_NOLONGERAVAILABLE.

What map was that on? Try removing RequestFrame() and putting DispatchSpawn() in its place.

Also change this line:
PHP Code:

SetEntProp(iTeamManagerProp_Send"m_iClasses"0_i); 

To this:
PHP Code:

SetEntProp(iTeamManagerProp_Send"m_iClasses"99_i); 


Mitchell 11-28-2017 15:45

Re: [H3LP] PlayerClass Fortress Forever
 
Also instead of doing "GetEngineVersion()" within your stock you can just save it in a static variable or use HasEntProp()

hlstriker 11-28-2017 16:04

Re: [H3LP] PlayerClass Fortress Forever
 
I went ahead and updated the ForceChangeClass function in my example plugin above. Although I would still like to know which map was giving you that message in console.

DarthMan 11-28-2017 16:21

Re: [H3LP] PlayerClass Fortress Forever
 
Quote:

Originally Posted by hlstriker (Post 2563374)
I went ahead and updated the ForceChangeClass function in my example plugin above. Although I would still like to know which map was giving you that message in console.

It was ff_monkey.


All times are GMT -4. The time now is 16:02.

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