Index: mangosd/mangosd.conf.in =================================================================== --- mangosd/mangosd.conf.in (revision 5569) +++ mangosd/mangosd.conf.in (working copy) @@ -680,6 +680,28 @@ # Default: 0 - no decrease # 75 - in 2 times each 75 skill points # +# 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. +# ################################################################################################################### Rate.Health = 1 @@ -727,6 +749,21 @@ SkillChance.Grey = 0 SkillChance.MiningSteps = 0 SkillChance.SkinningSteps = 0 +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 = 600 ################################################################################################################### # CONSOLE AND REMOTE ACCESS Index: game/World.h =================================================================== --- game/World.h (revision 5569) +++ game/World.h (working copy) @@ -167,6 +167,21 @@ RATE_MINING_NEXT, RATE_TALENT, RATE_LOYALTY, + CORPSE_DECAY_NORMAL, + CORPSE_DECAY_RARE, + CORPSE_DECAY_ELITE, + CORPSE_DECAY_RAREELITE, + CORPSE_DECAY_WORLDBOSS, + CORPSE_DECAY_NORMAL_INSTANCE, + CORPSE_DECAY_RARE_INSTANCE, + CORPSE_DECAY_ELITE_INSTANCE, + CORPSE_DECAY_RAREELITE_INSTANCE, + CORPSE_DECAY_WORLDBOSS_INSTANCE, + CORPSE_DECAY_NORMAL_LOOTED, + CORPSE_DECAY_RARE_LOOTED, + CORPSE_DECAY_ELITE_LOOTED, + CORPSE_DECAY_RAREELITE_LOOTED, + CORPSE_DECAY_WORLDBOSS_LOOTED, MAX_RATES }; Index: game/World.cpp =================================================================== --- game/World.cpp (revision 5569) +++ game/World.cpp (working copy) @@ -382,6 +382,21 @@ sLog.outError("Rate.Talent (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_TALENT]); rate_values[RATE_TALENT] = 1; } + rate_values[CORPSE_DECAY_NORMAL] = sConfig.GetFloatDefault("Corpse.Decay.NORMAL", 1); + rate_values[CORPSE_DECAY_RARE] = sConfig.GetFloatDefault("Corpse.Decay.RARE", 1); + rate_values[CORPSE_DECAY_ELITE] = sConfig.GetFloatDefault("Corpse.Decay.ELITE", 1); + rate_values[CORPSE_DECAY_RAREELITE] = sConfig.GetFloatDefault("Corpse.Decay.RAREELITE", 1); + rate_values[CORPSE_DECAY_WORLDBOSS] = sConfig.GetFloatDefault("Corpse.Decay.WORLDBOSS", 1); + rate_values[CORPSE_DECAY_NORMAL_INSTANCE] = sConfig.GetFloatDefault("Corpse.Decay.NORMAL.Instance", 1); + rate_values[CORPSE_DECAY_RARE_INSTANCE] = sConfig.GetFloatDefault("Corpse.Decay.RARE.Instance", 1); + rate_values[CORPSE_DECAY_ELITE_INSTANCE] = sConfig.GetFloatDefault("Corpse.Decay.ELITE.Instance", 1); + rate_values[CORPSE_DECAY_RAREELITE_INSTANCE] = sConfig.GetFloatDefault("Corpse.Decay.RAREELITE.Instance", 1); + rate_values[CORPSE_DECAY_WORLDBOSS_INSTANCE] = sConfig.GetFloatDefault("Corpse.Decay.WORLDBOSS.Instance", 1); + rate_values[CORPSE_DECAY_NORMAL_LOOTED] = sConfig.GetFloatDefault("Corpse.Decay.NORMAL.Looted", 1); + rate_values[CORPSE_DECAY_RARE_LOOTED] = sConfig.GetFloatDefault("Corpse.Decay.RARE.Looted", 1); + rate_values[CORPSE_DECAY_ELITE_LOOTED] = sConfig.GetFloatDefault("Corpse.Decay.ELITE.Looted", 1); + rate_values[CORPSE_DECAY_RAREELITE_LOOTED] = sConfig.GetFloatDefault("Corpse.Decay.RAREELITE.Looted", 1); + rate_values[CORPSE_DECAY_WORLDBOSS_LOOTED] = sConfig.GetFloatDefault("Corpse.Decay.WORLDBOSS.Looted", 1); ///- Read other configuration items from the config file Index: game/Creature.h =================================================================== --- game/Creature.h (revision 5569) +++ 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 5569) +++ 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,35 @@ 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; + switch (GetCreatureInfo()->rank) + { + case CREATURE_ELITE_RARE: + nDeathTimer = uint32(sWorld.getRate(CORPSE_DECAY_RARE_LOOTED) * 1000); + break; + case CREATURE_ELITE_ELITE: + nDeathTimer = uint32(sWorld.getRate(CORPSE_DECAY_ELITE_LOOTED) * 1000); + break; + case CREATURE_ELITE_RAREELITE: + nDeathTimer = uint32(sWorld.getRate(CORPSE_DECAY_RAREELITE_LOOTED) * 1000); + break; + case CREATURE_ELITE_WORLDBOSS: + nDeathTimer = uint32(sWorld.getRate(CORPSE_DECAY_WORLDBOSS_LOOTED) * 1000); + break; + default: + nDeathTimer = uint32(sWorld.getRate(CORPSE_DECAY_NORMAL_LOOTED) * 1000); + break; + } + + if (m_deathTimer > nDeathTimer) // update death timer only if looted timer is shorter + m_deathTimer = nDeathTimer; + } } break; @@ -1261,8 +1292,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 +1301,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 @@ -1450,8 +1480,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 + float fDeathTimer = 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: + fDeathTimer = sWorld.getRate(bInstance ? CORPSE_DECAY_RARE_INSTANCE : CORPSE_DECAY_RARE); + break; + case CREATURE_ELITE_ELITE: + fDeathTimer = sWorld.getRate(bInstance ? CORPSE_DECAY_ELITE_INSTANCE : CORPSE_DECAY_ELITE); + break; + case CREATURE_ELITE_RAREELITE: + fDeathTimer = sWorld.getRate(bInstance ? CORPSE_DECAY_RAREELITE_INSTANCE : CORPSE_DECAY_RAREELITE); + break; + case CREATURE_ELITE_WORLDBOSS: + fDeathTimer = sWorld.getRate(bInstance ? CORPSE_DECAY_WORLDBOSS_INSTANCE : CORPSE_DECAY_WORLDBOSS); + break; + default: + fDeathTimer = sWorld.getRate(bInstance ? CORPSE_DECAY_NORMAL_INSTANCE : CORPSE_DECAY_NORMAL); + break; + } + } + + m_deathTimer = uint32(fDeathTimer * 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(); @@ -1472,6 +1535,7 @@ if ( tab != skinStore.end() ) SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); } + m_corpseLooted = false; Unit::setDeathState(CORPSE); } if(s == JUST_ALIVED) @@ -1493,6 +1557,7 @@ if(getDeathState()==CORPSE && !m_isDeadByDefault ||getDeathState()==ALIVE && m_isDeadByDefault) { m_deathTimer = 0; + m_corpseLooted = false; Update(0); // despawn corpse } if(getDeathState()==DEAD)