Index: mangosd/mangosd.conf.in =================================================================== --- mangosd/mangosd.conf.in (revision 5629) +++ mangosd/mangosd.conf.in (working copy) @@ -377,6 +377,28 @@ # Motd # Message of the Day. Displayed at worldlogin for every user ('@' for a newline). # +# Corpse.Decay.NORMAL +# Corpse.Decay.RARE +# Corpse.Decay.ELITE +# Corpse.Decay.RAREELITE +# Corpse.Decay.WORLDBOSS +# Seconds until creature corpse will decay without being looted on non-instanced map. +# +# Corpse.Decay.NORMAL.Instance +# Corpse.Decay.RARE.Instance +# Corpse.Decay.ELITE.Instance +# Corpse.Decay.RAREELITE.Instance +# Corpse.Decay.WORLDBOSS.Instance +# Seconds until creature corpse will decay without being looted in instance. +# +# Corpse.Decay.NORMAL.Looted +# Corpse.Decay.RARE.Looted +# Corpse.Decay.ELITE.Looted +# Corpse.Decay.RAREELITE.Looted +# Corpse.Decay.WORLDBOSS.Looted +# Max seconds until creature corpse will decay after being looted. +# If not-looted timer decays sooner, it will be used instead. +# ################################################################################################################### GameType = 1 @@ -400,6 +422,21 @@ Event.Announce = 0 BeepAtStart = 1 Motd = "Welcome to the Massive Network Game Object Server." +Corpse.Decay.NORMAL = 60 +Corpse.Decay.RARE = 300 +Corpse.Decay.ELITE = 300 +Corpse.Decay.RAREELITE = 300 +Corpse.Decay.WORLDBOSS = 3600 +Corpse.Decay.NORMAL.Instance = 300 +Corpse.Decay.RARE.Instance = 600 +Corpse.Decay.ELITE.Instance = 600 +Corpse.Decay.RAREELITE.Instance = 600 +Corpse.Decay.WORLDBOSS.Instance = 3600 +Corpse.Decay.NORMAL.Looted = 5 +Corpse.Decay.RARE.Looted = 20 +Corpse.Decay.ELITE.Looted = 20 +Corpse.Decay.RAREELITE.Looted = 20 +Corpse.Decay.WORLDBOSS.Looted = 60 ################################################################################################################### # PLAYER INTERACTION Index: game/World.h =================================================================== --- game/World.h (revision 5629) +++ game/World.h (working copy) @@ -121,6 +121,21 @@ CONFIG_TALENTS_INSPECTING, CONFIG_CHAT_FAKE_MESSAGE_PREVENTING, CONFIG_TCP_NO_DELAY, + CONFIG_CORPSE_DECAY_NORMAL, + CONFIG_CORPSE_DECAY_RARE, + CONFIG_CORPSE_DECAY_ELITE, + CONFIG_CORPSE_DECAY_RAREELITE, + CONFIG_CORPSE_DECAY_WORLDBOSS, + CONFIG_CORPSE_DECAY_NORMAL_INSTANCE, + CONFIG_CORPSE_DECAY_RARE_INSTANCE, + CONFIG_CORPSE_DECAY_ELITE_INSTANCE, + CONFIG_CORPSE_DECAY_RAREELITE_INSTANCE, + CONFIG_CORPSE_DECAY_WORLDBOSS_INSTANCE, + CONFIG_CORPSE_DECAY_NORMAL_LOOTED, + CONFIG_CORPSE_DECAY_RARE_LOOTED, + CONFIG_CORPSE_DECAY_ELITE_LOOTED, + CONFIG_CORPSE_DECAY_RAREELITE_LOOTED, + CONFIG_CORPSE_DECAY_WORLDBOSS_LOOTED, CONFIG_VALUE_COUNT }; Index: game/World.cpp =================================================================== --- game/World.cpp (revision 5629) +++ game/World.cpp (working copy) @@ -510,6 +510,22 @@ m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true); m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false); + m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 1); + m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 1); + m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 1); + m_configs[CONFIG_CORPSE_DECAY_RAREELITE] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE", 1); + m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS", 1); + m_configs[CONFIG_CORPSE_DECAY_NORMAL_INSTANCE] = sConfig.GetIntDefault("Corpse.Decay.NORMAL.Instance", 1); + m_configs[CONFIG_CORPSE_DECAY_RARE_INSTANCE] = sConfig.GetIntDefault("Corpse.Decay.RARE.Instance", 1); + m_configs[CONFIG_CORPSE_DECAY_ELITE_INSTANCE] = sConfig.GetIntDefault("Corpse.Decay.ELITE.Instance", 1); + m_configs[CONFIG_CORPSE_DECAY_RAREELITE_INSTANCE] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE.Instance", 1); + m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS_INSTANCE] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS.Instance", 1); + m_configs[CONFIG_CORPSE_DECAY_NORMAL_LOOTED] = sConfig.GetIntDefault("Corpse.Decay.NORMAL.Looted", 1); + m_configs[CONFIG_CORPSE_DECAY_RARE_LOOTED] = sConfig.GetIntDefault("Corpse.Decay.RARE.Looted", 1); + m_configs[CONFIG_CORPSE_DECAY_ELITE_LOOTED] = sConfig.GetIntDefault("Corpse.Decay.ELITE.Looted", 1); + m_configs[CONFIG_CORPSE_DECAY_RAREELITE_LOOTED] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE.Looted", 1); + m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS_LOOTED] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS.Looted", 1); + m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) { Index: game/Creature.h =================================================================== --- game/Creature.h (revision 5629) +++ game/Creature.h (working copy) @@ -546,6 +546,8 @@ uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance float m_respawnradius; + bool m_corpseLooted; // creature corpse was looted and skinned (if skinnable) + bool m_gossipOptionLoaded; GossipOptionList m_goptions; uint32 m_NPCTextId; // cached value Index: game/Creature.cpp =================================================================== --- game/Creature.cpp (revision 5629) +++ game/Creature.cpp (working copy) @@ -46,7 +46,7 @@ Unit( instantiator ), i_AI(NULL), lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0), m_itemsLoaded(false), m_trainerSpellsLoaded(false), m_trainer_type(0), m_lootMoney(0), m_lootRecipient(0), -m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f), +m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(0), m_respawnradius(0.0f), m_corpseLooted(false), m_gossipOptionLoaded(false),m_NPCTextId(0), m_emoteState(0), m_isPet(false), m_isTotem(false), m_regenTimer(2000), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0), m_AlreadyCallAssistence(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false) @@ -157,6 +157,7 @@ return; m_deathTimer = 0; + m_corpseLooted = false; setDeathState(DEAD); ObjectAccessor::UpdateObjectVisibility(this); loot.clear(); @@ -192,6 +193,7 @@ m_respawnTime = 0; lootForPickPocketed = false; lootForBody = false; + m_corpseLooted = false; CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(this->GetEntry()); @@ -249,6 +251,36 @@ lootingGroupLeaderGUID = 0; } } + + if (m_corpseDelay == 0 && !m_corpseLooted && lootForBody && loot.empty() && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) + { + // corpse delay had been not set by script and this code had been not yet executed during this death + // and loot had been generated but is already empty and creature was skinned (or isn't skinnable) + m_corpseLooted = true; // mark that creature had been looted - to not repeat this code again + + uint32 nDeathTimer = 1000; + switch (GetCreatureInfo()->rank) + { + case CREATURE_ELITE_RARE: + nDeathTimer *= sWorld.getConfig(CONFIG_CORPSE_DECAY_RARE_LOOTED); + break; + case CREATURE_ELITE_ELITE: + nDeathTimer *= sWorld.getConfig(CONFIG_CORPSE_DECAY_ELITE_LOOTED); + break; + case CREATURE_ELITE_RAREELITE: + nDeathTimer *= sWorld.getConfig(CONFIG_CORPSE_DECAY_RAREELITE_LOOTED); + break; + case CREATURE_ELITE_WORLDBOSS: + nDeathTimer *= sWorld.getConfig(CONFIG_CORPSE_DECAY_WORLDBOSS_LOOTED); + break; + default: + nDeathTimer *= sWorld.getConfig(CONFIG_CORPSE_DECAY_NORMAL_LOOTED); + break; + } + + if (m_deathTimer > nDeathTimer) // update death timer only if looted timer is shorter + m_deathTimer = nDeathTimer; + } } break; @@ -1261,8 +1293,6 @@ m_DBTableGuid = stored_guid; LoadCreaturesAddon(); - if(GetCreatureInfo()->rank > 0) - this->m_corpseDelay *= 3; //if creature is elite, then remove corpse later m_respawnradius = data->spawndist; respawn_cord[0] = data->spawn_posX; @@ -1272,6 +1302,7 @@ m_respawnDelay = data->spawntimesecs; m_isDeadByDefault = data->is_dead; m_deathState = m_isDeadByDefault ? DEAD : ALIVE; + m_corpseLooted = false; m_respawnTime = objmgr.GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId()); if(m_respawnTime > time(NULL)) // not ready to respawn @@ -1452,8 +1483,41 @@ { if((s == JUST_DIED && !m_isDeadByDefault)||(s == JUST_ALIVED && m_isDeadByDefault)) { - m_deathTimer = m_corpseDelay*1000; + if (m_corpseDelay == 0) + { + // corpse delay had been not set by script + uint32 nDeathTimer = 60; // set base delay to 60s + if (!m_isDeadByDefault && !isPet()) + { + // ignore pets and mobs that are dead by default + const bool bInstance = MapManager::Instance().GetBaseMap(GetMapId())->Instanceable(); + + switch (GetCreatureInfo()->rank) + { + case CREATURE_ELITE_RARE: + nDeathTimer = sWorld.getConfig(bInstance ? CONFIG_CORPSE_DECAY_RARE_INSTANCE : CONFIG_CORPSE_DECAY_RARE); + break; + case CREATURE_ELITE_ELITE: + nDeathTimer = sWorld.getConfig(bInstance ? CONFIG_CORPSE_DECAY_ELITE_INSTANCE : CONFIG_CORPSE_DECAY_ELITE); + break; + case CREATURE_ELITE_RAREELITE: + nDeathTimer = sWorld.getConfig(bInstance ? CONFIG_CORPSE_DECAY_RAREELITE_INSTANCE : CONFIG_CORPSE_DECAY_RAREELITE); + break; + case CREATURE_ELITE_WORLDBOSS: + nDeathTimer = sWorld.getConfig(bInstance ? CONFIG_CORPSE_DECAY_WORLDBOSS_INSTANCE : CONFIG_CORPSE_DECAY_WORLDBOSS); + break; + default: + nDeathTimer = sWorld.getConfig(bInstance ? CONFIG_CORPSE_DECAY_NORMAL_INSTANCE : CONFIG_CORPSE_DECAY_NORMAL); + break; + } + } + + m_deathTimer = nDeathTimer * 1000; // set death timer according to configuration + } + else + m_deathTimer = m_corpseDelay * 1000; // corpse delay had been set by script -> use it + // always save boss respawn time at death to prevent crash cheating if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY) || isWorldBoss()) SaveRespawnTime(); @@ -1474,6 +1538,7 @@ if ( tab != skinStore.end() ) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); } + m_corpseLooted = false; Unit::setDeathState(CORPSE); } if(s == JUST_ALIVED) @@ -1495,6 +1560,7 @@ if(getDeathState()==CORPSE && !m_isDeadByDefault ||getDeathState()==ALIVE && m_isDeadByDefault) { m_deathTimer = 0; + m_corpseLooted = false; Update(0); // despawn corpse } if(getDeathState()==DEAD)