• This is a read only backup of the old Emudevs forum. If you want to have anything removed, please message me on Discord: KittyKaev

[SOLVED] C++ PvP combat teleport script

Status
Not open for further replies.

Visa

Sexy Member
I'm trying to make a script that will teleport any player that initiates PvP in a zone and or area to Gurubashi. I compile the following with no errors however it doesn't seem to wanna work, and i'm sure i'm using the wrong arguments however any help is appreciated!

Code:
#include "ScriptPCH.h"

class pvp_port : public PlayerScript
{
public:
    pvp_port() : PlayerScript("pvp_port") { }

    void OnUpdateZone(Player* player, uint32 /*newZone*/, uint32 newArea)
    {
        if (player->IsPvP() && newArea == 4089)
        {
            player->TeleportTo(0, -13184.7f, 311.396f, 21.8584f, 4.26875f);
            ChatHandler(player->GetSession()).PSendSysMessage("|cffff6060[PvP Restriction]:|r %s has been teleported to Gurubashi for PvPing in a Non-PvP Zone.", player->GetName());
        }
    }
};

void AddSC_pvp_port()
{
    new pvp_port();
}
 

Tommy

Founder
I'm trying to make a script that will teleport any player that initiates PvP in a zone and or area to Gurubashi. I compile the following with no errors however it doesn't seem to wanna work, and i'm sure i'm using the wrong arguments however any help is appreciated!

Code:
#include "ScriptPCH.h"

class pvp_port : public PlayerScript
{
public:
    pvp_port() : PlayerScript("pvp_port") { }

    void OnUpdateZone(Player* player, uint32 /*newZone*/, uint32 newArea)
    {
        if (player->IsPvP() && newArea == 4089)
        {
            player->TeleportTo(0, -13184.7f, 311.396f, 21.8584f, 4.26875f);
            ChatHandler(player->GetSession()).PSendSysMessage("|cffff6060[PvP Restriction]:|r %s has been teleported to Gurubashi for PvPing in a Non-PvP Zone.", player->GetName());
        }
    }
};

void AddSC_pvp_port()
{
    new pvp_port();
}

If I remember correctly OnUpdateZone is only called when you enter a new zone/area. If that's correct, you're probably assuming as soon as a player turns PvP on it will port them, but it will only happen if they re-enter that specific area.

Also, "player->GetName()" will cause a crash because you aren't calling const char: "c_str()";

Code:
ChatHandler(player->GetSession()).PSendSysMessage("|cffff6060[PvP Restriction]:|r %s has been teleported to Gurubashi for PvPing in a Non-PvP Zone.", player->GetName()[COLOR="#00FF00"].c_str()[/COLOR]);
 

Visa

Sexy Member
do you know off the top of your head which one detects pvp combat, i know it exists i just dont know which it is
 

Tommy

Founder
https://github.com/TrinityCore/Trin...60715eb/src/server/game/Scripting/ScriptMgr.h

I don't see any function there, that would trigger on PVP state changes. Maybe you can use an OutdoorPVP script for that, but i actually never used them nor could imagine how they work.

OutdoorPvP has 'OnPlayerEnter' and 'OnPlayerLeave' functions. Basically the same thing that player has. "OnUpdateZone" handles player entering a new area. OutdoorPvP isn't hard to setup, I even have a template in the C++ template thread via sticky in TrinityCore -> C++ section; however, I don't think making an OutdoorPvP script would be appropriate for this. I would honestly add it in Unit::SetPvP(bool state) function in Unit.cpp since it handles setting the player's PvP flag.
 

Visa

Sexy Member
I am so confused if I can only use a bool state for this unit function then how do i define player when it wont let me
 

Tommy

Founder
I am so confused if I can only use a bool state for this unit function then how do i define player when it wont let me

Check if the type of the unit is a player, if so, call player like so: "ToPlayer()->TeleportTo(...);"

Example:

Code:
void Unit::SetPvP(bool state)
{
[COLOR="#00FF00"]    Player* player;
    if (GetTypeId() == TYPEID_PLAYER)
        player = ToPlayer();[/COLOR]

    if (state)
    {
        SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
        [COLOR="#00FF00"]player->TeleportTo(...);[/COLOR]
    }
    else
        RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
}

