• 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] looking for help, [Learning Purposes]

Status
Not open for further replies.

callmephil

Respected Member
Hey guys, so i'm actually releasing somes script for my learning purposes and i would like to know if anyone can help me to optimises my scripts by giving me somes tips by replay like that everyone can have the info.

let's start with this :

http://emudevs.com/showthread.php/2390-Wotlk-Cata-Ultimate-Duel-Script

* : before you ask why i'm asking this just note this : i actually does not have enough time to learn by myself with testing few new things it's taking too much time to check & read everything on the net.
thanks anyway.
 

Tommy

Founder
v1.2:

For starters, you misspelled 'ScriptPCH.h' wrong. However, you don't need to include that header file, "Chat.h" and "MapManager.h" because CMake takes care of that.


Secondly, the configuration options really aren't necessary, especially, "Duel_Reward.Cata_User". It throws errors because it isn't Cataclysm, you need to set it up in a define directive with a '#if' statement.


Instead of having so many define directives and extra enumerators, you can put everything into one enumerator:

Code:
enum Misc
{
    TOKEN_LOSER = 1,
    TOKEN_WINNER = 3,
    AREA_ID = 5,
    ZONE_ID = 6,
    ITEM_REWARD_ID = 241
};


When you're running a query like this:

Code:
QueryResult result = CharacterDatabase.PQuery("SELECT duelR FROM characters WHERE guid = '%u'", player->GetGUID());

You don't need to use the 'do' statement, as you're selecting only one row.

Instead of snprintf, I suggest using 'ostringstream'. It's cleaner and better:

Code:
            std::ostringstream ss;
            ss << "|cffff6060[Rating] :|r |cffFFFF00" << fields[0].GetUInt32() << "|r \n";					
            ChatHandler(player->GetSession()).SendSysMessage(ss.str().c_str());

Even though this might not matter, you should always try and close your '|cff' colors with '|r'.

When using 'PSendSysMessage', it excepts an argument or arguments. If you don't have any arguments, use 'SendSysMessage' instead.


The variable 'plTarget' can be changed to 'playerTarget' as 'plTarget' is confusing and not really clean in my perspective.


I'm not entirely sure why you have so many PlayerScript classes. You only need one and only one.

When you have if statements with only one thing in it, you don't need brackets. For example:

Code:
			if (player->getLevel() >= 1 && playerTarget->getLevel() <= 79 && (type == DUEL_WON || type == DUEL_INTERRUPTED || type == DUEL_FLED))
			{
				return;
			}

Can be:

Code:
			if (player->getLevel() >= 1 && playerTarget->getLevel() <= 79 && (type == DUEL_WON || type == DUEL_INTERRUPTED || type == DUEL_FLED))
				return;

I don't see the real point in having some of the extra if statements like checking for latency, etc.

When saving, I suggest using 'GetGUIDLow()' instead of 'GetGUID()'.


