TrinityCore
Loading...
Searching...
No Matches
Garrison.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Garrison.h"
19#include "Creature.h"
20#include "DatabaseEnv.h"
21#include "DB2Stores.h"
22#include "GameObject.h"
23#include "GameTime.h"
24#include "GarrisonMgr.h"
25#include "Log.h"
26#include "Map.h"
27#include "MapManager.h"
28#include "ObjectMgr.h"
29#include "PhasingHandler.h"
30#include "Player.h"
31#include "VehicleDefines.h"
32#include "advstd.h"
33
34Garrison::Garrison(Player* owner) : _owner(owner), _siteLevel(nullptr), _followerActivationsRemainingToday(1)
35{
36}
37
39 PreparedQueryResult followers, PreparedQueryResult abilities)
40{
41 if (!garrison)
42 return false;
43
44 Field* fields = garrison->Fetch();
45 _siteLevel = sGarrSiteLevelStore.LookupEntry(fields[0].GetUInt32());
47 if (!_siteLevel)
48 return false;
49
51
52 if (blueprints)
53 {
54 do
55 {
56 fields = blueprints->Fetch();
57 if (GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(fields[0].GetUInt32()))
58 _knownBuildings.insert(building->ID);
59
60 } while (blueprints->NextRow());
61 }
62
63 if (buildings)
64 {
65 do
66 {
67 fields = buildings->Fetch();
68 uint32 plotInstanceId = fields[0].GetUInt32();
69 uint32 buildingId = fields[1].GetUInt32();
70 time_t timeBuilt = fields[2].GetInt64();
71 bool active = fields[3].GetBool();
72
73 Plot* plot = GetPlot(plotInstanceId);
74 if (!plot)
75 continue;
76
77 if (!sGarrBuildingStore.LookupEntry(buildingId))
78 continue;
79
80 plot->BuildingInfo.PacketInfo.emplace();
81 plot->BuildingInfo.PacketInfo->GarrPlotInstanceID = plotInstanceId;
82 plot->BuildingInfo.PacketInfo->GarrBuildingID = buildingId;
83 plot->BuildingInfo.PacketInfo->TimeBuilt = timeBuilt;
84 plot->BuildingInfo.PacketInfo->Active = active;
85
86 } while (buildings->NextRow());
87 }
88
89 // 0 1 2 3 4 5 6 7 8 9
90 // SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ?
91 if (followers)
92 {
93 do
94 {
95 fields = followers->Fetch();
96
97 uint64 dbId = fields[0].GetUInt64();
98 uint32 followerId = fields[1].GetUInt32();
99 if (!sGarrFollowerStore.LookupEntry(followerId))
100 continue;
101
102 _followerIds.insert(followerId);
103 Follower& follower = _followers[dbId];
104 follower.PacketInfo.DbID = dbId;
105 follower.PacketInfo.GarrFollowerID = followerId;
106 follower.PacketInfo.Quality = fields[2].GetUInt32();
107 follower.PacketInfo.FollowerLevel = fields[3].GetUInt32();
108 follower.PacketInfo.ItemLevelWeapon = fields[4].GetUInt32();
109 follower.PacketInfo.ItemLevelArmor = fields[5].GetUInt32();
110 follower.PacketInfo.Xp = fields[6].GetUInt32();
111 follower.PacketInfo.CurrentBuildingID = fields[7].GetUInt32();
112 follower.PacketInfo.CurrentMissionID = fields[8].GetUInt32();
113 follower.PacketInfo.FollowerStatus = fields[9].GetUInt32();
114 if (!sGarrBuildingStore.LookupEntry(follower.PacketInfo.CurrentBuildingID))
115 follower.PacketInfo.CurrentBuildingID = 0;
116
117 //if (!sGarrMissionStore.LookupEntry(follower.PacketInfo.CurrentMissionID))
118 // follower.PacketInfo.CurrentMissionID = 0;
119
120 } while (followers->NextRow());
121
122 if (abilities)
123 {
124 do
125 {
126 fields = abilities->Fetch();
127 uint64 dbId = fields[0].GetUInt64();
128 GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(fields[1].GetUInt32());
129
130 if (!ability)
131 continue;
132
133 auto itr = _followers.find(dbId);
134 if (itr == _followers.end())
135 continue;
136
137 itr->second.PacketInfo.AbilityID.push_back(ability);
138 } while (abilities->NextRow());
139 }
140 }
141
142 return true;
143}
144
146{
148
150 stmt->setUInt64(0, _owner->GetGUID().GetCounter());
151 stmt->setUInt32(1, _siteLevel->ID);
153 trans->Append(stmt);
154
155 for (uint32 building : _knownBuildings)
156 {
158 stmt->setUInt64(0, _owner->GetGUID().GetCounter());
159 stmt->setUInt32(1, building);
160 trans->Append(stmt);
161 }
162
163 for (auto const& p : _plots)
164 {
165 Plot const& plot = p.second;
166 if (plot.BuildingInfo.PacketInfo)
167 {
168 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS);
169 stmt->setUInt64(0, _owner->GetGUID().GetCounter());
170 stmt->setUInt32(1, plot.BuildingInfo.PacketInfo->GarrPlotInstanceID);
171 stmt->setUInt32(2, plot.BuildingInfo.PacketInfo->GarrBuildingID);
172 stmt->setInt64(3, plot.BuildingInfo.PacketInfo->TimeBuilt);
173 stmt->setBool(4, plot.BuildingInfo.PacketInfo->Active);
174 trans->Append(stmt);
175 }
176 }
177
178 for (auto const& p : _followers)
179 {
180 Follower const& follower = p.second;
181 uint8 index = 0;
182 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS);
183 stmt->setUInt64(index++, follower.PacketInfo.DbID);
184 stmt->setUInt64(index++, _owner->GetGUID().GetCounter());
185 stmt->setUInt32(index++, follower.PacketInfo.GarrFollowerID);
186 stmt->setUInt32(index++, follower.PacketInfo.Quality);
187 stmt->setUInt32(index++, follower.PacketInfo.FollowerLevel);
188 stmt->setUInt32(index++, follower.PacketInfo.ItemLevelWeapon);
189 stmt->setUInt32(index++, follower.PacketInfo.ItemLevelArmor);
190 stmt->setUInt32(index++, follower.PacketInfo.Xp);
191 stmt->setUInt32(index++, follower.PacketInfo.CurrentBuildingID);
192 stmt->setUInt32(index++, follower.PacketInfo.CurrentMissionID);
193 stmt->setUInt32(index++, follower.PacketInfo.FollowerStatus);
194 trans->Append(stmt);
195
196 uint8 slot = 0;
197 for (GarrAbilityEntry const* ability : follower.PacketInfo.AbilityID)
198 {
200 stmt->setUInt64(0, follower.PacketInfo.DbID);
201 stmt->setUInt32(1, ability->ID);
202 stmt->setUInt8(2, slot++);
203 trans->Append(stmt);
204 }
205 }
206}
207
209{
211 stmt->setUInt64(0, ownerGuid);
212 trans->Append(stmt);
213
215 stmt->setUInt64(0, ownerGuid);
216 trans->Append(stmt);
217
218 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS);
219 stmt->setUInt64(0, ownerGuid);
220 trans->Append(stmt);
221
222 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS);
223 stmt->setUInt64(0, ownerGuid);
224 trans->Append(stmt);
225}
226
227bool Garrison::Create(uint32 garrSiteId)
228{
229 GarrSiteLevelEntry const* siteLevel = sGarrisonMgr.GetGarrSiteLevelEntry(garrSiteId, 1);
230 if (!siteLevel)
231 return false;
232
233 _siteLevel = siteLevel;
234
236
238 garrisonCreateResult.GarrSiteLevelID = _siteLevel->ID;
239 _owner->SendDirectMessage(garrisonCreateResult.Write());
242 return true;
243}
244
246{
247 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
249 CharacterDatabase.CommitTransaction(trans);
250
252 garrisonDelete.Result = GARRISON_SUCCESS;
253 garrisonDelete.GarrSiteID = _siteLevel->GarrSiteID;
254 _owner->SendDirectMessage(garrisonDelete.Write());
255}
256
258{
259 if (std::vector<GarrSiteLevelPlotInstEntry const*> const* plots = sGarrisonMgr.GetGarrPlotInstForSiteLevel(_siteLevel->ID))
260 {
261 for (std::size_t i = 0; i < plots->size(); ++i)
262 {
263 uint32 garrPlotInstanceId = plots->at(i)->GarrPlotInstanceID;
264 GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId);
265 GameObjectsEntry const* gameObject = sGarrisonMgr.GetPlotGameObject(_siteLevel->MapID, garrPlotInstanceId);
266 if (!plotInstance || !gameObject)
267 continue;
268
269 GarrPlotEntry const* plot = sGarrPlotStore.LookupEntry(plotInstance->GarrPlotID);
270 if (!plot)
271 continue;
272
273 Plot& plotInfo = _plots[garrPlotInstanceId];
274 plotInfo.PacketInfo.GarrPlotInstanceID = garrPlotInstanceId;
275 plotInfo.PacketInfo.PlotPos = Position(gameObject->Pos.X, gameObject->Pos.Y, gameObject->Pos.Z, 2 * std::acos(gameObject->Rot[3]));
276 plotInfo.PacketInfo.PlotType = plot->PlotType;
277 plotInfo.Rotation = QuaternionData(gameObject->Rot[0], gameObject->Rot[1], gameObject->Rot[2], gameObject->Rot[3]);
278 plotInfo.EmptyGameObjectId = gameObject->ID;
279 plotInfo.GarrSiteLevelPlotInstId = plots->at(i)->ID;
280 }
281 }
282}
283
285{
286}
287
288void Garrison::Enter() const
289{
290 if (MapEntry const* map = sMapStore.LookupEntry(_siteLevel->MapID))
291 if (int32(_owner->GetMapId()) == map->ParentMapID)
293}
294
295void Garrison::Leave() const
296{
297 if (MapEntry const* map = sMapStore.LookupEntry(_siteLevel->MapID))
298 if (_owner->GetMapId() == _siteLevel->MapID)
300}
301
306
307std::vector<Garrison::Plot*> Garrison::GetPlots()
308{
309 std::vector<Plot*> plots;
310 plots.reserve(_plots.size());
311 for (auto& p : _plots)
312 plots.push_back(&p.second);
313
314 return plots;
315}
316
318{
319 auto itr = _plots.find(garrPlotInstanceId);
320 if (itr != _plots.end())
321 return &itr->second;
322
323 return nullptr;
324}
325
326Garrison::Plot const* Garrison::GetPlot(uint32 garrPlotInstanceId) const
327{
328 auto itr = _plots.find(garrPlotInstanceId);
329 if (itr != _plots.end())
330 return &itr->second;
331
332 return nullptr;
333}
334
336{
338 learnBlueprintResult.GarrTypeID = GetType();
339 learnBlueprintResult.BuildingID = garrBuildingId;
340 learnBlueprintResult.Result = GARRISON_SUCCESS;
341
342 if (!sGarrBuildingStore.LookupEntry(garrBuildingId))
343 learnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID;
344 else if (HasBlueprint(garrBuildingId))
345 learnBlueprintResult.Result = GARRISON_ERROR_BLUEPRINT_EXISTS;
346 else
347 _knownBuildings.insert(garrBuildingId);
348
349 _owner->SendDirectMessage(learnBlueprintResult.Write());
350}
351
353{
355 unlearnBlueprintResult.GarrTypeID = GetType();
356 unlearnBlueprintResult.BuildingID = garrBuildingId;
357 unlearnBlueprintResult.Result = GARRISON_SUCCESS;
358
359 if (!sGarrBuildingStore.LookupEntry(garrBuildingId))
360 unlearnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID;
361 else if (!HasBlueprint(garrBuildingId))
362 unlearnBlueprintResult.Result = GARRISON_ERROR_REQUIRES_BLUEPRINT;
363 else
364 _knownBuildings.erase(garrBuildingId);
365
366 _owner->SendDirectMessage(unlearnBlueprintResult.Write());
367}
368
369void Garrison::PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId)
370{
372 placeBuildingResult.GarrTypeID = GetType();
373 placeBuildingResult.Result = CheckBuildingPlacement(garrPlotInstanceId, garrBuildingId);
374 if (placeBuildingResult.Result == GARRISON_SUCCESS)
375 {
376 placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId;
377 placeBuildingResult.BuildingInfo.GarrBuildingID = garrBuildingId;
378 placeBuildingResult.BuildingInfo.TimeBuilt = GameTime::GetGameTime();
379
380 Plot* plot = GetPlot(garrPlotInstanceId);
381 uint32 oldBuildingId = 0;
382 Map* map = FindMap();
383 GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(garrBuildingId);
384 if (map)
385 plot->DeleteGameObject(map);
386
387 if (plot->BuildingInfo.PacketInfo)
388 {
389 oldBuildingId = plot->BuildingInfo.PacketInfo->GarrBuildingID;
390 if (sGarrBuildingStore.AssertEntry(oldBuildingId)->BuildingType != building->BuildingType)
392 }
393
394 plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner);
395 if (map)
396 if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
397 map->AddToMap(go);
398
400 _owner->ModifyMoney(-building->GoldCost * GOLD, false);
401
402 if (oldBuildingId)
403 {
405 buildingRemoved.GarrTypeID = GetType();
406 buildingRemoved.Result = GARRISON_SUCCESS;
407 buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId;
408 buildingRemoved.GarrBuildingID = oldBuildingId;
409 _owner->SendDirectMessage(buildingRemoved.Write());
410 }
411
413 }
414
415 _owner->SendDirectMessage(placeBuildingResult.Write());
416}
417
419{
421 buildingRemoved.GarrTypeID = GetType();
422 buildingRemoved.Result = CheckBuildingRemoval(garrPlotInstanceId);
423 if (buildingRemoved.Result == GARRISON_SUCCESS)
424 {
425 Plot* plot = GetPlot(garrPlotInstanceId);
426
427 buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId;
428 buildingRemoved.GarrBuildingID = plot->BuildingInfo.PacketInfo->GarrBuildingID;
429
430 Map* map = FindMap();
431 if (map)
432 plot->DeleteGameObject(map);
433
435 _owner->SendDirectMessage(buildingRemoved.Write());
436
437 GarrBuildingEntry const* constructing = sGarrBuildingStore.AssertEntry(buildingRemoved.GarrBuildingID);
438 // Refund construction/upgrade cost
440 _owner->ModifyMoney(constructing->GoldCost * GOLD, false);
441
442 if (constructing->UpgradeLevel > 1)
443 {
444 // Restore previous level building
445 uint32 restored = sGarrisonMgr.GetPreviousLevelBuildingId(constructing->BuildingType, constructing->UpgradeLevel);
446 ASSERT(restored);
447
449 placeBuildingResult.GarrTypeID = GetType();
450 placeBuildingResult.Result = GARRISON_SUCCESS;
451 placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId;
452 placeBuildingResult.BuildingInfo.GarrBuildingID = restored;
453 placeBuildingResult.BuildingInfo.TimeBuilt = GameTime::GetGameTime();
454 placeBuildingResult.BuildingInfo.Active = true;
455
456 plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner);
457 _owner->SendDirectMessage(placeBuildingResult.Write());
458 }
459
460 if (map)
461 if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
462 map->AddToMap(go);
463 }
464 else
465 _owner->SendDirectMessage(buildingRemoved.Write());
466}
467
468void Garrison::ActivateBuilding(uint32 garrPlotInstanceId)
469{
470 if (Plot* plot = GetPlot(garrPlotInstanceId))
471 {
472 if (plot->BuildingInfo.CanActivate() && plot->BuildingInfo.PacketInfo && !plot->BuildingInfo.PacketInfo->Active)
473 {
474 plot->BuildingInfo.PacketInfo->Active = true;
475 if (Map* map = FindMap())
476 {
477 plot->DeleteGameObject(map);
478 if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
479 map->AddToMap(go);
480 }
481
483 buildingActivated.GarrPlotInstanceID = garrPlotInstanceId;
484 _owner->SendDirectMessage(buildingActivated.Write());
485
486 _owner->UpdateCriteria(CriteriaType::ActivateAnyGarrisonBuilding, plot->BuildingInfo.PacketInfo->GarrBuildingID);
487 }
488 }
489}
490
491void Garrison::AddFollower(uint32 garrFollowerId)
492{
494 addFollowerResult.GarrTypeID = GetType();
495 GarrFollowerEntry const* followerEntry = sGarrFollowerStore.LookupEntry(garrFollowerId);
496 if (_followerIds.count(garrFollowerId) || !followerEntry)
497 {
498 addFollowerResult.Result = GARRISON_ERROR_FOLLOWER_EXISTS;
499 _owner->SendDirectMessage(addFollowerResult.Write());
500 return;
501 }
502
503 _followerIds.insert(garrFollowerId);
504 uint64 dbId = sGarrisonMgr.GenerateFollowerDbId();
505 Follower& follower = _followers[dbId];
506 follower.PacketInfo.DbID = dbId;
507 follower.PacketInfo.GarrFollowerID = garrFollowerId;
508 follower.PacketInfo.Quality = followerEntry->Quality; // TODO: handle magic upgrades
509 follower.PacketInfo.FollowerLevel = followerEntry->FollowerLevel;
510 follower.PacketInfo.ItemLevelWeapon = followerEntry->ItemLevelWeapon;
511 follower.PacketInfo.ItemLevelArmor = followerEntry->ItemLevelArmor;
512 follower.PacketInfo.Xp = 0;
513 follower.PacketInfo.CurrentBuildingID = 0;
514 follower.PacketInfo.CurrentMissionID = 0;
515 follower.PacketInfo.AbilityID = sGarrisonMgr.RollFollowerAbilities(garrFollowerId, followerEntry, follower.PacketInfo.Quality, GetFaction(), true);
516 follower.PacketInfo.FollowerStatus = 0;
517
518 addFollowerResult.Follower = follower.PacketInfo;
519 _owner->SendDirectMessage(addFollowerResult.Write());
520
522}
523
525{
526 auto itr = _followers.find(dbId);
527 if (itr != _followers.end())
528 return &itr->second;
529
530 return nullptr;
531}
532
534{
535 garrison.GarrTypeID = GetType();
536 garrison.GarrSiteID = _siteLevel->GarrSiteID;
537 garrison.GarrSiteLevelID = _siteLevel->ID;
539 for (auto& p : _plots)
540 {
541 Plot const& plot = p.second;
542 garrison.Plots.push_back(&plot.PacketInfo);
543 if (plot.BuildingInfo.PacketInfo)
544 garrison.Buildings.push_back(&*plot.BuildingInfo.PacketInfo);
545 }
546
547 for (auto const& p : _followers)
548 garrison.Followers.push_back(&p.second.PacketInfo);
549}
550
552{
553 MapEntry const* garrisonMap = sMapStore.LookupEntry(_siteLevel->MapID);
554 if (!garrisonMap || int32(_owner->GetMapId()) != garrisonMap->ParentMapID)
555 return;
556
558 remoteInfo.Sites.resize(1);
559
560 WorldPackets::Garrison::GarrisonRemoteSiteInfo& remoteSiteInfo = remoteInfo.Sites[0];
561 remoteSiteInfo.GarrSiteLevelID = _siteLevel->ID;
562 for (auto const& p : _plots)
563 if (p.second.BuildingInfo.PacketInfo)
564 remoteSiteInfo.Buildings.emplace_back(p.first, p.second.BuildingInfo.PacketInfo->GarrBuildingID);
565
566 _owner->SendDirectMessage(remoteInfo.Write());
567}
568
576
577void Garrison::SendMapData(Player* receiver) const
578{
580 mapData.Buildings.reserve(_plots.size());
581
582 for (auto const& p : _plots)
583 {
584 Plot const& plot = p.second;
585 if (plot.BuildingInfo.PacketInfo)
586 if (uint32 garrBuildingPlotInstId = sGarrisonMgr.GetGarrBuildingPlotInst(plot.BuildingInfo.PacketInfo->GarrBuildingID, plot.GarrSiteLevelPlotInstId))
587 mapData.Buildings.emplace_back(garrBuildingPlotInstId, plot.PacketInfo.PlotPos.Pos);
588 }
589
590 receiver->SendDirectMessage(mapData.Write());
591}
592
594{
595 return sMapMgr->FindMap(_siteLevel->MapID, _owner->GetGUID().GetCounter());
596}
597
598GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const
599{
600 GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId);
601 Plot const* plot = GetPlot(garrPlotInstanceId);
602 if (!plotInstance || !plot)
604
605 GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(garrBuildingId);
606 if (!building)
608
609 if (!sGarrisonMgr.IsPlotMatchingBuilding(plotInstance->GarrPlotID, garrBuildingId))
611
612 // Cannot place buldings of higher level than garrison level
615
617 {
618 if (!HasBlueprint(garrBuildingId))
620 }
621 else // Building is built as a quest reward
623
624 // Check all plots to find if we already have this building
625 GarrBuildingEntry const* existingBuilding;
626 for (auto const& p : _plots)
627 {
628 if (p.second.BuildingInfo.PacketInfo)
629 {
630 existingBuilding = sGarrBuildingStore.AssertEntry(p.second.BuildingInfo.PacketInfo->GarrBuildingID);
631 if (existingBuilding->BuildingType == building->BuildingType)
632 if (p.first != garrPlotInstanceId || existingBuilding->UpgradeLevel + 1 != building->UpgradeLevel) // check if its an upgrade in same plot
634 }
635 }
636
637 if (!_owner->HasCurrency(building->CurrencyTypeID, building->CurrencyQty))
639
640 if (!_owner->HasEnoughMoney(uint64(building->GoldCost) * GOLD))
642
643 // New building cannot replace another building currently under construction
644 if (plot->BuildingInfo.PacketInfo)
645 if (!plot->BuildingInfo.PacketInfo->Active)
647
648 return GARRISON_SUCCESS;
649}
650
652{
653 Plot const* plot = GetPlot(garrPlotInstanceId);
654 if (!plot)
656
657 if (!plot->BuildingInfo.PacketInfo)
659
660 if (plot->BuildingInfo.CanActivate())
662
663 return GARRISON_SUCCESS;
664}
665
666template<class T, void(T::*SecondaryRelocate)(Position const&)>
668{
669 T* spawn = new T();
670 if (!spawn->LoadFromDB(spawnId, map, false, false))
671 {
672 delete spawn;
673 return nullptr;
674 }
675
676 Position globalPosition = building->GetPositionWithOffset(spawn->GetPosition());
677
678 spawn->Relocate(globalPosition);
679 (spawn->*SecondaryRelocate)(globalPosition);
680
681 if (!spawn->IsPositionValid())
682 {
683 delete spawn;
684 return nullptr;
685 }
686
687 if (!map->AddToMap(spawn))
688 {
689 delete spawn;
690 return nullptr;
691 }
692
693 return spawn;
694}
695
697{
700 {
702 GarrPlotEntry const* plot = sGarrPlotStore.AssertEntry(plotInstance->GarrPlotID);
703 GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(BuildingInfo.PacketInfo->GarrBuildingID);
705 if (BuildingInfo.PacketInfo->Active || !entry)
706 entry = faction == GARRISON_FACTION_INDEX_HORDE ? building->HordeGameObjectID : building->AllianceGameObjectID;
707 }
708
709 if (!sObjectMgr->GetGameObjectTemplate(entry))
710 {
711 TC_LOG_ERROR("garrison", "Garrison attempted to spawn gameobject whose template doesn't exist ({})", entry);
712 return nullptr;
713 }
714
716 if (!building)
717 return nullptr;
718
720 {
721 if (FinalizeGarrisonPlotGOInfo const* finalizeInfo = sGarrisonMgr.GetPlotFinalizeGOInfo(PacketInfo.GarrPlotInstanceID))
722 {
723 Position const& pos2 = finalizeInfo->FactionInfo[faction].Pos;
724 if (GameObject* finalizer = GameObject::CreateGameObject(finalizeInfo->FactionInfo[faction].GameObjectId, map, pos2, QuaternionData::fromEulerAnglesZYX(pos2.GetOrientation(), 0.0f, 0.0f), 255, GO_STATE_READY))
725 {
726 // set some spell id to make the object delete itself after use
727 finalizer->SetSpellId(finalizer->GetGOInfo()->goober.spell);
728 finalizer->SetRespawnTime(0);
729
730 if (uint16 animKit = finalizeInfo->FactionInfo[faction].AnimKitId)
731 finalizer->SetAnimKitId(animKit, false);
732
733 map->AddToMap(finalizer);
734 }
735 }
736 }
737
739 {
740 if (CellObjectGuidsMap const* cells = sObjectMgr->GetMapObjectGuids(building->GetGOInfo()->garrisonBuilding.SpawnMap, map->GetDifficultyID()))
741 {
742 for (auto const& [cellId, guids] : *cells)
743 {
744 for (ObjectGuid::LowType spawnId : guids.gameobjects)
745 if (GameObject* spawn = BuildingSpawnHelper<GameObject, &GameObject::RelocateStationaryPosition>(building, spawnId, map))
746 BuildingInfo.Spawns.insert(spawn->GetGUID());
747
748 for (ObjectGuid::LowType spawnId : guids.creatures)
749 if (Creature* spawn = BuildingSpawnHelper<Creature, &Creature::SetHomePosition>(building, spawnId, map))
750 BuildingInfo.Spawns.insert(spawn->GetGUID());
751 }
752 }
753 }
754
755 BuildingInfo.Guid = building->GetGUID();
756 return building;
757}
758
760{
761 if (BuildingInfo.Guid.IsEmpty())
762 return;
763
764 for (ObjectGuid const& guid : BuildingInfo.Spawns)
765 {
766 WorldObject* object = nullptr;
767 switch (guid.GetHigh())
768 {
770 object = map->GetCreature(guid);
771 break;
773 object = map->GetGameObject(guid);
774 break;
775 default:
776 continue;
777 }
778
779 if (object)
780 object->AddObjectToRemoveList();
781 }
782
783 BuildingInfo.Spawns.clear();
784
785 if (GameObject* oldBuilding = map->GetGameObject(BuildingInfo.Guid))
786 oldBuilding->Delete();
787
788 BuildingInfo.Guid.Clear();
789}
790
792{
794 plotPlaced.GarrTypeID = garrisonType;
795 plotPlaced.PlotInfo = &PacketInfo;
796 owner->SendDirectMessage(plotPlaced.Write());
797
798 BuildingInfo.PacketInfo.reset();
799}
800
802{
803 if (!BuildingInfo.PacketInfo)
804 {
806 plotRemoved.GarrPlotInstanceID = PacketInfo.GarrPlotInstanceID;
807 owner->SendDirectMessage(plotRemoved.Write());
808 }
809
810 BuildingInfo.PacketInfo = buildingInfo;
811}
812
814{
815 if (PacketInfo)
816 {
817 GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(PacketInfo->GarrBuildingID);
818 if (PacketInfo->TimeBuilt + building->BuildSeconds <= GameTime::GetGameTime())
819 return true;
820 }
821
822 return false;
823}
824
826{
827 return (PacketInfo.ItemLevelWeapon + PacketInfo.ItemLevelArmor) / 2;
828}
829
830bool Garrison::Follower::HasAbility(uint32 garrAbilityId) const
831{
832 return advstd::ranges::contains(PacketInfo.AbilityID, garrAbilityId, &GarrAbilityEntry::ID);
833}
@ CHAR_DEL_CHARACTER_GARRISON
@ CHAR_INS_CHARACTER_GARRISON_BUILDINGS
@ CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS
@ CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS
@ CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS
@ CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES
@ CHAR_INS_CHARACTER_GARRISON
@ CHAR_DEL_CHARACTER_GARRISON_BUILDINGS
@ CHAR_INS_CHARACTER_GARRISON_FOLLOWERS
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
DB2Storage< GarrBuildingEntry > sGarrBuildingStore("GarrBuilding.db2", &GarrBuildingLoadInfo::Instance)
DB2Storage< GarrPlotInstanceEntry > sGarrPlotInstanceStore("GarrPlotInstance.db2", &GarrPlotInstanceLoadInfo::Instance)
DB2Storage< GarrSiteLevelEntry > sGarrSiteLevelStore("GarrSiteLevel.db2", &GarrSiteLevelLoadInfo::Instance)
DB2Storage< GarrFollowerEntry > sGarrFollowerStore("GarrFollower.db2", &GarrFollowerLoadInfo::Instance)
DB2Storage< GarrAbilityEntry > sGarrAbilityStore("GarrAbility.db2", &GarrAbilityLoadInfo::Instance)
DB2Storage< GarrPlotEntry > sGarrPlotStore("GarrPlot.db2", &GarrPlotLoadInfo::Instance)
@ ActivateAnyGarrisonBuilding
@ RecruitGarrisonFollower
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
#define ASSERT
Definition Errors.h:80
#define sGarrisonMgr
Definition GarrisonMgr.h:95
T * BuildingSpawnHelper(GameObject *building, ObjectGuid::LowType spawnId, Map *map)
Definition Garrison.cpp:667
GarrisonFactionIndex
Definition Garrison.h:43
@ GARRISON_FACTION_INDEX_HORDE
Definition Garrison.h:44
GarrisonType
Definition Garrison.h:35
@ GARRISON_BUILDING_FLAG_NEEDS_PLAN
Definition Garrison.h:50
GarrisonError
Definition Garrison.h:83
@ GARRISON_ERROR_REQUIRES_BLUEPRINT
Definition Garrison.h:106
@ GARRISON_ERROR_INVALID_BUILDINGID
Definition Garrison.h:95
@ GARRISON_SUCCESS
Definition Garrison.h:84
@ GARRISON_ERROR_INVALID_PLOT_BUILDING
Definition Garrison.h:100
@ GARRISON_ERROR_INVALID_PLOT_INSTANCEID
Definition Garrison.h:94
@ GARRISON_ERROR_NOT_ENOUGH_CURRENCY
Definition Garrison.h:130
@ GARRISON_ERROR_BUILDING_EXISTS
Definition Garrison.h:93
@ GARRISON_ERROR_NO_BUILDING
Definition Garrison.h:92
@ GARRISON_ERROR_NOT_ENOUGH_GOLD
Definition Garrison.h:131
@ GARRISON_ERROR_FOLLOWER_EXISTS
Definition Garrison.h:111
@ GARRISON_ERROR_BLUEPRINT_EXISTS
Definition Garrison.h:105
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define sMapMgr
Definition MapManager.h:186
std::unordered_map< uint32, CellObjectGuids > CellObjectGuidsMap
Definition ObjectMgr.h:478
#define sObjectMgr
Definition ObjectMgr.h:1885
@ TELE_TO_SEAMLESS
Definition Player.h:930
@ GAMEOBJECT_TYPE_GARRISON_BUILDING
@ GOLD
@ GO_STATE_READY
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
Class used to access individual fields of database query result.
Definition Field.h:94
uint64 GetUInt64() const noexcept
Definition Field.cpp:71
bool GetBool() const noexcept
Definition Field.h:102
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
int64 GetInt64() const noexcept
Definition Field.cpp:78
GameObjectTemplate const * GetGOInfo() const
Definition GameObject.h:203
static GameObject * CreateGameObject(uint32 entry, Map *map, Position const &pos, QuaternionData const &rotation, uint32 animProgress, GOState goState, uint32 artKit=0)
GameobjectTypes GetGoType() const
Definition GameObject.h:282
void SendRemoteInfo() const
Definition Garrison.cpp:551
GarrisonError CheckBuildingRemoval(uint32 garrPlotInstanceId) const
Definition Garrison.cpp:651
void SendBlueprintAndSpecializationData()
Definition Garrison.cpp:569
GarrSiteLevelEntry const * _siteLevel
Definition Garrison.h:277
std::unordered_map< uint64, Follower > _followers
Definition Garrison.h:282
void SaveToDB(CharacterDatabaseTransaction trans)
Definition Garrison.cpp:145
std::unordered_set< uint32 > _followerIds
Definition Garrison.h:283
bool Create(uint32 garrSiteId)
Definition Garrison.cpp:227
void InitializePlots()
Definition Garrison.cpp:257
Follower const * GetFollower(uint64 dbId) const
Definition Garrison.cpp:524
GarrisonType GetType() const
Definition Garrison.h:234
void UnlearnBlueprint(uint32 garrBuildingId)
Definition Garrison.cpp:352
void CancelBuildingConstruction(uint32 garrPlotInstanceId)
Definition Garrison.cpp:418
bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings, PreparedQueryResult followers, PreparedQueryResult abilities)
Definition Garrison.cpp:38
void AddFollower(uint32 garrFollowerId)
Definition Garrison.cpp:491
void PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId)
Definition Garrison.cpp:369
GarrisonFactionIndex GetFaction() const
Definition Garrison.cpp:302
void Delete()
Definition Garrison.cpp:245
void Enter() const
Definition Garrison.cpp:288
Plot * GetPlot(uint32 garrPlotInstanceId)
Definition Garrison.cpp:317
GarrisonError CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const
Definition Garrison.cpp:598
void LearnBlueprint(uint32 garrBuildingId)
Definition Garrison.cpp:335
bool HasBlueprint(uint32 garrBuildingId) const
Definition Garrison.h:245
std::unordered_map< uint32, Plot > _plots
Definition Garrison.h:280
std::unordered_set< uint32 > _knownBuildings
Definition Garrison.h:281
Garrison(Player *owner)
Definition Garrison.cpp:34
void SendMapData(Player *receiver) const
Definition Garrison.cpp:577
void BuildInfoPacket(WorldPackets::Garrison::GarrisonInfo &garrison) const
Definition Garrison.cpp:533
static void DeleteFromDB(ObjectGuid::LowType ownerGuid, CharacterDatabaseTransaction trans)
Definition Garrison.cpp:208
void ActivateBuilding(uint32 garrPlotInstanceId)
Definition Garrison.cpp:468
Player * _owner
Definition Garrison.h:276
uint32 _followerActivationsRemainingToday
Definition Garrison.h:278
Map * FindMap() const
Definition Garrison.cpp:593
void Upgrade()
Definition Garrison.cpp:284
void Leave() const
Definition Garrison.cpp:295
std::vector< Plot * > GetPlots()
Definition Garrison.cpp:307
Definition Map.h:225
bool AddToMap(T *)
Definition Map.cpp:517
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:3552
Difficulty GetDifficultyID() const
Definition Map.h:360
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:3542
LowType GetCounter() const
Definition ObjectGuid.h:336
uint64 LowType
Definition ObjectGuid.h:321
static bool OnConditionChange(WorldObject *object, bool updateVisibility=true)
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24850
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6283
bool HasCurrency(uint32 id, uint32 amount) const
Definition Player.cpp:7451
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27588
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition Player.cpp:1226
void RemoveCurrency(uint32 id, int32 amount, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Definition Player.cpp:7291
void AddCurrency(uint32 id, uint32 amount, CurrencyGainSource gainSource=CurrencyGainSource::Cheat)
Definition Player.cpp:7286
Team GetTeam() const
Definition Player.h:2423
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1907
void setUInt32(uint8 index, uint32 value)
void setInt64(uint8 index, int64 value)
void setBool(uint8 index, bool value)
void setUInt64(uint8 index, uint64 value)
void setUInt8(uint8 index, uint8 value)
constexpr uint32 GetMapId() const
Definition Position.h:216
void AddObjectToRemoveList()
Definition Object.cpp:1174
std::vector< GarrisonBuildingMapData > Buildings
std::vector< GarrisonRemoteSiteInfo > Sites
time_t GetGameTime()
Definition GameTime.cpp:52
struct advstd::ranges::Contains contains
struct GameObjectTemplate::@197::@237 garrisonBuilding
std::array< float, 4 > Rot
DBCPosition3D Pos
int32 HordeConstructObjID
int32 AllianceConstructObjID
ObjectGuid Guid
Definition Garrison.h:191
bool CanActivate() const
Definition Garrison.cpp:813
Optional< WorldPackets::Garrison::GarrisonBuildingInfo > PacketInfo
Definition Garrison.h:193
std::unordered_set< ObjectGuid > Spawns
Definition Garrison.h:192
WorldPackets::Garrison::GarrisonFollower PacketInfo
Definition Garrison.h:215
bool HasAbility(uint32 garrAbilityId) const
Definition Garrison.cpp:830
uint32 GetItemLevel() const
Definition Garrison.cpp:825
QuaternionData Rotation
Definition Garrison.h:204
WorldPackets::Garrison::GarrisonPlotInfo PacketInfo
Definition Garrison.h:203
GameObject * CreateGameObject(Map *map, GarrisonFactionIndex faction)
Definition Garrison.cpp:696
void SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const &buildingInfo, Player *owner)
Definition Garrison.cpp:801
uint32 EmptyGameObjectId
Definition Garrison.h:205
Building BuildingInfo
Definition Garrison.h:207
void DeleteGameObject(Map *map)
Definition Garrison.cpp:759
void ClearBuildingInfo(GarrisonType garrisonType, Player *owner)
Definition Garrison.cpp:791
uint32 GarrSiteLevelPlotInstId
Definition Garrison.h:206
int16 ParentMapID
Position GetPositionWithOffset(Position const &offset) const
Definition Position.cpp:61
constexpr void Relocate(float x, float y)
Definition Position.h:74
constexpr float GetOrientation() const
Definition Position.h:90
static QuaternionData fromEulerAnglesZYX(float Z, float Y, float X)
Position Pos
Definition Position.h:254
std::list< GarrAbilityEntry const * > AbilityID
std::vector< GarrisonFollower const * > Followers
std::vector< GarrisonBuildingInfo const * > Buildings
std::vector< GarrisonPlotInfo const * > Plots
TaggedPosition< Position::XYZO > PlotPos
std::vector< GarrisonRemoteBuildingInfo > Buildings