Merge remote-tracking branch 'zero/develop21' into develop21
This commit is contained in:
commit
1cfae0615b
@ -62,6 +62,12 @@ void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recv_data)
|
||||
if (bgTypeId == BATTLEGROUND_TYPE_NONE)
|
||||
{ return; }
|
||||
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId))
|
||||
{
|
||||
SendNotification(LANG_BG_IS_DISABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_player->GetBGAccessByLevel(bgTypeId))
|
||||
{
|
||||
// temp, must be gossip message...
|
||||
@ -103,12 +109,6 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recv_data)
|
||||
|
||||
DEBUG_LOG("WORLD: Received opcode CMSG_BATTLEMASTER_JOIN from %s", guid.GetString().c_str());
|
||||
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId))
|
||||
{
|
||||
ChatHandler(this).SendSysMessage(LANG_BG_IS_DISABLED);
|
||||
return;
|
||||
}
|
||||
|
||||
// can do this, since it's battleground, not arena
|
||||
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId);
|
||||
|
||||
|
@ -274,7 +274,7 @@ bool ChatHandler::HandleTriggerCommand(char* args)
|
||||
|
||||
AreaTrigger const* at = sObjectMgr.GetAreaTrigger(atEntry->id);
|
||||
if (at)
|
||||
{ PSendSysMessage(LANG_TRIGGER_REQ_LEVEL, at->requiredLevel); }
|
||||
{ PSendSysMessage(LANG_TRIGGER_CONDITION, at->condition); }
|
||||
|
||||
if (uint32 quest_id = sObjectMgr.GetQuestForAreaTrigger(atEntry->id))
|
||||
{
|
||||
@ -282,25 +282,6 @@ bool ChatHandler::HandleTriggerCommand(char* args)
|
||||
ShowQuestListHelper(quest_id, loc_idx, pl);
|
||||
}
|
||||
|
||||
if (at)
|
||||
{
|
||||
if (at->requiredItem || at->requiredItem2)
|
||||
{
|
||||
SendSysMessage(LANG_TRIGGER_REQ_ITEMS);
|
||||
|
||||
if (at->requiredItem)
|
||||
{ ShowItemListHelper(at->requiredItem, loc_idx, pl); }
|
||||
if (at->requiredItem2)
|
||||
{ ShowItemListHelper(at->requiredItem2, loc_idx, pl); }
|
||||
}
|
||||
|
||||
if (at->requiredQuest)
|
||||
{
|
||||
SendSysMessage(LANG_TRIGGER_REQ_QUEST);
|
||||
ShowQuestListHelper(at->requiredQuest, loc_idx, pl);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "CellImpl.h"
|
||||
#include "movement/MoveSplineInit.h"
|
||||
#include "CreatureLinkingMgr.h"
|
||||
#include "DisableMgr.h"
|
||||
#ifdef ENABLE_ELUNA
|
||||
#include "LuaEngine.h"
|
||||
#endif /* ENABLE_ELUNA */
|
||||
@ -150,7 +151,7 @@ Creature::Creature(CreatureSubtype subtype) : Unit(),
|
||||
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
|
||||
m_AI_locked(false), m_IsDeadByDefault(false), m_temporaryFactionFlags(TEMPFACTION_NONE),
|
||||
m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0),
|
||||
m_creatureInfo(NULL)
|
||||
m_creatureInfo(NULL), m_PlayerDamageReq(0)
|
||||
{
|
||||
/* Loot data */
|
||||
hasBeenLootedOnce = false;
|
||||
@ -187,7 +188,7 @@ void Creature::AddToWorld()
|
||||
#endif /* ENABLE_ELUNA */
|
||||
|
||||
///- Register the creature for guid lookup
|
||||
if (!IsInWorld() && GetObjectGuid().GetHigh() == HIGHGUID_UNIT)
|
||||
if (!IsInWorld() && GetObjectGuid().IsCreature())
|
||||
{ GetMap()->GetObjectsStore().insert<Creature>(GetObjectGuid(), (Creature*)this); }
|
||||
|
||||
Unit::AddToWorld();
|
||||
@ -211,7 +212,7 @@ void Creature::RemoveFromWorld()
|
||||
#endif /* ENABLE_ELUNA */
|
||||
|
||||
///- Remove the creature from the accessor
|
||||
if (IsInWorld() && GetObjectGuid().GetHigh() == HIGHGUID_UNIT)
|
||||
if (IsInWorld() && GetObjectGuid().IsCreature())
|
||||
{ GetMap()->GetObjectsStore().erase<Creature>(GetObjectGuid(), (Creature*)NULL); }
|
||||
|
||||
Unit::RemoveFromWorld();
|
||||
@ -1251,6 +1252,8 @@ void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth /*= 10
|
||||
else
|
||||
{ SetHealthPercent(percentHealth); }
|
||||
|
||||
ResetPlayerDamageReq();
|
||||
|
||||
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health));
|
||||
|
||||
// all power types
|
||||
@ -1335,6 +1338,12 @@ float Creature::_GetDamageMod(int32 Rank)
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::LowerPlayerDamageReq(uint32 unDamage)
|
||||
{
|
||||
if (m_PlayerDamageReq)
|
||||
m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0;
|
||||
}
|
||||
|
||||
float Creature::_GetSpellDamageMod(int32 Rank)
|
||||
{
|
||||
switch (Rank) // define rates for each elite rank
|
||||
@ -1651,6 +1660,7 @@ void Creature::SetDeathState(DeathState s)
|
||||
// Dynamic flags must be set on Tapped by default.
|
||||
SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
|
||||
LoadCreatureAddon(true);
|
||||
ResetPlayerDamageReq();
|
||||
|
||||
// Flags after LoadCreatureAddon. Any spell in *addon
|
||||
// will not be able to adjust these.
|
||||
@ -2116,7 +2126,7 @@ bool Creature::MeetsSelectAttackingRequirement(Unit* pTarget, SpellEntry const*
|
||||
if (selectFlags & SELECT_FLAG_NOT_IN_MELEE_RANGE && CanReachWithMeleeAttack(pTarget))
|
||||
{ return false; }
|
||||
|
||||
if (selectFlags & SELECT_FLAG_IN_LOS && !IsWithinLOSInMap(pTarget))
|
||||
if (selectFlags & SELECT_FLAG_IN_LOS && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, pSpellInfo->Id, pTarget, SPELL_DISABLE_LOS) && !IsWithinLOSInMap(pTarget))
|
||||
{ return false; }
|
||||
|
||||
if (pSpellInfo)
|
||||
|
@ -684,6 +684,9 @@ class Creature : public Unit
|
||||
Player* GetLootRecipient() const; // use group cases as prefered
|
||||
Group* GetGroupLootRecipient() const;
|
||||
bool IsTappedBy(Player const* player) const;
|
||||
bool IsDamageEnoughForLootingAndReward() const { return m_PlayerDamageReq == 0; }
|
||||
void LowerPlayerDamageReq(uint32 unDamage);
|
||||
void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; }
|
||||
|
||||
/**
|
||||
* function indicating whether the whether the creature has a looter recipient defined (either a group ID, either a player GUID).
|
||||
@ -842,6 +845,7 @@ class Creature : public Unit
|
||||
MovementGeneratorType m_defaultMovementType;
|
||||
Cell m_currentCell; // store current cell where creature listed
|
||||
uint32 m_equipmentId;
|
||||
uint32 m_PlayerDamageReq;
|
||||
|
||||
// below fields has potential for optimization
|
||||
bool m_AlreadyCallAssistance;
|
||||
|
@ -147,7 +147,7 @@ class CreatureAI
|
||||
* Called for reaction at stopping attack at no attackers or targets
|
||||
* This is called usually in Unit::SelectHostileTarget, if no more target exists
|
||||
*/
|
||||
virtual void EnterEvadeMode() {}
|
||||
virtual void EnterEvadeMode() { m_creature->ResetPlayerDamageReq(); }
|
||||
|
||||
/**
|
||||
* Called at reaching home after MoveTargetedHome
|
||||
|
@ -1163,6 +1163,7 @@ void CreatureEventAI::EnterEvadeMode()
|
||||
if (i->Event.event_type == EVENT_T_EVADE)
|
||||
{ ProcessEvent(*i); }
|
||||
}
|
||||
m_creature->ResetPlayerDamageReq();
|
||||
}
|
||||
|
||||
void CreatureEventAI::JustDied(Unit* killer)
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "SharedDefines.h"
|
||||
#include "DBCStores.h"
|
||||
#include "SQLStorages.h"
|
||||
#include "DisableMgr.h"
|
||||
|
||||
static eConfigFloatValues const qualityToRate[MAX_ITEM_QUALITY] =
|
||||
{
|
||||
@ -471,7 +472,7 @@ void Loot::AddItem(LootStoreItem const& item)
|
||||
if (m_questItems.size() < MAX_NR_QUEST_ITEMS)
|
||||
{ m_questItems.push_back(LootItem(item)); }
|
||||
}
|
||||
else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
|
||||
else if (items.size() < MAX_NR_LOOT_ITEMS && !DisableMgr::IsDisabledFor(DISABLE_TYPE_ITEM_DROP, item.itemid)) // Non-quest drop
|
||||
{
|
||||
items.push_back(LootItem(item));
|
||||
|
||||
@ -1003,7 +1004,7 @@ bool LootTemplate::LootGroup::HasStartingQuestDropForPlayer(Player const* player
|
||||
void LootTemplate::LootGroup::Process(Loot& loot) const
|
||||
{
|
||||
LootStoreItem const* item = Roll();
|
||||
if (item != NULL)
|
||||
if (item != NULL && !DisableMgr::IsDisabledFor(DISABLE_TYPE_ITEM_DROP, item->itemid))
|
||||
{ loot.AddItem(*item); }
|
||||
}
|
||||
|
||||
@ -1101,7 +1102,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint8
|
||||
// Rolling non-grouped items
|
||||
for (LootStoreItemList::const_iterator i = Entries.begin() ; i != Entries.end() ; ++i)
|
||||
{
|
||||
if (!i->Roll(rate))
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_ITEM_DROP, i->itemid) || !i->Roll(rate))
|
||||
{ continue; } // Bad luck for the entry
|
||||
|
||||
if (i->mincountOrRef < 0) // References processing
|
||||
|
@ -251,72 +251,49 @@ void Object::DestroyForPlayer(Player* target) const
|
||||
|
||||
void Object::BuildMovementUpdate(ByteBuffer* data, uint8 updateFlags) const
|
||||
{
|
||||
uint32 moveFlags = MOVEFLAG_NONE;
|
||||
Unit const* unit = NULL;
|
||||
uint32 highGuid = 0;
|
||||
MovementFlags moveflags = MOVEFLAG_NONE;
|
||||
|
||||
*data << uint8(updateFlags); // update flags
|
||||
switch (m_objectTypeId)
|
||||
{
|
||||
case TYPEID_OBJECT:
|
||||
case TYPEID_ITEM:
|
||||
case TYPEID_CONTAINER:
|
||||
case TYPEID_GAMEOBJECT:
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
case TYPEID_CORPSE:
|
||||
highGuid = uint32(GetObjectGuid().GetHigh());
|
||||
break;
|
||||
|
||||
case TYPEID_PLAYER:
|
||||
// TODO: this code must not be here
|
||||
if (static_cast<Player const*>(this)->GetTransport())
|
||||
((Unit*)this)->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
|
||||
else
|
||||
((Unit*)this)->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ONTRANSPORT);
|
||||
|
||||
case TYPEID_UNIT:
|
||||
unit = static_cast<Unit const*>(this);
|
||||
moveflags = unit->m_movementInfo.GetMovementFlags();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*data << uint8(updateFlags);
|
||||
|
||||
if (updateFlags & UPDATEFLAG_LIVING)
|
||||
{
|
||||
if (m_objectTypeId == TYPEID_PLAYER && ((Player*)this)->GetTransport())
|
||||
MANGOS_ASSERT(unit);
|
||||
if (unit->IsStopped() && unit->m_movementInfo.HasMovementFlag(MOVEFLAG_SPLINE_ENABLED))
|
||||
{
|
||||
moveFlags |= MOVEFLAG_ONTRANSPORT;
|
||||
}
|
||||
|
||||
float x; // not used anywhere
|
||||
if (m_objectTypeId == TYPEID_UNIT && ((Unit*)this)->movespline && ((Unit*)this)->GetMotionMaster()->GetDestination(x, x, x))
|
||||
{
|
||||
moveFlags |= MOVEFLAG_WALK_MODE | MOVEFLAG_FORWARD | MOVEFLAG_SPLINE_ENABLED;
|
||||
}
|
||||
|
||||
*data << uint32(moveFlags); // movement flags
|
||||
*data << uint32(WorldTimer::getMSTime()); // time (in milliseconds)
|
||||
}
|
||||
|
||||
if (updateFlags & UPDATEFLAG_HAS_POSITION) // 0x40
|
||||
{
|
||||
if (m_objectTypeId == TYPEID_PLAYER && ((Player*)this)->GetTransport())
|
||||
{
|
||||
*data << float(((Player*)this)->GetTransport()->GetPositionX());
|
||||
*data << float(((Player*)this)->GetTransport()->GetPositionY());
|
||||
*data << float(((Player*)this)->GetTransport()->GetPositionZ());
|
||||
*data << float(((Player*)this)->GetTransport()->GetOrientation());
|
||||
|
||||
*data << ObjectGuid(((Player*)this)->GetTransport()->GetObjectGuid());
|
||||
*data << float(((Player*)this)->GetTransOffsetX());
|
||||
*data << float(((Player*)this)->GetTransOffsetY());
|
||||
*data << float(((Player*)this)->GetTransOffsetZ());
|
||||
*data << float(((Player*)this)->GetTransOffsetO());
|
||||
}
|
||||
else if (GetObjectGuid().GetHigh() == HIGHGUID_TRANSPORT)
|
||||
{
|
||||
*data << float(0);
|
||||
*data << float(0);
|
||||
*data << float(0);
|
||||
*data << float(((WorldObject*)this)->GetOrientation());
|
||||
}
|
||||
else
|
||||
{
|
||||
*data << float(((WorldObject*)this)->GetPositionX());
|
||||
*data << float(((WorldObject*)this)->GetPositionY());
|
||||
*data << float(((WorldObject*)this)->GetPositionZ());
|
||||
*data << float(((WorldObject*)this)->GetOrientation());
|
||||
}
|
||||
}
|
||||
|
||||
if (updateFlags & UPDATEFLAG_LIVING) // 0x20
|
||||
{
|
||||
Unit* unit = ((Unit*)this);
|
||||
|
||||
*data << (float)0;
|
||||
|
||||
if (moveFlags & 0x02000) // update self MOVEFLAG_FALLING
|
||||
{
|
||||
*data << (float)0;
|
||||
*data << (float)1.0;
|
||||
*data << (float)0;
|
||||
*data << (float)0;
|
||||
sLog.outError("%s is not moving but have spline movement enabled!", GetGuidStr().c_str());
|
||||
((Unit*)this)->m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEFLAG_SPLINE_ENABLED | MOVEFLAG_FORWARD));
|
||||
}
|
||||
|
||||
*data << unit->m_movementInfo;
|
||||
// Unit speeds
|
||||
*data << float(unit->GetSpeed(MOVE_WALK));
|
||||
*data << float(unit->GetSpeed(MOVE_RUN));
|
||||
@ -325,25 +302,33 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint8 updateFlags) const
|
||||
*data << float(unit->GetSpeed(MOVE_SWIM_BACK));
|
||||
*data << float(unit->GetSpeed(MOVE_TURN_RATE));
|
||||
|
||||
if (m_objectTypeId == TYPEID_UNIT)
|
||||
{
|
||||
if (moveFlags & MOVEFLAG_SPLINE_ENABLED && ((Unit*)this)->movespline) // 0x00400000
|
||||
{
|
||||
Movement::PacketBuilder::WriteCreate((*((Unit*)this)->movespline), *data);
|
||||
}
|
||||
if (unit->m_movementInfo.HasMovementFlag(MOVEFLAG_SPLINE_ENABLED))
|
||||
Movement::PacketBuilder::WriteCreate(*unit->movespline, *data);
|
||||
}
|
||||
else if (updateFlags & UPDATEFLAG_HAS_POSITION)
|
||||
{
|
||||
*data << ((WorldObject*)this)->GetPositionX();
|
||||
*data << ((WorldObject*)this)->GetPositionY();
|
||||
*data << ((WorldObject*)this)->GetPositionZ();
|
||||
*data << ((WorldObject*)this)->GetOrientation();
|
||||
}
|
||||
|
||||
if (updateFlags & UPDATEFLAG_ALL) // 0x10
|
||||
{
|
||||
if (updateFlags & UPDATEFLAG_HIGHGUID)
|
||||
*data << highGuid;
|
||||
|
||||
if (updateFlags & UPDATEFLAG_ALL)
|
||||
*data << (uint32)0x1;
|
||||
|
||||
if (updateFlags & UPDATEFLAG_FULLGUID)
|
||||
{
|
||||
if (unit && unit->getVictim())
|
||||
*data << unit->getVictim()->GetPackGUID();
|
||||
else
|
||||
data->appendPackGUID(0);
|
||||
}
|
||||
|
||||
// 0x2
|
||||
if (updateFlags & UPDATEFLAG_TRANSPORT)
|
||||
{
|
||||
*data << uint32(WorldTimer::getMSTime()); // ms time
|
||||
}
|
||||
*data << uint32(WorldTimer::getMSTime());
|
||||
}
|
||||
|
||||
void Object::BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, UpdateMask* updateMask, Player* target) const
|
||||
|
@ -131,6 +131,38 @@ bool operator < (const HonorStanding& lhs, const HonorStanding& rhs)
|
||||
return lhs.honorPoints > rhs.honorPoints;
|
||||
}
|
||||
|
||||
// TODO improve the algorithm based on conditions
|
||||
bool AreaTrigger::IsLessOrEqualThan(AreaTrigger const* l) const // Expected to have same map
|
||||
{
|
||||
MANGOS_ASSERT(target_mapId == l->target_mapId);
|
||||
if (!condition)
|
||||
{ return true; }
|
||||
|
||||
if (!l->condition)
|
||||
{ return false; }
|
||||
|
||||
if (condition == l->condition)
|
||||
{ return true; }
|
||||
|
||||
// most conditions for AT have level requirement
|
||||
// let's order by the least restrictive
|
||||
const PlayerCondition* pCond1 = sConditionStorage.LookupEntry<PlayerCondition>(condition);
|
||||
const PlayerCondition* pCond2 = sConditionStorage.LookupEntry<PlayerCondition>(l->condition);
|
||||
if (pCond1->m_condition == CONDITION_LEVEL && pCond2->m_condition == CONDITION_LEVEL)
|
||||
{
|
||||
return (pCond1->m_value1 <= pCond2->m_value1);
|
||||
}
|
||||
if (pCond1->m_condition == CONDITION_LEVEL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pCond2->m_condition == CONDITION_LEVEL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectMgr::ObjectMgr() :
|
||||
m_AuctionIds("Auction ids"),
|
||||
m_GuildIds("Guild ids"),
|
||||
@ -1062,7 +1094,7 @@ void ObjectMgr::LoadCreatures()
|
||||
uint32 guid = fields[ 0].GetUInt32();
|
||||
uint32 entry = fields[ 1].GetUInt32();
|
||||
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_CREATURE_SPAWN, guid))
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_CREATURE_SPAWN, entry, NULL, 0, guid))
|
||||
{
|
||||
sLog.outDebug("Creature guid %u (entry %u) spawning is disabled.", guid, entry);
|
||||
continue;
|
||||
@ -1236,7 +1268,7 @@ void ObjectMgr::LoadGameObjects()
|
||||
uint32 guid = fields[ 0].GetUInt32();
|
||||
uint32 entry = fields[ 1].GetUInt32();
|
||||
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_GAMEOBJECT_SPAWN, guid))
|
||||
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_GAMEOBJECT_SPAWN, entry, NULL, 0, guid))
|
||||
{
|
||||
sLog.outDebug("Gameobject guid %u (entry %u) spawning is disabled.", guid, entry);
|
||||
continue;
|
||||
@ -5066,7 +5098,7 @@ void ObjectMgr::LoadAreaTriggerTeleports()
|
||||
uint32 count = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
QueryResult* result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, required_quest_done, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
|
||||
QueryResult* result = WorldDatabase.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation, condition_id FROM areatrigger_teleport");
|
||||
if (!result)
|
||||
{
|
||||
BarGoLink bar(1);
|
||||
@ -5090,15 +5122,12 @@ void ObjectMgr::LoadAreaTriggerTeleports()
|
||||
|
||||
AreaTrigger at;
|
||||
|
||||
at.requiredLevel = fields[1].GetUInt8();
|
||||
at.requiredItem = fields[2].GetUInt32();
|
||||
at.requiredItem2 = fields[3].GetUInt32();
|
||||
at.requiredQuest = fields[4].GetUInt32();
|
||||
at.target_mapId = fields[5].GetUInt32();
|
||||
at.target_X = fields[6].GetFloat();
|
||||
at.target_Y = fields[7].GetFloat();
|
||||
at.target_Z = fields[8].GetFloat();
|
||||
at.target_Orientation = fields[9].GetFloat();
|
||||
at.target_mapId = fields[1].GetUInt32();
|
||||
at.target_X = fields[2].GetFloat();
|
||||
at.target_Y = fields[3].GetFloat();
|
||||
at.target_Z = fields[4].GetFloat();
|
||||
at.target_Orientation = fields[5].GetFloat();
|
||||
at.condition = fields[6].GetUInt16();
|
||||
|
||||
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
|
||||
if (!atEntry)
|
||||
@ -5107,36 +5136,6 @@ void ObjectMgr::LoadAreaTriggerTeleports()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (at.requiredItem)
|
||||
{
|
||||
ItemPrototype const* pProto = GetItemPrototype(at.requiredItem);
|
||||
if (!pProto)
|
||||
{
|
||||
sLog.outError("Table `areatrigger_teleport` has nonexistent key item %u for trigger %u, removing key requirement.", at.requiredItem, Trigger_ID);
|
||||
at.requiredItem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (at.requiredItem2)
|
||||
{
|
||||
ItemPrototype const* pProto = GetItemPrototype(at.requiredItem2);
|
||||
if (!pProto)
|
||||
{
|
||||
sLog.outError("Table `areatrigger_teleport` has nonexistent second key item %u for trigger %u, remove key requirement.", at.requiredItem2, Trigger_ID);
|
||||
at.requiredItem2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (at.requiredQuest)
|
||||
{
|
||||
QuestMap::iterator qReqItr = mQuestTemplates.find(at.requiredQuest);
|
||||
if (qReqItr == mQuestTemplates.end())
|
||||
{
|
||||
sLog.outErrorDb("Table `areatrigger_teleport` has nonexistent required quest %u for trigger %u, remove quest done requirement.", at.requiredQuest, Trigger_ID);
|
||||
at.requiredQuest = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
|
||||
if (!mapEntry)
|
||||
{
|
||||
@ -5150,6 +5149,12 @@ void ObjectMgr::LoadAreaTriggerTeleports()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (at.condition && !sConditionStorage.LookupEntry<PlayerCondition>(at.condition))
|
||||
{
|
||||
sLog.outErrorDb("Table `areatrigger_teleport` has nonexistent condition (ID:%u) for Area trigger (ID:%u).", at.condition, Trigger_ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
mAreaTriggers[Trigger_ID] = at;
|
||||
}
|
||||
while (result->NextRow());
|
||||
@ -6870,10 +6875,10 @@ void ObjectMgr::LoadFishingBaseSkillLevel()
|
||||
}
|
||||
|
||||
// Check if a player meets condition conditionId
|
||||
bool ObjectMgr::IsPlayerMeetToCondition(uint16 conditionId, Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType) const
|
||||
bool ObjectMgr::IsPlayerMeetToCondition(uint16 conditionId, Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType, ConditionEntry* entry) const
|
||||
{
|
||||
if (const PlayerCondition* condition = sConditionStorage.LookupEntry<PlayerCondition>(conditionId))
|
||||
{ return condition->Meets(pPlayer, map, source, conditionSourceType); }
|
||||
{ return condition->Meets(pPlayer, map, source, conditionSourceType, entry); }
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -6891,15 +6896,23 @@ char const* conditionSourceToStr[] =
|
||||
"vendor's item check",
|
||||
"spell_area check",
|
||||
"npc_spellclick_spells check", // Unused. For 3.x and later.
|
||||
"DBScript engine"
|
||||
"DBScript engine",
|
||||
"area trigger check"
|
||||
};
|
||||
|
||||
// Checks if player meets the condition
|
||||
bool PlayerCondition::Meets(Player const* player, Map const* map, WorldObject const* source, ConditionSource conditionSourceType) const
|
||||
bool PlayerCondition::Meets(Player const* player, Map const* map, WorldObject const* source, ConditionSource conditionSourceType, ConditionEntry* entry) const
|
||||
{
|
||||
DEBUG_LOG("Condition-System: Check condition %u, type %i - called from %s with params plr: %s, map %i, src %s",
|
||||
m_entry, m_condition, conditionSourceToStr[conditionSourceType], player ? player->GetGuidStr().c_str() : "<NULL>", map ? map->GetId() : -1, source ? source->GetGuidStr().c_str() : "<NULL>");
|
||||
|
||||
if (entry)
|
||||
{
|
||||
entry->type = m_condition;
|
||||
entry->param1 = m_value1;
|
||||
entry->param2 = m_value2;
|
||||
}
|
||||
|
||||
if (!CheckParamRequirements(player, map, source, conditionSourceType))
|
||||
{ return false; }
|
||||
|
||||
@ -6907,13 +6920,13 @@ bool PlayerCondition::Meets(Player const* player, Map const* map, WorldObject co
|
||||
{
|
||||
case CONDITION_NOT:
|
||||
// Checked on load
|
||||
return !sConditionStorage.LookupEntry<PlayerCondition>(m_value1)->Meets(player, map, source, conditionSourceType);
|
||||
return !sConditionStorage.LookupEntry<PlayerCondition>(m_value1)->Meets(player, map, source, conditionSourceType, entry);
|
||||
case CONDITION_OR:
|
||||
// Checked on load
|
||||
return sConditionStorage.LookupEntry<PlayerCondition>(m_value1)->Meets(player, map, source, conditionSourceType) || sConditionStorage.LookupEntry<PlayerCondition>(m_value2)->Meets(player, map, source, conditionSourceType);
|
||||
return sConditionStorage.LookupEntry<PlayerCondition>(m_value1)->Meets(player, map, source, conditionSourceType, entry) || sConditionStorage.LookupEntry<PlayerCondition>(m_value2)->Meets(player, map, source, conditionSourceType, entry);
|
||||
case CONDITION_AND:
|
||||
// Checked on load
|
||||
return sConditionStorage.LookupEntry<PlayerCondition>(m_value1)->Meets(player, map, source, conditionSourceType) && sConditionStorage.LookupEntry<PlayerCondition>(m_value2)->Meets(player, map, source, conditionSourceType);
|
||||
return sConditionStorage.LookupEntry<PlayerCondition>(m_value1)->Meets(player, map, source, conditionSourceType, entry) && sConditionStorage.LookupEntry<PlayerCondition>(m_value2)->Meets(player, map, source, conditionSourceType, entry);
|
||||
case CONDITION_NONE:
|
||||
return true; // empty condition, always met
|
||||
case CONDITION_AURA:
|
||||
@ -7168,6 +7181,15 @@ bool PlayerCondition::Meets(Player const* player, Map const* map, WorldObject co
|
||||
}
|
||||
return pGo;
|
||||
}
|
||||
case CONDITION_PVP_RANK:
|
||||
{
|
||||
switch (m_value2)
|
||||
{
|
||||
case 0: return player->GetHonorRankInfo().rank == m_value1;
|
||||
case 1: return player->GetHonorRankInfo().rank >= m_value1;
|
||||
case 2: return player->GetHonorRankInfo().rank <= m_value1;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -7238,6 +7260,14 @@ bool PlayerCondition::CheckParamRequirements(Player const* pPlayer, Map const* m
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CONDITION_PVP_RANK:
|
||||
if (!pPlayer)
|
||||
{
|
||||
sLog.outErrorDb("CONDITION %u type %u used with bad parameters, called from %s, used with %s, map %i, src %s",
|
||||
m_entry, m_condition, conditionSourceToStr[conditionSourceType], pPlayer ? pPlayer->GetGuidStr().c_str() : "NULL", map ? map->GetId() : -1, source ? source->GetGuidStr().c_str() : "NULL");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!pPlayer)
|
||||
{
|
||||
@ -7600,6 +7630,15 @@ bool PlayerCondition::IsValid(uint16 entry, ConditionType condition, uint32 valu
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_PVP_RANK:
|
||||
{
|
||||
if (value2 > 2)
|
||||
{
|
||||
sLog.outErrorDb("PVP rank condition (entry %u, type %u) has invalid argument %u (must be 0..2), skipped", entry, condition, value2);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_NONE:
|
||||
break;
|
||||
default:
|
||||
|
@ -66,10 +66,7 @@ typedef UNORDERED_MAP<uint32, GameTele > GameTeleMap;
|
||||
|
||||
struct AreaTrigger
|
||||
{
|
||||
uint8 requiredLevel;
|
||||
uint32 requiredItem;
|
||||
uint32 requiredItem2;
|
||||
uint32 requiredQuest;
|
||||
uint32 condition;
|
||||
uint32 target_mapId;
|
||||
float target_X;
|
||||
float target_Y;
|
||||
@ -79,15 +76,10 @@ struct AreaTrigger
|
||||
// Operators
|
||||
bool IsMinimal() const
|
||||
{
|
||||
return requiredLevel == 0 && requiredItem == 0 && requiredItem2 == 0 && requiredQuest == 0;
|
||||
return condition == 0;
|
||||
}
|
||||
|
||||
bool IsLessOrEqualThan(AreaTrigger const* l) const // Expected to have same map
|
||||
{
|
||||
MANGOS_ASSERT(target_mapId == l->target_mapId);
|
||||
return requiredLevel <= l->requiredLevel && requiredItem <= l->requiredItem && requiredItem2 <= l->requiredItem2
|
||||
&& requiredQuest <= l->requiredQuest;
|
||||
}
|
||||
bool IsLessOrEqualThan(AreaTrigger const* l) const;
|
||||
};
|
||||
|
||||
typedef std::map < uint32/*player guid*/, uint32/*instance*/ > CellCorpseSet;
|
||||
@ -330,6 +322,7 @@ enum ConditionType
|
||||
// value2: if != 0 only consider players in range of this value
|
||||
CONDITION_CREATURE_IN_RANGE = 37, // value1: creature entry; value2: range; returns only alive creatures
|
||||
CONDITION_GAMEOBJECT_IN_RANGE = 38, // value1: gameobject entry; value2: range
|
||||
CONDITION_PVP_RANK = 39, // value1: rank; value2: 0 = eq, 1 = equal or higher, 2 = equal or less
|
||||
};
|
||||
|
||||
enum ConditionSource // From where was the condition called?
|
||||
@ -344,10 +337,20 @@ enum ConditionSource // From where was th
|
||||
CONDITION_FROM_SPELL_AREA = 7, // Used to check a condition from spell_area table
|
||||
CONDITION_FROM_RESERVED_1 = 8, // reserved for 3.x and later
|
||||
CONDITION_FROM_DBSCRIPTS = 9, // Used to check a condition from DB Scripts Engine
|
||||
CONDITION_AREA_TRIGGER = 10, // Used to check a condition from CMSG_AREATRIGGER
|
||||
};
|
||||
|
||||
struct ConditionEntry
|
||||
{
|
||||
ConditionEntry() : type(CONDITION_NONE), param1(0), param2(0) {}
|
||||
ConditionType type;
|
||||
uint32 param1;
|
||||
uint32 param2;
|
||||
};
|
||||
|
||||
class PlayerCondition
|
||||
{
|
||||
friend struct AreaTrigger;
|
||||
public:
|
||||
// Default constructor, required for SQL Storage (Will give errors if used elsewise)
|
||||
PlayerCondition() : m_entry(0), m_condition(CONDITION_AND), m_value1(0), m_value2(0) {}
|
||||
@ -365,7 +368,11 @@ class PlayerCondition
|
||||
static bool CanBeUsedWithoutPlayer(uint16 entry);
|
||||
|
||||
// Checks if the player meets the condition
|
||||
bool Meets(Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType) const;
|
||||
// if the param entry is not null, it will be filled at return as follows:
|
||||
// - if function fails, entry will contain the first faulty condition
|
||||
// - if function succeeds, entry will contain the last condition checked (if chained)
|
||||
// entry is only useful on failure case
|
||||
bool Meets(Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType, ConditionEntry* entry = NULL) const;
|
||||
|
||||
private:
|
||||
bool CheckParamRequirements(Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType) const;
|
||||
@ -987,7 +994,7 @@ class ObjectMgr
|
||||
LocaleConstant GetLocaleForIndex(int i);
|
||||
|
||||
// Check if a player meets condition conditionId
|
||||
bool IsPlayerMeetToCondition(uint16 conditionId, Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType) const;
|
||||
bool IsPlayerMeetToCondition(uint16 conditionId, Player const* pPlayer, Map const* map, WorldObject const* source, ConditionSource conditionSourceType, ConditionEntry* entry = NULL) const;
|
||||
|
||||
GameTele const* GetGameTele(uint32 id) const
|
||||
{
|
||||
|
@ -2073,7 +2073,6 @@ void Pet::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio)
|
||||
case MOVE_WALK:
|
||||
break;
|
||||
case MOVE_RUN:
|
||||
{
|
||||
if (!m_attacking && owner->HasAura(19596)) // Bestial Swiftness: prevent while following
|
||||
{
|
||||
AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_INCREASE_SPEED);
|
||||
@ -2087,7 +2086,6 @@ void Pet::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio)
|
||||
stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_SPEED_ALWAYS);
|
||||
non_stack_bonus = (100.0f + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_SPEED_NOT_STACK)) / 100.0f;
|
||||
break;
|
||||
}
|
||||
case MOVE_RUN_BACK:
|
||||
return;
|
||||
case MOVE_SWIM:
|
||||
|
@ -85,6 +85,7 @@ void PetAI::AttackStart(Unit* u)
|
||||
// thus with the following clear the original TMG gets invalidated and crash, doh
|
||||
// hope it doesn't start to leak memory without this :-/
|
||||
// i_pet->Clear();
|
||||
m_creature->UpdateSpeed(MOVE_RUN, false);
|
||||
HandleMovementOnAttackStart(u);
|
||||
inCombat = true;
|
||||
}
|
||||
@ -117,6 +118,7 @@ void PetAI::_stopAttack()
|
||||
if (owner && m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
|
||||
{
|
||||
m_creature->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
m_creature->UpdateSpeed(MOVE_RUN, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -14071,8 +14071,8 @@ bool Player::IsTappedByMeOrMyGroup(Creature* creature)
|
||||
* Called from Object::BuildValuesUpdate */
|
||||
bool Player::isAllowedToLoot(Creature* creature)
|
||||
{
|
||||
/* Nobody tapped the monster (solo kill by another NPC) */
|
||||
if (!creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED))
|
||||
/* Nobody tapped the monster (kill either solo or mostly by another NPC) */
|
||||
if (!creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED) || !creature->IsDamageEnoughForLootingAndReward())
|
||||
{ return false; }
|
||||
|
||||
/* If we there is a loot recipient, assign it to recipient */
|
||||
@ -17678,15 +17678,27 @@ void Player::SendTransferAbortedByLockStatus(MapEntry const* mapEntry, AreaLockS
|
||||
|
||||
switch (lockStatus)
|
||||
{
|
||||
case AREA_LOCKSTATUS_TOO_LOW_LEVEL:
|
||||
case AREA_LOCKSTATUS_LEVEL_TOO_LOW:
|
||||
GetSession()->SendAreaTriggerMessage(GetSession()->GetMangosString(LANG_LEVEL_MINREQUIRED), miscRequirement);
|
||||
break;
|
||||
case AREA_LOCKSTATUS_LEVEL_TOO_HIGH:
|
||||
GetSession()->SendAreaTriggerMessage(GetSession()->GetMangosString(LANG_LEVEL_MAXREQUIRED), miscRequirement);
|
||||
break;
|
||||
case AREA_LOCKSTATUS_LEVEL_NOT_EQUAL:
|
||||
GetSession()->SendAreaTriggerMessage(GetSession()->GetMangosString(LANG_LEVEL_EQUALREQUIRED), miscRequirement);
|
||||
break;
|
||||
case AREA_LOCKSTATUS_ZONE_IN_COMBAT:
|
||||
GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_ZONE_IN_COMBAT);
|
||||
break;
|
||||
case AREA_LOCKSTATUS_INSTANCE_IS_FULL:
|
||||
GetSession()->SendTransferAborted(mapEntry->MapID, TRANSFER_ABORT_MAX_PLAYERS);
|
||||
break;
|
||||
case AREA_LOCKSTATUS_WRONG_TEAM:
|
||||
if (miscRequirement == 469)
|
||||
GetSession()->SendAreaTriggerMessage("%s", GetSession()->GetMangosString(LANG_WRONG_TEAM_ALLIANCE));
|
||||
else
|
||||
GetSession()->SendAreaTriggerMessage("%s", GetSession()->GetMangosString(LANG_WRONG_TEAM_HORDE));
|
||||
break;
|
||||
case AREA_LOCKSTATUS_QUEST_NOT_COMPLETED:
|
||||
if (mapEntry->IsContinent()) // do not report anything for quest areatrigge
|
||||
{
|
||||
@ -17697,7 +17709,7 @@ void Player::SendTransferAbortedByLockStatus(MapEntry const* mapEntry, AreaLockS
|
||||
break;
|
||||
case AREA_LOCKSTATUS_MISSING_ITEM:
|
||||
if (AreaTrigger const* at = sObjectMgr.GetMapEntranceTrigger(mapEntry->MapID))
|
||||
{ GetSession()->SendAreaTriggerMessage(GetSession()->GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, sObjectMgr.GetItemPrototype(miscRequirement)->Name1); }
|
||||
{ GetSession()->SendAreaTriggerMessage(GetSession()->GetMangosString(LANG_REQUIRED_ITEM), sObjectMgr.GetItemPrototype(miscRequirement)->Name1); }
|
||||
break;
|
||||
case AREA_LOCKSTATUS_NOT_ALLOWED:
|
||||
case AREA_LOCKSTATUS_RAID_LOCKED:
|
||||
@ -19430,41 +19442,64 @@ AreaLockStatus Player::GetAreaTriggerLockStatus(AreaTrigger const* at, uint32& m
|
||||
if (isGameMaster())
|
||||
{ return AREA_LOCKSTATUS_OK; }
|
||||
|
||||
// Level Requirements
|
||||
if (getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL))
|
||||
{
|
||||
miscRequirement = at->requiredLevel;
|
||||
return AREA_LOCKSTATUS_TOO_LOW_LEVEL;
|
||||
}
|
||||
|
||||
// Raid Requirements
|
||||
if (mapEntry->IsRaid() && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID))
|
||||
if (!GetGroup() || !GetGroup()->isRaidGroup())
|
||||
{ return AREA_LOCKSTATUS_RAID_LOCKED; }
|
||||
|
||||
// Item Requirements: must have requiredItem OR requiredItem2, report the first one that's missing
|
||||
if (at->requiredItem)
|
||||
if (at->condition) //condition validity is checked at startup
|
||||
{
|
||||
if (!HasItemCount(at->requiredItem, 1) &&
|
||||
(!at->requiredItem2 || !HasItemCount(at->requiredItem2, 1)))
|
||||
ConditionEntry fault;
|
||||
if (!sObjectMgr.IsPlayerMeetToCondition(at->condition, this, GetMap(),NULL, CONDITION_AREA_TRIGGER, &fault))
|
||||
{
|
||||
miscRequirement = at->requiredItem;
|
||||
return AREA_LOCKSTATUS_MISSING_ITEM;
|
||||
switch (fault.type)
|
||||
{
|
||||
case CONDITION_LEVEL:
|
||||
{
|
||||
if (sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL))
|
||||
break;
|
||||
else
|
||||
{
|
||||
miscRequirement = fault.param1;
|
||||
switch (fault.param2)
|
||||
{
|
||||
case 0: { return AREA_LOCKSTATUS_LEVEL_NOT_EQUAL; }
|
||||
case 1: { return AREA_LOCKSTATUS_LEVEL_TOO_LOW; }
|
||||
case 2: { return AREA_LOCKSTATUS_LEVEL_TOO_HIGH; }
|
||||
}
|
||||
}
|
||||
else if (at->requiredItem2 && !HasItemCount(at->requiredItem2, 1))
|
||||
}
|
||||
|
||||
case CONDITION_ITEM:
|
||||
{
|
||||
miscRequirement = at->requiredItem2;
|
||||
miscRequirement = fault.param1;
|
||||
return AREA_LOCKSTATUS_MISSING_ITEM;
|
||||
}
|
||||
|
||||
// Quest Requirements
|
||||
if (at->requiredQuest && !GetQuestRewardStatus(at->requiredQuest))
|
||||
case CONDITION_QUESTREWARDED:
|
||||
{
|
||||
miscRequirement = at->requiredQuest;
|
||||
miscRequirement = fault.param1;
|
||||
return AREA_LOCKSTATUS_QUEST_NOT_COMPLETED;
|
||||
}
|
||||
|
||||
case CONDITION_TEAM:
|
||||
{
|
||||
miscRequirement = fault.param1;
|
||||
return AREA_LOCKSTATUS_WRONG_TEAM;
|
||||
}
|
||||
|
||||
case CONDITION_PVP_RANK:
|
||||
{
|
||||
miscRequirement = fault.param1;
|
||||
return AREA_LOCKSTATUS_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
default:
|
||||
return AREA_LOCKSTATUS_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the map is not created, assume it is possible to enter it.
|
||||
DungeonPersistentState* state = GetBoundInstanceSaveForSelfOrGroup(at->target_mapId);
|
||||
Map* map = sMapMgr.FindMap(at->target_mapId, state ? state->GetInstanceId() : 0);
|
||||
|
@ -230,7 +230,7 @@ void SocialMgr::GetFriendInfo(Player* player, uint32 friend_lowguid, FriendInfo&
|
||||
|
||||
PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friend_lowguid);
|
||||
if (itr != player->GetSocial()->m_playerSocialMap.end())
|
||||
|
||||
{
|
||||
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
|
||||
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
|
||||
if (pFriend && pFriend->GetName() &&
|
||||
@ -255,6 +255,7 @@ void SocialMgr::GetFriendInfo(Player* player, uint32 friend_lowguid, FriendInfo&
|
||||
friendInfo.Class = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocialMgr::MakeFriendStatusPacket(FriendsResult result, uint32 guid, WorldPacket* data)
|
||||
{
|
||||
|
@ -631,8 +631,14 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
|
||||
{ SetContestedPvP(attackedPlayer); }
|
||||
}
|
||||
|
||||
if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->IsPet() && !((Creature*)pVictim)->HasLootRecipient())
|
||||
{ ((Creature*)pVictim)->SetLootRecipient(this); }
|
||||
if (Creature* victim = pVictim->ToCreature())
|
||||
{
|
||||
if (!victim->IsPet() && !victim->HasLootRecipient())
|
||||
victim->SetLootRecipient(this);
|
||||
|
||||
if (IsControlledByPlayer()) // more narrow: IsPet(), IsGuardian() ?
|
||||
victim->LowerPlayerDamageReq(health < damage ? health : damage);
|
||||
}
|
||||
|
||||
if (health <= damage)
|
||||
{
|
||||
@ -681,23 +687,36 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa
|
||||
/*
|
||||
* Generic Actions (ProcEvents, Combat-Log, Kill Rewards, Stop Combat)
|
||||
*/
|
||||
bool isRewardAllowed = true;
|
||||
if (Creature* creature = pVictim->ToCreature())
|
||||
{
|
||||
isRewardAllowed = creature->IsDamageEnoughForLootingAndReward();
|
||||
if (!isRewardAllowed)
|
||||
creature->SetLootRecipient(NULL);
|
||||
}
|
||||
|
||||
// call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
|
||||
if (player_tap && player_tap != pVictim)
|
||||
{
|
||||
player_tap->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
|
||||
|
||||
if (isRewardAllowed)
|
||||
{
|
||||
WorldPacket data(SMSG_PARTYKILLLOG, (8 + 8)); // send event PARTY_KILL
|
||||
data << player_tap->GetObjectGuid(); // player with killing blow
|
||||
data << pVictim->GetObjectGuid(); // victim
|
||||
|
||||
if (group_tap)
|
||||
{ group_tap->BroadcastPacket(&data, false, group_tap->GetMemberGroup(player_tap->GetObjectGuid()), player_tap->GetObjectGuid()); }
|
||||
{
|
||||
group_tap->BroadcastPacket(&data, false, group_tap->GetMemberGroup(player_tap->GetObjectGuid()), player_tap->GetObjectGuid());
|
||||
}
|
||||
|
||||
player_tap->SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
// Reward player, his pets, and group/raid members
|
||||
if (player_tap != pVictim)
|
||||
if (isRewardAllowed && player_tap != pVictim)
|
||||
{
|
||||
if (group_tap)
|
||||
{ group_tap->RewardGroupAtKill(pVictim, player_tap); }
|
||||
|
@ -589,17 +589,17 @@ enum MovementFlags
|
||||
MOVEFLAG_WALK_MODE = 0x00000100, // Walking
|
||||
|
||||
MOVEFLAG_LEVITATING = 0x00000400,
|
||||
MOVEFLAG_ROOT = 0x00000800, // [-ZERO] is it really need and correct value
|
||||
MOVEFLAG_FLYING = 0x00000800, // [-ZERO] is it really need and correct value
|
||||
MOVEFLAG_FALLING = 0x00002000,
|
||||
MOVEFLAG_FALLINGFAR = 0x00004000,
|
||||
MOVEFLAG_SWIMMING = 0x00200000, // appears with fly flag also
|
||||
MOVEFLAG_SPLINE_ENABLED = 0x00400000,
|
||||
MOVEFLAG_CAN_FLY = 0x00800000, // [-ZERO] is it really need and correct value
|
||||
MOVEFLAG_FLYING = 0x01000000, // [-ZERO] is it really need and correct value
|
||||
MOVEFLAG_FLYING_OLD = 0x01000000, // [-ZERO] is it really need and correct value
|
||||
|
||||
MOVEFLAG_ONTRANSPORT = 0x02000000, // Used for flying on some creatures
|
||||
MOVEFLAG_SPLINE_ELEVATION = 0x04000000, // [-ZERO] checkme! used for flight paths
|
||||
//MOVEFLAG_SPLINE_ENABLED = 0x08000000, // [-ZERO] wrong!
|
||||
MOVEFLAG_SPLINE_ELEVATION = 0x04000000, // used for flight paths
|
||||
MOVEFLAG_ROOT = 0x08000000, // used for flight paths
|
||||
MOVEFLAG_WATERWALKING = 0x10000000, // prevent unit from falling through water
|
||||
MOVEFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive)
|
||||
MOVEFLAG_HOVER = 0x40000000
|
||||
|
@ -331,7 +331,7 @@ enum SpellAttributesEx
|
||||
SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE = 0x00010000, // 16 unaffected by school immunity
|
||||
SPELL_ATTR_EX_UNK17 = 0x00020000, // 17 for auras SPELL_AURA_TRACK_CREATURES, SPELL_AURA_TRACK_RESOURCES and SPELL_AURA_TRACK_STEALTHED select non-stacking tracking spells
|
||||
SPELL_ATTR_EX_UNK18 = 0x00040000, // 18
|
||||
SPELL_ATTR_EX_UNK19 = 0x00080000, // 19
|
||||
SPELL_ATTR_EX_CANT_TARGET_SELF = 0x00080000, // 19 spells that exclude the caster
|
||||
SPELL_ATTR_EX_REQ_TARGET_COMBO_POINTS = 0x00100000, // 20 Req combo points on target
|
||||
SPELL_ATTR_EX_UNK21 = 0x00200000, // 21
|
||||
SPELL_ATTR_EX_REQ_COMBO_POINTS = 0x00400000, // 22 Use combo points (in 4.x not required combo point target selected)
|
||||
@ -2548,15 +2548,17 @@ enum AreaLockStatus
|
||||
{
|
||||
AREA_LOCKSTATUS_OK = 0,
|
||||
AREA_LOCKSTATUS_UNKNOWN_ERROR = 1,
|
||||
AREA_LOCKSTATUS_TOO_LOW_LEVEL = 2,
|
||||
AREA_LOCKSTATUS_TOO_HIGH_LEVEL = 3,
|
||||
AREA_LOCKSTATUS_RAID_LOCKED = 4,
|
||||
AREA_LOCKSTATUS_QUEST_NOT_COMPLETED = 5,
|
||||
AREA_LOCKSTATUS_MISSING_ITEM = 6,
|
||||
AREA_LOCKSTATUS_ZONE_IN_COMBAT = 7,
|
||||
AREA_LOCKSTATUS_INSTANCE_IS_FULL = 8,
|
||||
AREA_LOCKSTATUS_NOT_ALLOWED = 9,
|
||||
AREA_LOCKSTATUS_HAS_BIND = 10,
|
||||
AREA_LOCKSTATUS_LEVEL_NOT_EQUAL = 2,
|
||||
AREA_LOCKSTATUS_LEVEL_TOO_LOW = 3,
|
||||
AREA_LOCKSTATUS_LEVEL_TOO_HIGH = 4,
|
||||
AREA_LOCKSTATUS_RAID_LOCKED = 5,
|
||||
AREA_LOCKSTATUS_QUEST_NOT_COMPLETED = 6,
|
||||
AREA_LOCKSTATUS_MISSING_ITEM = 7,
|
||||
AREA_LOCKSTATUS_ZONE_IN_COMBAT = 8,
|
||||
AREA_LOCKSTATUS_INSTANCE_IS_FULL = 9,
|
||||
AREA_LOCKSTATUS_NOT_ALLOWED = 10,
|
||||
AREA_LOCKSTATUS_HAS_BIND = 11,
|
||||
AREA_LOCKSTATUS_WRONG_TEAM = 12,
|
||||
};
|
||||
|
||||
enum TrackedAuraType
|
||||
|
@ -79,7 +79,7 @@ enum MangosStrings
|
||||
LANG_NON_EXIST_CHARACTER = 47,
|
||||
LANG_FRIEND_IGNORE_UNKNOWN = 48,
|
||||
LANG_LEVEL_MINREQUIRED = 49,
|
||||
LANG_LEVEL_MINREQUIRED_AND_ITEM = 50,
|
||||
LANG_REQUIRED_ITEM = 50,
|
||||
LANG_NPC_TAINER_HELLO = 51,
|
||||
LANG_COMMAND_INVALID_ITEM_COUNT = 52,
|
||||
LANG_COMMAND_MAIL_ITEMS_LIMIT = 53,
|
||||
@ -96,7 +96,11 @@ enum MangosStrings
|
||||
LANG_GM_NO_WHISPER = 64,
|
||||
LANG_USING_SCRIPT_LIB_UNKNOWN = 65,
|
||||
LANG_USING_SCRIPT_LIB_NONE = 66,
|
||||
// Room for more level 0 67-99 not used
|
||||
LANG_WRONG_TEAM_HORDE = 67,
|
||||
LANG_WRONG_TEAM_ALLIANCE = 68,
|
||||
LANG_LEVEL_MAXREQUIRED = 69,
|
||||
LANG_LEVEL_EQUALREQUIRED = 70,
|
||||
// Room for more level 0 71-99 not used
|
||||
|
||||
// level 1 chat
|
||||
LANG_GLOBAL_NOTIFY = 100,
|
||||
@ -363,9 +367,9 @@ enum MangosStrings
|
||||
LANG_TRIGGER_TAVERN = 364,
|
||||
LANG_TRIGGER_QUEST = 365,
|
||||
LANG_TRIGGER_EXPLORE_QUEST = 366,
|
||||
LANG_TRIGGER_REQ_LEVEL = 367,
|
||||
LANG_TRIGGER_REQ_ITEMS = 368,
|
||||
LANG_TRIGGER_REQ_QUEST = 369,
|
||||
LANG_TRIGGER_CONDITION = 367,
|
||||
// 368
|
||||
// 369
|
||||
// 370 used in master branch
|
||||
// 371 used in master branch
|
||||
// 372 used in master branch
|
||||
|
@ -54,6 +54,7 @@ Channel::Channel(const std::string& name)
|
||||
else // it's custom channel
|
||||
{
|
||||
m_flags |= CHANNEL_FLAG_CUSTOM;
|
||||
m_announce = (name.compare("world") != 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,8 @@ namespace
|
||||
DisableMap m_DisableMap;
|
||||
}
|
||||
|
||||
#define CONTINUE if (newData) delete data; continue
|
||||
|
||||
void LoadDisables()
|
||||
{
|
||||
// reload case
|
||||
@ -79,10 +81,14 @@ void LoadDisables()
|
||||
uint32 data0 = fields[3].GetUInt32();
|
||||
|
||||
DisableData* data;
|
||||
bool newData = false;
|
||||
if (m_DisableMap[type].find(entry) != m_DisableMap[type].end())
|
||||
data = &m_DisableMap[type][entry];
|
||||
else
|
||||
{
|
||||
data = new DisableData();
|
||||
newData = true;
|
||||
}
|
||||
|
||||
data->flags = flags;
|
||||
|
||||
@ -92,13 +98,13 @@ void LoadDisables()
|
||||
if (!(sSpellStore.LookupEntry(entry) || flags & SPELL_DISABLE_DEPRECATED_SPELL))
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Spell entry %u from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
|
||||
if (!flags || flags > MAX_SPELL_DISABLE_TYPE)
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Disable flags for spell %u are invalid, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
|
||||
if (flags & SPELL_DISABLE_MAP)
|
||||
@ -117,7 +123,7 @@ void LoadDisables()
|
||||
if (!mapEntry)
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Map entry %u from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
bool isFlagInvalid = false;
|
||||
switch (mapEntry->map_type)
|
||||
@ -131,12 +137,12 @@ void LoadDisables()
|
||||
case MAP_BATTLEGROUND:
|
||||
//case MAP_ARENA: [-ZERO]
|
||||
ERROR_DB_STRICT_LOG("Battleground map %u specified to be disabled in map case, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
if (isFlagInvalid)
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Disable flags for map %u are invalid, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -144,7 +150,7 @@ void LoadDisables()
|
||||
if (!sBattleGroundMgr.GetBattleGroundTemplate(BattleGroundTypeId(entry)))
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Battleground entry %u from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
if (flags)
|
||||
ERROR_DB_STRICT_LOG("Disable flags specified for battleground %u, useless data.", entry);
|
||||
@ -153,7 +159,7 @@ void LoadDisables()
|
||||
if (entry > MAX_OPVP_ID)
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("OutdoorPvPTypes value %u from `disables` is invalid, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
if (flags)
|
||||
ERROR_DB_STRICT_LOG("Disable flags specified for outdoor PvP %u, useless data.", entry);
|
||||
@ -173,7 +179,7 @@ void LoadDisables()
|
||||
if (!mapEntry)
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Map entry %u from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
switch (mapEntry->map_type)
|
||||
{
|
||||
@ -213,7 +219,7 @@ void LoadDisables()
|
||||
if (!mapEntry)
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Map entry %u from `disables` doesn't exist in dbc, skipped.", entry);
|
||||
continue;
|
||||
CONTINUE;
|
||||
}
|
||||
switch (mapEntry->map_type)
|
||||
{
|
||||
@ -237,6 +243,18 @@ void LoadDisables()
|
||||
}
|
||||
case DISABLE_TYPE_CREATURE_SPAWN:
|
||||
case DISABLE_TYPE_GAMEOBJECT_SPAWN:
|
||||
if ((flags & SPAWN_DISABLE_CHECK_GUID) != 0)
|
||||
{
|
||||
if (data0)
|
||||
data->params[0].insert(data0);
|
||||
else
|
||||
{
|
||||
ERROR_DB_STRICT_LOG("Disables type %u: required GUID is missing for entry %u, ignoring disable entry.", type, entry);
|
||||
CONTINUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DISABLE_TYPE_ITEM_DROP:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -278,7 +296,7 @@ void CheckQuestDisables()
|
||||
sLog.outString(">> Checked %u quest disables", count);
|
||||
}
|
||||
|
||||
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags)
|
||||
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags, uint32 adData)
|
||||
{
|
||||
MANGOS_ASSERT(type < MAX_DISABLE_TYPES);
|
||||
if (m_DisableMap[type].empty())
|
||||
@ -366,11 +384,13 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags
|
||||
case DISABLE_TYPE_OUTDOORPVP:
|
||||
case DISABLE_TYPE_ACHIEVEMENT_CRITERIA:
|
||||
case DISABLE_TYPE_MMAP:
|
||||
case DISABLE_TYPE_CREATURE_SPAWN:
|
||||
case DISABLE_TYPE_GAMEOBJECT_SPAWN:
|
||||
case DISABLE_TYPE_ITEM_DROP:
|
||||
return true;
|
||||
case DISABLE_TYPE_VMAP:
|
||||
return (flags & itr->second.flags) != 0;
|
||||
case DISABLE_TYPE_CREATURE_SPAWN:
|
||||
case DISABLE_TYPE_GAMEOBJECT_SPAWN:
|
||||
return (itr->second.flags & SPAWN_DISABLE_CHECK_GUID) == 0 || itr->second.params[0].count(adData) > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -36,7 +36,8 @@ enum DisableType
|
||||
DISABLE_TYPE_MMAP = 7,
|
||||
DISABLE_TYPE_CREATURE_SPAWN = 8,
|
||||
DISABLE_TYPE_GAMEOBJECT_SPAWN = 9,
|
||||
MAX_DISABLE_TYPES = 10
|
||||
DISABLE_TYPE_ITEM_DROP = 10,
|
||||
MAX_DISABLE_TYPES = 11
|
||||
};
|
||||
|
||||
enum SpellDisableTypes
|
||||
@ -55,14 +56,13 @@ enum SpellDisableTypes
|
||||
|
||||
enum SpawnDisableTypes
|
||||
{
|
||||
SPAWN_DISABLE_FOR_ENTRY = 0,
|
||||
SPAWN_DISABLE_FOR_GUID = 1
|
||||
SPAWN_DISABLE_CHECK_GUID = 0x1
|
||||
};
|
||||
|
||||
namespace DisableMgr
|
||||
{
|
||||
void LoadDisables();
|
||||
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit = NULL, uint8 flags = 0);
|
||||
bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit = NULL, uint8 flags = 0, uint32 data = 0);
|
||||
void CheckQuestDisables();
|
||||
bool IsVMAPDisabledFor(uint32 entry, uint8 flags);
|
||||
bool IsPathfindingEnabled(uint32 mapId);
|
||||
|
@ -430,6 +430,12 @@ void WorldSession::HandleSetSelectionOpcode(WorldPacket& recv_data)
|
||||
|
||||
_player->SetSelectionGuid(guid);
|
||||
|
||||
if (guid.IsEmpty()) // TODO this is probably a wrong place for such action, so it's a "hacky" or "wrong" fix
|
||||
{
|
||||
_player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// update reputation list if need
|
||||
Unit* unit = ObjectAccessor::GetUnit(*_player, guid); // can select group members at diff maps
|
||||
if (!unit)
|
||||
|
@ -56,6 +56,9 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recv_data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!unit->CanTrainAndResetTalentsOf(_player))
|
||||
{ return; }
|
||||
|
||||
// remove fake death
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
|
||||
{ GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); }
|
||||
|
@ -722,7 +722,7 @@ void Spell::prepareDataForTriggerSystem()
|
||||
// avoid triggering negative hit for only positive targets
|
||||
m_negativeEffectMask = 0x0;
|
||||
for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
|
||||
if (!IsPositiveEffect(m_spellInfo, SpellEffectIndex(i)))
|
||||
if (m_spellInfo->Effect[i] != SPELL_EFFECT_NONE && !IsPositiveEffect(m_spellInfo, SpellEffectIndex(i)))
|
||||
{ m_negativeEffectMask |= (1 << i); }
|
||||
|
||||
// Hunter traps spells (for Entrapment trigger)
|
||||
@ -962,6 +962,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
{
|
||||
DoSpellHitOnUnit(m_caster, mask, true);
|
||||
unitTarget = m_caster;
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_UNIT)
|
||||
m_caster->ToCreature()->LowerPlayerDamageReq(target->damage);
|
||||
}
|
||||
}
|
||||
else // in 1.12.1 we need explicit miss info
|
||||
@ -1749,8 +1752,6 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
|
||||
}
|
||||
}
|
||||
|
||||
// exclude caster
|
||||
targetUnitMap.remove(m_caster);
|
||||
break;
|
||||
}
|
||||
case TARGET_AREAEFFECT_CUSTOM:
|
||||
@ -2449,6 +2450,9 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetMode != TARGET_SELF && m_spellInfo->HasAttribute(SPELL_ATTR_EX_CANT_TARGET_SELF))
|
||||
{ targetUnitMap.remove(m_caster); }
|
||||
|
||||
if (unMaxTargets && targetUnitMap.size() > unMaxTargets)
|
||||
{
|
||||
// make sure one unit is always removed per iteration
|
||||
@ -3018,12 +3022,25 @@ void Spell::update(uint32 difftime)
|
||||
// update pointers based at it's GUIDs
|
||||
UpdatePointers();
|
||||
|
||||
if (m_targets.getUnitTargetGuid() && !m_targets.getUnitTarget())
|
||||
if (!m_targets.getUnitTargetGuid().IsEmpty() && !m_targets.getUnitTarget())
|
||||
{
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// check for target going invisiblity/fake death
|
||||
if (Unit* target = m_targets.getUnitTarget())
|
||||
{
|
||||
if (!target->IsVisibleForOrDetect(m_caster, m_caster, true) || target->HasAuraType(SPELL_AURA_FEIGN_DEATH))
|
||||
{
|
||||
if (m_caster->GetTargetGuid() == target->GetObjectGuid())
|
||||
m_caster->SetTargetGuid(ObjectGuid());
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_targets.getUnitTarget() && (m_targets.getUnitTarget() != m_caster) && IsSingleTargetSpell(m_spellInfo) &&
|
||||
!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell)
|
||||
{
|
||||
@ -4671,11 +4688,6 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
if (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth() * 0.2)
|
||||
{ return SPELL_FAILED_BAD_TARGETS; }
|
||||
}
|
||||
else if (m_spellInfo->Id == 51582) // Rocket Boots Engaged
|
||||
{
|
||||
if (m_caster->IsInWater())
|
||||
{ return SPELL_FAILED_ONLY_ABOVEWATER; }
|
||||
}
|
||||
else if (m_spellInfo->SpellIconID == 156) // Holy Shock
|
||||
{
|
||||
// spell different for friends and enemies
|
||||
|
@ -176,7 +176,7 @@ bool Weather::ReGenerate()
|
||||
uint32 chance2 = chance1 + m_weatherChances->data[season].snowChance;
|
||||
uint32 chance3 = chance2 + m_weatherChances->data[season].stormChance;
|
||||
|
||||
uint32 rnd = urand(0, 99);
|
||||
uint32 rnd = urand(1, 100);
|
||||
if (rnd <= chance1)
|
||||
{ m_type = WEATHER_TYPE_RAIN; }
|
||||
else if (rnd <= chance2)
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit a3b20b248e2e26e41bd03edb8cf2e024bcf35ec8
|
||||
Subproject commit 849d26e3a097bb7e6d7e09b7414d2e523c8d0b6b
|
@ -37,7 +37,7 @@
|
||||
#define CHAR_DB_UPDATE_DESCRIPTION "Fix SoR paladin"
|
||||
|
||||
#define WORLD_DB_VERSION_NR 21
|
||||
#define WORLD_DB_STRUCTURE_NR 3
|
||||
#define WORLD_DB_CONTENT_NR 2
|
||||
#define WORLD_DB_UPDATE_DESCRIPTION "Fix Random MMGen Scripts"
|
||||
#define WORLD_DB_STRUCTURE_NR 4
|
||||
#define WORLD_DB_CONTENT_NR 1
|
||||
#define WORLD_DB_UPDATE_DESCRIPTION "Refactor areatrigger_teleport"
|
||||
#endif // __REVISION_H__
|
||||
|
Loading…
x
Reference in New Issue
Block a user