Jump to content
metin2dev
Ekstasia2

Recommended Posts

Hello devs :)
Today I would like to present you a new solution that can make you feel more safe with your GMs. This is my first release and it's very simple to do, I'm just posting it here for the newbies and those who don't know how to start searching and other shit like that :P

WHAT IS THIS SYSTEM?

This system is a number of preventions for GameMaster characters about certain interractions with normal players in the game. The functions you are about to see are blocking GMs from:

  1. Trading items with normal players (and the opposite)
  2. Invite normal players to parties (and the opposite)
  3. Invite normal players to guilds (and the opposite)
  4. Adding normal players as friend contacts (I would say and the opposite but it already exists by default :P)
  5. Drop items to the ground
  6. Build their own private shops with the Bundle item
  7. Buy items from a private shop
  8. Block a GM from buffing normal players
  9. Using the commands /set, /a and /setskillother to normal players

WHO IS THIS SYSTEM FOR?

I believe we can all agree that trust in partnership is a rare thing these days. This system is released from me for the Admins out there that cannot trust their GMs (and many times their self) so much. Imagine having a server and your GM just gives away items for free to everyone. Bad huh? I thought so... So with this system you are sure that your GMs will do their job properly and won't violate any game rules behind your backs. Your server has rules (as all games out there) and if you wanted people to have some items for free you can easily put those items for sale into the town vendors. People who do this kind of things behind your backs are not authorized by you to do it but I believe that it happened (if not happening yet) to the best of you guys, that's why I'm releasing it. It's time to set some things right in your servers, GMs exist to answer questions and not helping players cheat without any authorization from the administrators, so without further ado, let's get started.

SORRY AGAIN, ONE MORE THING :P I BELIEVE THIS QUESTION IS IN THE MIND OF A DEVELOPER WHO READS THIS GUIDE:
MIND RAPIST, WHY DO YOU USE THE 
IsGM() BOOLEAN TO CHECK IF A PLAYER IS A GM AND NOT USE THE TRADITIONAL CHECK GetGMLevel() > GM_PLAYER?

In this tutorial, we will be using the bool IsGM() instead of the usual check because some of the guys who see this may have added @Alina's GM Elevation system. In that case, GetGMLevel() won't work before the character elevates, so our GMs will be able to bypass the check and just create a perfect item, relog and give it away before they elevate. We don't want that don't we? So who ever wants to use GetGMLevel() > GM_PLAYER instead of IsGM() there is no difference you can do that guys, except if you did the elevation system, then you need to use my function in order to work.

So let's get the party started.

PARTY INVITATION BLOCK

In char.cpp search for the function "void CHARACTER::PartyInvite(LPCHARACTER pchInvitee)" and under

Spoiler

    else if (pchInvitee->IsBlockMode(BLOCK_PARTY_INVITE))
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> %s 님이 파티 거부 상태입니다."), pchInvitee->GetName());
        return;
    }

add this:

Spoiler

    else if (IsGM() == true && pchInvitee->IsGM() == false)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<Party> You cannot send a party invitation to a player!"));
        return;
    }    
    
    else if (IsGM() == false && pchInvitee->IsGM() == true)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<Party> You cannot send a party invitation to a GameMaster!"));
        return;
    }

Done with party block, let's continue

BUNDLE USAGE BLOCK FOR CREATING PRIVATE SHOPS

In char_item.cpp search for the function "bool CHARACTER::UseItemEx(LPITEM item, TItemPos DestCell)" and under

Spoiler

                            case 50200: // 보따리
                                if (LC_IsYMIR() == true || LC_IsKorea() == true)
                                {
                                    if (IS_BOTARYABLE_ZONE(GetMapIndex()) == true)
                                    {
                                        __OpenPrivateShop();
                                    }
                                    else
                                    {
                                        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("개인 상점을 열 수 없는 지역입니다"));
                                    }
                                }

add this:

Spoiler

                                if (IsGM() == true)
                                {
                                    ChatPacket(CHAT_TYPE_INFO, LC_TEXT("GameMasters can't build private shops."));
                                    return false;
                                }

Done, let's continue

ITEM DROP BLOCK

Still in char_item.cpp search for the function "bool CHARACTER::DropItem(TItemPos Cell, BYTE bCount)" and under

