1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
|
/*
* This file is part of the TrinityCore 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/>.
*/
#ifndef Loot_h__
#define Loot_h__
#include "ConditionMgr.h"
#include "DBCEnums.h"
#include "Define.h"
#include "Duration.h"
#include "ItemEnchantmentMgr.h"
#include "LootItemType.h"
#include "ObjectGuid.h"
#include "Optional.h"
#include "SharedDefines.h"
#include <memory>
#include <unordered_map>
#include <vector>
constexpr Minutes LOOT_ROLL_TIMEOUT = 1min;
class Group;
class Item;
class LootStore;
class Map;
class Player;
struct ItemDisenchantLootEntry;
struct Loot;
struct LootStoreItem;
namespace WorldPackets
{
namespace Loot
{
struct LootItemData;
class LootResponse;
}
}
enum RollType
{
ROLL_PASS = 0,
ROLL_NEED = 1,
ROLL_GREED = 2,
ROLL_DISENCHANT = 3,
ROLL_TRANSMOG = 4,
MAX_ROLL_TYPE = 5
};
enum class RollVote
{
Pass = 0,
Need = 1,
Greed = 2,
Disenchant = 3,
NotEmitedYet = 4,
NotValid = 5
};
enum RollMask
{
ROLL_FLAG_TYPE_PASS = 0x01,
ROLL_FLAG_TYPE_NEED = 0x02,
ROLL_FLAG_TYPE_GREED = 0x04,
ROLL_FLAG_TYPE_DISENCHANT = 0x08,
ROLL_FLAG_TYPE_TRANSMOG = 0x10,
ROLL_ALL_TYPE_NO_DISENCHANT = 0x07,
ROLL_ALL_TYPE_MASK = 0x0F
};
#define MAX_NR_LOOT_ITEMS 18
enum LootMethod : uint8
{
FREE_FOR_ALL = 0,
ROUND_ROBIN = 1,
MASTER_LOOT = 2,
GROUP_LOOT = 3,
NEED_BEFORE_GREED = 4,
PERSONAL_LOOT = 5
};
enum LootType : uint8
{
LOOT_NONE = 0,
LOOT_CORPSE = 1,
LOOT_PICKPOCKETING = 2,
LOOT_FISHING = 3,
LOOT_DISENCHANTING = 4,
LOOT_ITEM = 5,
LOOT_SKINNING = 6,
LOOT_GATHERING_NODE = 8,
LOOT_CHEST = 9,
LOOT_CORPSE_PERSONAL = 14,
LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead
LOOT_INSIGNIA = 21, // unsupported by client, sending LOOT_CORPSE instead
LOOT_FISHING_JUNK = 22, // unsupported by client, sending LOOT_FISHING instead
LOOT_PROSPECTING = 23,
LOOT_MILLING = 24,
};
constexpr LootType GetLootTypeForClient(LootType lootType)
{
switch (lootType)
{
case LOOT_PROSPECTING:
case LOOT_MILLING:
return LOOT_DISENCHANTING;
case LOOT_INSIGNIA:
return LOOT_SKINNING;
case LOOT_FISHINGHOLE:
case LOOT_FISHING_JUNK:
return LOOT_FISHING;
default:
break;
}
return lootType;
}
enum LootError : uint8
{
LOOT_ERROR_DIDNT_KILL = 0, // You don't have permission to loot that corpse.
LOOT_ERROR_TOO_FAR = 4, // You are too far away to loot that corpse.
LOOT_ERROR_BAD_FACING = 5, // You must be facing the corpse to loot it.
LOOT_ERROR_LOCKED = 6, // Someone is already looting that corpse.
LOOT_ERROR_NOTSTANDING = 8, // You need to be standing up to loot something!
LOOT_ERROR_STUNNED = 9, // You can't loot anything while stunned!
LOOT_ERROR_PLAYER_NOT_FOUND = 10, // Player not found
LOOT_ERROR_PLAY_TIME_EXCEEDED = 11, // Maximum play time exceeded
LOOT_ERROR_MASTER_INV_FULL = 12, // That player's inventory is full
LOOT_ERROR_MASTER_UNIQUE_ITEM = 13, // Player has too many of that item already
LOOT_ERROR_MASTER_OTHER = 14, // Can't assign item to that player
LOOT_ERROR_ALREADY_PICKPOCKETED = 15, // Your target has already had its pockets picked
LOOT_ERROR_NOT_WHILE_SHAPESHIFTED = 16, // You can't do that while shapeshifted.
LOOT_ERROR_NO_LOOT = 17 // There is no loot.
};
// type of Loot Item in Loot View
enum LootSlotType
{
LOOT_SLOT_TYPE_ALLOW_LOOT = 0, // player can loot the item.
LOOT_SLOT_TYPE_ROLL_ONGOING = 1, // roll is ongoing. player cannot loot.
LOOT_SLOT_TYPE_MASTER = 3, // item can only be distributed by group loot master.
LOOT_SLOT_TYPE_LOCKED = 2, // item is shown in red. player cannot loot.
LOOT_SLOT_TYPE_OWNER = 4 // ignore binding confirmation and etc, for single player looting
};
enum class LootRollIneligibilityReason : uint32
{
None = 0,
UnusableByClass = 1, // Your class may not roll need on this item.
MaxUniqueItemCount = 2, // You already have the maximum amount of this item.
CannotBeDisenchanted = 3, // This item may not be disenchanted.
EnchantingSkillTooLow = 4, // You do not have an Enchanter of skill %d in your group.
NeedDisabled = 5, // Need rolls are disabled for this item.
OwnBetterItem = 6 // You already have a powerful version of this item.
};
struct TC_GAME_API LootItem
{
uint32 itemid = 0;
uint32 LootListId = 0;
ItemRandomBonusListId randomBonusListId = 0;
std::vector<int32> BonusListIDs;
ItemContext context = ItemContext::NONE;
ConditionsReference conditions; // additional loot condition
GuidSet allowedGUIDs;
ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list!
uint32 count = 0;
LootItemType type = LootItemType::Item;
bool is_looted : 1 = false;
bool is_blocked : 1 = false;
bool freeforall : 1 = false; // free for all
bool is_underthreshold : 1 = false;
bool is_counted : 1 = false;
bool needs_quest : 1 = false; // quest drop
bool follow_loot_rules : 1 = false;
// Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties
// Should be called for non-reference LootStoreItem entries only
explicit LootItem(LootStoreItem const& li);
// Empty constructor for creating an empty LootItem to be filled in with DB data
LootItem() = default;
LootItem(LootItem const&);
LootItem(LootItem&&) noexcept;
LootItem& operator=(LootItem const&);
LootItem& operator=(LootItem&&) noexcept;
~LootItem();
// Basic checks for player/item compatibility - if false no chance to see the item in the loot - used only for loot generation
bool AllowedForPlayer(Player const* player, Loot const* loot) const;
static bool AllowedForPlayer(Player const* player, LootStoreItem const& lootStoreItem, bool strictUsabilityCheck);
static bool ItemAllowedForPlayer(Player const* player, Loot const* loot, uint32 itemid, bool needs_quest, bool follow_loot_rules, bool strictUsabilityCheck,
ConditionsReference const& conditions);
static bool CurrencyAllowedForPlayer(Player const* player, uint32 currencyId, bool needs_quest, ConditionsReference const& conditions);
static bool TrackingQuestAllowedForPlayer(Player const* player, uint32 questId, ConditionsReference const& conditions);
void AddAllowedLooter(Player const* player);
GuidSet const& GetAllowedLooters() const { return allowedGUIDs; }
bool HasAllowedLooter(ObjectGuid const& looter) const;
Optional<LootSlotType> GetUiTypeForPlayer(Player const* player, Loot const& loot) const;
};
struct NotNormalLootItem
{
uint8 LootListId;
bool is_looted;
NotNormalLootItem()
: LootListId(0), is_looted(false) { }
NotNormalLootItem(uint8 _index, bool _islooted = false)
: LootListId(_index), is_looted(_islooted) { }
};
typedef std::vector<NotNormalLootItem> NotNormalLootItemList;
typedef std::vector<LootItem> LootItemList;
typedef std::unordered_map<ObjectGuid, std::unique_ptr<NotNormalLootItemList>> NotNormalLootItemMap;
//=====================================================
struct PlayerRollVote
{
PlayerRollVote() : Vote(RollVote::NotValid), RollNumber(0) { }
RollVote Vote;
uint8 RollNumber;
};
class LootRoll
{
public:
using RollVoteMap = std::unordered_map<ObjectGuid, PlayerRollVote>;
LootRoll() : m_map(nullptr), m_isStarted(false), m_lootItem(nullptr), m_loot(nullptr), m_voteMask(), m_endTime(TimePoint::min()) { }
~LootRoll();
LootRoll(LootRoll const&) = delete;
LootRoll(LootRoll&&) = delete;
LootRoll& operator=(LootRoll const&) = delete;
LootRoll& operator=(LootRoll&&) = delete;
bool TryToStart(Map* map, Loot& loot, uint32 lootListId, uint16 enchantingSkill);
bool PlayerVote(Player* player, RollVote vote);
bool UpdateRoll();
bool IsLootItem(ObjectGuid const& lootObject, uint32 lootListId) const;
private:
void SendStartRoll();
void SendAllPassed();
void SendRoll(ObjectGuid const& targetGuid, int32 rollNumber, RollVote rollType, Optional<ObjectGuid> const& rollWinner);
void SendLootRollWon(ObjectGuid const& targetGuid, int32 rollNumber, RollVote rollType);
void FillPacket(WorldPackets::Loot::LootItemData& lootItem) const;
void Finish(RollVoteMap::const_iterator winnerItr);
bool AllPlayerVoted(RollVoteMap::const_iterator& winnerItr);
Optional<uint32> GetItemDisenchantLootId() const;
Optional<uint16> GetItemDisenchantSkillRequired() const;
Map* m_map;
RollVoteMap m_rollVoteMap;
bool m_isStarted;
LootItem* m_lootItem;
Loot* m_loot;
RollMask m_voteMask;
TimePoint m_endTime;
};
struct TC_GAME_API Loot
{
NotNormalLootItemMap const& GetPlayerFFAItems() const { return PlayerFFAItems; }
std::vector<LootItem> items;
uint32 gold;
uint8 unlootedCount;
ObjectGuid roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released.
LootType loot_type; // required for achievement system
explicit Loot(Map* map, ObjectGuid owner, LootType type, Group const* group);
~Loot();
Loot(Loot const&) = delete;
Loot(Loot&&) = delete;
Loot& operator=(Loot const&) = delete;
Loot& operator=(Loot&&) = delete;
ObjectGuid const& GetGUID() const { return _guid; }
ObjectGuid const& GetOwnerGUID() const { return _owner; }
ItemContext GetItemContext() const { return _itemContext; }
void SetItemContext(ItemContext context) { _itemContext = context; }
LootMethod GetLootMethod() const { return _lootMethod; }
ObjectGuid const& GetLootMasterGUID() const { return _lootMaster; }
uint32 GetDungeonEncounterId() const { return _dungeonEncounterId; }
void SetDungeonEncounterId(uint32 dungeonEncounterId) { _dungeonEncounterId = dungeonEncounterId; }
bool isLooted() const { return gold == 0 && unlootedCount == 0; }
bool IsChanged() const { return _changed; }
void NotifyLootList(Map const* map) const;
void NotifyItemRemoved(uint8 lootListId, Map const* map);
void NotifyMoneyRemoved(Map const* map);
void OnLootOpened(Map* map, Player* looter);
void AddLooter(ObjectGuid GUID) { PlayersLooting.insert(GUID); }
void RemoveLooter(ObjectGuid GUID) { PlayersLooting.erase(GUID); }
bool HasAllowedLooter(ObjectGuid const& looter) const;
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount);
bool FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError = false, uint16 lootMode = LOOT_MODE_DEFAULT, ItemContext context = ItemContext::NONE);
void FillNotNormalLootFor(Player* player); // count unlooted items
// Inserts the item into the loot (called by LootTemplate processors)
void AddItem(LootStoreItem const& item);
bool AutoStore(Player* player, uint8 bag, uint8 slot, bool broadcast = false, bool createdByPlayer = false);
void AutoStoreTrackingQuests(Player* player, NotNormalLootItemList& ffaItems);
void LootMoney();
LootItem const* GetItemInSlot(uint32 lootListId) const;
LootItem* LootItemInSlot(uint32 lootListId, Player const* player, NotNormalLootItem** ffaItem = nullptr);
bool hasItemForAll() const;
bool hasItemFor(Player const* player) const;
bool hasOverThresholdItem() const;
// Builds data for SMSG_LOOT_RESPONSE
void BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player const* viewer) const;
void Update();
private:
GuidSet PlayersLooting;
NotNormalLootItemMap PlayerFFAItems;
// Loot GUID
ObjectGuid _guid;
ObjectGuid _owner; // The WorldObject that holds this loot
ItemContext _itemContext;
LootMethod _lootMethod;
std::unordered_map<uint32, LootRoll> _rolls; // used if an item is under rolling
ObjectGuid _lootMaster;
GuidUnorderedSet _allowedLooters;
bool _wasOpened; // true if at least one player received the loot content
bool _changed;
uint32 _dungeonEncounterId;
};
class TC_GAME_API AELootResult
{
public:
struct ResultValue
{
Item* item;
uint8 count;
LootType lootType;
uint32 dungeonEncounterId;
};
typedef std::vector<ResultValue> OrderedStorage;
void Add(Item* item, uint8 count, LootType lootType, uint32 dungeonEncounterId);
OrderedStorage::const_iterator begin() const;
OrderedStorage::const_iterator end() const;
OrderedStorage _byOrder;
std::unordered_map<Item*, OrderedStorage::size_type> _byItem;
};
#endif // Loot_h__
|