29#include "G3DPosition.hpp"
59#include <G3D/CoordinateFrame.h>
80 queryTemp.
Allow =
true;
101 if (std::vector<uint32>
const* items =
sObjectMgr->GetGameObjectQuestItemList(
entry))
102 for (
int32 item : *items)
110 return queryTemp.
Move();
115 return fabs(
x *
x +
y *
y +
z *
z +
w *
w - 1.0f) < 1e-5f;
120 G3D::Matrix3(G3D::Quat(
x,
y,
z,
w)).toEulerAnglesZYX(Z, Y, X);
125 G3D::Quat quat(G3D::Matrix3::fromEulerAnglesZYX(Z, Y, X));
203 newProgress = now % period;
206 int32 stopTargetTime = 0;
216 float stopTargetPathPct = float(stopTargetTime) / float(period);
217 float timeSinceStopProgressPct = float(now -
_stateChangeTime) / float(timeToStop);
223 stopTargetPathPct = 1.0f;
225 float pathPctBetweenStops = stopTargetPathPct - stopSourcePathPct;
226 if (pathPctBetweenStops < 0.0f)
227 pathPctBetweenStops += 1.0f;
229 progressPct = pathPctBetweenStops * timeSinceStopProgressPct + stopSourcePathPct;
230 if (progressPct > 1.0f)
231 progressPct = progressPct - 1.0f;
235 float pathPctBetweenStops = stopSourcePathPct - stopTargetPathPct;
236 if (pathPctBetweenStops < 0.0f)
237 pathPctBetweenStops += 1.0f;
239 progressPct = stopSourcePathPct - pathPctBetweenStops * timeSinceStopProgressPct;
240 if (progressPct < 0.0f)
244 newProgress =
uint32(
float(period) * progressPct) % period;
247 newProgress = stopTargetTime;
289 newState =
GOState(currentState - 1);
291 newState =
GOState(currentState - 1);
293 newState =
GOState(currentState + 1);
307 if (oldAnimation && newAnimation)
312 G3D::Vector3 prev(oldAnimation->
Pos.
X, oldAnimation->
Pos.
Y, oldAnimation->
Pos.
Z);
313 G3D::Vector3 next(newAnimation->
Pos.
X, newAnimation->
Pos.
Y, newAnimation->
Pos.
Z);
315 G3D::Vector3 dst = next;
320 dst = prev.lerp(next, animProgress);
323 dst = dst * pathRotation;
331 if (oldRotation && newRotation)
333 G3D::Quat prev(oldRotation->
Rot[0], oldRotation->
Rot[1], oldRotation->
Rot[2], oldRotation->
Rot[3]);
334 G3D::Quat next(newRotation->
Rot[0], newRotation->
Rot[1], newRotation->
Rot[2], newRotation->
Rot[3]);
336 G3D::Quat rotation = next;
342 rotation = prev.slerp(next, animProgress);
365 int32 stopPathProgress = 0;
393 int32 newToOldStateDelta = newState - oldState;
394 if (newToOldStateDelta < 0)
395 newToOldStateDelta += pauseTimesCount + 1;
397 int32 oldToNewStateDelta = oldState - newState;
398 if (oldToNewStateDelta < 0)
399 oldToNewStateDelta += pauseTimesCount + 1;
406 if (oldToNewStateDelta < newToOldStateDelta && !isAtStartOfPath)
422 passenger->m_movementInfo.transport.pos.GetPosition(x, y, z, o);
467 plr->SetFallInformation(0, plr->GetPositionZ());
511 transport->SetAutoCycleBetweenStopFrames(
_on);
545 zoneScript->OnFlagStateChange(&
_owner, oldState,
_state, player);
641 _value = RoundToInterval<float>(value, 0.0f, 100.0f);
647 std::vector<Player*> targetList;
652 if (pointsGained == 0)
658 if (oldRoundedValue == roundedValue)
664 if (oldControllingTeam != newControllingTeam)
692 for (
Player* player : targetList)
706 int32 hordePlayers = 0;
707 int32 alliancePlayers = 0;
709 for (
Player const* player : targetList)
711 if (!player->IsOutdoorPvPActive())
720 int8 factionCoefficient = 0;
722 if (alliancePlayers > hordePlayers)
723 factionCoefficient = 1;
724 else if (hordePlayers > alliancePlayers)
725 factionCoefficient = -1;
728 if (timeNeeded == 0.0f)
731 return 100.0f / timeNeeded *
static_cast<float>(factionCoefficient);
737 uint32 const delta = std::abs(alliancePlayers - hordePlayers);
740 if (delta < minSuperiority)
744 if (uncontestedTime && (hordePlayers == 0 || alliancePlayers == 0))
745 return static_cast<float>(uncontestedTime);
751 float const slope =
static_cast<float>(minTime - maxTime) /
static_cast<float>(std::max<uint32>(maxSuperiority - minSuperiority, 1));
752 float const intercept =
static_cast<float>(maxTime) - slope *
static_cast<float>(minSuperiority);
753 return slope *
static_cast<float>(delta) + intercept;
760 std::vector<Player*> enteringPlayers;
762 for (
Player* unit : newTargetList)
764 if (exitPlayers.erase(unit->GetGUID()) == 0)
765 enteringPlayers.push_back(unit);
770 for (
Player* player : enteringPlayers)
777 for (
ObjectGuid const& exitPlayerGuid : exitPlayers)
829 uint32 value = controlZone->GetStartingValue();
833 controlZone->SetValue(value);
839 m_model(nullptr), m_goValue(), m_stringIds(), m_AI(nullptr), m_respawnCompatibilityMode(false), _animKitId(0), _worldEffectID(0)
916 owner->RemoveGameObject(
this,
false);
922 TC_LOG_DEBUG(
"misc",
"Removed GameObject ({} Entry: {} SpellId: {} LinkedGO: {}) that just lost any reference to the owner ({}) GO list",
944 trans->SetDelayedAddModelToMap();
969 linkedTrap->DespawnOrUnsummon();
1015 TC_LOG_ERROR(
"sql.sql",
"Gameobject (Spawn id: {} Entry: {}) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.",
GetSpawnId(), entry);
1035 TC_LOG_ERROR(
"sql.sql",
"Gameobject ({} Spawn id: {} Entry: {}) not created: non-existing GO type '{}' in `gameobject_template`. It will crash client if created.", guid.
ToString(),
GetSpawnId(), entry, goInfo->
type);
1044 if (gameObjectAddon)
1085 switch (goInfo->
type)
1105 m_goTypeImpl = std::make_unique<GameObjectType::Transport>(*
this);
1133 m_goTypeImpl = std::make_unique<GameObjectType::ControlZone>(*
this);
1137 m_goTypeImpl = std::make_unique<GameObjectType::NewFlag>(*
this);
1163 if (gameObjectAddon)
1225 if (!go->
Create(entry, map, pos, rotation, animProgress, goState, artKit,
false, 0))
1253 TC_LOG_ERROR(
"misc",
"Could not initialize GameObjectAI");
1280 bool needsStateUpdate = itr->second.State !=
GetGoState();
1281 bool despawned = itr->second.Despawned;
1291 else if (needsStateUpdate)
1322 if (owner->IsInCombat())
1368 if (linkedRespawntime)
1371 if (targetGuid == dbtableHighGuid)
1460 Unit* target =
nullptr;
1472 Player* player =
nullptr;
1487 if (hordeCapturing || allianceCapturing)
1610 linkedTrap->DespawnOrUnsummon();
1622 owner->CastSpell(owner, spellId,
false);
1818 areaId = areaEntry->ParentAreaID;
1841 areaId = areaEntry->ParentAreaID;
1857 TC_LOG_ERROR(
"misc",
"GameObject::SaveToDB failed, cannot get gameobject data!");
1863 if (transport->GetMapIdForSpawning() >= 0)
1864 mapId = transport->GetMapIdForSpawning();
1906 trans->Append(stmt);
1912 stmt->
setString(index++, [&data]() -> std::string
1917 std::ostringstream os;
1919 os <<
int32(*itr++);
1922 os <<
',' <<
int32(*itr);
1939 trans->Append(stmt);
1949 TC_LOG_ERROR(
"sql.sql",
"Gameobject (GUID: {}) not found in table `gameobject`, can't load. ", spawnId);
1995 TC_LOG_WARN(
"sql.sql",
"GameObject {} (SpawnID {}) is not spawned by default, but tries to use a non-hack spawn system. This will not work. Defaulting to compatibility mode.", entry, spawnId);
2008 if (addToMap && !
GetMap()->AddToMap(
this))
2023 [spawnId, charTrans](
Map* map) ->
void
2026 std::vector<GameObject*> toUnload;
2027 for (auto const& pair : Trinity::Containers::MapEqualRange(map->GetGameObjectBySpawnIdStore(), spawnId))
2028 toUnload.push_back(pair.second);
2029 for (GameObject* obj : toUnload)
2030 map->AddObjectToRemoveList(obj);
2031 map->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, spawnId, charTrans);
2045 trans->Append(stmt);
2050 trans->Append(stmt);
2054 trans->Append(stmt);
2059 trans->Append(stmt);
2064 trans->Append(stmt);
2069 trans->Append(stmt);
2074 trans->Append(stmt);
2078 trans->Append(stmt);
2152 if (
GetGOInfo()->GetServerOnly() && !allowServersideObjects)
2159 return m_goTypeImpl->IsNeverVisibleFor(seer, allowServersideObjects);
2201 if (state->Despawned)
2210 return owner->GetLevelForTarget(target);
2216 return uint8(std::clamp<int16>(player->GetLevel(), userLevels->MinLevel, userLevels->MaxLevel));
2218 if (
Unit const* targetUnit = target->
ToUnit())
2219 return targetUnit->GetLevel();
2352 trapGO->CastSpell(target, trapSpell->
Id);
2381 if (!time_to_restore)
2392 Unit* unitCaster = spellCaster ? spellCaster->
ToUnit() :
nullptr;
2397 TC_LOG_FATAL(
"spell",
"Spell {} has action type NONE in effect {}", spellId, effectIndex);
2464 if (templateAddon !=
nullptr)
2465 artKitValue = templateAddon->
ArtKits[artKitIndex];
2467 if (artKitValue == 0)
2468 TC_LOG_ERROR(
"sql.sql",
"GameObject {} hit by spell {} needs `artkit{}` in `gameobject_template_addon`",
GetEntry(), spellId, artKitIndex);
2488 TC_LOG_ERROR(
"spell",
"Spell {} targeted non-transport gameobject for transport only action \"Go to Floor\" {} in effect {}", spellId,
int32(action), effectIndex);
2524 TC_LOG_ERROR(
"spell",
"Spell {} has unhandled action {} in effect {}", spellId,
int32(action), effectIndex);
2530 m_goTypeImpl->ActivateObject(action, param, spellCaster, spellId, effectIndex);
2550 data =
sObjectMgr->GetGameObjectData(lowguid);
2572 Unit* spellCaster = user;
2574 bool triggered =
false;
2584 playerUser->PlayerTalkClass->ClearMenus();
2585 if (
AI()->OnGossipHello(playerUser))
2655 std::vector<Player*> tappers;
2658 tappers.push_back(tapper);
2660 if (tappers.empty())
2661 tappers.push_back(player);
2746 bool found_free_slot =
false;
2752 float x_i =
GetPositionX() + relativeDistance * std::cos(orthogonalOrientation);
2753 float y_i =
GetPositionY() + relativeDistance * std::sin(orthogonalOrientation);
2755 if (!sittingUnit.IsEmpty())
2759 if (chairUser->IsSitState() && chairUser->GetStandState() !=
UNIT_STAND_STATE_SIT && chairUser->GetExactDist2d(x_i, y_i) < 0.1f)
2762 sittingUnit.Clear();
2765 sittingUnit.Clear();
2768 found_free_slot =
true;
2773 if (thisDistance <= lowestDist)
2775 nearest_slot = slot;
2776 lowestDist = thisDistance;
2782 if (found_free_slot)
2787 itr->second = user->
GetGUID();
2839 for (
GroupReference const* itr = group->GetFirstMember(); itr !=
nullptr; itr = itr->
next())
2840 if (
Player* member = itr->GetSource())
2841 if (member->IsAtGroupRewardDistance(
this))
2875 spellCaster =
nullptr;
2893 if (info->
camera.eventID)
2922 TC_LOG_ERROR(
"entities.gameobject",
"Gameobject '{}' ({}) spawned in unknown area (x: {} y: {} z: {} map: {})",
2929 if (!areaContentTuning)
2935 int32 areaFishingLevel =
sObjectMgr->GetFishingBaseSkillLevel(areaEntry);
2942 if (playerFishingLevel < areaFishingLevel)
2944 chance =
int32(pow((
double)playerFishingLevel / areaFishingLevel, 2) * 100);
2949 TC_LOG_DEBUG(
"misc",
"Fishing check (skill {} level: {} area skill level: {} chance {} roll: {}", playerFishingSkill, playerFishingLevel, areaFishingLevel, chance, roll);
2956 if (chance >= roll || fishingPool)
2966 fishingPool->
Use(player);
3007 Player* m_ritualOwner =
nullptr;
3012 if (!m_ritualOwner && !owner)
3015 m_ritualOwner = player;
3032 spellCaster = owner;
3039 spellCaster = player;
3056 spellCaster = m_ritualOwner;
3060 if (spellId == 62330)
3132 if (!targetPlayer || targetPlayer == player || !targetPlayer->
IsInSameRaidWith(player))
3137 if (player->
GetLevel() < userLevels->MaxLevel)
3141 if (targetPlayer->
GetLevel() < targetLevels->MaxLevel)
3144 if (info->
entry == 194097)
3258 spellCaster =
nullptr;
3285 bool defenderInteract = !owner->IsFriendlyTo(user);
3286 if (defenderInteract && owner->GetGOInfo()->newflag.ReturnonDefenderInteract)
3424 player->
GiveXP(xp,
nullptr);
3449 TC_LOG_ERROR(
"misc",
"GameObject::Use(): unit ({}, name: {}) tries to use object ({}, name: {}) of unknown type ({})",
3459 if (!player->GetQuestRewardStatus(
m_vignette->Data->RewardQuestID))
3462 if (
m_vignette->Data->VisibleTrackingQuestID)
3463 player->SetRewardedQuest(
m_vignette->Data->VisibleTrackingQuestID);
3468 if (
GetGOInfo()->ClearObjectVignetteonOpening())
3480 TC_LOG_DEBUG(
"outdoorpvp",
"WORLD: {} non-dbc spell was handled by OutdoorPvP", spellId);
3488 spellCaster->
CastSpell(user, spellId, triggered);
3519 float dist = std::sqrt(dx*dx + dy*dy);
3522 if (G3D::fuzzyEq(dist, 0.0f))
3525 float sinB = dx / dist;
3526 float cosB = dy / dist;
3527 dx = dist * (cosA * cosB + sinA * sinB);
3528 dy = dist * (cosA * sinB - sinA * cosB);
3554 return std::ranges::any_of(
m_stringIds, [
id](std::string
const* stringId) {
return stringId && *stringId == id; });
3576 if (cl->Name.size() > locale && !cl->Name[locale].empty())
3577 return cl->Name[locale];
3584 static const int32 PACK_YZ = 1 << 20;
3585 static const int32 PACK_X = PACK_YZ << 1;
3587 static const int32 PACK_YZ_MASK = (PACK_YZ << 1) - 1;
3588 static const int32 PACK_X_MASK = (PACK_X << 1) - 1;
3599 G3D::Quat rotation(qx, qy, qz, qw);
3615 G3D::Quat quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot));
3626 G3D::Quat worldRotationQuat(worldRotation.
x, worldRotation.
y, worldRotation.
z, worldRotation.
w);
3627 G3D::Quat localRotationQuat(localRotation.
x, localRotation.
y, localRotation.
z, localRotation.
w);
3629 G3D::Quat resultRotation = localRotationQuat * worldRotationQuat;
3631 return QuaternionData(resultRotation.x, resultRotation.y, resultRotation.z, resultRotation.w);
3633 return localRotation;
3662 packet.
Owner = player->GetGUID();
3664 player->SendDirectMessage(packet.
Write());
3713 if (modelData->State1Wmo)
3714 modelId = modelData->State1Wmo;
3739 if (modelData->State2Wmo)
3740 modelId = modelData->State2Wmo;
3759 if (modelData->State3Wmo)
3760 modelId = modelData->State3Wmo;
3794 bool collision =
false;
3797 collision = !collision;
3806 std::unique_ptr<Loot> loot(std::move(
m_loot));
3807 std::unordered_map<ObjectGuid, std::unique_ptr<Loot>> personalLoot(std::move(
m_personalLoot));
3810 personalLoot.clear();
3821 if (!loot->isLooted())
3879 bool collision =
false;
3881 collision = !collision;
3892 return *state->State;
3901 perPlayerState.
State = state;
3905 setStateLocal.
State = state;
3925 return modelData->State0NameSet;
3927 return modelData->State1NameSet;
3929 return modelData->State2NameSet;
3931 return modelData->State3NameSet;
3978 if (loot->isLooted())
3980 if (!loot->HasAllowedLooter(
GetGUID()) || (!loot->hasItemForAll() && !loot->hasItemFor(player)))
4009 std::size_t sizePos = data->
wpos();
4020 std::size_t sizePos = data->
wpos();
4037 if (requestedObjectMask.IsAnySet())
4040 if (requestedGameObjectMask.IsAnySet())
4044 std::size_t sizePos = buffer.
wpos();
4049 m_objectData->WriteUpdate(buffer, requestedObjectMask,
true,
this, target);
4052 m_gameObjectData->WriteUpdate(buffer, requestedGameObjectMask,
true,
this, target);
4079 return transport->GetPauseTimes();
4093 dynamicFlags &= 0xFFFF;
4094 dynamicFlags |=
uint32(progress * 65535.0f) << 16;
4127 return static_cast<Transport const*
>(
this);
4151 if (
GetGOInfo()->GetInteractRadiusOverride())
4152 return float(
GetGOInfo()->GetInteractRadiusOverride()) / 100.0f;
4219 activateAnimKit.
Maintain = !oneshot;
4255 if (ai->OnCapturePointAssaulted(player))
4339 uint32 spellVisualId = 0;
4367 if (customAnim != 0)
4383 bg->SendPacketToAll(packet.
Write());