Spoiler

    LPITEM item = NULL; 

add this:

Spoiler

    if (IsGM() == true)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("GameMasters can't drop items."));
        return false;
    }

Done with that one, you can close char_item.cpp. Let's move on

BUFF BLOCK

In char_skill.cpp find this:

Spoiler

bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaster)
{

and paste this under it:

Spoiler

    int pTableSkill[] = {94,95,96,109,110,111};
    
    for (int i = 0; i < _countof(pTableSkill); i++)
    {
        if (dwVnum == pTableSkill && IsGM() == true && pkVictim->IsGM() == false)
        {
            pkVictim = this; // That will return the buff to the buffer and not the target.
        }
    }

Done with that, next!

/SET COMMAND BLOCK FOR PLAYERS

In cmd_gm.cpp search for the function "ACMD(do_set)" and under

Spoiler

    tch = CHARACTER_MANAGER::instance().FindPC(arg1);

add this:

Spoiler

    if (tch->IsGM() == false)
    {
        ch->ChatPacket(CHAT_TYPE_INFO, "You can only use this on GM characters.");
        return;
    }

Done, but do not close, we have more commands to block!

/A COMMAND BLOCK FOR PLAYERS

Still in cmd_gm.cpp, search for the function "ACMD(do_advance)" and under

Spoiler

    LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg1);

add this:

Spoiler

    if (tch->IsGM() == false)
    {
        ch->ChatPacket(CHAT_TYPE_INFO, "You can only change the level of GM characters.");
        return;
    }

Do not close that file yet, one more command left to block :P

/SETSKILLOTHER COMMAND BLOCK FOR PLAYERS

Still in this file, search for the function "ACMD(do_setskillother)" and under

Spoiler

    tch = CHARACTER_MANAGER::instance().FindPC(arg1);

add this:

Spoiler

    if (tch->IsGM() == false)
    {
        ch->ChatPacket(CHAT_TYPE_INFO, "You can only change GM characters' skills.");
        return;
    }

Done with the commands, you may close cmd_gm.cpp and move on :)

EXCHANGE BLOCK

In exchange.cpp search for the function "bool CHARACTER::ExchangeStart(LPCHARACTER victim)" and under

Spoiler

    if ( IsOpenSafebox() || GetShopOwner() || GetMyShop() || IsCubeOpen() )
    {
        ChatPacket( CHAT_TYPE_INFO, LC_TEXT("다른 거래창이 열려있을경우 거래를 할수 없습니다." ) );
        return false;
    }

(if you have sash system in your source, the top line may be "if ( IsOpenSafebox() || GetShopOwner() || GetMyShop() || IsCubeOpen() || IsAcceOpen() )")
add this:

Spoiler

    if (IsGM() == false && victim->IsGM() == true)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("You cannot trade items with a Game Master."));
        return false;
    }

    if (IsGM() == true && victim->IsGM() == false)
    {
        ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Game Masters cannot trade items with players."));
        return false;
    }

Done with the exchange, moving on!

GUILD INVITATION BLOCK

In guild.cpp search for the function "void CGuild::Invite( LPCHARACTER pchInviter, LPCHARACTER pchInvitee )" and under

Spoiler

    else if ( pchInvitee->GetEmpire() != pchInviter->GetEmpire() ) 
    {
        pchInviter->ChatPacket( CHAT_TYPE_INFO, LC_TEXT("<길드> 다른 제국 사람을 길드에 초대할 수 없습니다.") );
        return;
    }

add this:

Spoiler

    else if (pchInviter->IsGM() == true && pchInvitee->IsGM() == false)
    {
        pchInviter->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<Guild> You can not invite a player to your guild!"));
        return;
    }    
    
    else if (pchInviter->IsGM() == false && pchInvitee->IsGM() == true)
    {
        pchInviter->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<Guild> You can not invite a GM to your guild!"));
        return;
    }

Here goes the guild invitation, let's move forward

FRIEND LIST BLOCK

In input_main.cpp search for the function "int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes)" and find this line:

Spoiler

if (ch->GetGMLevel() == GM_PLAYER && ch_companion->GetGMLevel() != GM_PLAYER)

change it like this:

Spoiler

if (ch->IsGM() == false && ch_companion->IsGM() == true)

