mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-18 03:15:41 +00:00
feat(Core/Maps): Implement dynamic respawn rates (#21417)
Co-authored-by: r00ty-tc <r00ty-tc@users.noreply.github.com>
Co-authored-by: Jelle Meeus <sogladev@gmail.com>
Co-authored-by Treeston
This is a partial cherry-pick of: 59db2eeea0
This commit is contained in:
@@ -59,6 +59,8 @@ u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} };
|
||||
static uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
|
||||
static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
|
||||
|
||||
#define MAP_INVALID_ZONE 0xFFFFFFFF
|
||||
|
||||
ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), WeatherId(WEATHER_STATE_FINE),
|
||||
WeatherGrade(0.0f), OverrideLightId(0), LightFadeInTime(0) { }
|
||||
|
||||
@@ -252,6 +254,8 @@ Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
|
||||
}
|
||||
}
|
||||
|
||||
_zonePlayerCountMap.clear();
|
||||
|
||||
//lets initialize visibility distance for map
|
||||
Map::InitVisibilityDistance();
|
||||
|
||||
@@ -736,6 +740,23 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::Objec
|
||||
}
|
||||
}
|
||||
|
||||
void Map::UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone)
|
||||
{
|
||||
// Nothing to do if no change
|
||||
if (oldZone == newZone)
|
||||
return;
|
||||
|
||||
if (oldZone != MAP_INVALID_ZONE)
|
||||
{
|
||||
uint32& oldZoneCount = _zonePlayerCountMap[oldZone];
|
||||
if (!oldZoneCount)
|
||||
LOG_ERROR("maps", "A player left zone {} (went to {}) - but there were no players in the zone!", oldZone, newZone);
|
||||
else
|
||||
--oldZoneCount;
|
||||
}
|
||||
++_zonePlayerCountMap[newZone];
|
||||
}
|
||||
|
||||
void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
||||
{
|
||||
if (t_diff)
|
||||
@@ -913,6 +934,8 @@ struct ResetNotifier
|
||||
|
||||
void Map::RemovePlayerFromMap(Player* player, bool remove)
|
||||
{
|
||||
// Before leaving map, update zone/area for stats
|
||||
player->UpdateZone(MAP_INVALID_ZONE, 0);
|
||||
player->getHostileRefMgr().deleteReferences(true); // pussywizard: multithreading crashfix
|
||||
|
||||
bool inWorld = player->IsInWorld();
|
||||
@@ -2635,6 +2658,40 @@ void Map::SendObjectUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
void Map::ApplyDynamicModeRespawnScaling(WorldObject const* obj, uint32& respawnDelay) const
|
||||
{
|
||||
ASSERT(obj->GetMap() == this);
|
||||
|
||||
float rate = sWorld->getFloatConfig(obj->IsGameObject() ? CONFIG_RESPAWN_DYNAMICRATE_GAMEOBJECT : CONFIG_RESPAWN_DYNAMICRATE_CREATURE);
|
||||
|
||||
if (rate == 1.0f)
|
||||
return;
|
||||
|
||||
// No instanced maps (dungeons, battlegrounds, arenas etc.)
|
||||
if (obj->GetMap()->Instanceable())
|
||||
return;
|
||||
|
||||
// No quest givers or world bosses
|
||||
if (Creature const* creature = obj->ToCreature())
|
||||
if (creature->IsQuestGiver() || creature->isWorldBoss())
|
||||
return;
|
||||
|
||||
auto it = _zonePlayerCountMap.find(obj->GetZoneId());
|
||||
if (it == _zonePlayerCountMap.end())
|
||||
return;
|
||||
uint32 const playerCount = it->second;
|
||||
if (!playerCount)
|
||||
return;
|
||||
double const adjustFactor = rate / playerCount;
|
||||
if (adjustFactor >= 1.0) // nothing to do here
|
||||
return;
|
||||
uint32 const timeMinimum = sWorld->getIntConfig(obj->IsGameObject() ? CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT : CONFIG_RESPAWN_DYNAMICMINIMUM_CREATURE);
|
||||
if (respawnDelay <= timeMinimum)
|
||||
return;
|
||||
|
||||
respawnDelay = std::max<uint32>(std::ceil(respawnDelay * adjustFactor), timeMinimum);
|
||||
}
|
||||
|
||||
void Map::DelayedUpdate(const uint32 t_diff)
|
||||
{
|
||||
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
|
||||
|
||||
Reference in New Issue
Block a user