*Fix a crash and merge.
--HG-- branch : trunk
This commit is contained in:
+108
-4
@@ -27,6 +27,7 @@
|
||||
#include "GameEvent.h"
|
||||
#include "World.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "CellImpl.h"
|
||||
@@ -374,6 +375,18 @@ void AchievementMgr::CheckAllAchievementCriteria()
|
||||
UpdateAchievementCriteria(AchievementCriteriaTypes(i));
|
||||
}
|
||||
|
||||
static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = { 1057, 1107, 1108 };
|
||||
static const uint32 achievIdForDangeon[][4] =
|
||||
{
|
||||
// ach_cr_id,is_dungeon,is_raid,is_heroic_dungeon
|
||||
{ 321, true, true, true },
|
||||
{ 916, false, true, false },
|
||||
{ 917, false, true, false },
|
||||
{ 918, true, false, false },
|
||||
{ 2219, false, false, true },
|
||||
{ 0, false, false, false }
|
||||
};
|
||||
|
||||
/**
|
||||
* this function will be called whenever the user might have done a criteria relevant action
|
||||
*/
|
||||
@@ -408,7 +421,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
{
|
||||
// std. case: increment at 1
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if(!miscvalue1)
|
||||
continue;
|
||||
@@ -493,6 +505,79 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
continue;
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
|
||||
{
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if(!miscvalue1)
|
||||
continue;
|
||||
// skip wrong arena achievements, if not achievIdByArenaSlot then normal totla death counter
|
||||
bool notfit = false;
|
||||
for(int i = 0; i < MAX_ARENA_SLOT; ++i)
|
||||
{
|
||||
if(achievIdByArenaSlot[i] == achievement->ID)
|
||||
{
|
||||
BattleGround* bg = GetPlayer()->GetBattleGround();
|
||||
if(!bg || ArenaTeam::GetSlotByType(bg->GetArenaType())!=i)
|
||||
notfit = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(notfit)
|
||||
continue;
|
||||
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
|
||||
{
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if(!miscvalue1)
|
||||
continue;
|
||||
|
||||
Map const* map = GetPlayer()->GetMap();
|
||||
if(!map->IsDungeon())
|
||||
continue;
|
||||
|
||||
// search case
|
||||
bool found = false;
|
||||
for(int i = 0; achievIdForDangeon[i][0]; ++i)
|
||||
{
|
||||
if(achievIdForDangeon[i][0] == achievement->ID)
|
||||
{
|
||||
if(map->IsRaid())
|
||||
{
|
||||
// if raid accepted (ignore difficulty)
|
||||
if(!achievIdForDangeon[i][2])
|
||||
break; // for
|
||||
}
|
||||
else if(GetPlayer()->GetDifficulty()==DIFFICULTY_NORMAL)
|
||||
{
|
||||
// dungeon in normal mode accepted
|
||||
if(!achievIdForDangeon[i][1])
|
||||
break; // for
|
||||
}
|
||||
else
|
||||
{
|
||||
// dungeon in heroic mode accepted
|
||||
if(!achievIdForDangeon[i][3])
|
||||
break; // for
|
||||
}
|
||||
|
||||
found = true;
|
||||
break; // for
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
continue;
|
||||
|
||||
//FIXME: work only for instances where max==min for players
|
||||
if(((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit)
|
||||
continue;
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if(!miscvalue1)
|
||||
@@ -501,6 +586,17 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
continue;
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if(!miscvalue1)
|
||||
continue;
|
||||
|
||||
// if team check required: must kill by opposition faction
|
||||
if(achievement->ID==318 && miscvalue2==GetPlayer()->GetTeam())
|
||||
continue;
|
||||
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
|
||||
{
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
@@ -518,6 +614,14 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SetCriteriaProgress(achievementCriteria, miscvalue1);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if(!miscvalue1)
|
||||
continue;
|
||||
if(miscvalue2 != achievementCriteria->death_from.type)
|
||||
continue;
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
|
||||
if(GetPlayer()->GetQuestRewardStatus(achievementCriteria->complete_quest.questID))
|
||||
SetCriteriaProgress(achievementCriteria, 1);
|
||||
@@ -680,10 +784,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
|
||||
@@ -836,8 +937,11 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
|
||||
// handle all statistic-only criteria here
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
|
||||
|
||||
@@ -230,7 +230,6 @@ void BattleGround::Update(uint32 diff)
|
||||
{
|
||||
m_PrematureCountDown = true;
|
||||
m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
|
||||
SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
|
||||
}
|
||||
else if(m_PrematureCountDownTimer < diff)
|
||||
{
|
||||
@@ -242,8 +241,17 @@ void BattleGround::Update(uint32 diff)
|
||||
{
|
||||
uint32 newtime = m_PrematureCountDownTimer - diff;
|
||||
// announce every minute
|
||||
if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
|
||||
SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
|
||||
if( newtime > (MINUTE * IN_MILISECONDS) )
|
||||
{
|
||||
if( newtime / (MINUTE * IN_MILISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS) )
|
||||
PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, (uint32)(m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS)));
|
||||
}
|
||||
else
|
||||
{
|
||||
//announce every 15 seconds
|
||||
if( newtime / (15 * IN_MILISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILISECONDS) )
|
||||
PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, (uint32)(m_PrematureCountDownTimer / IN_MILISECONDS));
|
||||
}
|
||||
m_PrematureCountDownTimer = newtime;
|
||||
}
|
||||
}
|
||||
@@ -1047,7 +1055,7 @@ void BattleGround::RemoveFromBGFreeSlotQueue()
|
||||
// returns the number how many players can join battleground to MaxPlayersPerTeam
|
||||
uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
|
||||
{
|
||||
//if BG is starting ... invite anyone
|
||||
//return free slot count to MaxPlayerPerTeam
|
||||
if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS)
|
||||
return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
|
||||
|
||||
@@ -1414,6 +1422,18 @@ void BattleGround::SendMessageToAll(int32 entry)
|
||||
SendPacketToAll(&data);
|
||||
}
|
||||
|
||||
//copied from void ChatHandler::PSendSysMessage(int32 entry, ...)
|
||||
void BattleGround::PSendMessageToAll(int32 entry, ...)
|
||||
{
|
||||
const char *format = GetMangosString(entry);
|
||||
va_list ap;
|
||||
char str [2048];
|
||||
va_start(ap, entry);
|
||||
vsnprintf(str,2048,format, ap );
|
||||
va_end(ap);
|
||||
SendMessageToAll(str);
|
||||
}
|
||||
|
||||
void BattleGround::EndNow()
|
||||
{
|
||||
RemoveFromBGFreeSlotQueue();
|
||||
|
||||
@@ -402,6 +402,7 @@ class BattleGround
|
||||
|
||||
void SendMessageToAll(char const* text);
|
||||
void SendMessageToAll(int32 entry);
|
||||
void PSendMessageToAll(int32 entry, ... );
|
||||
|
||||
/* Raid Group */
|
||||
Group *GetBgRaid(uint32 TeamID) const { return TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE]; }
|
||||
|
||||
+7
-2
@@ -654,7 +654,7 @@ enum TrinityStrings
|
||||
LANG_ARENA_NOT_ENOUGH_PLAYERS = 723, // "Your group does not have enough players to join this match."
|
||||
LANG_ARENA_GOLD_WINS = 724, // "The Gold Team wins!"
|
||||
LANG_ARENA_GREEN_WINS = 725, // "The Green Team wins!"
|
||||
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 726, // The battleground will end soon, because there aren't enough players. Get more ppl or win already!
|
||||
// = 726, not used
|
||||
LANG_BG_GROUP_OFFLINE_MEMBER = 727, // "Your group has an offline member. Please remove him before joining."
|
||||
LANG_BG_GROUP_MIXED_FACTION = 728, // "Your group has players from the opposing faction. You can't join the battleground as a group."
|
||||
LANG_BG_GROUP_MIXED_LEVELS = 729, // "Your group has players from different battleground brakets. You can't join as group."
|
||||
@@ -676,7 +676,12 @@ enum TrinityStrings
|
||||
LANG_DIST_ARENA_POINTS_TEAM_START = 744,
|
||||
LANG_DIST_ARENA_POINTS_TEAM_END = 745,
|
||||
LANG_DIST_ARENA_POINTS_END = 746,
|
||||
// Room for batleground/arena strings 747-799 not used
|
||||
// = 747, not used
|
||||
// = 748, not used
|
||||
// = 749, not used
|
||||
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins."
|
||||
LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds."
|
||||
// Room for batleground/arena strings 752-799 not used
|
||||
|
||||
// Room for BG/ARENA 750-769 not used
|
||||
|
||||
|
||||
@@ -278,6 +278,13 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
|
||||
store.GetName(), entry, itemid, chance);
|
||||
return false;
|
||||
}
|
||||
|
||||
if( maxcount < mincountOrRef) // wrong max count
|
||||
{
|
||||
sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, uint32(maxcount), mincountOrRef);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else // mincountOrRef < 0
|
||||
{
|
||||
|
||||
+1
-3
@@ -125,9 +125,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 cost = money + 30;
|
||||
if (items_count)
|
||||
cost = 30 * items_count;
|
||||
uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client
|
||||
|
||||
uint32 reqmoney = cost + money;
|
||||
|
||||
|
||||
+17
-9
@@ -898,6 +898,9 @@ void Player::StopMirrorTimer(MirrorTimerType Type)
|
||||
|
||||
void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage)
|
||||
{
|
||||
if(!isAlive() || isGameMaster())
|
||||
return;
|
||||
|
||||
WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21));
|
||||
data << (uint64)guid;
|
||||
data << (uint8)(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL);
|
||||
@@ -908,13 +911,18 @@ void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 da
|
||||
|
||||
DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
|
||||
if(type==DAMAGE_FALL && !isAlive()) // DealDamage not apply item durability loss at self damage
|
||||
if(!isAlive())
|
||||
{
|
||||
DEBUG_LOG("We are fall to death, loosing 10 percents durability");
|
||||
DurabilityLossAll(0.10f,false);
|
||||
// durability lost message
|
||||
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
if(type==DAMAGE_FALL) // DealDamage not apply item durability loss at self damage
|
||||
{
|
||||
DEBUG_LOG("We are fall to death, loosing 10 percents durability");
|
||||
DurabilityLossAll(0.10f,false);
|
||||
// durability lost message
|
||||
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,9 +1006,7 @@ void Player::HandleLava()
|
||||
uint64 guid = GetGUID();
|
||||
uint32 damage = urand(600, 700); // TODO: Get more detailed information about lava damage
|
||||
|
||||
// if not gamemaster then deal damage
|
||||
if ( !isGameMaster() )
|
||||
EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
|
||||
EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
|
||||
|
||||
m_breathTimer = 1*IN_MILISECONDS;
|
||||
}
|
||||
@@ -1385,6 +1391,8 @@ void Player::setDeathState(DeathState s)
|
||||
if(!ressSpellId)
|
||||
ressSpellId = GetResurrectionSpellId();
|
||||
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, 1);
|
||||
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1);
|
||||
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON, 1);
|
||||
}
|
||||
Unit::setDeathState(s);
|
||||
|
||||
|
||||
+15
-12
@@ -743,6 +743,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
|
||||
|
||||
if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->isPet() && !((Creature*)pVictim)->hasLootRecipient())
|
||||
((Creature*)pVictim)->SetLootRecipient(this);
|
||||
|
||||
if (health <= damage)
|
||||
{
|
||||
DEBUG_LOG("DealDamage: victim just died");
|
||||
@@ -820,12 +821,12 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
|
||||
((Creature*)this)->AI()->KilledUnit(pVictim);
|
||||
|
||||
// achievement stuff
|
||||
if ( pVictim->GetTypeId() == TYPEID_PLAYER)
|
||||
if (pVictim->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if(GetTypeId() == TYPEID_UNIT)
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
|
||||
else if(GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1);
|
||||
else if(GetTypeId() == TYPEID_PLAYER && pVictim != this)
|
||||
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ((Player*)this)->GetTeam());
|
||||
}
|
||||
|
||||
// 10% durability loss on death
|
||||
@@ -5561,6 +5562,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
|
||||
return false;
|
||||
basepoints0 = triggerAmount * GetMaxHealth() / 100;
|
||||
triggered_spell_id = 34299;
|
||||
break;
|
||||
}
|
||||
// Healing Touch (Dreamwalker Raiment set)
|
||||
case 28719:
|
||||
@@ -5664,6 +5666,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
|
||||
{
|
||||
triggered_spell_id = 60889;
|
||||
basepoints0 = triggerAmount * GetMaxPower(POWER_MANA) / 100;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -12506,14 +12509,14 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
|
||||
}
|
||||
}
|
||||
|
||||
// achievement stuff
|
||||
if ( pVictim->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if(GetTypeId() == TYPEID_UNIT)
|
||||
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
|
||||
else if(GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1);
|
||||
}
|
||||
// achievement stuff
|
||||
if (pVictim->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
|
||||
else if(GetTypeId() == TYPEID_PLAYER && pVictim != this)
|
||||
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ((Player*)this)->GetTeam());
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::SetControlled(bool apply, UnitState state)
|
||||
|
||||
Reference in New Issue
Block a user