Explanation:

"if (state)"

The above is checking if state is true: which will set the player flagged PvP and in your code logic: teleports the player to gurubashi.

"else"

state is not true: which will remove the PvP flag from the player.
 

Visa

Sexy Member
Hmm fair enough however it still seems to outcome wrong somehow..

gmnwKVU.png
 

Attachments

  • gmnwKVU.jpg
    gmnwKVU.jpg
    13.6 KB · Views: 43

Tommy

Founder
Hmm fair enough however it still seems to outcome wrong somehow..

If Unit::SetPvP(bool state) was a PlayerScript hook I would've said so. If you read my post describing this function, I did write it was located in "Unit.cpp":

I would honestly add it in Unit::SetPvP(bool state) function in Unit.cpp since it handles setting the player's PvP flag.

Open Unit.cpp, press Ctrl + F and search for Unit::SetPvP.

Also, the "player->TeleportTo(...)" the periods in TeleportTo are for you to replace it with the appropriate x, y, z (etc) arguments, not leave it as is. :p
 

Visa

Sexy Member
yes i know whereabouts its located but if its not a playerscript then its a unitscript or does it not require any headers at all will that even work and yeah i know abt the teleport args i just left it for now but ive never worked with something outside of player,item, or creature script
 

Tommy

Founder
yes i know whereabouts its located but if its not a playerscript then its a unitscript or does it not require any headers at all will that even work and yeah i know abt the teleport args i just left it for now but ive never worked with something outside of player,item, or creature script

I don't get why you're worrying about things that don't need to be worried about. It isn't as complicated as you think. Just go into Unit.cpp, search for Unit::SetPvP and do what I coded for you above. Simple as that. And no, there's no such thing as "UnitScript" -- just the Unit class itself.
 

Rochet2

Moderator / Eluna Dev
SQL:
You could use the booty bay bruiser type guards.
5 years back we used the booty bay bruiser with a few modifications so that it casted the spell 5 (instant kill) on any player who attacked other players.
That is completely doable from DB by using smart_scripts and using the booty bay bruiser as a base NPC. Similar NPCs can be found in silithus as well.

C++ script:
Another option is to script your own creature to teleport the players who PvP in range.

Another option would be to use the original script you have or similar and use the map update tick with a player zone / area check.
Or make a timed event for the player on area enter to do the check all the time and remove it when he exits the area.

You can also make a script for OnPacketSend hook, and only check the attacking packet.
If the player is in the zone/area and sends the packet, kick him in the butt.

You can also make an aura script and make the aura apply on area enter by using spell_area table and then the aura script would do the check on tick.

One damage only alternative could be using UnitScript hooks for doing melee and spell or simple damage and teleport the player when the damage happened in the given area etc.
Btw. PlayerScript is a derivative of UnitScript. Make a PlayerScript and use UnitScript hooks.

So many possibilities if the only goal is to use the haspvp check or similar.
You dont have to have a hook for the specific thing, you can almost always use packet hooks if nothing better exists.
Even jumping can be scripted with those.

Coremod:
what tommy said
 
Last edited:

Visa

Sexy Member
oh tommy you want me to coreedit unit.cpp directly? I thought i had to make a new separate .cpp file and hook it to the scriptloader. but if i put it directly in unit.cpp where Unit::SetPvP is set then how will it know which map, zone, area i want it to occur in and yes rotchet i could've done those but i just thought something that teleports people that pvp in your mall or so to gurubashi and announce in world chat would be a little more cooler :p thanks though i appreciate your feedback heavily.

sometimes i feel like a retard lmao


----------------edit--------------

i think i answered my own question
maybe
Code:
void Unit::SetPvP(bool state)
{
    Player* player;
    if (player->GetTypeId() == TYPEID_PLAYER)
        player = ToPlayer();

    if (state && player->GetAreaId == 4089)
    {
        SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
        player->TeleportTo(0, -13184.7f, 311.396f, 21.8584f, 4.26875f);
    }
    else
    {
        RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
    }
}
 
Last edited:

Tommy

