// written and created by tommy emudevs.com/forum.php //
struct KillStreak
{
uint16 kills;
uint32 lastKilledGUID; // Prevents cheating
};
std::unordered_map<uint32, KillStreak> KillStreakMap;
class killstreak_world_load : public WorldScript
{
public:
killstreak_world_load() : WorldScript("killstreak_world_load") { }
void OnStartup()
{
QueryResult result = CharacterDatabase.Query("SELECT killerGUID, kills, lastKilledGUID FROM character_killstreak");
if (result)
{
do
{
Field* fields = result->Fetch();
KillStreak killStreak;
killStreak.kills = fields[1].GetUInt16();
killStreak.lastKilledGUID = fields[2].GetUInt32();
KillStreakMap[fields[0].GetUInt32()] = killStreak;
} while (result->NextRow());
}
}
};
class killstreak_player_system : public PlayerScript
{
public:
killstreak_player_system() : PlayerScript("killstreak_player_system") { }
void OnSave(Player* player) // Save killstreak when player saves (it is best to do this for performance reasons.)
{
std::unordered_map<uint32, KillStreak>::iterator itr = KillStreakMap.find(player->GetGUIDLow());
if (itr != KillStreakMap.end())
{
QueryResult result = CharacterDatabase.PQuery("SELECT `kills`, `lastKilledGUID` FROM `character_killstreak` WHERE killerGUID=%u", player->GetGUIDLow());
if (!result) // Player isn't saved yet
CharacterDatabase.PExecute("INSERT INTO `character_killstreak` VALUES(%u, %u, %u)", itr->first, itr->second.kills, itr->second.lastKilledGUID);
else
{
Field* fields = result->Fetch();
uint16 kills = fields[0].GetUInt16();
uint32 lastKilledGUID = fields[1].GetUInt32();
if (itr->second.kills < kills) // Did they lose their KS?
CharacterDatabase.PExecute("DELETE FROM `character_killstreak` WHERE killerGUID=%u", itr->first);
else // Else just continue updating
{
kills += itr->second.kills;
if (lastKilledGUID == itr->second.lastKilledGUID)
CharacterDatabase.PExecute("UPDATE `character_killstreak` SET kills=%u WHERE killerGUID=%u", kills, itr->first);
else
CharacterDatabase.PExecute("UPDATE `character_killstreak` SET kills=%u, lastKilledGUID=%u WHERE killerGUID=%u", kills, itr->second.lastKilledGUID, itr->first);
}
}
}
}
void OnPVPKill(Player* killer, Player* victim)
{
if (killer->GetGUIDLow() == victim->GetGUIDLow())
return;
std::ostringstream ss;
std::unordered_map<uint32, KillStreak>::iterator itr = KillStreakMap.find(victim->GetGUIDLow());
if (itr != KillStreakMap.end()) // KillStreak ends
{
ss << victim->GetName() << "'s "
<< "killstreak ended at "
<< itr->second.kills << " kills!";
sWorld->SendGlobalText(ss.str().c_str(), NULL);
KillStreakMap.erase(victim->GetGUIDLow());
}
std::unordered_map<uint32, KillStreak>::iterator itr2 = KillStreakMap.find(killer->GetGUIDLow());
if (itr2 != KillStreakMap.end()) // KillStreak exists
{
if (victim->GetGUIDLow() == itr2->second.lastKilledGUID)
{
ChatHandler(killer->GetSession()).SendSysMessage("Kill someone else besides the same person!");
return;
}
switch (itr2->second.kills)
{
case 5: // 5 kills
break;
case 10: // 10 kills
break;
case 20: // 20 kills
ss.str("");
if (RewardTitle(killer, 30)) // Change 30 to the appropriate itemId!
{
ss << killer->GetName()
<< " has earned a title for getting 20 kills on their killstreak!";
sWorld->SendGlobalText(ss.str().c_str(), NULL);
}
break;
// case X: etc...
}
}
else // Killstreak begins
{
KillStreak newKillStreak;
newKillStreak.kills = 1; // Kills starting
newKillStreak.lastKilledGUID = victim->GetGUIDLow(); // Last victim killed
KillStreakMap[killer->GetGUIDLow()] = newKillStreak;
}
}
bool RewardTitle(Player* player, uint32 title)
{
CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(title);
if (!titleEntry) // Invalid entry
return false;
if (!player->HasTitle(titleEntry)) // Reward this Title
player->SetTitle(titleEntry);
else // Already has this title
return false;
}
};
void SetupKillStreak()
{
new killstreak_player_system;
new killstreak_world_load;
}