mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-27 22:16:11 +00:00
feat(Core/Scripts): Add gameobject_summon_groups with quaternion rotation support (#24708)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
-- DB update 2026_02_13_00 >> 2026_02_13_01
|
||||
-- Add gameobject_summon_groups table
|
||||
DROP TABLE IF EXISTS `gameobject_summon_groups`;
|
||||
CREATE TABLE IF NOT EXISTS `gameobject_summon_groups` (
|
||||
`summonerId` int unsigned NOT NULL DEFAULT '0',
|
||||
`summonerType` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`groupId` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`entry` int unsigned NOT NULL DEFAULT '0',
|
||||
`position_x` float NOT NULL DEFAULT '0',
|
||||
`position_y` float NOT NULL DEFAULT '0',
|
||||
`position_z` float NOT NULL DEFAULT '0',
|
||||
`orientation` float NOT NULL DEFAULT '0',
|
||||
`rotation0` float NOT NULL DEFAULT '0',
|
||||
`rotation1` float NOT NULL DEFAULT '0',
|
||||
`rotation2` float NOT NULL DEFAULT '0',
|
||||
`rotation3` float NOT NULL DEFAULT '0',
|
||||
`respawnTime` int unsigned NOT NULL DEFAULT '120',
|
||||
`Comment` varchar(255) CHARACTER SET `utf8mb4` COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT ''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=`utf8mb4` COLLATE=`utf8mb4_unicode_ci`;
|
||||
|
||||
-- Quest 619 "Enticing Negolash" - Gameobject spawns on quest turn-in at Ruined Lifeboat (GO 2289)
|
||||
-- Sniff data: Barbequed Buzzard Wings (2332), Stranglevine Wine (2333), Baked Bread (2562)
|
||||
DELETE FROM `gameobject_summon_groups` WHERE `summonerId` = 2289 AND `summonerType` = 1;
|
||||
INSERT INTO `gameobject_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `respawnTime`, `Comment`) VALUES
|
||||
(2289, 1, 0, 2332, -14652.3798828125, 146.5117950439453125, 3.501179933547973632, 0.349065244197845458, 0, 0, 0.173647880554199218, 0.984807789325714111, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14652.9423828125, 146.867401123046875, 2.506906986236572265, 2.949595451354980468, 0, 0, 0.995395660400390625, 0.095851235091686248, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14653.017578125, 146.524169921875, 2.355585098266601562, 6.003933906555175781, 0, 0, -0.13917255401611328, 0.990268170833587646, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14653.044921875, 145.137908935546875, 2.653269052505493164, 5.84685373306274414, 0, 0, -0.21643924713134765, 0.976296067237854003, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14654.0361328125, 147.3063201904296875, 2.467313051223754882, 0.942476630210876464, 0, 0, 0.453989982604980468, 0.891006767749786376, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14654.45703125, 147.324005126953125, 2.456363916397094726, 1.815141916275024414, 0, 0, 0.788010597229003906, 0.615661680698394775, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14654.703125, 146.1419219970703125, 2.089060068130493164, 2.373644113540649414, 0, 0, 0.927183151245117187, 0.37460830807685852, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14654.87890625, 147.2779693603515625, 2.425240993499755859, 5.881760597229003906, 0, 0, -0.19936752319335937, 0.979924798011779785, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14655.1357421875, 146.6710968017578125, 2.230948925018310546, 2.652894020080566406, 0, 0, 0.970294952392578125, 0.241925001144409179, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14655.2763671875, 147.80206298828125, 2.639719009399414062, 6.161012649536132812, 0, 0, -0.06104850769042968, 0.998134791851043701, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14656.1884765625, 147.0958404541015625, 2.387770891189575195, 0.174532130360603332, 0, 0, 0.087155342102050781, 0.996194720268249511, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2332, -14656.8330078125, 148.8932647705078125, 3.288661956787109375, 5.096362113952636718, 0, 0, -0.55919265747070312, 0.829037725925445556, 120, 'Enticing Negolash - Barbequed Buzzard Wings'),
|
||||
(2289, 1, 0, 2333, -14653.044921875, 145.3892364501953125, 2.85199904441833496, 4.852017402648925781, 0, 0, -0.65605831146240234, 0.754710197448730468, 120, 'Enticing Negolash - Stranglevine Wine'),
|
||||
(2289, 1, 0, 2333, -14655.728515625, 148.9776458740234375, 4.056398868560791015, 3.473210096359252929, 0, 0, -0.98628520965576171, 0.165049895644187927, 120, 'Enticing Negolash - Stranglevine Wine'),
|
||||
(2289, 1, 0, 2333, -14656.4482421875, 147.5946807861328125, 3.129076004028320312, 1.588248729705810546, 0, 0, 0.713250160217285156, 0.700909554958343505, 120, 'Enticing Negolash - Stranglevine Wine'),
|
||||
(2289, 1, 0, 2333, -14656.8408203125, 147.4337310791015625, 3.102070093154907226, 3.019413232803344726, 0, 0, 0.998134613037109375, 0.061051756143569946, 120, 'Enticing Negolash - Stranglevine Wine'),
|
||||
(2289, 1, 0, 2333, -14657.1513671875, 148.227569580078125, 2.886320114135742187, 1.535889506340026855, 0, 0, 0.694658279418945312, 0.719339847564697265, 120, 'Enticing Negolash - Stranglevine Wine'),
|
||||
(2289, 1, 0, 2562, -14652.4326171875, 145.7533721923828125, 3.254641056060791015, 2.932138919830322265, 0, 0, 0.994521141052246093, 0.104535527527332305, 120, 'Enticing Negolash - Baked Bread'),
|
||||
(2289, 1, 0, 2562, -14653.8486328125, 146.2042694091796875, 2.14631199836730957, 4.886923789978027343, 0, 0, -0.64278697967529296, 0.766044974327087402, 120, 'Enticing Negolash - Baked Bread'),
|
||||
(2289, 1, 0, 2562, -14656.138671875, 148.3673248291015625, 3.515635967254638671, 5.637413978576660156, 0, 0, -0.31730461120605468, 0.948323667049407958, 120, 'Enticing Negolash - Baked Bread');
|
||||
|
||||
-- SmartAI: Ruined Lifeboat (GO 2289) - On Quest 619 Reward - Summon Gameobject Group 0
|
||||
DELETE FROM `smart_scripts` WHERE `entryorguid` = 2289 AND `source_type` = 1 AND `id` = 1;
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(2289, 1, 1, 0, 20, 0, 100, 0, 619, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Ruined Lifeboat - On Quest ''Enticing Negolash'' Rewarded - Summon Gameobject Group 0');
|
||||
@@ -3332,6 +3332,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_SUMMON_GAMEOBJECT_GROUP:
|
||||
{
|
||||
if (!GetBaseObject())
|
||||
break;
|
||||
|
||||
GetBaseObject()->SummonGameObjectGroup(e.action.gameobjectGroup.group);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
break;
|
||||
|
||||
@@ -886,6 +886,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_DISABLE_REWARD: return sizeof(SmartAction::reward);
|
||||
case SMART_ACTION_SET_ANIM_TIER: return sizeof(SmartAction::animTier);
|
||||
case SMART_ACTION_SET_GOSSIP_MENU: return sizeof(SmartAction::setGossipMenu);
|
||||
case SMART_ACTION_SUMMON_GAMEOBJECT_GROUP: return sizeof(SmartAction::gameobjectGroup);
|
||||
case SMART_ACTION_DISMOUNT: return NO_PARAMS;
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
|
||||
@@ -2042,6 +2043,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_MOVEMENT_RESUME:
|
||||
case SMART_ACTION_WORLD_SCRIPT:
|
||||
case SMART_ACTION_SET_GOSSIP_MENU:
|
||||
case SMART_ACTION_SUMMON_GAMEOBJECT_GROUP:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -725,8 +725,9 @@ enum SMART_ACTION
|
||||
SMART_ACTION_DISABLE_REWARD = 238, // reputation 0/1, loot 0/1
|
||||
SMART_ACTION_SET_ANIM_TIER = 239, // animtier
|
||||
SMART_ACTION_SET_GOSSIP_MENU = 240, // gossipMenuId
|
||||
SMART_ACTION_SUMMON_GAMEOBJECT_GROUP = 241, // group
|
||||
|
||||
SMART_ACTION_AC_END = 241, // placeholder
|
||||
SMART_ACTION_AC_END = 242, // placeholder
|
||||
};
|
||||
|
||||
enum class SmartActionSummonCreatureFlags
|
||||
@@ -1517,6 +1518,11 @@ struct SmartAction
|
||||
{
|
||||
uint32 gossipMenuId;
|
||||
} setGossipMenu;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 group;
|
||||
} gameobjectGroup;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define AZEROTHCORE_TEMPSUMMON_H
|
||||
|
||||
#include "Creature.h"
|
||||
#include "G3D/Quat.h"
|
||||
|
||||
enum SummonerType
|
||||
{
|
||||
@@ -36,6 +37,15 @@ struct TempSummonData
|
||||
uint32 time; ///< Despawn time, usable only with certain temp summon types
|
||||
};
|
||||
|
||||
/// Stores data for temp gameobject summons
|
||||
struct GameObjectSummonData
|
||||
{
|
||||
uint32 entry;
|
||||
Position pos;
|
||||
G3D::Quat rot;
|
||||
uint32 respawnTime; ///< Duration in seconds; passed to SummonGameObject's respawnTime parameter
|
||||
};
|
||||
|
||||
class TempSummon : public Creature
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -2284,6 +2284,18 @@ void Map::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= null
|
||||
list->push_back(summon);
|
||||
}
|
||||
|
||||
void Map::SummonGameObjectGroup(uint8 group, std::list<GameObject*>* list /*= nullptr*/)
|
||||
{
|
||||
std::vector<GameObjectSummonData> const* data = sObjectMgr->GetGameObjectSummonGroup(GetId(), SUMMONER_TYPE_MAP, group);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (std::vector<GameObjectSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
|
||||
if (GameObject* go = SummonGameObject(itr->entry, itr->pos.GetPositionX(), itr->pos.GetPositionY(), itr->pos.GetPositionZ(), itr->pos.GetOrientation(), itr->rot.x, itr->rot.y, itr->rot.z, itr->rot.w, itr->respawnTime))
|
||||
if (list)
|
||||
list->push_back(go);
|
||||
}
|
||||
|
||||
TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang, TempSummonType spwtype, uint32 despwtime, SummonPropertiesEntry const* properties, bool visibleBySummonerOnly)
|
||||
{
|
||||
if (!x && !y && !z)
|
||||
@@ -2440,6 +2452,20 @@ void WorldObject::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list
|
||||
list->push_back(summon);
|
||||
}
|
||||
|
||||
void WorldObject::SummonGameObjectGroup(uint8 group, std::list<GameObject*>* list /*= nullptr*/)
|
||||
{
|
||||
ASSERT((IsGameObject() || IsCreature()) && "Only GOs and creatures can summon gameobject groups!");
|
||||
|
||||
std::vector<GameObjectSummonData> const* data = sObjectMgr->GetGameObjectSummonGroup(GetEntry(), IsGameObject() ? SUMMONER_TYPE_GAMEOBJECT : SUMMONER_TYPE_CREATURE, group);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (std::vector<GameObjectSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr)
|
||||
if (GameObject* go = SummonGameObject(itr->entry, itr->pos.GetPositionX(), itr->pos.GetPositionY(), itr->pos.GetPositionZ(), itr->pos.GetOrientation(), itr->rot.x, itr->rot.y, itr->rot.z, itr->rot.w, itr->respawnTime))
|
||||
if (list)
|
||||
list->push_back(go);
|
||||
}
|
||||
|
||||
Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive) const
|
||||
{
|
||||
Creature* creature = nullptr;
|
||||
|
||||
@@ -630,6 +630,7 @@ public:
|
||||
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport = true, GOSummonType summonType = GO_SUMMON_TIMED_OR_CORPSE_DESPAWN);
|
||||
Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, bool setLevel = false, CreatureAI * (*GetAI)(Creature*) = nullptr);
|
||||
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = nullptr);
|
||||
void SummonGameObjectGroup(uint8 group, std::list<GameObject*>* list = nullptr);
|
||||
|
||||
[[nodiscard]] Creature* FindNearestCreature(uint32 entry, float range, bool alive = true) const;
|
||||
[[nodiscard]] GameObject* FindNearestGameObject(uint32 entry, float range, bool onlySpawned = false) const;
|
||||
|
||||
@@ -2224,6 +2224,87 @@ void ObjectMgr::LoadTempSummons()
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadGameObjectSummons()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
_goSummonDataStore.clear();
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
QueryResult result = WorldDatabase.Query("SELECT summonerId, summonerType, groupId, entry, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, respawnTime FROM gameobject_summon_groups");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 gameobject summons. DB table `gameobject_summon_groups` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 summonerId = fields[0].Get<uint32>();
|
||||
SummonerType summonerType = SummonerType(fields[1].Get<uint8>());
|
||||
uint8 group = fields[2].Get<uint8>();
|
||||
|
||||
switch (summonerType)
|
||||
{
|
||||
case SUMMONER_TYPE_CREATURE:
|
||||
if (!GetCreatureTemplate(summonerId))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `gameobject_summon_groups` has summoner with non existing entry {} for creature summoner type, skipped.", summonerId);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SUMMONER_TYPE_GAMEOBJECT:
|
||||
if (!GetGameObjectTemplate(summonerId))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `gameobject_summon_groups` has summoner with non existing entry {} for gameobject summoner type, skipped.", summonerId);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SUMMONER_TYPE_MAP:
|
||||
if (!sMapStore.LookupEntry(summonerId))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `gameobject_summon_groups` has summoner with non existing entry {} for map summoner type, skipped.", summonerId);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "Table `gameobject_summon_groups` has unhandled summoner type {} for summoner {}, skipped.", summonerType, summonerId);
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObjectSummonData data;
|
||||
data.entry = fields[3].Get<uint32>();
|
||||
|
||||
if (!GetGameObjectTemplate(data.entry))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Table `gameobject_summon_groups` has gameobject in group [Summoner ID: {}, Summoner Type: {}, Group ID: {}] with non existing gameobject entry {}, skipped.", summonerId, summonerType, group, data.entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
float posX = fields[4].Get<float>();
|
||||
float posY = fields[5].Get<float>();
|
||||
float posZ = fields[6].Get<float>();
|
||||
float orientation = fields[7].Get<float>();
|
||||
|
||||
data.pos.Relocate(posX, posY, posZ, orientation);
|
||||
|
||||
data.rot = G3D::Quat(fields[8].Get<float>(), fields[9].Get<float>(), fields[10].Get<float>(), fields[11].Get<float>());
|
||||
data.respawnTime = fields[12].Get<uint32>();
|
||||
|
||||
TempSummonGroupKey key(summonerId, summonerType, group);
|
||||
_goSummonDataStore[key].push_back(data);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Gameobject Summons in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadCreatures()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
@@ -507,6 +507,7 @@ typedef std::map<ObjectGuid, ObjectGuid> LinkedRespawnContainer;
|
||||
typedef std::unordered_map<ObjectGuid::LowType, CreatureData> CreatureDataContainer;
|
||||
typedef std::unordered_map<ObjectGuid::LowType, GameObjectData> GameObjectDataContainer;
|
||||
typedef std::map<TempSummonGroupKey, std::vector<TempSummonData> > TempSummonDataContainer;
|
||||
typedef std::map<TempSummonGroupKey, std::vector<GameObjectSummonData> > GameObjectSummonDataContainer;
|
||||
typedef std::unordered_map<uint32, CreatureLocale> CreatureLocaleContainer;
|
||||
typedef std::unordered_map<uint32, GameObjectLocale> GameObjectLocaleContainer;
|
||||
typedef std::unordered_map<uint32, ItemLocale> ItemLocaleContainer;
|
||||
@@ -1036,6 +1037,7 @@ public:
|
||||
void LoadGameObjectQuestItems();
|
||||
void LoadCreatureQuestItems();
|
||||
void LoadTempSummons();
|
||||
void LoadGameObjectSummons();
|
||||
void LoadCreatures();
|
||||
void LoadCreatureSparring();
|
||||
void LoadLinkedRespawn();
|
||||
@@ -1208,6 +1210,15 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<GameObjectSummonData> const* GetGameObjectSummonGroup(uint32 summonerId, SummonerType summonerType, uint8 group) const
|
||||
{
|
||||
GameObjectSummonDataContainer::const_iterator itr = _goSummonDataStore.find(TempSummonGroupKey(summonerId, summonerType, group));
|
||||
if (itr != _goSummonDataStore.end())
|
||||
return &itr->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] BroadcastText const* GetBroadcastText(uint32 id) const
|
||||
{
|
||||
BroadcastTextContainer::const_iterator itr = _broadcastTextStore.find(id);
|
||||
@@ -1635,6 +1646,8 @@ private:
|
||||
GameObjectTemplateAddonContainer _gameObjectTemplateAddonStore;
|
||||
/// Stores temp summon data grouped by summoner's entry, summoner's type and group id
|
||||
TempSummonDataContainer _tempSummonDataStore;
|
||||
/// Stores gameobject summon data grouped by summoner's entry, summoner's type and group id
|
||||
GameObjectSummonDataContainer _goSummonDataStore;
|
||||
|
||||
BroadcastTextContainer _broadcastTextStore;
|
||||
ItemTemplateContainer _itemTemplateStore;
|
||||
|
||||
@@ -337,6 +337,7 @@ public:
|
||||
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport = true);
|
||||
GameObject* SummonGameObject(uint32 entry, Position const& pos, float rotation0 = 0.0f, float rotation1 = 0.0f, float rotation2 = 0.0f, float rotation3 = 0.0f, uint32 respawnTime = 100, bool checkTransport = true);
|
||||
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = nullptr);
|
||||
void SummonGameObjectGroup(uint8 group, std::list<GameObject*>* list = nullptr);
|
||||
|
||||
Corpse* GetCorpse(ObjectGuid const& guid);
|
||||
Creature* GetCreature(ObjectGuid const& guid);
|
||||
|
||||
@@ -570,6 +570,9 @@ void World::SetInitialWorldSettings()
|
||||
LOG_INFO("server.loading", "Loading Temporary Summon Data...");
|
||||
sObjectMgr->LoadTempSummons(); // must be after LoadCreatureTemplates() and LoadGameObjectTemplates()
|
||||
|
||||
LOG_INFO("server.loading", "Loading Gameobject Summon Data...");
|
||||
sObjectMgr->LoadGameObjectSummons(); // must be after LoadCreatureTemplates() and LoadGameObjectTemplates()
|
||||
|
||||
LOG_INFO("server.loading", "Loading Pet Levelup Spells...");
|
||||
sSpellMgr->LoadPetLevelupSpellMap();
|
||||
|
||||
|
||||
141
src/test/server/game/Globals/GameObjectSummonGroupTest.cpp
Normal file
141
src/test/server/game/Globals/GameObjectSummonGroupTest.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "SmartScriptMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "WorldMock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
class GameObjectSummonGroupTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
_previousWorld = std::move(sWorld);
|
||||
auto* worldMock =
|
||||
new ::testing::NiceMock<WorldMock>();
|
||||
ON_CALL(*worldMock, getIntConfig(::testing::_))
|
||||
.WillByDefault(::testing::Return(0));
|
||||
sWorld.reset(worldMock);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
sWorld = std::move(_previousWorld);
|
||||
}
|
||||
|
||||
std::unique_ptr<IWorld> _previousWorld;
|
||||
};
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, DataStructStoresFields)
|
||||
{
|
||||
GameObjectSummonData data;
|
||||
data.entry = 2332;
|
||||
data.pos.Relocate(-14652.38f, 146.51f, 3.50f, 0.35f);
|
||||
data.rot = G3D::Quat(0.0f, 0.0f, 0.17f, 0.98f);
|
||||
data.respawnTime = 120;
|
||||
|
||||
EXPECT_EQ(data.entry, 2332u);
|
||||
EXPECT_FLOAT_EQ(data.pos.GetPositionX(), -14652.38f);
|
||||
EXPECT_FLOAT_EQ(data.pos.GetPositionY(), 146.51f);
|
||||
EXPECT_FLOAT_EQ(data.pos.GetPositionZ(), 3.50f);
|
||||
EXPECT_FLOAT_EQ(data.pos.GetOrientation(), 0.35f);
|
||||
EXPECT_FLOAT_EQ(data.rot.x, 0.0f);
|
||||
EXPECT_FLOAT_EQ(data.rot.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(data.rot.z, 0.17f);
|
||||
EXPECT_FLOAT_EQ(data.rot.w, 0.98f);
|
||||
EXPECT_EQ(data.respawnTime, 120u);
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, QuaternionIdentity)
|
||||
{
|
||||
GameObjectSummonData data;
|
||||
data.rot = G3D::Quat(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(data.rot.x, 0.0f);
|
||||
EXPECT_FLOAT_EQ(data.rot.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(data.rot.z, 0.0f);
|
||||
EXPECT_FLOAT_EQ(data.rot.w, 1.0f);
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, AccessorReturnsNullForMissing)
|
||||
{
|
||||
auto const* result = sObjectMgr->GetGameObjectSummonGroup(
|
||||
99999, SUMMONER_TYPE_CREATURE, 0);
|
||||
EXPECT_EQ(result, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, AccessorReturnsNullForAllTypes)
|
||||
{
|
||||
auto const* r1 = sObjectMgr->GetGameObjectSummonGroup(
|
||||
99999, SUMMONER_TYPE_CREATURE, 0);
|
||||
auto const* r2 = sObjectMgr->GetGameObjectSummonGroup(
|
||||
99999, SUMMONER_TYPE_GAMEOBJECT, 0);
|
||||
auto const* r3 = sObjectMgr->GetGameObjectSummonGroup(
|
||||
99999, SUMMONER_TYPE_MAP, 0);
|
||||
|
||||
EXPECT_EQ(r1, nullptr);
|
||||
EXPECT_EQ(r2, nullptr);
|
||||
EXPECT_EQ(r3, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, DifferentGroupsAreIndependent)
|
||||
{
|
||||
auto const* g0 = sObjectMgr->GetGameObjectSummonGroup(
|
||||
2289, SUMMONER_TYPE_GAMEOBJECT, 0);
|
||||
auto const* g1 = sObjectMgr->GetGameObjectSummonGroup(
|
||||
2289, SUMMONER_TYPE_GAMEOBJECT, 1);
|
||||
|
||||
// Both should be null since DB isn't loaded in tests,
|
||||
// but they should be independent lookups
|
||||
EXPECT_EQ(g0, nullptr);
|
||||
EXPECT_EQ(g1, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, SmartActionEnumValue)
|
||||
{
|
||||
EXPECT_EQ(SMART_ACTION_SUMMON_GAMEOBJECT_GROUP, 241);
|
||||
EXPECT_EQ(SMART_ACTION_AC_END, 242);
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, SmartActionUnionSize)
|
||||
{
|
||||
SmartAction action{};
|
||||
action.gameobjectGroup.group = 5;
|
||||
EXPECT_EQ(action.gameobjectGroup.group, 5u);
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, TempSummonGroupKeyOrdering)
|
||||
{
|
||||
TempSummonGroupKey k1(100, SUMMONER_TYPE_CREATURE, 0);
|
||||
TempSummonGroupKey k2(100, SUMMONER_TYPE_GAMEOBJECT, 0);
|
||||
TempSummonGroupKey k3(100, SUMMONER_TYPE_CREATURE, 1);
|
||||
TempSummonGroupKey k4(200, SUMMONER_TYPE_CREATURE, 0);
|
||||
|
||||
// std::tuple ordering: summoner ID first, then type, then group
|
||||
EXPECT_LT(k1, k2); // same id, creature < gameobject
|
||||
EXPECT_LT(k1, k3); // same id+type, group 0 < 1
|
||||
EXPECT_LT(k1, k4); // id 100 < 200
|
||||
}
|
||||
|
||||
TEST_F(GameObjectSummonGroupTest, SummonerTypeValues)
|
||||
{
|
||||
EXPECT_EQ(SUMMONER_TYPE_CREATURE, 0);
|
||||
EXPECT_EQ(SUMMONER_TYPE_GAMEOBJECT, 1);
|
||||
EXPECT_EQ(SUMMONER_TYPE_MAP, 2);
|
||||
}
|
||||
Reference in New Issue
Block a user