Still in the same function, find this line in "case MESSENGER_SUBHEADER_CG_ADD_BY_NAME:":

Spoiler

                strlcpy(name, c_pData, sizeof(name));

and add this:

Spoiler

                if (ch->IsGM() == true && gm_get_level(name) == GM_PLAYER)
                {
                    ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("GameMasters can't have player friends."));
                    return CHARACTER_NAME_MAX_LEN;
                }

Friends are done. Let's move on to the last one!

BUYING ITEMS FROM PRIVATE SHOPS BLOCK

In shop_manager.cpp search for the function "void CShopManager::Buy(LPCHARACTER ch, BYTE pos)" and under

Spoiler

    CShop* pkShop = ch->GetShop();

add this:

Spoiler

    if (ch->IsGM() && pkShop->IsPCShop())
    {
        ch->ChatPacket(CHAT_TYPE_INFO, "GameMasters cannot buy items from players' shops.");
        return;
    }

Done :)
It's not something hard to do, I just gathered everything in one place, you can now sleep at night knowing that your GMs cannot fraud you.

I would like to give special thanks to @VegaS who wrote the blocks for buffs, party and guild invitation, thanks so much buddy :)

Note: These will block any interraction between a GM and a normal player, but a GM will be able to interract with another GM (example trade GM with GM).

And before someone asks yes I thought about a safebox block for GMs but there is no need for that since you can login to his account and create 3 players, then logout and delete them directly from their database, leaving 3 warriors with Level 0 that cannot login to the game. Let the poor GMs have their safebox it's the only thing left to them after that I think xD

So I hope I helped some folks here the tutorial is done :)

Kind regards ~ Mind Rapist

  • Like 7

Share this post


Link to post
Share on other sites

This is function good xD, in that tutorial I made a little mistake. now is fixed :ph34r:

#ifdef ENABLE_PROTECT_BUFF_GM
//testcodevegas_Function134
	int pTableSkill[] = {94, 95, 96, 109, 110, 111};
    
	for (int skill = 0; skill < _countof(pTableSkill); skill++)
	{
		if (pTableSkill[skill] == dwVnum && IsGM() && !pkVictim->IsGM())
		{
			ChatPacket(CHAT_TYPE_NOTICE, "<<Debug>> You try to give buff for player [%s], and this is player, you can't make that, the buff was returned to you.", pkVictim->GetName());
			pkVictim = this;
		} 
	}
#endif

 

And IsGM is same with GetGMLevel, only what is different:

CHARACTER::IsGM()

	if (m_pointsInstant.gm_level != GM_PLAYER)
		return true;

He have check if is not player return function with true and else with false so:

IsGM() or IsGM() == true ------->>  = true, you are are GameMaster.

!IsGM() or IsGM() == false ------->> = false, you are not a GameMaster.

CHARACTER::GetGMLevel()

He give you chance to check grade, like implementator, low_wizard etc etc

	return m_pointsInstant.gm_level;

He return your grade actual from character and you if you want to check if you are gm need to check like this:

GetGMLevel() > GM_PLAYER

 

So it depends on cases in which you want to use if you want to do a special check of a degree such as:

  • - IMPLEMENTOR
  • - HIGH_WIZARD
  • - GOD
  • - LOW_WIZARD

You can use GetGMLevel()

And if you want only to check if is GM, that means, all grade more as a player, you can check only with IsGM()

  • Like 5

Share this post


Link to post
Share on other sites

Just an info to shorten the code:

IsGM() == true          equals to:    IsGM()

Also

IsGM() == false   equals to:   !IsGM()

 

Btw, at private shop blocking, you forgot to block the item 71049.

 

If anyone wants to block the safebox, here a easy way for that:

Before:

