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();
}