Merge branch '3.3.5-instanceextend' into 3.3.5 (PR #16392)
This commit is contained in:
commit
62aff401f6
17 files changed
+232
-77
No files matched your search
@@ -783,6 +783,7 @@ CREATE TABLE `character_instance` (
|
||||
`guid` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`instance` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`permanent` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`extendState` TINYINT(2) UNSIGNED NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`guid`,`instance`),
|
||||
KEY `instance` (`instance`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
@@ -2539,7 +2540,7 @@ CREATE TABLE `updates` (
|
||||
|
||||
LOCK TABLES `updates` WRITE;
|
||||
/*!40000 ALTER TABLE `updates` DISABLE KEYS */;
|
||||
INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','C2CC6E50AFA1ACCBEBF77CC519AAEB09F3BBAEBC','ARCHIVED','2015-07-13 23:49:22',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2015_08_26_00_characters_335.sql','C7D6A3A00FECA3EBFF1E71744CA40D3076582374','ARCHIVED','2015-08-26 21:00:00',0),('2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-06 16:06:38',0),('2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-07 23:32:00',0),('2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-12 15:35:47',0),('2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-19 14:32:22',0),('2015_10_29_00_characters_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 17:05:43',0),('2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-10-12 15:23:33',0),('2015_11_07_00_characters.sql','BAF9F6B8F97A30D04BDBBA8127A62A1720F9B904','RELEASED','2015-11-07 15:40:47',0);
|
||||
INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','C2CC6E50AFA1ACCBEBF77CC519AAEB09F3BBAEBC','ARCHIVED','2015-07-13 23:49:22',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2015_08_26_00_characters_335.sql','C7D6A3A00FECA3EBFF1E71744CA40D3076582374','ARCHIVED','2015-08-26 21:00:00',0),('2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-06 16:06:38',0),('2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-07 23:32:00',0),('2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-12 15:35:47',0),('2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-19 14:32:22',0),('2015_10_29_00_characters_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 17:05:43',0),('2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-10-12 15:23:33',0),('2015_11_07_00_characters.sql','BAF9F6B8F97A30D04BDBBA8127A62A1720F9B904','RELEASED','2015-11-07 15:40:47',0),('2016_02_10_00_characters.sql','418F9639F558346E0F7A33512059906E94E30E49','RELEASED','2016-02-10 00:00:00',0);
|
||||
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- extend=0 is expired, extend=1 is normal, extend=2 is extended
|
||||
ALTER TABLE `character_instance` ADD COLUMN `extendState` TINYINT(2) UNSIGNED NOT NULL DEFAULT '1';
|
||||
@@ -0,0 +1,6 @@
|
||||
--
|
||||
DELETE FROM `command` WHERE `name`="debug raidreset";
|
||||
INSERT INTO `command` (`name`,`permission`,`help`) VALUES ("debug raidreset",414,"Syntax: .debug raidreset mapid [difficulty]
|
||||
Forces a global reset of the specified map on all difficulties (or only the specific difficulty if specified). Effectively the same as setting the specified map's reset timer to now.");
|
||||
|
||||
UPDATE `trinity_string` SET `content_default`="Map: %d | ID: %d | perm: %s | extended: %s | diff: %d | canReset: %s | TTR: %s" WHERE `entry`=5045;
|
||||
@@ -72,7 +72,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
"FROM characters WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, "
|
||||
"base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC);
|
||||
@@ -405,8 +405,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_UPD_WORLDSTATE, "UPDATE worldstates SET value = ? WHERE entry = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_WORLDSTATE, "INSERT INTO worldstates (entry, value) VALUES (?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, "DELETE FROM character_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ? WHERE guid = ? AND instance = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_CHAR_INSTANCE, "INSERT INTO character_instance (guid, instance, permanent) VALUES (?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ?, extendState = ? WHERE guid = ? AND instance = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_CHAR_INSTANCE, "INSERT INTO character_instance (guid, instance, permanent, extendState) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_GENDER_PLAYERBYTES, "UPDATE characters SET gender = ?, playerBytes = ?, playerBytes2 = ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHARACTER_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_ADD_CHARACTER_SOCIAL_FLAGS, "UPDATE character_social SET flags = flags | ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC);
|
||||
@@ -434,6 +434,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_SEL_CHAR_CLASS_LVL_AT_LOGIN, "SELECT class, level, at_login, knownTitles FROM characters WHERE guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_AT_LOGIN_TITLES, "SELECT at_login, knownTitles FROM characters WHERE guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_INSTANCE, "SELECT data, completedEncounters FROM instance WHERE map = ? AND id = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE, "SELECT guid FROM character_instance WHERE instance = ? and permanent = 1", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL, "SELECT id, messageType, mailTemplateId, sender, subject, body, money, has_items FROM mail WHERE receiver = ? AND has_items <> 0 AND cod <> 0", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH);
|
||||
@@ -470,9 +471,10 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_INS_CHAR_GIFT, "INSERT INTO character_gifts (guid, item_guid, entry, flags) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_INSTANCE_BY_INSTANCE, "DELETE FROM instance WHERE id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE, "DELETE FROM character_instance WHERE instance = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF, "DELETE FROM character_instance USING character_instance LEFT JOIN instance ON character_instance.instance = id WHERE map = ? and difficulty = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF, "DELETE FROM character_instance USING character_instance LEFT JOIN instance ON character_instance.instance = id WHERE (extendState = 0 or permanent = 0) and map = ? and difficulty = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF, "DELETE FROM group_instance USING group_instance LEFT JOIN instance ON group_instance.instance = id WHERE map = ? and difficulty = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_INSTANCE_BY_MAP_DIFF, "DELETE FROM instance WHERE map = ? and difficulty = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF, "DELETE FROM instance WHERE map = ? and difficulty = ? and (SELECT guid FROM character_instance WHERE extendState != 0 AND instance = id LIMIT 1) IS NULL", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_EXPIRE_CHAR_INSTANCE_BY_MAP_DIFF, "UPDATE character_instance LEFT JOIN instance ON character_instance.instance = id SET extendState = extendState-1 WHERE map = ? and difficulty = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_MAIL_ITEM_BY_ID, "DELETE FROM mail_items WHERE mail_id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_PETITION, "INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PETITION_BY_GUID, "DELETE FROM petition WHERE petitionguid = ?", CONNECTION_ASYNC);
|
||||
|
||||
@@ -365,6 +365,7 @@ enum CharacterDatabaseStatements
|
||||
CHAR_SEL_CHAR_CLASS_LVL_AT_LOGIN,
|
||||
CHAR_SEL_CHAR_AT_LOGIN_TITLES,
|
||||
CHAR_SEL_INSTANCE,
|
||||
CHAR_SEL_PERM_BIND_BY_INSTANCE,
|
||||
CHAR_SEL_CHAR_COD_ITEM_MAIL,
|
||||
CHAR_SEL_CHAR_SOCIAL,
|
||||
CHAR_SEL_CHAR_OLD_CHARS,
|
||||
@@ -396,9 +397,10 @@ enum CharacterDatabaseStatements
|
||||
CHAR_INS_CHAR_GIFT,
|
||||
CHAR_DEL_INSTANCE_BY_INSTANCE,
|
||||
CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE,
|
||||
CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF,
|
||||
CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF,
|
||||
CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF,
|
||||
CHAR_DEL_INSTANCE_BY_MAP_DIFF,
|
||||
CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF,
|
||||
CHAR_UPD_EXPIRE_CHAR_INSTANCE_BY_MAP_DIFF,
|
||||
CHAR_DEL_MAIL_ITEM_BY_ID,
|
||||
CHAR_INS_PETITION,
|
||||
CHAR_DEL_PETITION_BY_GUID,
|
||||
|
||||
@@ -18375,8 +18375,9 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
|
||||
uint32 mapId = fields[2].GetUInt16();
|
||||
uint32 instanceId = fields[0].GetUInt32();
|
||||
uint8 difficulty = fields[3].GetUInt8();
|
||||
BindExtensionState extendState = BindExtensionState(fields[4].GetUInt8());
|
||||
|
||||
time_t resetTime = time_t(fields[4].GetUInt32());
|
||||
time_t resetTime = time_t(fields[5].GetUInt32());
|
||||
// the resettime for normal instances is only saved when the InstanceSave is unloaded
|
||||
// so the value read from the DB may be wrong here but only if the InstanceSave is loaded
|
||||
// and in that case it is not used
|
||||
@@ -18425,13 +18426,13 @@ void Player::_LoadBoundInstances(PreparedQueryResult result)
|
||||
|
||||
// since non permanent binds are always solo bind, they can always be reset
|
||||
if (InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapId, instanceId, Difficulty(difficulty), resetTime, !perm, true))
|
||||
BindToInstance(save, perm, true);
|
||||
BindToInstance(save, perm, extendState, true);
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty)
|
||||
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired)
|
||||
{
|
||||
// some instances only have one difficulty
|
||||
MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(mapid, difficulty);
|
||||
@@ -18440,9 +18441,9 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty
|
||||
|
||||
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
|
||||
if (itr != m_boundInstances[difficulty].end())
|
||||
return &itr->second;
|
||||
else
|
||||
return NULL;
|
||||
if (itr->second.extendState || withExpired)
|
||||
return &itr->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InstanceSave* Player::GetInstanceSave(uint32 mapid, bool raid)
|
||||
@@ -18485,24 +18486,32 @@ void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficu
|
||||
}
|
||||
}
|
||||
|
||||
InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, bool load)
|
||||
InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, BindExtensionState extendState, bool load)
|
||||
{
|
||||
if (save)
|
||||
{
|
||||
InstancePlayerBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()];
|
||||
if (extendState == EXTEND_STATE_KEEP) // special flag, keep the player's current extend state when updating for new boss down
|
||||
{
|
||||
if (save == bind.save)
|
||||
extendState = bind.extendState;
|
||||
else
|
||||
extendState = EXTEND_STATE_NORMAL;
|
||||
}
|
||||
if (!load)
|
||||
{
|
||||
if (bind.save)
|
||||
{
|
||||
// update the save when the group kills a boss
|
||||
if (permanent != bind.perm || save != bind.save)
|
||||
if (permanent != bind.perm || save != bind.save || extendState != bind.extendState)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INSTANCE);
|
||||
|
||||
stmt->setUInt32(0, save->GetInstanceId());
|
||||
stmt->setBool(1, permanent);
|
||||
stmt->setUInt32(2, GetGUID().GetCounter());
|
||||
stmt->setUInt32(3, bind.save->GetInstanceId());
|
||||
stmt->setUInt8(2, extendState);
|
||||
stmt->setUInt32(3, GetGUID().GetCounter());
|
||||
stmt->setUInt32(4, bind.save->GetInstanceId());
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
@@ -18514,6 +18523,7 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b
|
||||
stmt->setUInt32(0, GetGUID().GetCounter());
|
||||
stmt->setUInt32(1, save->GetInstanceId());
|
||||
stmt->setBool(2, permanent);
|
||||
stmt->setUInt8(3, extendState);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
@@ -18531,9 +18541,10 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b
|
||||
|
||||
bind.save = save;
|
||||
bind.perm = permanent;
|
||||
bind.extendState = extendState;
|
||||
if (!load)
|
||||
TC_LOG_DEBUG("maps", "Player::BindToInstance: %s(%d) is now bound to map %d, instance %d, difficulty %d", GetName().c_str(), GetGUID().GetCounter(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty());
|
||||
sScriptMgr->OnPlayerBindToInstance(this, save->GetDifficulty(), save->GetMapId(), permanent);
|
||||
sScriptMgr->OnPlayerBindToInstance(this, save->GetDifficulty(), save->GetMapId(), permanent, uint8(extendState));
|
||||
return &bind;
|
||||
}
|
||||
|
||||
@@ -18551,7 +18562,7 @@ void Player::BindToInstance()
|
||||
GetSession()->SendPacket(&data);
|
||||
if (!IsGameMaster())
|
||||
{
|
||||
BindToInstance(mapSave, true);
|
||||
BindToInstance(mapSave, true, EXTEND_STATE_KEEP);
|
||||
GetSession()->SendCalendarRaidLockout(mapSave, true);
|
||||
}
|
||||
}
|
||||
@@ -18577,15 +18588,19 @@ void Player::SendRaidInfo()
|
||||
{
|
||||
for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
|
||||
{
|
||||
if (itr->second.perm)
|
||||
InstancePlayerBind const& bind = itr->second;
|
||||
if (bind.perm)
|
||||
{
|
||||
InstanceSave* save = itr->second.save;
|
||||
data << uint32(save->GetMapId()); // map id
|
||||
data << uint32(save->GetDifficulty()); // difficulty
|
||||
data << uint64(save->GetInstanceId()); // instance id
|
||||
data << uint8(1); // expired = 0
|
||||
data << uint8(0); // extended = 1
|
||||
data << uint32(save->GetResetTime() - now); // reset time
|
||||
InstanceSave* save = bind.save;
|
||||
data << uint32(save->GetMapId()); // map id
|
||||
data << uint32(save->GetDifficulty()); // difficulty
|
||||
data << uint64(save->GetInstanceId()); // instance id
|
||||
data << uint8(bind.extendState != EXTEND_STATE_EXPIRED); // expired = 0
|
||||
data << uint8(bind.extendState == EXTEND_STATE_EXTENDED); // extended = 1
|
||||
time_t nextReset = save->GetResetTime();
|
||||
if (bind.extendState == EXTEND_STATE_EXTENDED)
|
||||
nextReset = sInstanceSaveMgr->GetSubsequentResetTime(save->GetMapId(), save->GetDifficulty(), save->GetResetTime());
|
||||
data << uint32(nextReset - now); // reset time
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,14 +834,27 @@ enum PlayerDelayedOperations
|
||||
// Maximum money amount : 2^31 - 1
|
||||
extern uint32 const MAX_MONEY_AMOUNT;
|
||||
|
||||
enum BindExtensionState
|
||||
{
|
||||
EXTEND_STATE_EXPIRED = 0,
|
||||
EXTEND_STATE_NORMAL = 1,
|
||||
EXTEND_STATE_EXTENDED = 2,
|
||||
EXTEND_STATE_KEEP = 255 // special state: keep current save type
|
||||
};
|
||||
struct InstancePlayerBind
|
||||
{
|
||||
InstanceSave* save;
|
||||
bool perm;
|
||||
/* permanent PlayerInstanceBinds are created in Raid/Heroic instances for players
|
||||
that aren't already permanently bound when they are inside when a boss is killed
|
||||
or when they enter an instance that the group leader is permanently bound to. */
|
||||
InstancePlayerBind() : save(NULL), perm(false) { }
|
||||
that aren't already permanently bound when they are inside when a boss is killed
|
||||
or when they enter an instance that the group leader is permanently bound to. */
|
||||
bool perm;
|
||||
/* extend state listing:
|
||||
EXPIRED - doesn't affect anything unless manually re-extended by player
|
||||
NORMAL - standard state
|
||||
EXTENDED - won't be promoted to EXPIRED at next reset period, will instead be promoted to NORMAL */
|
||||
BindExtensionState extendState;
|
||||
|
||||
InstancePlayerBind() : save(NULL), perm(false), extendState(EXTEND_STATE_NORMAL) { }
|
||||
};
|
||||
|
||||
struct AccessRequirement
|
||||
@@ -2115,12 +2128,12 @@ class Player : public Unit, public GridObject<Player>
|
||||
bool m_InstanceValid;
|
||||
// permanent binds and solo binds by difficulty
|
||||
BoundInstancesMap m_boundInstances[MAX_DIFFICULTY];
|
||||
InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty);
|
||||
InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired = false);
|
||||
BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; }
|
||||
InstanceSave* GetInstanceSave(uint32 mapid, bool raid);
|
||||
void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload = false);
|
||||
void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false);
|
||||
InstancePlayerBind* BindToInstance(InstanceSave* save, bool permanent, bool load = false);
|
||||
InstancePlayerBind* BindToInstance(InstanceSave* save, bool permanent, BindExtensionState extendState = EXTEND_STATE_NORMAL, bool load = false);
|
||||
void BindToInstance();
|
||||
void SetPendingBind(uint32 instanceId, uint32 bindTimer);
|
||||
bool HasPendingBind() const { return _pendingBindId > 0; }
|
||||
|
||||
@@ -687,7 +687,8 @@ void Group::ConvertLeaderInstancesToGroup(Player* player, Group* group, bool swi
|
||||
for (Player::BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();)
|
||||
{
|
||||
if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficulty(), itr->first))
|
||||
group->BindToInstance(itr->second.save, itr->second.perm, false);
|
||||
if (itr->second.extendState) // not expired
|
||||
group->BindToInstance(itr->second.save, itr->second.perm, false);
|
||||
|
||||
// permanent binds are not removed
|
||||
if (switchLeader && !itr->second.perm)
|
||||
|
||||
@@ -695,6 +695,21 @@ void WorldSession::HandleSetSavedInstanceExtend(WorldPacket& recvData)
|
||||
recvData >> mapId >> difficulty>> toggleExtend;
|
||||
TC_LOG_DEBUG("network", "CMSG_SET_SAVED_INSTANCE_EXTEND - MapId: %u, Difficulty: %u, ToggleExtend: %s", mapId, difficulty, toggleExtend ? "On" : "Off");
|
||||
|
||||
if (Player* player = GetPlayer())
|
||||
{
|
||||
InstancePlayerBind* instanceBind = player->GetBoundInstance(mapId, Difficulty(difficulty), toggleExtend == 1); // include expired instances if we are toggling extend on
|
||||
if (!instanceBind || !instanceBind->save || !instanceBind->perm)
|
||||
return;
|
||||
|
||||
BindExtensionState newState;
|
||||
if (!toggleExtend || instanceBind->extendState == EXTEND_STATE_EXPIRED)
|
||||
newState = EXTEND_STATE_NORMAL;
|
||||
else
|
||||
newState = EXTEND_STATE_EXTENDED;
|
||||
|
||||
player->BindToInstance(instanceBind->save, true, newState, false);
|
||||
}
|
||||
|
||||
/*
|
||||
InstancePlayerBind* instanceBind = _player->GetBoundInstance(mapId, Difficulty(difficulty));
|
||||
if (!instanceBind || !instanceBind->save)
|
||||
|
||||
@@ -439,6 +439,23 @@ void InstanceSaveManager::LoadResetTimes()
|
||||
}
|
||||
}
|
||||
|
||||
time_t InstanceSaveManager::GetSubsequentResetTime(uint32 mapid, Difficulty difficulty, time_t resetTime) const
|
||||
{
|
||||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
||||
if (!mapDiff || !mapDiff->resetTime)
|
||||
{
|
||||
TC_LOG_ERROR("misc", "InstanceSaveManager::GetSubsequentResetTime: not valid difficulty or no reset delay for map %u", mapid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR;
|
||||
time_t period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME)) / DAY) * DAY);
|
||||
if (period < DAY)
|
||||
period = DAY;
|
||||
|
||||
return ((resetTime + MINUTE) / DAY * DAY) + period + diff;
|
||||
}
|
||||
|
||||
void InstanceSaveManager::ScheduleReset(bool add, time_t time, InstResetEvent event)
|
||||
{
|
||||
if (!add)
|
||||
@@ -476,6 +493,17 @@ void InstanceSaveManager::ScheduleReset(bool add, time_t time, InstResetEvent ev
|
||||
m_resetTimeQueue.insert(std::pair<time_t, InstResetEvent>(time, event));
|
||||
}
|
||||
|
||||
void InstanceSaveManager::ForceGlobalReset(uint32 mapId, Difficulty difficulty)
|
||||
{
|
||||
if (!GetDownscaledMapDifficultyData(mapId, difficulty))
|
||||
return;
|
||||
// remove currently scheduled reset times
|
||||
ScheduleReset(false, 0, InstResetEvent(1, mapId, difficulty, 0));
|
||||
ScheduleReset(false, 0, InstResetEvent(4, mapId, difficulty, 0));
|
||||
// force global reset on the instance
|
||||
_ResetOrWarnAll(mapId, difficulty, false, time(nullptr));
|
||||
}
|
||||
|
||||
void InstanceSaveManager::Update()
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
@@ -516,10 +544,26 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr)
|
||||
// do not allow UnbindInstance to automatically unload the InstanceSaves
|
||||
lock_instLists = true;
|
||||
|
||||
bool shouldDelete = true;
|
||||
InstanceSave::PlayerListType &pList = itr->second->m_playerList;
|
||||
while (!pList.empty())
|
||||
std::vector<Player*> temp; // list of expired binds that should be unbound
|
||||
for (Player* player : pList)
|
||||
{
|
||||
if (InstancePlayerBind* bind = player->GetBoundInstance(itr->second->GetMapId(), itr->second->GetDifficulty()))
|
||||
{
|
||||
ASSERT(bind->save == itr->second);
|
||||
if (bind->perm && bind->extendState) // permanent and not already expired
|
||||
{
|
||||
// actual promotion in DB already happened in caller
|
||||
bind->extendState = bind->extendState == EXTEND_STATE_EXTENDED ? EXTEND_STATE_NORMAL : EXTEND_STATE_EXPIRED;
|
||||
shouldDelete = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
temp.push_back(player);
|
||||
}
|
||||
for (Player* player : temp)
|
||||
{
|
||||
Player* player = *(pList.begin());
|
||||
player->UnbindInstance(itr->second->GetMapId(), itr->second->GetDifficulty(), true);
|
||||
}
|
||||
|
||||
@@ -530,8 +574,13 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr)
|
||||
group->UnbindInstance(itr->second->GetMapId(), itr->second->GetDifficulty(), true);
|
||||
}
|
||||
|
||||
delete itr->second;
|
||||
m_instanceSaveById.erase(itr++);
|
||||
if (shouldDelete)
|
||||
{
|
||||
delete itr->second;
|
||||
itr = m_instanceSaveById.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
|
||||
lock_instLists = false;
|
||||
}
|
||||
@@ -572,31 +621,21 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(mapid);
|
||||
if (!mapEntry->Instanceable())
|
||||
return;
|
||||
TC_LOG_DEBUG("misc", "InstanceSaveManager::ResetOrWarnAll: Processing map %s (%u) on difficulty %u (warn? %u)", mapEntry->name[0], mapid, uint8(difficulty), warn);
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (!warn)
|
||||
{
|
||||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
||||
if (!mapDiff || !mapDiff->resetTime)
|
||||
{
|
||||
TC_LOG_ERROR("misc", "InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
|
||||
// calculate the next reset time
|
||||
time_t next_reset = GetSubsequentResetTime(mapid, difficulty, resetTime);
|
||||
if (!next_reset)
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all binds to instances of the given map
|
||||
for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end();)
|
||||
{
|
||||
if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty)
|
||||
_ResetSave(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
// delete them from the DB, even if not loaded
|
||||
// delete/promote instance binds from the DB, even if not loaded
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF);
|
||||
stmt->setUInt16(0, uint16(mapid));
|
||||
stmt->setUInt8(1, uint8(difficulty));
|
||||
trans->Append(stmt);
|
||||
@@ -606,21 +645,26 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b
|
||||
stmt->setUInt8(1, uint8(difficulty));
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INSTANCE_BY_MAP_DIFF);
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF);
|
||||
stmt->setUInt16(0, uint16(mapid));
|
||||
stmt->setUInt8(1, uint8(difficulty));
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_EXPIRE_CHAR_INSTANCE_BY_MAP_DIFF);
|
||||
stmt->setUInt16(0, uint16(mapid));
|
||||
stmt->setUInt8(1, uint8(difficulty));
|
||||
trans->Append(stmt);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
// calculate the next reset time
|
||||
uint32 diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR;
|
||||
|
||||
uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME))/DAY) * DAY);
|
||||
if (period < DAY)
|
||||
period = DAY;
|
||||
|
||||
uint32 next_reset = uint32(((resetTime + MINUTE) / DAY * DAY) + period + diff);
|
||||
// promote loaded binds to instances of the given map
|
||||
for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end();)
|
||||
{
|
||||
if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty)
|
||||
_ResetSave(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
SetResetTimeFor(mapid, difficulty, next_reset);
|
||||
ScheduleReset(true, time_t(next_reset-3600), InstResetEvent(1, mapid, difficulty, 0));
|
||||
|
||||
@@ -190,6 +190,7 @@ class InstanceSaveManager
|
||||
ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid, d));
|
||||
return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0;
|
||||
}
|
||||
time_t GetSubsequentResetTime(uint32 mapid, Difficulty difficulty, time_t resetTime) const;
|
||||
|
||||
// Use this on startup when initializing reset times
|
||||
void InitializeResetTimeFor(uint32 mapid, Difficulty d, time_t t)
|
||||
@@ -210,6 +211,7 @@ class InstanceSaveManager
|
||||
return m_resetTimeByMapDifficulty;
|
||||
}
|
||||
void ScheduleReset(bool add, time_t time, InstResetEvent event);
|
||||
void ForceGlobalReset(uint32 mapId, Difficulty difficulty);
|
||||
|
||||
void Update();
|
||||
|
||||
|
||||
@@ -3257,22 +3257,37 @@ bool InstanceMap::Reset(uint8 method)
|
||||
}
|
||||
else
|
||||
{
|
||||
bool doUnload = true;
|
||||
if (method == INSTANCE_RESET_GLOBAL)
|
||||
{
|
||||
// set the homebind timer for players inside (1 minute)
|
||||
for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
|
||||
itr->GetSource()->m_InstanceValid = false;
|
||||
{
|
||||
InstancePlayerBind* bind = itr->GetSource()->GetBoundInstance(GetId(), GetDifficulty());
|
||||
if (bind && bind->extendState && bind->save->GetInstanceId() == GetInstanceId())
|
||||
doUnload = false;
|
||||
else
|
||||
itr->GetSource()->m_InstanceValid = false;
|
||||
}
|
||||
|
||||
// the unload timer is not started
|
||||
// instead the map will unload immediately after the players have left
|
||||
m_unloadWhenEmpty = true;
|
||||
m_resetAfterUnload = true;
|
||||
if (doUnload && HasPermBoundPlayers()) // check if any unloaded players have a nonexpired save to this
|
||||
doUnload = false;
|
||||
}
|
||||
|
||||
if (doUnload)
|
||||
{
|
||||
// the unload timer is not started
|
||||
// instead the map will unload immediately after the players have left
|
||||
m_unloadWhenEmpty = true;
|
||||
m_resetAfterUnload = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// unloaded at next update
|
||||
m_unloadTimer = MIN_UNLOAD_DELAY;
|
||||
m_resetAfterUnload = true;
|
||||
m_resetAfterUnload = !(method == INSTANCE_RESET_GLOBAL && HasPermBoundPlayers());
|
||||
}
|
||||
|
||||
return m_mapRefManager.isEmpty();
|
||||
@@ -3353,6 +3368,13 @@ MapDifficulty const* Map::GetMapDifficulty() const
|
||||
return GetMapDifficultyData(GetId(), GetDifficulty());
|
||||
}
|
||||
|
||||
bool InstanceMap::HasPermBoundPlayers() const
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE);
|
||||
stmt->setUInt16(0,GetInstanceId());
|
||||
return !!CharacterDatabase.Query(stmt);
|
||||
}
|
||||
|
||||
uint32 InstanceMap::GetMaxPlayers() const
|
||||
{
|
||||
MapDifficulty const* mapDiff = GetMapDifficulty();
|
||||
|
||||
@@ -771,6 +771,9 @@ class InstanceMap : public Map
|
||||
void SendResetWarnings(uint32 timeLeft) const;
|
||||
void SetResetSchedule(bool on);
|
||||
|
||||
/* this checks if any players have a permanent bind (included reactivatable expired binds) to the instance ID
|
||||
it needs a DB query, so use sparingly */
|
||||
bool HasPermBoundPlayers() const;
|
||||
uint32 GetMaxPlayers() const;
|
||||
uint32 GetMaxResetDelay() const;
|
||||
|
||||
|
||||
@@ -1368,9 +1368,9 @@ void ScriptMgr::OnPlayerSave(Player* player)
|
||||
FOREACH_SCRIPT(PlayerScript)->OnSave(player);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent)
|
||||
void ScriptMgr::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState)
|
||||
{
|
||||
FOREACH_SCRIPT(PlayerScript)->OnBindToInstance(player, difficulty, mapid, permanent);
|
||||
FOREACH_SCRIPT(PlayerScript)->OnBindToInstance(player, difficulty, mapid, permanent, extendState);
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea)
|
||||
|
||||
@@ -734,7 +734,7 @@ class PlayerScript : public UnitScript
|
||||
virtual void OnSave(Player* /*player*/) { }
|
||||
|
||||
// Called when a player is bound to an instance
|
||||
virtual void OnBindToInstance(Player* /*player*/, Difficulty /*difficulty*/, uint32 /*mapId*/, bool /*permanent*/) { }
|
||||
virtual void OnBindToInstance(Player* /*player*/, Difficulty /*difficulty*/, uint32 /*mapId*/, bool /*permanent*/, uint8 /*extendState*/) { }
|
||||
|
||||
// Called when a player switches to a new zone
|
||||
virtual void OnUpdateZone(Player* /*player*/, uint32 /*newZone*/, uint32 /*newArea*/) { }
|
||||
@@ -1054,7 +1054,7 @@ class ScriptMgr
|
||||
void OnPlayerDelete(ObjectGuid guid, uint32 accountId);
|
||||
void OnPlayerFailedDelete(ObjectGuid guid, uint32 accountId);
|
||||
void OnPlayerSave(Player* player);
|
||||
void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent);
|
||||
void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState);
|
||||
void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea);
|
||||
void OnQuestStatusChange(Player* player, uint32 questId, QuestStatus status);
|
||||
|
||||
|
||||
@@ -93,7 +93,8 @@ public:
|
||||
{ "moveflags", rbac::RBAC_PERM_COMMAND_DEBUG_MOVEFLAGS, false, &HandleDebugMoveflagsCommand, "" },
|
||||
{ "transport", rbac::RBAC_PERM_COMMAND_DEBUG_TRANSPORT, false, &HandleDebugTransportCommand, "" },
|
||||
{ "loadcells", rbac::RBAC_PERM_COMMAND_DEBUG_LOADCELLS, false, &HandleDebugLoadCellsCommand, "" },
|
||||
{ "boundary", rbac::RBAC_PERM_COMMAND_DEBUG_BOUNDARY, false, &HandleDebugBoundaryCommand, "" }
|
||||
{ "boundary", rbac::RBAC_PERM_COMMAND_DEBUG_BOUNDARY, false, &HandleDebugBoundaryCommand, "" },
|
||||
{ "raidreset", rbac::RBAC_PERM_COMMAND_INSTANCE_UNBIND, false, &HandleDebugRaidResetCommand, "" }
|
||||
};
|
||||
static std::vector<ChatCommand> commandTable =
|
||||
{
|
||||
@@ -1442,6 +1443,32 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDebugRaidResetCommand(ChatHandler* /*handler*/, char const* args)
|
||||
{
|
||||
char* map_str = args ? strtok((char*)args, " ") : nullptr;
|
||||
char* difficulty_str = args ? strtok(nullptr, " ") : nullptr;
|
||||
|
||||
int32 map = map_str ? atoi(map_str) : -1;
|
||||
if (map <= 0)
|
||||
return false;
|
||||
MapEntry const* mEntry = sMapStore.LookupEntry(map);
|
||||
if (!mEntry || !mEntry->IsRaid())
|
||||
return false;
|
||||
int32 difficulty = difficulty_str ? atoi(difficulty_str) : -1;
|
||||
if (difficulty >= MAX_RAID_DIFFICULTY || difficulty < -1)
|
||||
return false;
|
||||
|
||||
if (difficulty == -1)
|
||||
for (uint8 diff = 0; diff < MAX_RAID_DIFFICULTY; ++diff)
|
||||
{
|
||||
if (GetMapDifficultyData(mEntry->MapID, Difficulty(diff)))
|
||||
sInstanceSaveMgr->ForceGlobalReset(mEntry->MapID, Difficulty(diff));
|
||||
}
|
||||
else
|
||||
sInstanceSaveMgr->ForceGlobalReset(mEntry->MapID, Difficulty(difficulty));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_debug_commandscript()
|
||||
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
{
|
||||
InstanceSave* save = itr->second.save;
|
||||
std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL));
|
||||
handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", itr->second.extendState == EXTEND_STATE_EXPIRED ? "expired" : itr->second.extendState == EXTEND_STATE_EXTENDED ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
{
|
||||
InstanceSave* save = itr->second.save;
|
||||
std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL));
|
||||
handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", "-", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str());
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user