TrinityCore
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
33Garrison::Garrison(Player* owner) : _owner(owner), _siteLevel(nullptr), _followerActivationsRemainingToday(1)
34{
35}
36
38 PreparedQueryResult followers, PreparedQueryResult abilities)
39{
40 if (!garrison)
41 return false;
42
43 Field* fields = garrison->Fetch();
44 _siteLevel = sGarrSiteLevelStore.LookupEntry(fields[0].GetUInt32());
46 if (!_siteLevel)
47 return false;
48
50
51 if (blueprints)
52 {
53 do
54 {
55 fields = blueprints->Fetch();
56 if (GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(fields[0].GetUInt32()))
57 _knownBuildings.insert(building->ID);
58
59 } while (blueprints->NextRow());
60 }
61
62 if (buildings)
63 {
64 do
65 {
66 fields = buildings->Fetch();
67 uint32 plotInstanceId = fields[0].GetUInt32();
68 uint32 buildingId = fields[1].GetUInt32();
69 time_t timeBuilt = fields[2].GetInt64();
70 bool active = fields[3].GetBool();
71
72 Plot* plot = GetPlot(plotInstanceId);
73 if (!plot)
74 continue;
75
76 if (!sGarrBuildingStore.LookupEntry(buildingId))
77 continue;
78
79 plot->BuildingInfo.PacketInfo.emplace();
80 plot->BuildingInfo.PacketInfo->GarrPlotInstanceID = plotInstanceId;
81 plot->BuildingInfo.PacketInfo->GarrBuildingID = buildingId;
82 plot->BuildingInfo.PacketInfo->TimeBuilt = timeBuilt;
83 plot->BuildingInfo.PacketInfo->Active = active;
84
85 } while (buildings->NextRow());
86 }
87
88 // 0 1 2 3 4 5 6 7 8 9
89 // SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ?
90 if (followers)
91 {
92 do
93 {
94 fields = followers->Fetch();
95
96 uint64 dbId = fields[0].GetUInt64();
97 uint32 followerId = fields[1].GetUInt32();
98 if (!sGarrFollowerStore.LookupEntry(followerId))
99 continue;
100
101 _followerIds.insert(followerId);
102 Follower& follower = _followers[dbId];
103 follower.PacketInfo.DbID = dbId;
104 follower.PacketInfo.GarrFollowerID = followerId;
105 follower.PacketInfo.Quality = fields[2].GetUInt32();
106 follower.PacketInfo.FollowerLevel = fields[3].GetUInt32();
107 follower.PacketInfo.ItemLevelWeapon = fields[4].GetUInt32();
108 follower.PacketInfo.ItemLevelArmor = fields[5].GetUInt32();
109 follower.PacketInfo.Xp = fields[6].GetUInt32();
110 follower.PacketInfo.CurrentBuildingID = fields[7].GetUInt32();
111 follower.PacketInfo.CurrentMissionID = fields[8].GetUInt32();
112 follower.PacketInfo.FollowerStatus = fields[9].GetUInt32();
113 if (!sGarrBuildingStore.LookupEntry(follower.PacketInfo.CurrentBuildingID))
114 follower.PacketInfo.CurrentBuildingID = 0;
115
116 //if (!sGarrMissionStore.LookupEntry(follower.PacketInfo.CurrentMissionID))
117 // follower.PacketInfo.CurrentMissionID = 0;
118
119 } while (followers->NextRow());
120
121 if (abilities)
122 {
123 do
124 {
125 fields = abilities->Fetch();
126 uint64 dbId = fields[0].GetUInt64();
127 GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(fields[1].GetUInt32());
128
129 if (!ability)
130 continue;
131
132 auto itr = _followers.find(dbId);
133 if (itr == _followers.end())
134 continue;
135
136 itr->second.PacketInfo.AbilityID.push_back(ability);
137 } while (abilities->NextRow());
138 }
139 }
140
141 return true;
142}
143
145{
147
149 stmt->setUInt64(0, _owner->GetGUID().GetCounter());
150 stmt->setUInt32(1, _siteLevel->ID);
152 trans->Append(stmt);
153
154 for (uint32 building : _knownBuildings)
155 {
157 stmt->setUInt64(0, _owner->GetGUID().GetCounter());
158 stmt->setUInt32(1, building);
159 trans->Append(stmt);
160 }
161
162 for (auto const& p : _plots)
163 {
164 Plot const& plot = p.second;
165 if (plot.BuildingInfo.PacketInfo)
166 {
167 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS);
168 stmt->setUInt64(0, _owner->GetGUID().GetCounter());
169 stmt->setUInt32(1, plot.BuildingInfo.PacketInfo->GarrPlotInstanceID);
170 stmt->setUInt32(2, plot.BuildingInfo.PacketInfo->GarrBuildingID);
171 stmt->setInt64(3, plot.BuildingInfo.PacketInfo->TimeBuilt);
172 stmt->setBool(4, plot.BuildingInfo.PacketInfo->Active);
173 trans->Append(stmt);
174 }
175 }
176
177 for (auto const& p : _followers)
178 {
179 Follower const& follower = p.second;
180 uint8 index = 0;
181 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS);
182 stmt->setUInt64(index++, follower.PacketInfo.DbID);
183 stmt->setUInt64(index++, _owner->GetGUID().GetCounter());
184 stmt->setUInt32(index++, follower.PacketInfo.GarrFollowerID);
185 stmt->setUInt32(index++, follower.PacketInfo.Quality);
186 stmt->setUInt32(index++, follower.PacketInfo.FollowerLevel);
187 stmt->setUInt32(index++, follower.PacketInfo.ItemLevelWeapon);
188 stmt->setUInt32(index++, follower.PacketInfo.ItemLevelArmor);
189 stmt->setUInt32(index++, follower.PacketInfo.Xp);
190 stmt->setUInt32(index++, follower.PacketInfo.CurrentBuildingID);
191 stmt->setUInt32(index++, follower.PacketInfo.CurrentMissionID);
192 stmt->setUInt32(index++, follower.PacketInfo.FollowerStatus);
193 trans->Append(stmt);
194
195 uint8 slot = 0;
196 for (GarrAbilityEntry const* ability : follower.PacketInfo.AbilityID)
197 {
199 stmt->setUInt64(0, follower.PacketInfo.DbID);
200 stmt->setUInt32(1, ability->ID);
201 stmt->setUInt8(2, slot++);
202 trans->Append(stmt);
203 }
204 }
205}
206
208{
210 stmt->setUInt64(0, ownerGuid);
211 trans->Append(stmt);
212
214 stmt->setUInt64(0, ownerGuid);
215 trans->Append(stmt);
216
217 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS);
218 stmt->setUInt64(0, ownerGuid);
219 trans->Append(stmt);
220
221 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS);
222 stmt->setUInt64(0, ownerGuid);
223 trans->Append(stmt);
224}
225
226bool Garrison::Create(uint32 garrSiteId)
227{
228 GarrSiteLevelEntry const* siteLevel = sGarrisonMgr.GetGarrSiteLevelEntry(garrSiteId, 1);
229 if (!siteLevel)
230 return false;
231
232 _siteLevel = siteLevel;
233
235
237 garrisonCreateResult.GarrSiteLevelID = _siteLevel->ID;
238 _owner->SendDirectMessage(garrisonCreateResult.Write());
241 return true;
242}
243
245{
246 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
248 CharacterDatabase.CommitTransaction(trans);
249
251 garrisonDelete.Result = GARRISON_SUCCESS;
252 garrisonDelete.GarrSiteID = _siteLevel->GarrSiteID;
253 _owner->SendDirectMessage(garrisonDelete.Write());
254}
255
257{
258 if (std::vector<GarrSiteLevelPlotInstEntry const*> const* plots = sGarrisonMgr.GetGarrPlotInstForSiteLevel(_siteLevel->ID))
259 {
260 for (std::size_t i = 0; i < plots->size(); ++i)
261 {
262 uint32 garrPlotInstanceId = plots->at(i)->GarrPlotInstanceID;
263 GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId);
264 GameObjectsEntry const* gameObject = sGarrisonMgr.GetPlotGameObject(_siteLevel->MapID, garrPlotInstanceId);
265 if (!plotInstance || !gameObject)
266 continue;
267
268 GarrPlotEntry const* plot = sGarrPlotStore.LookupEntry(plotInstance->GarrPlotID);
269 if (!plot)
270 continue;
271
272 Plot& plotInfo = _plots[garrPlotInstanceId];
273 plotInfo.PacketInfo.GarrPlotInstanceID = garrPlotInstanceId;
274 plotInfo.PacketInfo.PlotPos = Position(gameObject->Pos.X, gameObject->Pos.Y, gameObject->Pos.Z, 2 * std::acos(gameObject->Rot[3]));
275 plotInfo.PacketInfo.PlotType = plot->PlotType;
276 plotInfo.Rotation = QuaternionData(gameObject->Rot[0], gameObject->Rot[1], gameObject->Rot[2], gameObject->Rot[3]);
277 plotInfo.EmptyGameObjectId = gameObject->ID;
278 plotInfo.GarrSiteLevelPlotInstId = plots->at(i)->ID;
279 }
280 }
281}
282
284{
285}
286
287void Garrison::Enter() const
288{
289 if (MapEntry const* map = sMapStore.LookupEntry(_siteLevel->MapID))
290 {
291 if (int32(_owner->GetMapId()) == map->ParentMapID)
292 {
294 loc.Relocate(_owner);
296 }
297 }
298}
299
300void Garrison::Leave() const
301{
302 if (MapEntry const* map = sMapStore.LookupEntry(_siteLevel->MapID))
303 {
304 if (_owner->GetMapId() == _siteLevel->MapID)
305 {
306 WorldLocation loc(map->ParentMapID);
307 loc.Relocate(_owner);
309 }
310 }
311}
312
314{
316}
317
318std::vector<Garrison::Plot*> Garrison::GetPlots()
319{
320 std::vector<Plot*> plots;
321 plots.reserve(_plots.size());
322 for (auto& p : _plots)
323 plots.push_back(&p.second);
324
325 return plots;
326}
327
329{
330 auto itr = _plots.find(garrPlotInstanceId);
331 if (itr != _plots.end())
332 return &itr->second;
333
334 return nullptr;
335}
336
337Garrison::Plot const* Garrison::GetPlot(uint32 garrPlotInstanceId) const
338{
339 auto itr = _plots.find(garrPlotInstanceId);
340 if (itr != _plots.end())
341 return &itr->second;
342
343 return nullptr;
344}
345
347{
349 learnBlueprintResult.GarrTypeID = GetType();
350 learnBlueprintResult.BuildingID = garrBuildingId;
351 learnBlueprintResult.Result = GARRISON_SUCCESS;
352
353 if (!sGarrBuildingStore.LookupEntry(garrBuildingId))
354 learnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID;
355 else if (HasBlueprint(garrBuildingId))
356 learnBlueprintResult.Result = GARRISON_ERROR_BLUEPRINT_EXISTS;
357 else
358 _knownBuildings.insert(garrBuildingId);
359
360 _owner->SendDirectMessage(learnBlueprintResult.Write());
361}
362
364{
366 unlearnBlueprintResult.GarrTypeID = GetType();
367 unlearnBlueprintResult.BuildingID = garrBuildingId;
368 unlearnBlueprintResult.Result = GARRISON_SUCCESS;
369
370 if (!sGarrBuildingStore.LookupEntry(garrBuildingId))
371 unlearnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID;
372 else if (!HasBlueprint(garrBuildingId))
373 unlearnBlueprintResult.Result = GARRISON_ERROR_REQUIRES_BLUEPRINT;
374 else
375 _knownBuildings.erase(garrBuildingId);
376
377 _owner->SendDirectMessage(unlearnBlueprintResult.Write());
378}
379
380void Garrison::PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId)
381{
383 placeBuildingResult.GarrTypeID = GetType();
384 placeBuildingResult.Result = CheckBuildingPlacement(garrPlotInstanceId, garrBuildingId);
385 if (placeBuildingResult.Result == GARRISON_SUCCESS)
386 {
387 placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId;
388 placeBuildingResult.BuildingInfo.GarrBuildingID = garrBuildingId;
389 placeBuildingResult.BuildingInfo.TimeBuilt = GameTime::GetGameTime();
390
391 Plot* plot = GetPlot(garrPlotInstanceId);
392 uint32 oldBuildingId = 0;
393 Map* map = FindMap();
394 GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(garrBuildingId);
395 if (map)
396 plot->DeleteGameObject(map);
397
398 if (plot->BuildingInfo.PacketInfo)
399 {
400 oldBuildingId = plot->BuildingInfo.PacketInfo->GarrBuildingID;
401 if (sGarrBuildingStore.AssertEntry(oldBuildingId)->BuildingType != building->BuildingType)
403 }
404
405 plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner);
406 if (map)
407 if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
408 map->AddToMap(go);
409
411 _owner->ModifyMoney(-building->GoldCost * GOLD, false);
412
413 if (oldBuildingId)
414 {
416 buildingRemoved.GarrTypeID = GetType();
417 buildingRemoved.Result = GARRISON_SUCCESS;
418 buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId;
419 buildingRemoved.GarrBuildingID = oldBuildingId;
420 _owner->SendDirectMessage(buildingRemoved.Write());
421 }
422
424 }
425
426 _owner->SendDirectMessage(placeBuildingResult.Write());
427}
428
430{
432 buildingRemoved.GarrTypeID = GetType();
433 buildingRemoved.Result = CheckBuildingRemoval(garrPlotInstanceId);
434 if (buildingRemoved.Result == GARRISON_SUCCESS)
435 {
436 Plot* plot = GetPlot(garrPlotInstanceId);
437
438 buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId;
439 buildingRemoved.GarrBuildingID = plot->BuildingInfo.PacketInfo->GarrBuildingID;
440
441 Map* map = FindMap();
442 if (map)
443 plot->DeleteGameObject(map);
444
446 _owner->SendDirectMessage(buildingRemoved.Write());
447
448 GarrBuildingEntry const* constructing = sGarrBuildingStore.AssertEntry(buildingRemoved.GarrBuildingID);
449 // Refund construction/upgrade cost
451 _owner->ModifyMoney(constructing->GoldCost * GOLD, false);
452
453 if (constructing->UpgradeLevel > 1)
454 {
455 // Restore previous level building
456 uint32 restored = sGarrisonMgr.GetPreviousLevelBuildingId(constructing->BuildingType, constructing->UpgradeLevel);
457 ASSERT(restored);
458
460 placeBuildingResult.GarrTypeID = GetType();
461 placeBuildingResult.Result = GARRISON_SUCCESS;
462 placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId;
463 placeBuildingResult.BuildingInfo.GarrBuildingID = restored;
464 placeBuildingResult.BuildingInfo.TimeBuilt = GameTime::GetGameTime();
465 placeBuildingResult.BuildingInfo.Active = true;
466
467 plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner);
468 _owner->SendDirectMessage(placeBuildingResult.Write());
469 }
470
471 if (map)
472 if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
473 map->AddToMap(go);
474 }
475 else
476 _owner->SendDirectMessage(buildingRemoved.Write());
477}
478
479void Garrison::ActivateBuilding(uint32 garrPlotInstanceId)
480{
481 if (Plot* plot = GetPlot(garrPlotInstanceId))
482 {
483 if (plot->BuildingInfo.CanActivate() && plot->BuildingInfo.PacketInfo && !plot->BuildingInfo.PacketInfo->Active)
484 {
485 plot->BuildingInfo.PacketInfo->Active = true;
486 if (Map* map = FindMap())
487 {
488 plot->DeleteGameObject(map);
489 if (GameObject* go = plot->CreateGameObject(map, GetFaction()))
490 map->AddToMap(go);
491 }
492
494 buildingActivated.GarrPlotInstanceID = garrPlotInstanceId;
495 _owner->SendDirectMessage(buildingActivated.Write());
496
497 _owner->UpdateCriteria(CriteriaType::ActivateAnyGarrisonBuilding, plot->BuildingInfo.PacketInfo->GarrBuildingID);
498 }
499 }
500}
501
502void Garrison::AddFollower(uint32 garrFollowerId)
503{
505 addFollowerResult.GarrTypeID = GetType();
506 GarrFollowerEntry const* followerEntry = sGarrFollowerStore.LookupEntry(garrFollowerId);
507 if (_followerIds.count(garrFollowerId) || !followerEntry)
508 {
509 addFollowerResult.Result = GARRISON_ERROR_FOLLOWER_EXISTS;
510 _owner->SendDirectMessage(addFollowerResult.Write());
511 return;
512 }
513
514 _followerIds.insert(garrFollowerId);
515 uint64 dbId = sGarrisonMgr.GenerateFollowerDbId();
516 Follower& follower = _followers[dbId];
517 follower.PacketInfo.DbID = dbId;
518 follower.PacketInfo.GarrFollowerID = garrFollowerId;
519 follower.PacketInfo.Quality = followerEntry->Quality; // TODO: handle magic upgrades
520 follower.PacketInfo.FollowerLevel = followerEntry->FollowerLevel;
521 follower.PacketInfo.ItemLevelWeapon = followerEntry->ItemLevelWeapon;
522 follower.PacketInfo.ItemLevelArmor = followerEntry->ItemLevelArmor;
523 follower.PacketInfo.Xp = 0;
524 follower.PacketInfo.CurrentBuildingID = 0;
525 follower.PacketInfo.CurrentMissionID = 0;
526 follower.PacketInfo.AbilityID = sGarrisonMgr.RollFollowerAbilities(garrFollowerId, followerEntry, follower.PacketInfo.Quality, GetFaction(), true);
527 follower.PacketInfo.FollowerStatus = 0;
528
529 addFollowerResult.Follower = follower.PacketInfo;
530 _owner->SendDirectMessage(addFollowerResult.Write());
531
533}
534
536{
537 auto itr = _followers.find(dbId);
538 if (itr != _followers.end())
539 return &itr->second;
540
541 return nullptr;
542}
543
545{
547 garrisonInfo.FactionIndex = GetFaction();
548 garrisonInfo.Garrisons.emplace_back();
549
550 WorldPackets::Garrison::GarrisonInfo& garrison = garrisonInfo.Garrisons.back();
551 garrison.GarrTypeID = GetType();
552 garrison.GarrSiteID = _siteLevel->GarrSiteID;
553 garrison.GarrSiteLevelID = _siteLevel->ID;
555 for (auto& p : _plots)
556 {
557 Plot& plot = p.second;
558 garrison.Plots.push_back(&plot.PacketInfo);
559 if (plot.BuildingInfo.PacketInfo)
560 garrison.Buildings.push_back(&*plot.BuildingInfo.PacketInfo);
561 }
562
563 for (auto const& p : _followers)
564 garrison.Followers.push_back(&p.second.PacketInfo);
565
566 _owner->SendDirectMessage(garrisonInfo.Write());
567}
568
570{
571 MapEntry const* garrisonMap = sMapStore.LookupEntry(_siteLevel->MapID);
572 if (!garrisonMap || int32(_owner->GetMapId()) != garrisonMap->ParentMapID)
573 return;
574
576 remoteInfo.Sites.resize(1);
577
578 WorldPackets::Garrison::GarrisonRemoteSiteInfo& remoteSiteInfo = remoteInfo.Sites[0];
579 remoteSiteInfo.GarrSiteLevelID = _siteLevel->ID;
580 for (auto const& p : _plots)
581 if (p.second.BuildingInfo.PacketInfo)
582 remoteSiteInfo.Buildings.emplace_back(p.first, p.second.BuildingInfo.PacketInfo->GarrBuildingID);
583
584 _owner->SendDirectMessage(remoteInfo.Write());
585}
586
588{
590 data.GarrTypeID = GetType();
593}
594
595void Garrison::SendMapData(Player* receiver) const
596{
598 mapData.Buildings.reserve(_plots.size());
599
600 for (auto const& p : _plots)
601 {
602 Plot const& plot = p.second;
603 if (plot.BuildingInfo.PacketInfo)
604 if (uint32 garrBuildingPlotInstId = sGarrisonMgr.GetGarrBuildingPlotInst(plot.BuildingInfo.PacketInfo->GarrBuildingID, plot.GarrSiteLevelPlotInstId))
605 mapData.Buildings.emplace_back(garrBuildingPlotInstId, plot.PacketInfo.PlotPos.Pos);
606 }
607
608 receiver->SendDirectMessage(mapData.Write());
609}
610
612{
613 return sMapMgr->FindMap(_siteLevel->MapID, _owner->GetGUID().GetCounter());
614}
615
616GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const
617{
618 GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId);
619 Plot const* plot = GetPlot(garrPlotInstanceId);
620 if (!plotInstance || !plot)
622
623 GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(garrBuildingId);
624 if (!building)
626
627 if (!sGarrisonMgr.IsPlotMatchingBuilding(plotInstance->GarrPlotID, garrBuildingId))
629
630 // Cannot place buldings of higher level than garrison level
633
635 {
636 if (!HasBlueprint(garrBuildingId))
638 }
639 else // Building is built as a quest reward
641
642 // Check all plots to find if we already have this building
643 GarrBuildingEntry const* existingBuilding;
644 for (auto const& p : _plots)
645 {
646 if (p.second.BuildingInfo.PacketInfo)
647 {
648 existingBuilding = sGarrBuildingStore.AssertEntry(p.second.BuildingInfo.PacketInfo->GarrBuildingID);
649 if (existingBuilding->BuildingType == building->BuildingType)
650 if (p.first != garrPlotInstanceId || existingBuilding->UpgradeLevel + 1 != building->UpgradeLevel) // check if its an upgrade in same plot
652 }
653 }
654
655 if (!_owner->HasCurrency(building->CurrencyTypeID, building->CurrencyQty))
657
658 if (!_owner->HasEnoughMoney(uint64(building->GoldCost) * GOLD))
660
661 // New building cannot replace another building currently under construction
662 if (plot->BuildingInfo.PacketInfo)
663 if (!plot->BuildingInfo.PacketInfo->Active)
665
666 return GARRISON_SUCCESS;
667}
668
670{
671 Plot const* plot = GetPlot(garrPlotInstanceId);
672 if (!plot)
674
675 if (!plot->BuildingInfo.PacketInfo)
677
678 if (plot->BuildingInfo.CanActivate())
680
681 return GARRISON_SUCCESS;
682}
683
684template<class T, void(T::*SecondaryRelocate)(float,float,float,float)>
686{
687 T* spawn = new T();
688 if (!spawn->LoadFromDB(spawnId, map, false, false))
689 {
690 delete spawn;
691 return nullptr;
692 }
693
694 float x = spawn->GetPositionX();
695 float y = spawn->GetPositionY();
696 float z = spawn->GetPositionZ();
697 float o = spawn->GetOrientation();
698 TransportBase::CalculatePassengerPosition(x, y, z, &o, building->GetPositionX(), building->GetPositionY(), building->GetPositionZ(), building->GetOrientation());
699
700 spawn->Relocate(x, y, z, o);
701 (spawn->*SecondaryRelocate)(x, y, z, o);
702
703 if (!spawn->IsPositionValid())
704 {
705 delete spawn;
706 return nullptr;
707 }
708
709 if (!map->AddToMap(spawn))
710 {
711 delete spawn;
712 return nullptr;
713 }
714
715 return spawn;
716}
717
719{
722 {
724 GarrPlotEntry const* plot = sGarrPlotStore.AssertEntry(plotInstance->GarrPlotID);
725 GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(BuildingInfo.PacketInfo->GarrBuildingID);
727 if (BuildingInfo.PacketInfo->Active || !entry)
728 entry = faction == GARRISON_FACTION_INDEX_HORDE ? building->HordeGameObjectID : building->AllianceGameObjectID;
729 }
730
731 if (!sObjectMgr->GetGameObjectTemplate(entry))
732 {
733 TC_LOG_ERROR("garrison", "Garrison attempted to spawn gameobject whose template doesn't exist ({})", entry);
734 return nullptr;
735 }
736
738 if (!building)
739 return nullptr;
740
742 {
743 if (FinalizeGarrisonPlotGOInfo const* finalizeInfo = sGarrisonMgr.GetPlotFinalizeGOInfo(PacketInfo.GarrPlotInstanceID))
744 {
745 Position const& pos2 = finalizeInfo->FactionInfo[faction].Pos;
746 if (GameObject* finalizer = GameObject::CreateGameObject(finalizeInfo->FactionInfo[faction].GameObjectId, map, pos2, QuaternionData::fromEulerAnglesZYX(pos2.GetOrientation(), 0.0f, 0.0f), 255, GO_STATE_READY))
747 {
748 // set some spell id to make the object delete itself after use
749 finalizer->SetSpellId(finalizer->GetGOInfo()->goober.spell);
750 finalizer->SetRespawnTime(0);
751
752 if (uint16 animKit = finalizeInfo->FactionInfo[faction].AnimKitId)
753 finalizer->SetAnimKitId(animKit, false);
754
755 map->AddToMap(finalizer);
756 }
757 }
758 }
759
761 {
762 if (CellObjectGuidsMap const* cells = sObjectMgr->GetMapObjectGuids(building->GetGOInfo()->garrisonBuilding.SpawnMap, map->GetDifficultyID()))
763 {
764 for (auto const& [cellId, guids] : *cells)
765 {
766 for (ObjectGuid::LowType spawnId : guids.gameobjects)
767 if (GameObject* spawn = BuildingSpawnHelper<GameObject, &GameObject::RelocateStationaryPosition>(building, spawnId, map))
768 BuildingInfo.Spawns.insert(spawn->GetGUID());
769
770 for (ObjectGuid::LowType spawnId : guids.creatures)
771 if (Creature* spawn = BuildingSpawnHelper<Creature, &Creature::SetHomePosition>(building, spawnId, map))
772 BuildingInfo.Spawns.insert(spawn->GetGUID());
773 }
774 }
775 }
776
777 BuildingInfo.Guid = building->GetGUID();
778 return building;
779}
780
782{
783 if (BuildingInfo.Guid.IsEmpty())
784 return;
785
786 for (ObjectGuid const& guid : BuildingInfo.Spawns)
787 {
788 WorldObject* object = nullptr;
789 switch (guid.GetHigh())
790 {
792 object = map->GetCreature(guid);
793 break;
795 object = map->GetGameObject(guid);
796 break;
797 default:
798 continue;
799 }
800
801 if (object)
802 object->AddObjectToRemoveList();
803 }
804
805 BuildingInfo.Spawns.clear();
806
807 if (GameObject* oldBuilding = map->GetGameObject(BuildingInfo.Guid))
808 oldBuilding->Delete();
809
810 BuildingInfo.Guid.Clear();
811}
812
814{
816 plotPlaced.GarrTypeID = garrisonType;
817 plotPlaced.PlotInfo = &PacketInfo;
818 owner->SendDirectMessage(plotPlaced.Write());
819
820 BuildingInfo.PacketInfo.reset();
821}
822
824{
825 if (!BuildingInfo.PacketInfo)
826 {
828 plotRemoved.GarrPlotInstanceID = PacketInfo.GarrPlotInstanceID;
829 owner->SendDirectMessage(plotRemoved.Write());
830 }
831
832 BuildingInfo.PacketInfo = buildingInfo;
833}
834
836{
837 if (PacketInfo)
838 {
839 GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(PacketInfo->GarrBuildingID);
840 if (PacketInfo->TimeBuilt + building->BuildSeconds <= GameTime::GetGameTime())
841 return true;
842 }
843
844 return false;
845}
846
848{
849 return (PacketInfo.ItemLevelWeapon + PacketInfo.ItemLevelArmor) / 2;
850}
851
852bool Garrison::Follower::HasAbility(uint32 garrAbilityId) const
853{
854 return std::find_if(PacketInfo.AbilityID.begin(), PacketInfo.AbilityID.end(), [garrAbilityId](GarrAbilityEntry const* garrAbility)
855 {
856 return garrAbility->ID == garrAbilityId;
857 }) != PacketInfo.AbilityID.end();
858}
@ 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.
Definition: DatabaseEnv.cpp:21
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define ASSERT
Definition: Errors.h:68
#define sGarrisonMgr
Definition: GarrisonMgr.h:88
T * BuildingSpawnHelper(GameObject *building, ObjectGuid::LowType spawnId, Map *map)
Definition: Garrison.cpp:685
GarrisonFactionIndex
Definition: Garrison.h:42
@ GARRISON_FACTION_INDEX_HORDE
Definition: Garrison.h:43
@ GARRISON_FACTION_INDEX_ALLIANCE
Definition: Garrison.h:44
GarrisonType
Definition: Garrison.h:34
@ GARRISON_BUILDING_FLAG_NEEDS_PLAN
Definition: Garrison.h:49
GarrisonError
Definition: Garrison.h:82
@ GARRISON_ERROR_REQUIRES_BLUEPRINT
Definition: Garrison.h:105
@ GARRISON_ERROR_INVALID_BUILDINGID
Definition: Garrison.h:94
@ GARRISON_SUCCESS
Definition: Garrison.h:83
@ GARRISON_ERROR_INVALID_PLOT_BUILDING
Definition: Garrison.h:99
@ GARRISON_ERROR_INVALID_PLOT_INSTANCEID
Definition: Garrison.h:93
@ GARRISON_ERROR_NOT_ENOUGH_CURRENCY
Definition: Garrison.h:129
@ GARRISON_ERROR_BUILDING_EXISTS
Definition: Garrison.h:92
@ GARRISON_ERROR_NO_BUILDING
Definition: Garrison.h:91
@ GARRISON_ERROR_NOT_ENOUGH_GOLD
Definition: Garrison.h:130
@ GARRISON_ERROR_FOLLOWER_EXISTS
Definition: Garrison.h:110
@ GARRISON_ERROR_BLUEPRINT_EXISTS
Definition: Garrison.h:104
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sMapMgr
Definition: MapManager.h:184
std::unordered_map< uint32, CellObjectGuids > CellObjectGuidsMap
Definition: ObjectMgr.h:485
#define sObjectMgr
Definition: ObjectMgr.h:1946
@ TELE_TO_SEAMLESS
Definition: Player.h:809
@ GAMEOBJECT_TYPE_GARRISON_BUILDING
@ HORDE
@ GOLD
@ GO_STATE_READY
Class used to access individual fields of database query result.
Definition: Field.h:90
int64 GetInt64() const
Definition: Field.cpp:86
uint64 GetUInt64() const
Definition: Field.cpp:78
bool GetBool() const
Definition: Field.h:98
uint32 GetUInt32() const
Definition: Field.cpp:62
GameObjectTemplate const * GetGOInfo() const
Definition: GameObject.h:202
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:279
void SendRemoteInfo() const
Definition: Garrison.cpp:569
GarrisonError CheckBuildingRemoval(uint32 garrPlotInstanceId) const
Definition: Garrison.cpp:669
void SendBlueprintAndSpecializationData()
Definition: Garrison.cpp:587
GarrSiteLevelEntry const * _siteLevel
Definition: Garrison.h:275
std::unordered_map< uint64, Follower > _followers
Definition: Garrison.h:280
void SaveToDB(CharacterDatabaseTransaction trans)
Definition: Garrison.cpp:144
std::unordered_set< uint32 > _followerIds
Definition: Garrison.h:281
bool Create(uint32 garrSiteId)
Definition: Garrison.cpp:226
void InitializePlots()
Definition: Garrison.cpp:256
Follower const * GetFollower(uint64 dbId) const
Definition: Garrison.cpp:535
GarrisonType GetType() const
Definition: Garrison.h:232
void UnlearnBlueprint(uint32 garrBuildingId)
Definition: Garrison.cpp:363
void CancelBuildingConstruction(uint32 garrPlotInstanceId)
Definition: Garrison.cpp:429
bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings, PreparedQueryResult followers, PreparedQueryResult abilities)
Definition: Garrison.cpp:37
void AddFollower(uint32 garrFollowerId)
Definition: Garrison.cpp:502
void PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId)
Definition: Garrison.cpp:380
GarrisonFactionIndex GetFaction() const
Definition: Garrison.cpp:313
void Delete()
Definition: Garrison.cpp:244
void Enter() const
Definition: Garrison.cpp:287
Plot * GetPlot(uint32 garrPlotInstanceId)
Definition: Garrison.cpp:328
void SendInfo()
Definition: Garrison.cpp:544
GarrisonError CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const
Definition: Garrison.cpp:616
void LearnBlueprint(uint32 garrBuildingId)
Definition: Garrison.cpp:346
bool HasBlueprint(uint32 garrBuildingId) const
Definition: Garrison.h:243
std::unordered_map< uint32, Plot > _plots
Definition: Garrison.h:278
std::unordered_set< uint32 > _knownBuildings
Definition: Garrison.h:279
Garrison(Player *owner)
Definition: Garrison.cpp:33
void SendMapData(Player *receiver) const
Definition: Garrison.cpp:595
static void DeleteFromDB(ObjectGuid::LowType ownerGuid, CharacterDatabaseTransaction trans)
Definition: Garrison.cpp:207
void ActivateBuilding(uint32 garrPlotInstanceId)
Definition: Garrison.cpp:479
Player * _owner
Definition: Garrison.h:274
uint32 _followerActivationsRemainingToday
Definition: Garrison.h:276
Map * FindMap() const
Definition: Garrison.cpp:611
void Upgrade()
Definition: Garrison.cpp:283
void Leave() const
Definition: Garrison.cpp:300
std::vector< Plot * > GetPlots()
Definition: Garrison.cpp:318
Definition: Map.h:189
bool AddToMap(T *)
Definition: Map.cpp:550
GameObject * GetGameObject(ObjectGuid const &guid)
Definition: Map.cpp:3489
Difficulty GetDifficultyID() const
Definition: Map.h:324
Creature * GetCreature(ObjectGuid const &guid)
Definition: Map.cpp:3479
LowType GetCounter() const
Definition: ObjectGuid.h:293
uint64 LowType
Definition: ObjectGuid.h:278
HighGuid GetHigh() const
Definition: ObjectGuid.h:288
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static bool OnConditionChange(WorldObject *object, bool updateVisibility=true)
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
bool HasCurrency(uint32 id, uint32 amount) const
Definition: Player.cpp:7413
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
void RemoveCurrency(uint32 id, int32 amount, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Definition: Player.cpp:7253
void AddCurrency(uint32 id, uint32 amount, CurrencyGainSource gainSource=CurrencyGainSource::Cheat)
Definition: Player.cpp:7248
Team GetTeam() const
Definition: Player.h:2235
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
void setUInt8(const uint8 index, const uint8 value)
void setInt64(const uint8 index, const int64 value)
void setBool(const uint8 index, const bool value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt64(const uint8 index, const uint64 value)
virtual void CalculatePassengerPosition(float &x, float &y, float &z, float *o=nullptr) const =0
This method transforms supplied transport offsets into global coordinates.
constexpr uint32 GetMapId() const
Definition: Position.h:201
void AddObjectToRemoveList()
Definition: Object.cpp:1824
std::vector< GarrisonBuildingMapData > Buildings
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< GarrisonRemoteSiteInfo > Sites
time_t GetGameTime()
Definition: GameTime.cpp:44
struct GameObjectTemplate::@213::@253 garrisonBuilding
std::array< float, 4 > Rot
DBCPosition3D Pos
int32 HordeConstructObjID
int32 AllianceConstructObjID
ObjectGuid Guid
Definition: Garrison.h:190
bool CanActivate() const
Definition: Garrison.cpp:835
Optional< WorldPackets::Garrison::GarrisonBuildingInfo > PacketInfo
Definition: Garrison.h:192
std::unordered_set< ObjectGuid > Spawns
Definition: Garrison.h:191
WorldPackets::Garrison::GarrisonFollower PacketInfo
Definition: Garrison.h:214
bool HasAbility(uint32 garrAbilityId) const
Definition: Garrison.cpp:852
uint32 GetItemLevel() const
Definition: Garrison.cpp:847
QuaternionData Rotation
Definition: Garrison.h:203
WorldPackets::Garrison::GarrisonPlotInfo PacketInfo
Definition: Garrison.h:202
GameObject * CreateGameObject(Map *map, GarrisonFactionIndex faction)
Definition: Garrison.cpp:718
void SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const &buildingInfo, Player *owner)
Definition: Garrison.cpp:823
uint32 EmptyGameObjectId
Definition: Garrison.h:204
Building BuildingInfo
Definition: Garrison.h:206
void DeleteGameObject(Map *map)
Definition: Garrison.cpp:781
void ClearBuildingInfo(GarrisonType garrisonType, Player *owner)
Definition: Garrison.cpp:813
uint32 GarrSiteLevelPlotInstId
Definition: Garrison.h:205
int16 ParentMapID
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr void Relocate(float x, float y)
Definition: Position.h:63
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
static QuaternionData fromEulerAnglesZYX(float Z, float Y, float X)
Definition: GameObject.cpp:118
Position Pos
Definition: Position.h:236
std::list< GarrAbilityEntry const * > AbilityID
std::vector< GarrisonPlotInfo * > Plots
std::vector< GarrisonFollower const * > Followers
std::vector< GarrisonBuildingInfo const * > Buildings
TaggedPosition< Position::XYZO > PlotPos
std::vector< GarrisonRemoteBuildingInfo > Buildings