void CHARACTER::ReqSafeboxLoad(const char* pszPassword)
{
	if (!*pszPassword || strlen(pszPassword) > SAFEBOX_PASSWORD_MAX_LEN)
	{
		ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> À߸øµÈ ¾ÏÈ£¸¦ ÀÔ·ÂÇϼ̽À´Ï´Ù."));
		return;
	}

 

After:

void CHARACTER::ReqSafeboxLoad(const char* pszPassword)
{
	if (!*pszPassword || strlen(pszPassword) > SAFEBOX_PASSWORD_MAX_LEN)
	{
		ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<â°í> À߸øµÈ ¾ÏÈ£¸¦ ÀÔ·ÂÇϼ̽À´Ï´Ù."));
		return;
	}
	else  if (IsGM())
	{
		ChatPacket(CHAT_TYPE_INFO, "Proibido mover itens para o armazem como GM.");
		return;
	}
  • Like 3

Share this post


Link to post
Share on other sites
13 hours ago, tierrilopes said:

Just an info to shorten the code:

IsGM() == true          equals to:    IsGM()

Also

IsGM() == false   equals to:   !IsGM()

Is it really necessary to repeat again what I wrote above?

 

23 hours ago, VegaS said:

CHARACTER::IsGM()


	if (m_pointsInstant.gm_level != GM_PLAYER)
		return true;

He have check if is not player return function with true and else with false so:

IsGM() or IsGM() == true ------->>  = true, you are are GameMaster.

!IsGM() or IsGM() == false ------->> = false, you are not a GameMaster.

And if you want only to check if is GM, that means, all grade more as a player, you can check only with IsGM().

 

Share this post


Link to post
Share on other sites

For offline shop:

offlineshop_manager.cpp

search: void COfflineShopManager::Buy(LPCHARACTER ch, BYTE pos)

and after     LPOFFLINESHOP pkOfflineShop = ch->GetOfflineShop();

add:

	if (ch->IsGM())
    {
        ch->ChatPacket(CHAT_TYPE_INFO, "GameMasters cannot buy items from players' shops.");
        return;
    }
	
  • Like 1

Share this post


Link to post
Share on other sites

Well I just saw Vegas' reply in a topic about the buffs so I did it and then I started playing with the IsGM() bool around the files. I tried to block any item/help interraction between a GM player and a normal player without affecting interraction between a GM with another GM or a player with another player. GMs exist to answer questions and solve problems not to help others cheat. I didn't had offline shop so thanks @ladcatalin for your function if I forgot anything else just post it here :)

 

Share this post


Link to post
Share on other sites

Thanks for release :)

I was too lazy for 'if (IsGM() && ch->GetGMLevel() < IMPLEMENTOR)' :D

Here is a replacement:

BOOL CHARACTER::IsLowGM() const
{
	return m_pointsInstant.gm_level > GM_PLAYER && m_pointsInstant.gm_level < GM_IMPLEMENTOR;
}

Regards

  • Like 1

Share this post


Link to post
Share on other sites

my friend i have a question how to block adding items to magazin for gms?

i mean; when gm will add item /i id he cant trade from gm hero but he can move made item to magazine and take this item from magazin from another  hero on same account without gm, then he can trade with this item

 

 

soory for my english

Share this post


Link to post
Share on other sites

For offline shop :

Open cmd_general.cpp in src/game search for :

ACMD(do_open_offline_shop)

add under :

	// If character is a gm and this server is not test server, return false
	if (ch->IsGM() && !test_server)
	{
		ch->ChatPacket(CHAT_TYPE_INFO, "Game admin can not open offline shop!");
		return;
	}

 

Share this post


Link to post
Share on other sites

I have a problem, when my GM character on CH99 and other character CH1, and i wrote ( /a name level ), CH99 does stop.

 

/A COMMAND BLOCK FOR PLAYERS

Still in cmd_gm.cpp, search for the function "ACMD(do_advance)" and under

    LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(arg1);

 

    if (tch->IsGM() == false)
    {
        ch->ChatPacket(CHAT_TYPE_INFO, "You can only change the level of GM characters.");
        return;
    }

Share this post


Link to post
Share on other sites

Haha, nice..but is kind of useless, gamemasters can get level 60 and set their alignment to negative, after that they can disable their protection and let the players kill 'Em..their items will drop.

Share this post


Link to post
Share on other sites
4 hours ago, Rudhon said:

Haha, nice..but is kind of useless, gamemasters can get level 60 and set their alignment to negative, after that they can disable their protection and let the players kill 'Em..their items will drop.

Remove their permission to that command (shortest) or add a check at the drop when pk function

 

  • Like 1

Share this post


Link to post
Share on other sites
Acum 15 ore, tierrilopes a spus:

Remove their permission to that command (shortest) or add a check at the drop when pk function

 

How to add a check at the drop dude you know ? How to stop admin to set him to free atack ?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×