You have a huge amount of executing into the database. It honestly would be wise to have a nice world timer to execute that data every 10-15 minutes (that's the default player save time) to reduce the amount of executions.

Code:
				player->SaveToDB();
				playerTarget->SaveToDB();

That isn't needed as the player already saves every so often. I'm also not sure what you're saving. The tokens? Either way, it can be removed.


Comments are a nice way to tell/show people what a certain variable, function or if statement does - the way you're commenting isn't really clean at all. Reduce the amount of comments and simplify them.

Code:
/* SQL (Only if you use Rating System) (Characters database) 
UPDATE `characters` create `duelW` int(10) unsigned NOT NULL DEFAULT '0';
UPDATE `characters` create `duelL` int(10) unsigned NOT NULL DEFAULT '0';
UPDATE `characters` create `duelR` int(10) unsigned NOT NULL DEFAULT '1000';
*/

/* WorldConf (At the end of the file) 
# Duel_Reward.Cata_User
#        Default:     0 - (Disabled)
#                     1 - (Enabled)

Duel_Reward.Cata_User = 0

# Duel_Reward.Wotlk_User
#        Default:     0 - (Disabled)
#                     1 - (Enabled)

Duel_Reward.Wotlk_User = 0

# Duel_Reward.Rating
#        Default:     0 - (Disabled)
#                     1 - (Enabled)

Duel_Reward.Rating = 0
*/

That can be delete and put into your main post as information on how to set it up, and what you need to query. The configuration settings aren't needed, so those can be deleted.


When coding, it is wise to know what functions can do. You can right click a function -> Go To Definition to view it. The 'void Unit::CombatStop(bool includingCast)' already calls 'AttackStop()' and interrupts non-melee spells so you don't need to call those again.

Lastly, indentation makes your script readable. Indentation increases by 4 blocks. Using tab and not paying attention to what is being indented can cause whitespaces and messed up code. You can also mess up indentation by copying it from sites like pastebin.


Everything I mentioned above, I corrected:

Code:
#include "Pet.h"

/* SQL (Only if you use Rating System) (Characters database) 
    UPDATE `characters` create `duelW` int(10) unsigned NOT NULL DEFAULT '0';
    UPDATE `characters` create `duelL` int(10) unsigned NOT NULL DEFAULT '0';
    UPDATE `characters` create `duelR` int(10) unsigned NOT NULL DEFAULT '1000';
*/

/*
    Ultimate Duel Script (Reward/Rating/Phasing/Security/Zoned & Reset)
    Author : Philippe
    Release Date : 14/01/14
    Script Complete : 100 %
    Version : 3.3.5 & 4.3.4
    TrinityCore based.
    Tested on 4.3.4 Works Well

Note :
    -Reward Part is explain you need to read. 
    -For the Rating system please use SQL given. You can add a Top for you're website or create a rating npc. 

    -Phasing system isn't done by me, Credits go to Deathmane1337 (*******) & Rewrite by Rochet & Tommy (EmuDevs)
    Rochet & Tommy (EmuDevs) : 
    http://emudevs.com/showthread.php/2316-new-phaseing-out-duel-dont-work-100?highlight=duel
    http://emudevs.com/showthread.php/2282-phase-out-dueling-error/page2
*/

enum Misc
{
    TOKEN_LOSER = 1,
    TOKEN_WINNER = 3,
    AREA_ID = 5,
    ZONE_ID = 6,
    ITEM_REWARD_ID = 241
};

// Shows/Saves your rating
bool showRating = true;

#define REWARD_CATA 0 // 0 = WotLK, 1 = Cataclysm


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

    // Resets players and starts the duel!
    void OnDuelStart(Player* player, Player* playerTarget)
    {
        RevivePlayer(player);
        RevivePlayer(playerTarget);
        player->SetPower(POWER_RAGE, 0);
        playerTarget->SetPower(POWER_RAGE, 0);
        player->SetPower(POWER_RUNIC_POWER, 0);
        playerTarget->SetPower(POWER_RUNIC_POWER, 0);

        if(showRating)
        {
            // Not Tested
            RatingInfo(player);
            RatingInfo(playerTarget);
        }

        Map* map = player->GetMap();
        uint32 usedPhases = 0; // used phases
        Map::PlayerList const& players = map->GetPlayers();
        for (Map::PlayerList::const_iterator iter = players.begin(); iter != players.end(); ++iter)
        {
            Player* check = iter->GetSource();
           if (!check || !check->GetSession())
               continue;
           usedPhases |= check->GetPhaseMask(); // insert player's phases to used phases
        }

        for (uint32 phase = 2; phase <= ULONG_MAX/2; phase *= 2) // loop all unique phases
        {
            if (usedPhases & phase) // If phase in use
                continue;

            player->SetPhaseMask(phase, true);
            playerTarget->SetPhaseMask(phase, true);
            if (GameObject* go = map->GetGameObject(player->GetUInt64Value(PLAYER_DUEL_ARBITER)))
                go->SetPhaseMask(phase, true);

            return;
        }
        // Could not phase players :(
    }	

    // Removing spell CD, resetting players, gives rewards and ends the duel
    void OnDuelEnd(Player* player, Player* playerTarget,  DuelCompleteType type)
    {
        player->RemoveAllSpellCooldown();
        playerTarget->RemoveAllSpellCooldown();
        RevivePlayer(player);
        RevivePlayer(playerTarget);		
        player->CombatStop();
        playerTarget->CombatStop();

        player->SetPhaseMask(GetPhase(player), true);
        if (Pet* pet = player->GetPet())
            pet->SetPhaseMask(GetPhase(player), true);
        playerTarget->SetPhaseMask(GetPhase(playerTarget), true);
        if (Pet* pet = playerTarget->GetPet())
            pet->SetPhaseMask(GetPhase(playerTarget), true);

        if ((player->GetZoneId() == ZONE_ID && playerTarget->GetZoneId() == ZONE_ID || player->GetAreaId() == AREA_ID &&  playerTarget->GetAreaId() == AREA_ID) && type == DUEL_WON)
        {
            if (player->getLevel() >= 1 && playerTarget->getLevel() <= 79 && (type == DUEL_WON || type == DUEL_INTERRUPTED || type == DUEL_FLED))
                return;

            if (playerTarget->GetSession()->GetSecurity() >= 2 && (type == DUEL_WON || type == DUEL_INTERRUPTED || type == DUEL_FLED) || 
                player->GetSession()->GetSecurity() >= 2 && (type == DUEL_WON || type == DUEL_INTERRUPTED || type == DUEL_FLED))
                return;

            if (playerTarget->GetStat(STAT_STAMINA) < 4000 && type == DUEL_WON)
                return;

            if (player->GetSession()->GetRemoteAddress() == playerTarget->GetSession()->GetRemoteAddress())
            {
                ChatHandler(player->GetSession()).SendSysMessage("|cFFFFFC00[Cheating System]|cFF00FFFF you can't claim reward vs a same ip !");
                return;
            }
        }
#if REWARD_CATA == 1
        player->ModifyCurrency(ITEM_REWARD_ID, TOKEN_WINNER, true, true);
        playerTarget->ModifyCurrency(ITEM_REWARD_ID, TOKEN_LOSER, true, true);
#else // WotLK
        player->AddItem(ITEM_REWARD_ID, TOKEN_WINNER);
        playerTarget->AddItem(ITEM_REWARD_ID, TOKEN_LOSER);
#endif

        if(showRating)
        {
            // Saving Data
            CharacterDatabase.PExecute("UPDATE characters SET duelW = (duelW+1) WHERE guid = '%u'", player->GetGUIDLow());
            CharacterDatabase.PExecute("UPDATE characters SET duelL = (duelL+1) WHERE guid = '%u'", playerTarget->GetGUIDLow());
            CharacterDatabase.PExecute("UPDATE characters SET duelR = (duelR+14) WHERE guid = '%u'", player->GetGUIDLow());
            CharacterDatabase.PExecute("UPDATE characters SET duelR = (duelR-7) WHERE guid = '%u'", playerTarget->GetGUIDLow()); 
            ChatHandler(player->GetSession()).SendSysMessage("|cFFFFFC00[System]|cFF00FFFF Well done you won 14 Points !");
            ChatHandler(playerTarget->GetSession()).SendSysMessage("|cFFFFFC00[System]|cFF00FFFF Ow you lose 7 Points !");
        }
    }

    // Rating Info Setup Config - Not Tested
    void RatingInfo(Player* player)
    {
        if(showRating)
        {
            QueryResult result = CharacterDatabase.PQuery("SELECT duelR FROM characters WHERE guid = '%u'", player->GetGUID());
            if(!result)
                return;

            Field * fields = result->Fetch();
            std::ostringstream ss;
            ss << "|cffff6060[Rating] :|r |cffFFFF00" << fields[0].GetUInt32() << "|r \n";					
            ChatHandler(player->GetSession()).SendSysMessage(ss.str().c_str());
        }
    }

    void RevivePlayer(Player* player)
    {
        player->SetHealth(player->GetMaxHealth());
        if(player->getPowerType() == POWER_MANA)
            player->SetPower(POWER_MANA, player->GetMaxPower(POWER_MANA));
        if(player->getPowerType() == POWER_ENERGY)
            player->SetPower(POWER_ENERGY, player->GetMaxPower(POWER_ENERGY));
    }

    // Attempt in storing the player phase with spell phases included.
    uint32 GetPhase(Player* player) const
    {
        if (player->IsGameMaster())
           return uint32(PHASEMASK_ANYWHERE);

        // GetPhaseMaskForSpawn copypaste
        uint32 phase = PHASEMASK_NORMAL;
        Player::AuraEffectList const& phases = player->GetAuraEffectsByType(SPELL_AURA_PHASE);
        if (!phases.empty())
            phase = phases.front()->GetMiscValue();
        if (uint32 n_phase = phase & ~PHASEMASK_NORMAL)
            return n_phase;

        return PHASEMASK_NORMAL;
    }
};