Founder
oh tommy you want me to coreedit unit.cpp directly? I thought i had to make a new separate .cpp file and hook it to the scriptloader. but if i put it directly in unit.cpp where Unit::SetPvP is set then how will it know which map, zone, area i want it to occur in

You almost answered your own question. You shouldn't put the area check in the if (state) statement since it will only allow you to flag via that AreaId only. Do it like so:

Code:
void Unit::SetPvP(bool state)
{
    Player* player;
    if (player->GetTypeId() == TYPEID_PLAYER)
        player = ToPlayer();

    if (state)
    {
        SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
        [COLOR="#00FF00"]if (player->GetAreaId() == 4089)[/COLOR]
            player->TeleportTo(0, -13184.7f, 311.396f, 21.8584f, 4.26875f);
    }
    else
    {
        RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
    }
}
 

Visa

Sexy Member
Oh god I hope this works, I have a random question for you if i'm allowed to ask that LOL, how would you go about adding a cooldown / timer to a certain command within a commandscript?
 

Tommy

Founder
Oh god I hope this works, I have a random question for you if i'm allowed to ask that LOL, how would you go about adding a cooldown / timer to a certain command within a commandscript?

I'd either use a BasicEvent (if I'm correct that you can) or log the last time the command was used and compare it to a specific time the command can be used again.
 

Visa

Sexy Member
I'd either use a BasicEvent (if I'm correct that you can) or log the last time the command was used and compare it to a specific time the command can be used again.

I see, fascinating.

OT: I'm getting the following warning:
Code:
warning C4700: uninitialized local variable 'player' used '.../unit.cpp'

Code:
void Unit::SetPvP(bool state)
{
    Player* player;
    [COLOR="#FF0000"]if (player->GetTypeId() == TYPEID_PLAYER)[/COLOR]
        player = ToPlayer();

    if (state)
        SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
        if (player->GetAreaId() == 4089)
            player->TeleportTo(0, -13184.7f, 311.396f, 21.8584f, 4.26875f);
    else
        RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
}

^ Currently what I have, will compile with no errors only that warning however upon worldserver startup it will crash @ Starting Battlefield System.

Code:
Starting Battleground System
>> Loaded 11 battlegrounds in 0 ms
Starting Outdoor PvP System
>> Loaded 6 outdoor PvP definitions in 0 ms
Starting Battlefield System

-worldserver.exe has stopped working-

The code with red text is where the warning is pointing to, the exact line.
 

Tommy

Founder
Well, the code is wrong, actually. Instead of calling player (which is NULL) and checking what the typeId is. You also removed the brackets from "if (state)", why? Regardless, I failed to see one problem which is checking if player does not equal null via GetAreaId() statement.

Code:
void Unit::SetPvP(bool state)
{
    Player* player;
    if ([COLOR="#00FF00"]GetTypeId()[/COLOR] == TYPEID_PLAYER)
        player = ToPlayer();

    if (state)
    {
        SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
        if ([COLOR="#00FF00"]player != NULL &&[/COLOR] player->GetAreaId() == 4089)
            player->TeleportTo(0, -13184.7f, 311.396f, 21.8584f, 4.26875f);
    }
    else
        RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
}

You must've added player yourself in the TYPEID_PLAYER check, because in this post: http://emudevs.com/showthread.php/4639-C-PvP-combat-teleport-script?p=32295&viewfull=1#post32295 -- mine was correct. If the warning still occurs, change "Player* player;" to: "Player* player = NULL;"
 

Rochet2

Moderator / Eluna Dev
change "Player* player;" to: "Player* player = NULL;"
should do that in any case, since otherwise the variable is not initialized to anything and using it, including testing against null is undefined.
 

Visa

Sexy Member
Compiled using:
Code:
Player* player;" to: "Player* player = NULL;

if (player != NULL && ...

It works flawlessly, when player in the specified area has their pvp flag enabled it will send them to the selected coords.

However people can just for amusement enable their pvp in that area and get sent as well

Or if someone who was pvping before decides to go to the specified area (mall) it will teleport them to guru as well.

Maybe I can actually use that void OnUpdateZone to remove their pvp flag before the script catches them and sends them to guru, which would act first?
 
Status
Not open for further replies.
Top