void AddSC_Reset()
{
    new Duel_Reset();
}
 
Last edited:

callmephil

Respected Member
for info V1.3 is cleaner And Wow, Awesome thanks for all thoses tips.
but i'm still confused about few things like suppressing few things like security, all security added are like checking life - gamemaster - ip etc are here to check any eventuallity of farming etc & also explanation because if you remove thoses explanation to the player, he will always ask why he isin't winning any reward or something..
also combat stop is here to stop "Auto-Attack" Exploit i don't know if you already got this problem when someone kill another guy directly after a duel even if they are in sanctuary zone.
btw putting everything together will be harder to understand or edit the file no ?

also here
Code:
 #if REWARD_CATA == 1
        player->ModifyCurrency(ITEM_REWARD_ID, TOKEN_WINNER, true, true);
        playerTarget->ModifyCurrency(ITEM_REWARD_ID, TOKEN_LOSER, true, true);
#else // WotLK
        player->AddItem(ITEM_REWARD_ID, TOKEN_WINNER);
        playerTarget->AddItem(ITEM_REWARD_ID, TOKEN_LOSER);
#endif

Actually on 3.3.5 there is no function for modifycurrency so i've added a small explication about deleting or commenting lines for different user.

another thing wierd, why removing worldconfig modification ? if someone want to use it for a repack ?

& also removing runic/rage power is bad at the start of a duel probably because alot of warrior/dk prepare therself before the fight (3.2.1 sec) because the reset occurs at 0 when the duel start. so.. as player i can say it's a pain in the ass. (Will be removed soon)

adding the choice between area or zone checking could be a nice idea if we don't want to add a large map & also i should see where i can find something like adding multi-area do you think NULL can work here?
 
Last edited:

callmephil

Respected Member
btw
Code:
    UPDATE `characters` create `duelW` int(10) unsigned NOT NULL DEFAULT '0';
    UPDATE `characters` create `duelL` int(10) unsigned NOT NULL DEFAULT '0';
    UPDATE `characters` create `duelR` int(10) unsigned NOT NULL DEFAULT '1000';

Not working for me. maybe SQLYOG ?
 

Tommy

Founder
for info V1.3 is cleaner And Wow, Awesome thanks for all thoses tips.
but i'm still confused about few things like suppressing few things like security, all security added are like checking life - gamemaster - ip etc are here to check any eventuallity of farming etc & also explanation because if you remove thoses explanation to the player, he will always ask why he isin't winning any reward or something..
also combat stop is here to stop "Auto-Attack" Exploit i don't know if you already got this problem when someone kill another guy directly after a duel even if they are in sanctuary zone.
btw putting everything together will be harder to understand or edit the file no ?

also here
Code:
 #if REWARD_CATA == 1
        player->ModifyCurrency(ITEM_REWARD_ID, TOKEN_WINNER, true, true);
        playerTarget->ModifyCurrency(ITEM_REWARD_ID, TOKEN_LOSER, true, true);
#else // WotLK
        player->AddItem(ITEM_REWARD_ID, TOKEN_WINNER);
        playerTarget->AddItem(ITEM_REWARD_ID, TOKEN_LOSER);
#endif

Actually on 3.3.5 there is no function for modifycurrency so i've added a small explication about deleting or commenting lines for different user.

another thing wierd, why removing worldconfig modification ? if someone want to use it for a repack ?

& also removing runic/rage power is bad at the start of a duel probably because alot of warrior/dk prepare therself before the fight (3.2.1 sec) because the reset occurs at 0 when the duel start. so.. as player i can say it's a pain in the ass. (Will be removed soon)

adding the choice between area or zone checking could be a nice idea if we don't want to add a large map & also i should see where i can find something like adding multi-area do you think NULL can work here?

If you didn't notice, I kept the if statements regarding the gamemaster and IP checks. I just removed the messaging. Why did I remove the messages? Well, a lot of those error statements were really obvious and I'm sure they will get as to why they aren't receiving their token.

also combat stop is here to stop "Auto-Attack" Exploit i don't know if you already got this problem when someone kill another guy directly after a duel even if they are in sanctuary zone.
btw putting everything together will be harder to understand or edit the file no ?

I didn't ask for CombatStop() is for, considering I know what it is for. What I said is that 'CombatStop()' already calls 'AttackStop()', so you don't need to call 'AttackStop()' again since 'CombatStop()' already calls it. 'CombatStop()' interrupts non-melee spell cast, hence why that wasn't needed as well. Double check your functions so you don't come up with duplicate code.

What do you mean putting everything together? All the PlayerScript you had? The way you had it was very wrong and unclean. Just because you think it will help the user understand the code more by spamming 'PlayerScript', doesn't make it clean and understandable at all. It is very, very bad code practice. If people looked at the code they will think it is okay to do the same, but it is not okay. I put the code together because there was no point in having 2 extra PlayerScript classes when you can put it all into one, which is correct and clean.

When programming CreatureScript, PlayerScript, ItemScript, etc - if there's no need for extra classes, don't do it. One PlayerScript class can be used for anything. It depletes the purpose in having more, which it should be that way. You want to find the most suitable way to do this without spamming classes of the same script type.

Comments still exists, but in a more clean way. I mean, there's really nothing clean about comments, so you can re-add whatever you like.

& also removing runic/rage power is bad at the start of a duel probably because alot of warrior/dk prepare therself before the fight (3.2.1 sec) because the reset occurs at 0 when the duel start. so.. as player i can say it's a pain in the ass. (Will be removed soon)

I don't get what you're implying. The rage and runic power is being reset to 0 which is logical and correct, expect it should check the class of the player.

another thing wierd, why removing worldconfig modification ? if someone want to use it for a repack ?

Because they wasn't needed at all. If you look at the script I replaced:

'Duel_Reward.Rating' with a boolean called 'showRating' you can edit via the script (it's on the top)
'Duel_Reward.Cata_User'/'Duel_Reward.Wotlk_User' with '#define REWARD_CATA 0 // 0 = WotLK, 1 = Cataclysm' - You can change it from 1 to 0 if you're wanting to use it via a different patch.

Well, the way you had it, it errored because the code was for Cataclysm and not WotLK.

Actually on 3.3.5 there is no function for modifycurrency so i've added a small explication about deleting or commenting lines for different user.

Doing it like:

Code:
 #if REWARD_CATA == 1
        player->ModifyCurrency(ITEM_REWARD_ID, TOKEN_WINNER, true, true);
        playerTarget->ModifyCurrency(ITEM_REWARD_ID, TOKEN_LOSER, true, true);
#else // WotLK
        player->AddItem(ITEM_REWARD_ID, TOKEN_WINNER);
        playerTarget->AddItem(ITEM_REWARD_ID, TOKEN_LOSER);
#endif

Users will only need to edit 'REWARD_CATA' value at the top of the script instead of removing code. Think of REWARD_CATA as a Preprocessor Definition, except it is defined in the script. Instead of it erroring because 'ModifyCurrency' is Cataclysm, it will ignore the code until REWARD_CATA value is 1 - in that case, it will ignore the WotLK 'AddItem' code.

adding the choice between area or zone checking could be a nice idea if we don't want to add a large map & also i should see where i can find something like adding multi-area do you think NULL can work here?

What do you mean, 'can NULL work here'?

btw
Code:
    UPDATE `characters` create `duelW` int(10) unsigned NOT NULL DEFAULT '0';
    UPDATE `characters` create `duelL` int(10) unsigned NOT NULL DEFAULT '0';
    UPDATE `characters` create `duelR` int(10) unsigned NOT NULL DEFAULT '1000';

Not working for me. maybe SQLYOG ?

No, the query is wrong. Instead of 'UPDATE', it should be 'ALTER' and you need to specify what column it needs to be after.

Here is the correct way:

Code:
ALTER TABLE `characters` ADD COLUMN `duelW` int(10) UNSIGNED DEFAULT 0 NULL AFTER `deleteDate`;
ALTER TABLE `characters` ADD COLUMN `duelL` int(10) UNSIGNED DEFAULT 0 NULL AFTER `duelW`;
ALTER TABLE `characters` ADD COLUMN `duelR` int(10) UNSIGNED DEFAULT 1000 NULL AFTER `duelL`;
 
Status
Not open for further replies.
Top