diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua
index 628ff2f7bd..cac20da97e 100644
--- a/data/events/scripts/player.lua
+++ b/data/events/scripts/player.lua
@@ -182,20 +182,6 @@ function Player:onLook(thing, position, distance)
description = string.format("%s, Unique ID: %d", description, uniqueId)
end
- if thing:isContainer() then
- local quickLootCategories = {}
- local container = Container(thing.uid)
- for categoryId = LOOT_START, LOOT_END do
- if container ~= nil then
- if container:hasQuickLootCategory(categoryId) then
- table.insert(quickLootCategories, categoryId)
- end
- end
- end
-
- description = string.format("%s, QuickLootCategory: (%s)", description, table.concat(quickLootCategories, ", "))
- end
-
local itemType = thing:getType()
local transformEquipId = itemType:getTransformEquipId()
@@ -436,16 +422,6 @@ function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder,
-- Handle move items to the ground
if toPosition.x ~= CONTAINER_POSITION then
- if item:isContainer() then
- local container = Container(item.uid)
- for categoryId = LOOT_START, LOOT_END do
- if container:hasQuickLootCategory(categoryId) then
- container:removeQuickLootCategory(categoryId)
- self:setQuickLootBackpack(categoryId, nil)
- end
- end
- end
-
return true
end
diff --git a/data/items/items.xml b/data/items/items.xml
index f99fd6fbeb..74629370f5 100644
--- a/data/items/items.xml
+++ b/data/items/items.xml
@@ -427,7 +427,7 @@
-
+
@@ -954,6 +954,7 @@
-
+
-
@@ -1295,6 +1296,7 @@
-
+
-
@@ -1347,14 +1349,14 @@
-
-
+
-
-
+
@@ -1393,33 +1395,33 @@
-
-
+
-
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
-
@@ -1476,7 +1478,7 @@
-
-
+
-
@@ -1510,28 +1512,28 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -1627,7 +1629,7 @@
-
-
+
@@ -1640,12 +1642,12 @@
-
-
+
-
-
+
@@ -1674,7 +1676,7 @@
-
-
+
@@ -1706,37 +1708,37 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -1759,7 +1761,7 @@
-
-
+
@@ -1775,7 +1777,7 @@
-
-
+
@@ -1793,7 +1795,7 @@
-
-
+
@@ -1844,7 +1846,7 @@
-
-
+
@@ -1854,22 +1856,22 @@
-
-
+
-
-
+
-
-
+
-
-
-
+
-
@@ -1981,25 +1983,25 @@
-
-
+
-
-
+
-
-
+
-
-
-
+
-
@@ -2023,7 +2025,7 @@
-
-
+
-
@@ -2031,71 +2033,71 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -2103,112 +2105,112 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -2224,7 +2226,7 @@
-
-
+
@@ -2233,7 +2235,7 @@
-
-
+
@@ -2241,7 +2243,7 @@
-
-
+
@@ -2249,7 +2251,7 @@
-
-
+
@@ -2257,7 +2259,7 @@
-
-
+
@@ -2265,7 +2267,7 @@
-
-
+
@@ -2273,7 +2275,7 @@
-
-
+
@@ -2284,12 +2286,12 @@
-
+
-
-
+
@@ -2298,12 +2300,12 @@
-
-
+
-
-
-
+
+
-
@@ -2311,32 +2313,32 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -2344,7 +2346,7 @@
-
+
@@ -2352,19 +2354,19 @@
-
+
-
-
+
-
-
+
@@ -2372,7 +2374,7 @@
-
+
@@ -2380,7 +2382,7 @@
-
+
@@ -2388,7 +2390,7 @@
-
+
@@ -2396,7 +2398,7 @@
-
+
@@ -2404,7 +2406,7 @@
-
+
@@ -2412,27 +2414,27 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -2440,12 +2442,12 @@
-
-
+
-
-
+
@@ -2455,7 +2457,7 @@
-
-
+
@@ -2464,7 +2466,7 @@
-
-
+
@@ -2473,7 +2475,7 @@
-
-
+
@@ -2482,7 +2484,7 @@
-
-
+
@@ -2491,7 +2493,7 @@
-
-
+
@@ -2502,7 +2504,7 @@
-
-
+
@@ -2512,7 +2514,7 @@
-
-
+
@@ -2523,7 +2525,7 @@
-
-
+
@@ -2537,7 +2539,7 @@
-
-
+
@@ -2548,7 +2550,7 @@
-
-
+
@@ -2556,7 +2558,7 @@
-
-
+
@@ -2564,7 +2566,7 @@
-
-
+
@@ -2572,7 +2574,7 @@
-
-
+
@@ -2582,7 +2584,7 @@
-
-
+
@@ -2592,7 +2594,7 @@
-
-
+
@@ -2602,7 +2604,7 @@
-
-
+
@@ -2610,7 +2612,7 @@
-
-
+
@@ -2618,7 +2620,7 @@
-
-
+
@@ -2629,7 +2631,7 @@
-
-
+
@@ -2645,19 +2647,19 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -2670,11 +2672,11 @@
-
-
+
-
-
+
-
@@ -2684,11 +2686,11 @@
-
-
+
-
-
+
-
@@ -2701,25 +2703,25 @@
-
-
+
-
-
-
+
-
-
-
+
-
-
+
-
@@ -2729,11 +2731,11 @@
-
-
+
-
-
+
-
@@ -2743,7 +2745,7 @@
-
-
+
-
@@ -2754,296 +2756,296 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -3065,7 +3067,7 @@
-
+
-
@@ -3077,7 +3079,7 @@
-
+
-
@@ -3151,14 +3153,14 @@
-
+
-
-
+
@@ -3174,54 +3176,54 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -3238,13 +3240,13 @@
-
+
-
-
+
-
@@ -3260,6 +3262,7 @@
-
+
-
@@ -3281,7 +3284,7 @@
-
-
+
-
@@ -3308,7 +3311,7 @@
-
+
@@ -3317,7 +3320,7 @@
-
+
-
@@ -3325,7 +3328,7 @@
-
+
-
@@ -3333,21 +3336,21 @@
-
+
-
-
+
-
-
+
-
@@ -3355,7 +3358,7 @@
-
+
-
@@ -3363,7 +3366,7 @@
-
+
@@ -3372,7 +3375,7 @@
-
+
-
@@ -3380,7 +3383,7 @@
-
+
-
@@ -3388,14 +3391,14 @@
-
+
-
-
+
-
@@ -3403,13 +3406,13 @@
-
+
-
-
+
@@ -3420,7 +3423,7 @@
-
+
-
@@ -3428,7 +3431,7 @@
-
+
@@ -3439,7 +3442,7 @@
-
+
-
@@ -3448,7 +3451,7 @@
-
+
@@ -3457,14 +3460,14 @@
-
+
-
-
+
-
@@ -3473,7 +3476,7 @@
-
+
@@ -3482,20 +3485,20 @@
-
+
-
-
+
-
-
+
@@ -3506,7 +3509,7 @@
-
+
@@ -3515,7 +3518,7 @@
-
+
-
@@ -3523,24 +3526,24 @@
-
+
-
-
+
-
-
+
-
-
+
@@ -3551,7 +3554,7 @@
-
+
-
@@ -3559,7 +3562,7 @@
-
+
@@ -3569,7 +3572,7 @@
-
+
-
@@ -3577,7 +3580,7 @@
-
+
@@ -3585,7 +3588,7 @@
-
+
@@ -3596,14 +3599,14 @@
-
+
-
-
+
-
@@ -3611,7 +3614,7 @@
-
+
-
@@ -3620,7 +3623,7 @@
-
+
@@ -3630,7 +3633,7 @@
-
+
@@ -3640,33 +3643,33 @@
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -3678,7 +3681,7 @@
-
+
@@ -3687,14 +3690,14 @@
-
+
-
-
+
@@ -3704,7 +3707,7 @@
-
+
@@ -3713,7 +3716,7 @@
-
+
-
@@ -3721,7 +3724,7 @@
-
+
-
@@ -3729,7 +3732,7 @@
-
+
@@ -3738,14 +3741,14 @@
-
+
-
-
+
@@ -3754,7 +3757,7 @@
-
+
@@ -3764,7 +3767,7 @@
-
+
@@ -3775,7 +3778,7 @@
-
+
-
@@ -3784,7 +3787,7 @@
-
+
@@ -3794,14 +3797,14 @@
-
+
-
-
+
@@ -3811,7 +3814,7 @@
-
+
@@ -3820,14 +3823,14 @@
-
+
-
-
+
-
@@ -3835,14 +3838,14 @@
-
+
-
-
+
-
@@ -3850,10 +3853,10 @@
-
+
-
-
+
@@ -3864,7 +3867,7 @@
-
+
@@ -3874,7 +3877,7 @@
-
+
@@ -3884,7 +3887,7 @@
-
+
-
@@ -3892,7 +3895,7 @@
-
+
-
@@ -3900,7 +3903,7 @@
-
+
@@ -3910,7 +3913,7 @@
-
+
-
@@ -3918,21 +3921,21 @@
-
+
-
-
+
-
-
+
@@ -3942,7 +3945,7 @@
-
+
@@ -3952,7 +3955,7 @@
-
+
@@ -3961,14 +3964,14 @@
-
+
-
-
+
@@ -3977,7 +3980,7 @@
-
-
+
@@ -3986,229 +3989,229 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -4216,33 +4219,33 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -4250,14 +4253,14 @@
-
+
-
-
+
-
@@ -4265,20 +4268,20 @@
-
+
-
-
+
-
-
+
@@ -4286,7 +4289,7 @@
-
+
@@ -4294,14 +4297,14 @@
-
+
-
-
+
-
@@ -4309,70 +4312,70 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -4380,20 +4383,20 @@
-
+
-
-
+
-
-
+
-
@@ -4401,21 +4404,21 @@
-
+
-
-
+
-
-
+
-
@@ -4423,39 +4426,39 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -4463,32 +4466,32 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -4496,61 +4499,61 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -4558,7 +4561,7 @@
-
+
@@ -4568,7 +4571,7 @@
-
+
@@ -4578,7 +4581,7 @@
-
+
@@ -4588,7 +4591,7 @@
-
+
@@ -4598,20 +4601,20 @@
-
+
-
-
+
-
-
-
+
@@ -4619,45 +4622,45 @@
-
-
+
-
-
-
+
-
-
+
-
-
+
-
-
-
+
-
-
+
-
-
+
-
-
-
+
@@ -4674,11 +4677,11 @@
-
-
+
-
-
+
-
@@ -4707,14 +4710,14 @@
-
-
+
-
-
-
+
-
@@ -4762,7 +4765,7 @@
-
-
+
@@ -4777,7 +4780,7 @@
-
-
+
@@ -4834,7 +4837,7 @@
-
-
+
@@ -4849,137 +4852,137 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -4987,7 +4990,7 @@
-
+
-
@@ -4995,122 +4998,123 @@
-
+
-
-
+
-
-
+
-
-
+
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -5120,15 +5124,15 @@
-
-
+
-
-
+
-
-
+
@@ -5173,18 +5177,18 @@
-
-
+
-
-
+
-
-
-
+
@@ -5199,7 +5203,7 @@
-
-
+
@@ -5231,27 +5235,27 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -5259,11 +5263,11 @@
-
-
+
-
-
+
@@ -5271,31 +5275,31 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -7755,22 +7759,22 @@
-
-
+
-
-
+
-
-
-
+
-
-
+
-
@@ -7789,7 +7793,7 @@
-
+
-
@@ -7799,14 +7803,14 @@
-
+
-
-
+
@@ -7815,7 +7819,7 @@
-
+
-
@@ -7823,14 +7827,14 @@
-
+
-
-
+
@@ -7840,69 +7844,69 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
+
@@ -7913,13 +7917,13 @@
-
+
-
-
+
-
@@ -8569,7 +8573,7 @@
-
-
+
-
@@ -8581,7 +8585,7 @@
-
-
+
-
@@ -8603,7 +8607,7 @@
-
-
+
@@ -8671,7 +8675,7 @@
-
-
+
@@ -8750,7 +8754,7 @@
-
-
+
@@ -8758,7 +8762,7 @@
-
-
+
-
@@ -8830,14 +8834,14 @@
-
-
+
-
-
+
-
@@ -9161,14 +9165,14 @@
-
+
-
-
+
-
@@ -9201,7 +9205,7 @@
-
-
+
@@ -9406,7 +9410,7 @@
-
-
+
@@ -9516,7 +9520,7 @@
-
-
+
-
@@ -9529,7 +9533,7 @@
-
-
+
@@ -9570,7 +9574,7 @@
-
-
+
@@ -9627,7 +9631,7 @@
-
+
@@ -9693,7 +9697,7 @@
-
-
+
@@ -9702,11 +9706,11 @@
-
-
+
-
-
+
@@ -9719,7 +9723,7 @@
-
-
+
@@ -9730,7 +9734,7 @@
-
+
@@ -9738,7 +9742,7 @@
-
-
+
@@ -9755,21 +9759,21 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -9800,135 +9804,135 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -9937,28 +9941,28 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -9967,27 +9971,27 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -9996,29 +10000,29 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -10026,7 +10030,7 @@
-
-
+
-
@@ -10039,7 +10043,7 @@
-
+
-
@@ -10048,7 +10052,7 @@
-
-
+
-
@@ -10102,7 +10106,7 @@
-
+
-
@@ -10113,7 +10117,7 @@
-
-
+
-
@@ -10132,7 +10136,7 @@
-
-
+
@@ -10148,7 +10152,7 @@
-
-
+
-
@@ -10158,11 +10162,11 @@
-
-
+
-
-
+
@@ -11015,22 +11019,22 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -11039,7 +11043,7 @@
-
-
+
@@ -11053,30 +11057,30 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -11084,19 +11088,19 @@
-
+
-
-
+
-
-
+
-
-
+
-
@@ -11162,7 +11166,7 @@
-
-
+
@@ -11173,12 +11177,12 @@
-
+
-
-
+
@@ -11343,7 +11347,7 @@
-
-
+
-
@@ -11364,7 +11368,7 @@
-
-
+
@@ -11373,7 +11377,7 @@
-
-
+
@@ -11788,16 +11792,16 @@
-
+
-
-
+
-
-
+
@@ -11810,7 +11814,7 @@
-
+
@@ -11882,7 +11886,7 @@
-
-
+
-
@@ -11890,6 +11894,7 @@
-
+
@@ -11903,7 +11908,7 @@
-
-
+
@@ -11913,24 +11918,26 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -11943,6 +11950,7 @@
-
+
-
@@ -11994,7 +12002,7 @@
-
-
+
@@ -12004,7 +12012,7 @@
-
+
@@ -12013,20 +12021,20 @@
-
+
-
-
+
-
-
+
-
@@ -12039,20 +12047,20 @@
-
-
+
-
-
+
-
-
-
+
+
-
-
+
-
@@ -12061,19 +12069,19 @@
-
-
+
-
-
-
+
+
-
-
-
+
-
@@ -12105,7 +12113,7 @@
-
+
@@ -12114,8 +12122,8 @@
-
-
-
+
+
@@ -12146,11 +12154,11 @@
-
-
+
-
-
+
-
@@ -12162,7 +12170,7 @@
-
-
+
-
@@ -12179,7 +12187,7 @@
-
+
-
@@ -12594,11 +12602,11 @@
-
-
+
-
-
+
@@ -12772,7 +12780,7 @@
-
-
+
@@ -12965,7 +12973,7 @@
-
-
+
-
@@ -13023,7 +13031,7 @@
-
+
@@ -13033,7 +13041,7 @@
-
+
@@ -13043,7 +13051,7 @@
-
+
@@ -13053,7 +13061,7 @@
-
+
@@ -13062,7 +13070,7 @@
-
+
@@ -13072,7 +13080,7 @@
-
+
@@ -13106,7 +13114,7 @@
-
-
+
@@ -13114,7 +13122,7 @@
-
+
@@ -13124,7 +13132,7 @@
-
+
@@ -13135,7 +13143,7 @@
-
+
-
@@ -13144,14 +13152,14 @@
-
+
-
-
+
@@ -13160,7 +13168,7 @@
-
+
@@ -13170,7 +13178,7 @@
-
+
@@ -13179,7 +13187,7 @@
-
+
@@ -13189,7 +13197,7 @@
-
+
-
@@ -13198,14 +13206,14 @@
-
+
-
-
+
-
@@ -13213,7 +13221,7 @@
-
+
@@ -13223,7 +13231,7 @@
-
+
@@ -13232,7 +13240,7 @@
-
+
@@ -13241,45 +13249,45 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -13287,7 +13295,7 @@
-
+
@@ -13296,7 +13304,7 @@
-
+
@@ -13305,7 +13313,7 @@
-
+
@@ -13314,7 +13322,7 @@
-
+
@@ -13323,7 +13331,7 @@
-
+
@@ -13333,7 +13341,7 @@
-
+
@@ -13342,7 +13350,7 @@
-
+
@@ -13351,7 +13359,7 @@
-
+
-
@@ -13359,7 +13367,7 @@
-
+
-
@@ -13367,7 +13375,7 @@
-
+
-
@@ -13375,7 +13383,7 @@
-
+
-
@@ -13383,7 +13391,7 @@
-
+
-
@@ -13392,7 +13400,7 @@
-
+
@@ -13401,7 +13409,7 @@
-
+
@@ -13411,7 +13419,7 @@
-
+
@@ -13420,7 +13428,7 @@
-
+
@@ -13429,7 +13437,7 @@
-
+
@@ -13438,7 +13446,7 @@
-
+
@@ -13447,7 +13455,7 @@
-
+
-
@@ -13455,7 +13463,7 @@
-
+
-
@@ -13463,7 +13471,7 @@
-
+
-
@@ -13471,7 +13479,7 @@
-
+
@@ -13480,7 +13488,7 @@
-
+
@@ -13489,7 +13497,7 @@
-
+
-
@@ -13497,7 +13505,7 @@
-
+
@@ -13507,7 +13515,7 @@
-
+
-
@@ -13516,7 +13524,7 @@
-
+
-
@@ -13525,7 +13533,7 @@
-
+
@@ -13535,7 +13543,7 @@
-
+
-
@@ -13544,7 +13552,7 @@
-
+
-
@@ -13552,7 +13560,7 @@
-
+
-
@@ -13560,7 +13568,7 @@
-
+
-
@@ -13568,7 +13576,7 @@
-
+
@@ -13578,7 +13586,7 @@
-
+
@@ -13587,7 +13595,7 @@
-
+
-
@@ -13596,7 +13604,7 @@
-
+
-
@@ -13604,19 +13612,19 @@
-
+
-
-
+
-
-
+
@@ -13628,7 +13636,7 @@
-
-
+
@@ -13652,7 +13660,7 @@
-
+
-
@@ -13660,7 +13668,7 @@
-
+
-
@@ -13668,7 +13676,7 @@
-
+
-
@@ -13676,7 +13684,7 @@
-
+
@@ -13685,7 +13693,7 @@
-
+
@@ -13694,7 +13702,7 @@
-
+
-
@@ -13702,7 +13710,7 @@
-
+
@@ -13711,7 +13719,7 @@
-
+
-
@@ -13719,7 +13727,7 @@
-
+
@@ -13728,40 +13736,40 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -13769,7 +13777,7 @@
-
+
-
@@ -13818,7 +13826,7 @@
-
-
+
-
@@ -13855,7 +13863,7 @@
-
+
-
@@ -13975,22 +13983,22 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -13998,12 +14006,12 @@
-
-
+
-
-
+
-
@@ -14071,7 +14079,7 @@
-
-
+
-
@@ -14266,14 +14274,14 @@
-
-
+
-
-
-
+
-
@@ -14303,7 +14311,7 @@
-
-
+
@@ -14351,19 +14359,19 @@
-
+
-
-
-
+
-
-
+
-
@@ -14415,7 +14423,7 @@
-
+
@@ -14427,7 +14435,7 @@
-
+
@@ -14439,7 +14447,7 @@
-
+
@@ -14451,7 +14459,7 @@
-
+
@@ -14463,7 +14471,7 @@
-
+
@@ -14475,7 +14483,7 @@
-
+
@@ -14486,7 +14494,7 @@
-
+
@@ -14498,7 +14506,7 @@
-
+
@@ -14510,7 +14518,7 @@
-
+
@@ -14522,7 +14530,7 @@
-
+
@@ -14534,7 +14542,7 @@
-
+
@@ -14546,7 +14554,7 @@
-
+
@@ -14558,7 +14566,7 @@
-
+
@@ -14570,7 +14578,7 @@
-
+
@@ -14583,7 +14591,7 @@
-
+
@@ -14591,19 +14599,19 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -14611,7 +14619,7 @@
-
+
@@ -14623,7 +14631,7 @@
-
+
@@ -14635,7 +14643,7 @@
-
+
@@ -14647,7 +14655,7 @@
-
+
@@ -14659,7 +14667,7 @@
-
+
@@ -14671,7 +14679,7 @@
-
+
@@ -14684,7 +14692,7 @@
-
+
@@ -14696,7 +14704,7 @@
-
+
@@ -14708,7 +14716,7 @@
-
+
@@ -14720,7 +14728,7 @@
-
+
@@ -14732,7 +14740,7 @@
-
+
@@ -14744,7 +14752,7 @@
-
+
@@ -14756,7 +14764,7 @@
-
+
@@ -14768,7 +14776,7 @@
-
+
@@ -14780,7 +14788,7 @@
-
+
@@ -15038,7 +15046,7 @@
-
+
@@ -15049,7 +15057,7 @@
-
+
@@ -15060,7 +15068,7 @@
-
+
@@ -15110,7 +15118,7 @@
-
+
@@ -15121,7 +15129,7 @@
-
+
@@ -15133,7 +15141,7 @@
-
+
@@ -15145,7 +15153,7 @@
-
+
@@ -15157,7 +15165,7 @@
-
+
@@ -15169,7 +15177,7 @@
-
+
@@ -15181,7 +15189,7 @@
-
+
@@ -15193,7 +15201,7 @@
-
+
@@ -15204,7 +15212,7 @@
-
+
@@ -15216,7 +15224,7 @@
-
+
@@ -15228,7 +15236,7 @@
-
+
@@ -15240,7 +15248,7 @@
-
+
@@ -15252,7 +15260,7 @@
-
+
@@ -15264,7 +15272,7 @@
-
+
@@ -15276,7 +15284,7 @@
-
+
@@ -15288,7 +15296,7 @@
-
+
@@ -15300,7 +15308,7 @@
-
+
@@ -15312,7 +15320,7 @@
-
+
@@ -15324,7 +15332,7 @@
-
+
@@ -15336,7 +15344,7 @@
-
+
@@ -15348,7 +15356,7 @@
-
+
@@ -15360,7 +15368,7 @@
-
+
@@ -15371,7 +15379,7 @@
-
+
@@ -15383,7 +15391,7 @@
-
+
@@ -15395,7 +15403,7 @@
-
+
@@ -15407,7 +15415,7 @@
-
+
@@ -15419,7 +15427,7 @@
-
+
@@ -15431,7 +15439,7 @@
-
+
@@ -15443,7 +15451,7 @@
-
+
@@ -15455,7 +15463,7 @@
-
+
@@ -15467,7 +15475,7 @@
-
+
@@ -15478,7 +15486,7 @@
-
+
@@ -15486,7 +15494,7 @@
-
+
@@ -15494,7 +15502,7 @@
-
+
@@ -15502,7 +15510,7 @@
-
-
+
@@ -15512,7 +15520,7 @@
-
-
+
@@ -15522,7 +15530,7 @@
-
-
+
@@ -15532,7 +15540,7 @@
-
-
+
@@ -15545,14 +15553,14 @@
-
+
-
-
+
@@ -15563,7 +15571,7 @@
-
+
-
@@ -15572,7 +15580,7 @@
-
+
-
@@ -15580,13 +15588,13 @@
-
+
-
-
+
@@ -15594,7 +15602,7 @@
-
+
@@ -15604,7 +15612,7 @@
-
+
-
@@ -15612,7 +15620,7 @@
-
+
-
@@ -15620,7 +15628,7 @@
-
+
-
@@ -15628,7 +15636,7 @@
-
+
-
@@ -15636,7 +15644,7 @@
-
+
-
@@ -15644,7 +15652,7 @@
-
+
-
@@ -15660,15 +15668,16 @@
-
+
-
-
+
-
-
+
@@ -15741,7 +15750,7 @@
-
+
-
@@ -15765,7 +15774,7 @@
-
+
-
@@ -15786,7 +15795,7 @@
-
-
+
@@ -15794,7 +15803,7 @@
-
-
+
-
@@ -15950,7 +15959,7 @@
-
+
-
@@ -15986,13 +15995,13 @@
-
-
+
-
-
+
@@ -16059,16 +16068,16 @@
-
-
+
-
-
+
-
-
+
-
@@ -16076,26 +16085,26 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -16115,11 +16124,11 @@
-
-
+
-
-
+
@@ -16198,12 +16207,12 @@
-
-
+
-
-
+
@@ -16353,14 +16362,14 @@
-
+
-
-
+
@@ -16370,7 +16379,7 @@
-
-
+
@@ -16461,7 +16470,7 @@
-
-
+
@@ -16469,7 +16478,7 @@
-
-
+
-
@@ -16513,10 +16522,10 @@
-
-
+
-
+
-
@@ -16589,13 +16598,13 @@
-
+
-
-
+
-
@@ -16604,41 +16613,41 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -16655,7 +16664,7 @@
-
+
@@ -16665,7 +16674,7 @@
-
+
@@ -16675,7 +16684,7 @@
-
+
@@ -16686,7 +16695,7 @@
-
+
@@ -16697,7 +16706,7 @@
-
+
@@ -16707,7 +16716,7 @@
-
+
@@ -16718,7 +16727,7 @@
-
+
@@ -16729,7 +16738,7 @@
-
+
@@ -16738,7 +16747,7 @@
-
+
@@ -16748,13 +16757,13 @@
-
+
-
-
+
@@ -16772,7 +16781,7 @@
-
+
-
@@ -16781,13 +16790,13 @@
-
+
-
-
+
@@ -16799,7 +16808,7 @@
-
+
-
@@ -16807,12 +16816,12 @@
-
+
-
-
+
@@ -16820,39 +16829,39 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -16860,7 +16869,7 @@
-
+
-
@@ -16868,7 +16877,7 @@
-
+
-
@@ -16876,7 +16885,7 @@
-
+
-
@@ -16884,7 +16893,7 @@
-
+
-
@@ -16893,12 +16902,12 @@
-
+
-
-
+
@@ -16911,7 +16920,7 @@
-
+
-
@@ -16920,12 +16929,12 @@
-
+
-
-
+
@@ -16933,7 +16942,7 @@
-
-
+
@@ -16941,7 +16950,7 @@
-
-
+
@@ -16949,7 +16958,7 @@
-
-
+
@@ -16960,20 +16969,20 @@
-
+
-
-
+
-
-
+
@@ -16981,7 +16990,7 @@
-
-
+
@@ -16993,7 +17002,7 @@
-
+
-
@@ -17002,7 +17011,7 @@
-
+
-
@@ -17011,7 +17020,7 @@
-
+
-
@@ -17019,7 +17028,7 @@
-
+
-
@@ -17027,21 +17036,21 @@
-
+
-
-
+
-
-
+
@@ -17051,7 +17060,7 @@
-
+
@@ -17060,7 +17069,7 @@
-
+
@@ -17070,7 +17079,7 @@
-
+
@@ -17082,7 +17091,7 @@
-
+
@@ -17091,7 +17100,7 @@
-
+
@@ -17100,7 +17109,7 @@
-
+
@@ -17111,7 +17120,7 @@
-
+
-
@@ -17120,7 +17129,7 @@
-
+
@@ -17129,7 +17138,7 @@
-
+
@@ -17138,7 +17147,7 @@
-
+
@@ -17147,14 +17156,14 @@
-
+
-
-
+
@@ -17163,7 +17172,7 @@
-
+
@@ -17172,7 +17181,7 @@
-
+
@@ -17181,7 +17190,7 @@
-
+
-
@@ -17189,7 +17198,7 @@
-
+
@@ -17198,7 +17207,7 @@
-
+
@@ -17207,7 +17216,7 @@
-
+
@@ -17216,7 +17225,7 @@
-
+
@@ -17225,7 +17234,7 @@
-
+
-
@@ -17452,7 +17461,7 @@
-
-
+
@@ -17485,7 +17494,7 @@
-
-
+
@@ -17506,6 +17515,7 @@
-
+
-
@@ -17531,11 +17541,11 @@
-
-
+
-
-
+
-
@@ -17573,7 +17583,7 @@
-
-
+
@@ -17600,7 +17610,7 @@
-
-
+
@@ -17647,7 +17657,7 @@
-
-
+
@@ -17671,7 +17681,7 @@
-
-
+
-
@@ -17878,9 +17888,11 @@
-
+
-
+
@@ -18017,7 +18029,7 @@
-
-
+
-
@@ -18039,7 +18051,7 @@
-
-
+
-
@@ -18052,30 +18064,30 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -18093,7 +18105,7 @@
-
-
+
@@ -18111,7 +18123,7 @@
-
-
+
@@ -18151,14 +18163,14 @@
-
+
-
-
+
@@ -18166,7 +18178,7 @@
-
+
@@ -18233,32 +18245,32 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -18267,55 +18279,55 @@
-
+
-
-
+
-
+
-
-
+
-
+
-
-
+
-
+
-
-
+
-
+
-
-
+
-
+
-
-
+
-
+
-
@@ -18571,7 +18583,7 @@
-
-
+
-
@@ -18579,11 +18591,11 @@
-
-
+
-
-
+
@@ -18596,7 +18608,7 @@
-
+
@@ -18609,7 +18621,7 @@
-
+
@@ -18644,12 +18656,12 @@
-
-
+
-
-
+
@@ -18741,28 +18753,28 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -18797,7 +18809,7 @@
-
-
+
@@ -18959,7 +18971,7 @@
-
+
@@ -18974,13 +18986,13 @@
-
+
-
-
+
-
@@ -19140,7 +19152,7 @@
-
-
+
@@ -19412,7 +19424,7 @@
-
+
@@ -19423,7 +19435,7 @@
-
+
@@ -19434,7 +19446,7 @@
-
+
@@ -19444,7 +19456,7 @@
-
+
@@ -19546,7 +19558,7 @@
-
+
@@ -19556,14 +19568,14 @@
-
+
-
-
+
-
@@ -19572,7 +19584,7 @@
-
+
-
@@ -19580,14 +19592,14 @@
-
+
-
-
+
-
@@ -19595,7 +19607,7 @@
-
+
@@ -19605,7 +19617,7 @@
-
+
-
@@ -19613,7 +19625,7 @@
-
+
-
@@ -19621,7 +19633,7 @@
-
+
-
@@ -19629,7 +19641,7 @@
-
+
-
@@ -19637,7 +19649,7 @@
-
+
-
@@ -19645,7 +19657,7 @@
-
+
-
@@ -19654,7 +19666,7 @@
-
+
-
@@ -19662,7 +19674,7 @@
-
+
-
@@ -19671,7 +19683,7 @@
-
+
-
@@ -19686,7 +19698,7 @@
-
-
+
@@ -19694,14 +19706,14 @@
-
+
-
-
+
-
@@ -19723,13 +19735,13 @@
-
+
-
-
+
-
@@ -19743,21 +19755,21 @@
-
+
-
-
+
-
-
+
-
@@ -19800,7 +19812,7 @@
-
+
-
@@ -19809,7 +19821,7 @@
-
+
@@ -19929,16 +19941,16 @@
-
-
+
-
-
+
-
-
+
-
@@ -19952,7 +19964,7 @@
-
+
-
@@ -20004,7 +20016,7 @@
-
-
+
@@ -20015,7 +20027,7 @@
-
-
+
-
@@ -20043,7 +20055,7 @@
-
-
+
-
@@ -20053,7 +20065,7 @@
-
-
+
@@ -20083,12 +20095,12 @@
-
-
+
-
-
+
@@ -20096,92 +20108,92 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -20189,115 +20201,115 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -20309,7 +20321,7 @@
-
-
+
@@ -20554,7 +20566,7 @@
-
-
+
@@ -20602,7 +20614,7 @@
-
-
+
@@ -20619,7 +20631,7 @@
-
+
@@ -20628,7 +20640,7 @@
-
+
@@ -20718,7 +20730,7 @@
-
-
+
@@ -20728,52 +20740,52 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -20788,47 +20800,47 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -20836,95 +20848,95 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -20935,7 +20947,7 @@
-
+
@@ -20962,7 +20974,7 @@
-
-
+
-
@@ -21025,27 +21037,27 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -21196,14 +21208,14 @@
-
+
-
-
+
@@ -21211,7 +21223,7 @@
-
+
@@ -21219,7 +21231,7 @@
-
+
-
@@ -21227,7 +21239,7 @@
-
+
@@ -21236,7 +21248,7 @@
-
+
-
@@ -21244,7 +21256,7 @@
-
+
@@ -21253,7 +21265,7 @@
-
+
-
@@ -21261,7 +21273,7 @@
-
+
@@ -21290,11 +21302,11 @@
-
-
+
-
-
+
-
@@ -21326,11 +21338,11 @@
-
-
+
-
-
+
@@ -21338,72 +21350,72 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -21461,7 +21473,7 @@
-
+
@@ -21469,7 +21481,7 @@
-
+
@@ -21501,7 +21513,7 @@
-
-
+
-
@@ -21530,11 +21542,11 @@
-
-
+
-
-
+
-
@@ -21542,37 +21554,37 @@
-
+
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -21605,7 +21617,7 @@
-
+
-
@@ -22005,7 +22017,7 @@
-
-
+
-
@@ -22041,74 +22053,74 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -22119,7 +22131,7 @@
-
-
+
@@ -22127,164 +22139,164 @@
-
-
+
-
-
+
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
+
@@ -22307,7 +22319,7 @@
-
-
+
@@ -22318,7 +22330,7 @@
-
-
+
-
@@ -22335,14 +22347,14 @@
-
-
+
-
-
-
+
-
@@ -22391,7 +22403,7 @@
-
+
@@ -22616,12 +22628,12 @@
-
+
-
-
+
-
@@ -22653,30 +22665,30 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -22704,15 +22716,15 @@
-
-
+
-
-
+
-
-
+
-
@@ -22722,7 +22734,7 @@
-
+
-
@@ -22747,16 +22759,16 @@
-
-
+
-
-
+
-
-
+
@@ -22768,7 +22780,7 @@
-
-
+
-
@@ -22778,7 +22790,7 @@
-
+
@@ -22786,7 +22798,7 @@
-
+
@@ -22795,7 +22807,7 @@
-
+
@@ -22803,7 +22815,7 @@
-
+
@@ -22813,7 +22825,7 @@
-
+
-
@@ -22822,14 +22834,14 @@
-
+
-
-
+
@@ -22838,12 +22850,12 @@
-
+
-
-
+
-
@@ -22864,21 +22876,21 @@
-
+
-
-
+
-
-
+
-
-
+
-
@@ -22897,7 +22909,7 @@
-
-
+
@@ -23036,7 +23048,7 @@
-
-
+
@@ -23069,15 +23081,15 @@
-
-
+
-
-
+
-
-
+
@@ -23119,7 +23131,7 @@
-
-
+
@@ -23190,7 +23202,7 @@
-
-
+
@@ -23282,7 +23294,7 @@
-
-
+
@@ -23340,17 +23352,17 @@
-
-
+
-
-
+
-
-
+
@@ -23359,55 +23371,55 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -23647,7 +23659,7 @@
-
-
+
@@ -23677,11 +23689,11 @@
-
-
+
-
-
+
@@ -23815,7 +23827,7 @@
-
-
+
-
@@ -23825,17 +23837,17 @@
-
-
+
-
-
+
-
-
+
@@ -23844,47 +23856,47 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -23933,7 +23945,7 @@
-
-
+
@@ -24078,14 +24090,14 @@
-
+
-
-
+
-
-
+
-
@@ -24096,7 +24108,7 @@
-
+
@@ -24178,7 +24190,7 @@
-
+
-
@@ -24192,7 +24204,7 @@
-
+
-
@@ -24234,7 +24246,7 @@
-
+
-
@@ -24296,7 +24308,7 @@
-
-
+
@@ -24305,7 +24317,7 @@
-
+
@@ -24314,7 +24326,7 @@
-
+
@@ -24324,7 +24336,7 @@
-
-
+
@@ -24338,15 +24350,15 @@
-
-
+
-
-
+
-
+
-
@@ -24356,7 +24368,7 @@
-
+
@@ -24364,7 +24376,7 @@
-
-
+
@@ -24399,38 +24411,38 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -24643,12 +24655,12 @@
-
+
-
-
+
-
@@ -24720,7 +24732,7 @@
-
+
-
@@ -24781,7 +24793,7 @@
-
-
+
@@ -25247,7 +25259,7 @@
-
-
+
-
@@ -25332,7 +25344,7 @@
-
+
@@ -25341,7 +25353,7 @@
-
+
@@ -25350,7 +25362,7 @@
-
+
-
@@ -25359,7 +25371,7 @@
-
+
@@ -25369,7 +25381,7 @@
-
+
@@ -25381,13 +25393,13 @@
-
+
-
-
+
@@ -25395,7 +25407,7 @@
-
+
@@ -25405,7 +25417,7 @@
-
+
@@ -25414,7 +25426,7 @@
-
+
@@ -25424,7 +25436,7 @@
-
+
-
@@ -25432,7 +25444,7 @@
-
+
-
@@ -25460,48 +25472,48 @@
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -25516,17 +25528,17 @@
-
-
+
-
-
+
-
-
+
@@ -25588,18 +25600,18 @@
-
+
-
-
+
-
-
+
-
@@ -25607,11 +25619,11 @@
-
+
-
-
+
@@ -25638,35 +25650,35 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -25674,14 +25686,14 @@
-
-
+
-
-
+
@@ -25689,7 +25701,7 @@
-
+
@@ -25697,7 +25709,7 @@
-
+
-
@@ -25705,7 +25717,7 @@
-
+
-
@@ -25734,7 +25746,7 @@
-
-
+
@@ -25748,7 +25760,7 @@
-
-
+
@@ -25786,7 +25798,7 @@
-
-
+
@@ -25816,7 +25828,7 @@
-
-
+
-
@@ -25834,7 +25846,7 @@
-
+
@@ -25845,7 +25857,7 @@
-
+
@@ -25854,14 +25866,14 @@
-
-
+
-
-
+
@@ -25870,7 +25882,7 @@
-
+
-
@@ -25878,7 +25890,7 @@
-
+
@@ -25888,7 +25900,7 @@
-
+
@@ -25904,7 +25916,7 @@
-
+
-
@@ -25912,17 +25924,17 @@
-
-
+
-
-
+
-
-
+
@@ -25989,11 +26001,11 @@
-
-
+
-
-
+
-
@@ -26038,7 +26050,7 @@
-
+
@@ -26050,13 +26062,13 @@
-
+
-
-
+
@@ -26593,7 +26605,7 @@
-
-
+
-
@@ -26651,7 +26663,7 @@
-
+
@@ -26661,7 +26673,7 @@
-
+
@@ -26858,7 +26870,7 @@
-
+
@@ -26875,7 +26887,7 @@
-
+
-
@@ -26889,19 +26901,19 @@
-
-
+
-
-
+
-
-
+
@@ -26910,7 +26922,7 @@
-
+
@@ -26919,7 +26931,7 @@
-
+
@@ -26930,7 +26942,7 @@
-
+
@@ -26938,7 +26950,7 @@
-
-
+
@@ -26949,7 +26961,7 @@
-
+
@@ -26958,7 +26970,7 @@
-
+
@@ -26966,7 +26978,7 @@
-
+
@@ -26974,7 +26986,7 @@
-
+
@@ -26983,7 +26995,7 @@
-
-
+
@@ -26993,7 +27005,7 @@
-
-
+
@@ -27005,7 +27017,7 @@
-
+
@@ -27015,7 +27027,7 @@
-
+
@@ -27023,7 +27035,7 @@
-
+
@@ -27032,97 +27044,97 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -27130,7 +27142,7 @@
-
+
@@ -27140,7 +27152,7 @@
-
+
@@ -27151,7 +27163,7 @@
-
+
@@ -27219,7 +27231,7 @@
-
-
+
@@ -27228,7 +27240,7 @@
-
+
-
@@ -27236,7 +27248,7 @@
-
+
@@ -27247,7 +27259,7 @@
-
+
@@ -27256,7 +27268,7 @@
-
+
@@ -27266,7 +27278,7 @@
-
+
@@ -27274,7 +27286,7 @@
-
-
+
-
@@ -27303,7 +27315,7 @@
-
+
@@ -27423,11 +27435,11 @@
-
-
+
-
-
+
-
@@ -27512,7 +27524,7 @@
-
-
+
@@ -27634,24 +27646,24 @@
-
+
-
-
+
-
-
+
-
-
+
@@ -28015,31 +28027,31 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -28357,14 +28369,14 @@
-
-
+
-
-
+
-
@@ -28372,7 +28384,7 @@
-
+
-
@@ -28380,38 +28392,38 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -28419,18 +28431,18 @@
-
+
-
-
+
-
-
+
-
-
+
-
@@ -28438,77 +28450,77 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -28520,7 +28532,7 @@
-
+
-
@@ -30888,38 +30900,38 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -30933,7 +30945,7 @@
-
-
+
@@ -30942,12 +30954,12 @@
-
-
+
-
-
+
@@ -31264,24 +31276,24 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -31447,11 +31459,11 @@
-
-
+
-
-
+
-
@@ -31539,11 +31551,11 @@
-
-
+
-
-
+
-
@@ -31640,12 +31652,12 @@
-
-
+
-
-
+
@@ -31654,7 +31666,7 @@
-
-
+
@@ -31784,7 +31796,7 @@
-
+
@@ -31796,7 +31808,7 @@
-
+
@@ -31804,7 +31816,7 @@
-
+
@@ -31812,11 +31824,11 @@
-
+
-
-
+
@@ -31824,7 +31836,7 @@
-
+
@@ -31836,12 +31848,12 @@
-
+
-
-
+
@@ -31849,17 +31861,17 @@
-
+
-
-
+
-
-
+
@@ -31867,7 +31879,7 @@
-
+
@@ -31876,7 +31888,7 @@
-
+
@@ -31897,7 +31909,7 @@
-
+
@@ -32035,7 +32047,7 @@
-
-
+
@@ -32091,11 +32103,11 @@
-
-
+
-
-
+
-
@@ -32103,7 +32115,7 @@
-
+
-
@@ -32111,7 +32123,7 @@
-
+
@@ -32120,7 +32132,7 @@
-
+
@@ -32130,7 +32142,7 @@
-
+
-
@@ -32138,7 +32150,7 @@
-
+
@@ -32147,7 +32159,7 @@
-
+
@@ -32158,7 +32170,7 @@
-
+
-
@@ -32166,7 +32178,7 @@
-
+
@@ -32175,7 +32187,7 @@
-
+
@@ -32185,7 +32197,7 @@
-
+
-
@@ -32193,7 +32205,7 @@
-
+
@@ -32202,7 +32214,7 @@
-
+
@@ -32213,7 +32225,7 @@
-
+
-
@@ -32221,7 +32233,7 @@
-
+
@@ -32230,7 +32242,7 @@
-
+
@@ -32240,7 +32252,7 @@
-
+
-
@@ -32248,7 +32260,7 @@
-
+
@@ -32257,7 +32269,7 @@
-
+
@@ -32267,7 +32279,7 @@
-
+
@@ -32277,7 +32289,7 @@
-
+
@@ -32288,7 +32300,7 @@
-
+
@@ -32300,7 +32312,7 @@
-
+
@@ -32310,7 +32322,7 @@
-
+
@@ -32321,7 +32333,7 @@
-
+
@@ -32338,7 +32350,7 @@
-
+
-
@@ -32349,7 +32361,7 @@
-
+
-
@@ -32361,7 +32373,7 @@
-
+
@@ -32434,7 +32446,7 @@
-
+
-
@@ -32625,18 +32637,18 @@
-
-
+
-
-
+
-
-
+
-
@@ -32661,49 +32673,49 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -32827,7 +32839,7 @@
-
-
+
@@ -32849,16 +32861,16 @@
-
-
+
-
-
+
-
-
+
-
@@ -32874,7 +32886,7 @@
-
-
+
@@ -32968,7 +32980,7 @@
-
-
+
@@ -33450,7 +33462,7 @@
-
-
+
@@ -33548,19 +33560,19 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -33587,7 +33599,7 @@
-
-
+
@@ -33601,7 +33613,7 @@
-
-
+
@@ -33609,7 +33621,7 @@
-
-
+
@@ -33618,28 +33630,28 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -33647,21 +33659,21 @@
-
-
+
-
-
+
-
-
+
@@ -33669,7 +33681,7 @@
-
+
@@ -33677,20 +33689,20 @@
-
+
-
-
+
-
-
+
@@ -33699,14 +33711,14 @@
-
+
-
-
+
@@ -33716,7 +33728,7 @@
-
+
@@ -33726,19 +33738,19 @@
-
+
-
-
+
-
-
+
@@ -33778,51 +33790,51 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -33852,14 +33864,14 @@
-
-
+
-
-
+
@@ -33881,7 +33893,7 @@
-
-
+
@@ -33938,27 +33950,27 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -33996,7 +34008,7 @@
-
-
+
-
@@ -34213,7 +34225,7 @@
-
-
+
@@ -34222,7 +34234,7 @@
-
+
@@ -34346,7 +34358,7 @@
-
-
+
@@ -34366,7 +34378,7 @@
-
-
+
-
@@ -34426,11 +34438,11 @@
-
-
+
-
-
+
-
@@ -34455,11 +34467,11 @@
-
-
+
-
-
+
-
@@ -34668,7 +34680,7 @@
-
-
+
@@ -34704,11 +34716,11 @@
-
-
+
-
-
+
-
@@ -34718,11 +34730,11 @@
-
-
+
-
-
+
-
@@ -34738,11 +34750,11 @@
-
-
+
-
-
+
-
@@ -34835,7 +34847,7 @@
-
-
+
-
@@ -34883,11 +34895,11 @@
-
-
+
-
-
+
-
@@ -34917,7 +34929,7 @@
-
-
+
@@ -35071,7 +35083,7 @@
-
-
+
-
@@ -35193,37 +35205,37 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -35240,7 +35252,7 @@
-
-
+
@@ -35342,20 +35354,20 @@
-
-
+
-
-
+
-
-
+
@@ -35364,7 +35376,7 @@
-
-
+
@@ -35372,7 +35384,7 @@
-
-
+
@@ -35381,7 +35393,7 @@
-
+
@@ -35421,15 +35433,15 @@
-
-
+
-
-
+
-
-
+
-
@@ -35468,7 +35480,7 @@
-
+
@@ -35480,7 +35492,7 @@
-
+
@@ -35492,7 +35504,7 @@
-
+
@@ -35504,7 +35516,7 @@
-
+
@@ -35512,7 +35524,7 @@
- -
+
-
@@ -35533,7 +35545,7 @@
-
-
+
@@ -35546,7 +35558,7 @@
-
+
@@ -35558,7 +35570,7 @@
-
+
@@ -35570,7 +35582,7 @@
-
+
@@ -35588,7 +35600,7 @@
-
+
@@ -35604,7 +35616,7 @@
-
-
+
@@ -35739,7 +35751,7 @@
-
+
-
@@ -35747,7 +35759,7 @@
-
+
@@ -35758,36 +35770,36 @@
-
-
+
-
-
+
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
+
-
@@ -35795,22 +35807,22 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -35818,7 +35830,7 @@
-
+
@@ -35898,7 +35910,7 @@
-
-
+
-
@@ -35911,7 +35923,7 @@
-
+
-
@@ -35920,7 +35932,7 @@
-
+
-
@@ -35929,7 +35941,7 @@
-
+
-
@@ -35938,7 +35950,7 @@
-
+
-
@@ -35947,7 +35959,7 @@
-
+
-
@@ -35956,7 +35968,7 @@
-
+
-
@@ -35965,7 +35977,7 @@
-
+
-
@@ -35974,7 +35986,7 @@
-
+
-
@@ -35983,7 +35995,7 @@
-
+
-
@@ -35992,7 +36004,7 @@
-
+
-
@@ -36001,7 +36013,7 @@
-
+
-
@@ -36010,7 +36022,7 @@
-
+
-
@@ -36019,7 +36031,7 @@
-
+
-
@@ -36028,7 +36040,7 @@
-
+
-
@@ -36037,7 +36049,7 @@
-
+
-
@@ -36046,7 +36058,7 @@
-
+
-
@@ -36055,7 +36067,7 @@
-
+
-
@@ -36064,7 +36076,7 @@
-
+
-
@@ -36073,7 +36085,7 @@
-
+
-
@@ -36082,7 +36094,7 @@
-
+
@@ -36279,7 +36291,7 @@
-
-
+
-
@@ -36292,14 +36304,14 @@
-
-
+
-
-
+
@@ -36308,20 +36320,20 @@
-
+
-
-
+
-
-
+
-
-
+
@@ -36395,7 +36407,7 @@
-
+
-
@@ -36403,14 +36415,14 @@
-
+
-
-
+
-
@@ -36418,13 +36430,13 @@
-
+
-
-
+
-
@@ -36432,7 +36444,7 @@
-
+
@@ -36441,7 +36453,7 @@
-
+
@@ -36455,7 +36467,7 @@
-
+
-
@@ -36467,13 +36479,13 @@
-
+
-
-
+
@@ -36481,7 +36493,7 @@
-
+
@@ -36491,17 +36503,17 @@
-
+
-
-
+
-
-
+
@@ -36510,7 +36522,7 @@
-
-
+
@@ -36523,7 +36535,7 @@
-
+
-
@@ -36667,7 +36679,7 @@
-
+
@@ -36678,7 +36690,7 @@
-
+
@@ -36748,7 +36760,7 @@
-
+
@@ -36757,7 +36769,7 @@
-
+
@@ -36767,7 +36779,7 @@
-
+
@@ -36776,7 +36788,7 @@
-
+
@@ -36786,7 +36798,7 @@
-
+
@@ -36795,7 +36807,7 @@
-
+
@@ -36805,7 +36817,7 @@
-
+
@@ -36817,7 +36829,7 @@
-
+
@@ -36828,7 +36840,7 @@
-
+
@@ -36837,7 +36849,7 @@
-
+
@@ -36877,7 +36889,7 @@
-
+
@@ -36887,7 +36899,7 @@
-
+
@@ -36897,7 +36909,7 @@
-
+
@@ -36906,7 +36918,7 @@
-
+
@@ -36916,7 +36928,7 @@
-
+
@@ -36925,7 +36937,7 @@
-
+
@@ -36935,7 +36947,7 @@
-
+
@@ -36947,7 +36959,7 @@
-
+
@@ -36958,7 +36970,7 @@
-
+
@@ -36967,7 +36979,7 @@
-
+
@@ -36977,7 +36989,7 @@
-
+
@@ -36986,7 +36998,7 @@
-
+
@@ -36996,7 +37008,7 @@
-
+
@@ -37005,7 +37017,7 @@
-
+
@@ -37015,7 +37027,7 @@
-
+
@@ -37024,7 +37036,7 @@
-
+
@@ -37034,7 +37046,7 @@
-
+
@@ -37046,7 +37058,7 @@
-
+
@@ -37057,7 +37069,7 @@
-
+
@@ -37066,7 +37078,7 @@
-
+
@@ -37109,17 +37121,17 @@
-
-
+
-
-
+
-
-
+
@@ -37429,7 +37441,7 @@
-
+
@@ -37441,7 +37453,7 @@
-
+
@@ -37459,7 +37471,7 @@
-
+
@@ -37477,7 +37489,7 @@
-
+
@@ -37502,7 +37514,7 @@
- -
+
-
@@ -37543,52 +37555,52 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -37596,58 +37608,58 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -37659,7 +37671,7 @@
-
-
+
@@ -37671,7 +37683,7 @@
-
-
+
@@ -37686,7 +37698,7 @@
-
-
+
@@ -37700,7 +37712,7 @@
-
-
+
@@ -37708,7 +37720,7 @@
-
-
+
@@ -37720,7 +37732,7 @@
-
-
+
@@ -37728,7 +37740,7 @@
-
-
+
@@ -37743,7 +37755,7 @@
-
-
+
@@ -37751,7 +37763,7 @@
-
-
+
@@ -37763,7 +37775,7 @@
-
-
+
-
@@ -37786,7 +37798,7 @@
-
-
+
@@ -37794,7 +37806,7 @@
-
-
+
@@ -37802,13 +37814,13 @@
-
-
+
-
-
+
@@ -37913,17 +37925,17 @@
-
-
+
-
-
+
-
-
+
@@ -38123,7 +38135,7 @@
-
-
+
@@ -38182,7 +38194,7 @@
-
-
+
@@ -38232,63 +38244,63 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -38310,38 +38322,38 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -38456,7 +38468,7 @@
-
-
+
@@ -38471,27 +38483,27 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -38501,7 +38513,7 @@
-
-
+
@@ -38518,18 +38530,18 @@
-
-
+
-
-
-
+
-
-
+
@@ -38537,60 +38549,60 @@
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -38796,7 +38808,7 @@
-
-
+
@@ -39146,13 +39158,13 @@
-
+
-
-
+
@@ -39220,7 +39232,7 @@
- -
+
-
-
@@ -39300,48 +39312,48 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -39352,14 +39364,14 @@
-
+
-
-
+
@@ -39371,7 +39383,7 @@
-
-
+
@@ -39442,7 +39454,7 @@
-
+
@@ -39450,33 +39462,33 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -39493,7 +39505,7 @@
-
+
@@ -39504,7 +39516,7 @@
-
+
@@ -39519,7 +39531,7 @@
-
+
@@ -39530,7 +39542,7 @@
-
+
@@ -39551,7 +39563,7 @@
-
+
@@ -39899,420 +39911,420 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -40335,7 +40347,7 @@
-
- -
+
-
-
@@ -40349,126 +40361,126 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -40476,7 +40488,7 @@
-
+
-
@@ -40484,7 +40496,7 @@
-
+
-
@@ -40492,7 +40504,7 @@
-
+
-
@@ -40500,7 +40512,7 @@
-
+
-
@@ -40508,7 +40520,7 @@
-
+
-
@@ -40516,175 +40528,175 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -40692,7 +40704,7 @@
-
+
-
@@ -40700,7 +40712,7 @@
-
+
-
@@ -40708,7 +40720,7 @@
-
+
-
@@ -40716,7 +40728,7 @@
-
+
-
@@ -40724,7 +40736,7 @@
-
+
-
@@ -40732,175 +40744,175 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -40908,7 +40920,7 @@
-
+
-
@@ -40916,7 +40928,7 @@
-
+
-
@@ -40924,7 +40936,7 @@
-
+
-
@@ -40932,7 +40944,7 @@
-
+
-
@@ -40940,7 +40952,7 @@
-
+
-
@@ -40948,49 +40960,49 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -41035,7 +41047,7 @@
-
+
-
@@ -41321,25 +41333,25 @@
-
+
-
-
+
-
-
+
-
-
+
-
@@ -41389,7 +41401,7 @@
-
-
+
-
@@ -41399,7 +41411,7 @@
-
-
+
@@ -41443,7 +41455,7 @@
-
+
-
@@ -41451,7 +41463,7 @@
-
+
@@ -41460,7 +41472,7 @@
-
+
-
@@ -41468,7 +41480,7 @@
-
+
@@ -41477,7 +41489,7 @@
-
+
-
@@ -41485,14 +41497,14 @@
-
+
-
-
+
@@ -41503,7 +41515,7 @@
-
-
+
@@ -41514,7 +41526,7 @@
-
-
+
@@ -41523,7 +41535,7 @@
-
-
+
@@ -41540,11 +41552,11 @@
-
-
+
-
-
+
-
@@ -41655,10 +41667,10 @@
-
+
-
-
+
@@ -41668,10 +41680,10 @@
-
+
-
-
+
@@ -41795,7 +41807,7 @@
-
-
+
@@ -41807,121 +41819,121 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -41976,7 +41988,7 @@
-
-
+
@@ -41987,7 +41999,7 @@
-
-
+
@@ -41998,7 +42010,7 @@
-
-
+
@@ -42007,7 +42019,7 @@
-
-
+
@@ -42018,7 +42030,7 @@
-
-
+
@@ -42033,36 +42045,36 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -42408,7 +42420,7 @@
-
-
+
@@ -42645,8 +42657,8 @@
- -
-
+
-
+
@@ -42666,7 +42678,7 @@
-
-
+
@@ -42675,7 +42687,7 @@
-
-
+
@@ -42686,7 +42698,7 @@
-
-
+
@@ -42696,7 +42708,7 @@
-
-
+
@@ -42706,7 +42718,7 @@
-
-
+
@@ -42719,7 +42731,7 @@
-
-
+
@@ -42728,7 +42740,7 @@
-
-
+
@@ -42740,7 +42752,7 @@
-
-
+
@@ -42749,7 +42761,7 @@
-
-
+
@@ -42758,7 +42770,7 @@
-
-
+
@@ -42769,7 +42781,7 @@
-
-
+
@@ -42781,7 +42793,7 @@
-
-
+
@@ -42875,7 +42887,7 @@
-
-
+
-
@@ -43054,17 +43066,17 @@
-
-
+
-
-
+
-
-
+
@@ -43141,26 +43153,26 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -43170,7 +43182,7 @@
-
-
+
@@ -43180,7 +43192,7 @@
-
-
+
@@ -43191,7 +43203,7 @@
-
-
+
@@ -43202,7 +43214,7 @@
-
-
+
@@ -43213,7 +43225,7 @@
-
-
+
@@ -43246,7 +43258,7 @@
-
-
+
@@ -43364,7 +43376,7 @@
-
-
+
@@ -43386,15 +43398,15 @@
-
-
+
-
-
+
-
-
+
@@ -43624,7 +43636,7 @@
-
-
+
@@ -43668,30 +43680,30 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -44350,12 +44362,12 @@
-
-
+
-
-
+
@@ -44473,7 +44485,7 @@
-
+
@@ -44507,7 +44519,7 @@
-
-
+
@@ -44553,19 +44565,19 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -44577,7 +44589,7 @@
-
-
+
@@ -44590,7 +44602,7 @@
-
-
+
@@ -44600,7 +44612,7 @@
-
-
+
@@ -44610,7 +44622,7 @@
-
-
+
@@ -44620,7 +44632,7 @@
-
-
+
@@ -44631,7 +44643,7 @@
-
-
+
@@ -44642,7 +44654,7 @@
-
-
+
@@ -44651,7 +44663,7 @@
-
-
+
@@ -44659,7 +44671,7 @@
-
-
+
@@ -44670,7 +44682,7 @@
-
-
+
@@ -44679,7 +44691,7 @@
-
-
+
@@ -44688,17 +44700,17 @@
-
-
+
- -
+
-
-
+
-
-
+
@@ -44709,7 +44721,7 @@
-
-
+
@@ -44724,23 +44736,23 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -44790,7 +44802,7 @@
-
-
+
-
@@ -44800,7 +44812,7 @@
-
-
+
@@ -44970,28 +44982,29 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
- -
-
+
-
+
+
-
@@ -45113,7 +45126,7 @@
-
-
+
@@ -45121,7 +45134,7 @@
-
-
+
@@ -45129,7 +45142,7 @@
-
-
+
@@ -45141,11 +45154,11 @@
-
-
+
-
-
+
-
@@ -45372,22 +45385,22 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -45438,7 +45451,7 @@
-
-
+
-
@@ -45480,7 +45493,7 @@
-
-
+
@@ -45494,7 +45507,7 @@
-
-
+
@@ -45503,7 +45516,7 @@
-
-
+
@@ -45517,7 +45530,7 @@
-
-
+
@@ -45614,35 +45627,35 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -45652,25 +45665,25 @@
-
-
-
+
+
-
-
+
-
-
+
-
-
+
-
@@ -45680,15 +45693,15 @@
-
-
+
-
-
+
-
-
+
-
@@ -45763,19 +45776,19 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -45786,37 +45799,37 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -45824,16 +45837,16 @@
-
+
-
-
+
-
-
+
-
@@ -45901,32 +45914,32 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -45934,11 +45947,11 @@
-
-
+
-
-
+
-
@@ -45977,7 +45990,7 @@
-
-
+
-
@@ -46078,7 +46091,7 @@
-
-
+
@@ -46090,7 +46103,7 @@
-
-
+
@@ -46101,7 +46114,7 @@
-
+
@@ -46112,7 +46125,7 @@
-
+
@@ -46121,7 +46134,7 @@
-
-
+
@@ -46135,7 +46148,7 @@
-
+
@@ -46143,7 +46156,7 @@
-
-
+
@@ -46154,7 +46167,7 @@
-
-
+
@@ -46164,7 +46177,7 @@
-
-
+
-
@@ -46172,7 +46185,7 @@
-
+
@@ -46182,7 +46195,7 @@
-
-
+
@@ -46642,7 +46655,7 @@
-
-
+
-
@@ -46818,7 +46831,7 @@
-
-
+
-
@@ -46840,11 +46853,11 @@
-
-
+
-
-
+
@@ -46869,15 +46882,15 @@
-
-
+
-
-
+
-
-
+
@@ -46898,7 +46911,7 @@
-
-
+
-
@@ -46936,7 +46949,7 @@
-
-
+
-
@@ -47156,7 +47169,7 @@
-
-
+
@@ -47166,59 +47179,59 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -47335,7 +47348,7 @@
-
-
+
-
@@ -47570,7 +47583,7 @@
-
+
@@ -47579,23 +47592,23 @@
-
+
-
-
+
-
-
+
-
-
-
+
+
-
-
+
@@ -47619,19 +47632,19 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -47639,7 +47652,7 @@
-
-
+
@@ -47652,7 +47665,7 @@
-
-
+
@@ -47662,7 +47675,7 @@
-
-
+
@@ -47671,7 +47684,7 @@
-
-
+
@@ -47682,7 +47695,7 @@
-
-
+
@@ -47695,7 +47708,7 @@
-
-
+
@@ -47706,7 +47719,7 @@
-
-
+
@@ -47720,35 +47733,35 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -47808,7 +47821,7 @@
-
-
+
@@ -47822,7 +47835,7 @@
-
-
+
@@ -47833,7 +47846,7 @@
-
-
+
@@ -47853,7 +47866,7 @@
-
-
+
@@ -47861,21 +47874,21 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -47884,7 +47897,7 @@
-
+
@@ -48097,7 +48110,7 @@
-
-
+
-
@@ -48227,7 +48240,7 @@
-
-
+
-
@@ -48249,11 +48262,11 @@
-
-
+
-
-
+
@@ -48276,7 +48289,7 @@
-
-
+
@@ -48429,7 +48442,7 @@
-
-
+
@@ -48480,7 +48493,7 @@
-
-
+
@@ -48547,7 +48560,7 @@
-
+
-
@@ -48559,52 +48572,52 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
-
-
+
-
-
+
@@ -48657,7 +48670,7 @@
-
-
+
@@ -49012,7 +49025,7 @@
-
-
+
@@ -49021,7 +49034,7 @@
-
-
+
@@ -49043,7 +49056,7 @@
-
-
+
@@ -49127,7 +49140,7 @@
-
+
@@ -49136,7 +49149,7 @@
-
+
@@ -49148,7 +49161,7 @@
-
+
@@ -49156,7 +49169,7 @@
-
+
@@ -49164,42 +49177,42 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
@@ -49207,22 +49220,22 @@
-
-
+
-
-
+
-
-
+
-
-
+
-
@@ -49232,7 +49245,7 @@
-
-
+
@@ -49243,7 +49256,7 @@
-
-
+
@@ -49287,7 +49300,7 @@
-
-
+
-
@@ -49326,17 +49339,17 @@
-
-
+
-
-
+
-
-
+
@@ -49513,22 +49526,22 @@
-
-
+
-
-
+
-
-
+
-
-
+
@@ -49628,259 +49641,613 @@
+
+
+
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
- -
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+ -
+
+
+ -
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+
+ -
+
+
+ -
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
-
+
- -
+
-
-
+
- -
+
-
-
-
+
+
- -
+
-
-
+
- -
+
-
- -
+
-
- -
+
-
-
+
- -
+
-
- -
+
-
- -
+
-
- -
+
-
-
+
- -
+
-
- -
+
-
- -
+
-
- -
+
-
-
+
- -
+
-
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
- -
+
-
+
+
+
+
+
+ -
- -
+
-
- -
+
-
-
+
- -
+
-
+
+ -
+
+
+
- -
+
-
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
- -
+
-
- -
+
-
-
+
- -
+
-
- -
+
-
- -
+
-
- -
+
-
- -
+
-
+
+ -
+
+
+
- -
+
-
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
-
+
- -
+
-
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
-
+
- -
+
-
-
-
+
+
- -
+
-
-
+
- -
+
-
-
+
- -
+
-
-
+
- -
+
-
-
-
+
+
- -
+
-
-
+
- -
+
-
- -
+
-
- -
+
-
-
+
- -
+
-
- -
+
-
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
- -
+
-
- -
+
-
-
+
- -
+
-
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ -
+
-
@@ -49900,10 +50267,10 @@
-
- -
+
-
- -
+
-
-
@@ -49912,17 +50279,18 @@
-
- -
+
-
- -
+
-
+
-
-
-
+
-
@@ -49940,20 +50308,20 @@
-
+
-
-
+
-
-
+
-
-
+
-
-
@@ -49964,56 +50332,177 @@
-
- -
+
-
-
-
-
+
+
+ -
+
- -
+
-
+
+
+ -
- -
+
-
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
- -
+
-
-
+
- -
+
-
+
+ -
+
+
+
+
+ -
+
+
+
+
- -
+
-
+
+
+
+
+
+ -
+
+
+
+
+
+ -
- -
+
-
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
- -
+
-
-
+
- -
+
-
@@ -50022,9 +50511,34 @@
-
+ -
+
+
+
-
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
-
@@ -50032,7 +50546,7 @@
- -
+
-
@@ -50043,7 +50557,7 @@
-
-
+
-
@@ -50075,8 +50589,9 @@
-
-
+
+
-
@@ -50088,7 +50603,7 @@
-
+
@@ -50101,7 +50616,7 @@
-
+
@@ -50116,7 +50631,7 @@
-
+
@@ -50129,22 +50644,22 @@
-
+
-
-
+
-
+
@@ -50157,14 +50672,14 @@
-
+
-
-
+
@@ -50177,7 +50692,7 @@
-
-
+
@@ -50189,7 +50704,7 @@
-
-
+
@@ -50201,7 +50716,7 @@
-
-
+
@@ -50229,7 +50744,7 @@
-
-
+
@@ -50239,7 +50754,7 @@
-
-
+
@@ -50248,7 +50763,7 @@
-
-
+
@@ -50265,7 +50780,7 @@
-
+
-
@@ -50275,12 +50790,12 @@
-
+
-
-
+
@@ -50311,119 +50826,129 @@
-
-
+
+
-
+
+
+
- -
+
-
+
- -
+
-
- -
+
-
-
+
- -
+
-
- -
+
-
+
- -
+
-
- -
+
-
-
+
- -
+
-
-
- -
+
+ -
+
- -
+
-
- -
+
-
-
+
- -
+
-
-
- -
+
+ -
+
- -
+
-
- -
+
-
-
+
- -
+
-
-
- -
+
+ -
+
- -
+
-
- -
+
-
-
+
- -
+
-
@@ -50480,7 +51005,7 @@
-
-
+
@@ -50492,7 +51017,7 @@
-
-
+
@@ -50503,7 +51028,7 @@
-
-
+
@@ -50519,12 +51044,12 @@
-
+
-
-
+
@@ -50537,7 +51062,7 @@
-
+
@@ -50548,12 +51073,12 @@
-
+
-
-
+
@@ -50569,7 +51094,7 @@
-
+
-
@@ -50591,6 +51116,19 @@
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
-
@@ -50683,14 +51221,154 @@
- -
+
-
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
- -
+
-
+
+ -
+
+
+
+ -
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+ -
+
+
-
@@ -50714,6 +51392,11 @@
+ -
+
+
+ -
+
-
@@ -50721,7 +51404,7 @@
-
+
@@ -50732,18 +51415,24 @@
-
+
+ -
+
+
+
+
-
+
-
-
+
@@ -50764,4 +51453,4 @@
-
\ No newline at end of file
+
diff --git a/data/migrations/3.lua b/data/migrations/3.lua
index f772d9b389..f67c4210dd 100644
--- a/data/migrations/3.lua
+++ b/data/migrations/3.lua
@@ -5,6 +5,5 @@ function onUpdateDatabase()
ALTER TABLE `prey_slots`
ADD `tick` smallint(3) NOT NULL DEFAULT '0';
]])
-
return true
end
diff --git a/data/migrations/5.lua b/data/migrations/5.lua
index 2c7477d680..b80badf395 100644
--- a/data/migrations/5.lua
+++ b/data/migrations/5.lua
@@ -1,3 +1,5 @@
function onUpdateDatabase()
- return false -- true = There are others migrations file | false = this is the last migration file
+ print("> Updating database to version 6 (quickloot)")
+ db.query("ALTER TABLE `players` ADD `quickloot_fallback` TINYINT DEFAULT 0")
+ return true
end
diff --git a/data/migrations/6.lua b/data/migrations/6.lua
new file mode 100644
index 0000000000..2c7477d680
--- /dev/null
+++ b/data/migrations/6.lua
@@ -0,0 +1,3 @@
+function onUpdateDatabase()
+ return false -- true = There are others migrations file | false = this is the last migration file
+end
diff --git a/data/modules/modules.xml b/data/modules/modules.xml
index 341557359b..594a3cb48b 100644
--- a/data/modules/modules.xml
+++ b/data/modules/modules.xml
@@ -19,11 +19,6 @@
-
-
-
-
-
diff --git a/data/modules/scripts/quickloot/quickloot.lua b/data/modules/scripts/quickloot/quickloot.lua
deleted file mode 100644
index 695c69873d..0000000000
--- a/data/modules/scripts/quickloot/quickloot.lua
+++ /dev/null
@@ -1,608 +0,0 @@
-QuickLootSystem = {
- Developer = "Ticardo (Rick), lBaah, dudantas, gpedro, DudZ",
- Version = "1.0",
- lastUpdate = "29/03/2020 - 12:00"
-}
-
---[[
- missing features:
- - autowalk if corpse is far (+1sqm)
- - better loot messages
- - update container to refresh quickLootFlags after save quickloot backpacks
-]]--
-
-local ClientPackets = {
- ManageItemList = 0x91,
- SelectBackpack = 0x90,
- LootCorpse = 0x8F
-}
-
-local ServerPackets = {
- SendBackpack = 0xC0
-}
-
- -- TODO: check a better storage no
-local StorageQuickLoot = {
- ItemsToLoot = "831831",
- LootMode = 832832,
- MainContainerFallback = 833833,
-}
-
-local QUICKLOOT_CATEGORY_ATTRIBUTE = "quickLootCategory"
-
-local QUICKLOOT_MODE_BLACKLIST = 0
-local QUICKLOOT_MODE_WHITELIST = 1
-
-local QuickLootCategory = {
- UnassignedLoot = 31,
- Gold = 30,
- Armors = 1,
- Amulets = 2,
- Boots = 3,
- Containers = 4,
- CreatureProducts = 24,
- Decoration = 5,
- Food = 6,
- Helmets = 7,
- Legs = 8,
- Others = 9,
- Potions = 10,
- Rings = 11,
- Runes = 12,
- Shields = 13,
- Tools = 14,
- Valuables = 15,
- WeaponsAmmo = 16,
- WeaponsAxe = 17,
- WeaponsClubs = 18,
- WeaponsDistance = 19 ,
- WeaponsSwords = 20,
- WeaponsWands = 21,
- StashRetrieve = 27,
-}
-
-local QuickLootReturn = {
- ITEM_LOOTED = { looted = true, id = 1, message = ""},
- ITEM_WITH_NO_CATEGORY = {looted = false, id = 2, message = "Couldn't find the category for this item."},
- PLAYER_HAS_NO_BP_AND_FALLBACK_DISABLED = {looted = false, id = 3, message = "Couldn't find any of the loot containers defined for this item."},
- COULD_NOT_FIND_ANY_BP = {looted = false, id = 4, message = "Couldn't find any of the loot containers defined for this item."},
- NO_FREE_SLOTS_LEFT = {looted = false, id = 5, message = "There is no empty slots left in the loot containers defined."},
- NO_CAPACITY ={looted = false, id = 6, message = "You don't have enough capacity."}
-}
-
-
-function onRecvbyte(player, msg, byte)
- setupDatabase()
- if byte == ClientPackets.ManageItemList then
- local lootMode = msg:getByte()
- local itemCount = msg:getU16()
- local itemList = {}
-
- if itemCount >= 1 then
- local item = nil
- for i = 1, itemCount do
- item = Game.getItemIdByClientId(msg:getU16())
- if item then
- table.insert(itemList, item:getId())
- end
- end
- end
-
- player:setQuickLootMode(lootMode)
- player:setQuickLootItems(itemList)
- player:sendLootBackpacks()
- elseif byte == ClientPackets.LootCorpse then
- -- TODO add spam protection
- local position = msg:getPosition()
- local itemId = msg:getU16()
- local stackPos = msg:getByte()
-
- local lootMode = player:getQuickLootMode()
- local lootList = player:getQuickLootItems()
- local quickLootBackpacks = player:getQuickLootBackpacks()
- if position.x == CONTAINER_POSITION then
- local container = player:getContainerById(position.y - 64)
- if container then
- local item = container:getItem(position.z)
- if item then
- local itemLooted = lootItem(player, quickLootBackpacks, item)
- if not itemLooted.looted then
- player:sendCancelMessage(itemLooted.message)
- else
- player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You looted " .. item:getCount().. "x "..item:getName() .. ".")
- end
- return
- end
- end
- end
-
- local itemTile = Tile(position)
- if not itemTile then
- return
- end
-
- if player:getPosition():getDistance(position) > 1 then
- return
- end
-
- local thing = itemTile:getThing(stackPos)
- if thing and thing:isItem() then
- local corpseOwner = thing:getCorpseOwner()
- if corpseOwner ~= 0 and not player:canOpenCorpse(corpseOwner) then
- player:sendCancelMessage("You are not the owner.")
- return
- end
-
- if thing:isContainer() then
- local itemsBefore = getContainerItems(thing)
- if #itemsBefore == 0 then
- player:sendTextMessage(MESSAGE_LOOT, "No loot.")
- return
- end
-
- lootContainer(player, quickLootBackpacks, thing, lootMode, lootList)
-
- local itemsAfter = getContainerItems(thing)
- local lootedItems = {}
- local notLootedItemsFromList = {}
- local notLootedItemsAtAll = {}
- for i, k in pairs(itemsBefore) do
- local itemStr = k:getCount().. "x "..k:getName()
- if not table.contains(itemsAfter, k) then
- table.insert(lootedItems, itemStr)
- player:updateLootTracker(k)
- elseif canLootItem(k.itemid, lootMode, lootList) then
- table.insert(notLootedItemsFromList, itemStr)
- else
- table.insert(notLootedItemsAtAll, itemStr)
- end
- end
-
- if #lootedItems > 0 then
- player:sendTextMessage(MESSAGE_LOOT, "You looted " .. table.concat(lootedItems, ", ") .. ".")
- else
- player:sendTextMessage(MESSAGE_LOOT, "You looted none of the dropped items.")
- end
-
- if #notLootedItemsFromList > 0 then
- player:sendCancelMessage("Could not loot " .. table.concat(notLootedItemsFromList, ", ") .. ".")
- end
- elseif thing:isItem() and canLootItem(thing.itemid, lootMode, lootList) then
- local itemType = thing:getType()
- if itemType:isCorpse() then
- return
- end
-
- local itemLooted = lootItem(player, quickLootBackpacks, thing)
- if not itemLooted.looted then
- player:sendCancelMessage(itemLooted.message)
- else
- player:sendTextMessage(MESSAGE_LOOT, "You looted " .. item:getCount().. "x "..item:getName() .. ".")
- end
- end
- end
- elseif byte == ClientPackets.SelectBackpack then
- local action = msg:getByte()
- if action == 0 then
- local category = msg:getByte()
- local containerType = msg:getU16()
- local containerSlot = msg:getU16()
- local containerPosition = msg:getByte()
- local containerId = msg:getU16()
-
- player:setQuickLootBackpack(category, containerSlot, containerPosition, containerId)
- player:sendLootBackpacks()
- player:updateQuickLootContainers()
- elseif action == 1 then
- local category = msg:getByte()
- player:setQuickLootBackpack(category, nil)
- player:sendLootBackpacks()
- player:updateQuickLootContainers()
- elseif action == 2 then
- local categoryId = msg:getByte()
- local quickLootBackpacks = player:getQuickLootBackpacks()
-
- if quickLootBackpacks[categoryId] then
- local category = quickLootBackpacks[categoryId]
- local container = getContainerByQuickLootCategory(player, categoryId, category.sid)
- if container then
- player:sendContainer(container)
- end
- end
- elseif action == 3 then
- local bpFallback = player:getQuickLootMainContainerFallback()
- if bpFallback ~= nil then
- player:setQuickLootMainContainerFallback((bpFallback == 1) and 0 or 1)
- else
- player:setQuickLootMainContainerFallback(1)
- end
- player:sendLootBackpacks()
- end
-
- end
-end
-
--- Helpers Methods
-function getContainerItems(container)
- local rtn = {}
- for i = 0, container:getSize() do
- local item = container:getItem(i)
- if item then
- table.insert(rtn, item)
- if item:isContainer() then
- thisItems = getContainerItems(item)
- for i,k in pairs(thisItems) do
- table.insert(rtn, k)
- end
- end
- end
- end
- return rtn
-end
-
-function canLootItem(itemId, lootMode, lootList)
- if lootMode == QUICKLOOT_MODE_BLACKLIST then
- return not table.contains(lootList, itemId)
- end
-
- if lootMode == QUICKLOOT_MODE_WHITELIST then
- return table.contains(lootList, itemId)
- end
-
- return false
-end
-
-function lootContainer(player, backpacks, containerItem, lootMode, lootList)
- local container = Container(containerItem.uid)
- for i = 0, container:getSize() do
- local item = container:getItem(i)
- if item then
- if item:isContainer() then
- lootContainer(player, backpacks, item, lootMode, lootList)
- elseif item:isItem() then
- if canLootItem(item.itemid, lootMode, lootList) then
- if lootItem(player, backpacks, item).looted then
- lootContainer(player, backpacks, container, lootMode, lootList)
- break
- end
- end
- end
- end
- end
-end
-
-function lootItem(player, backpacks, item)
- if item:getWeight() > player:getFreeCapacity() then
- return QuickLootReturn.NO_CAPACITY
- end
- local itemType = ItemType(item.itemid)
- if not itemType or not itemType:getLootCategory() then
- return QuickLootReturn.ITEM_WITH_NO_CATEGORY
- end
- local category = itemType:getLootCategory()
- local definedBackpack = backpacks[category]
-
- -- If there is no bp defined for this category, set UnassignedLoot backpack as the target
- if not definedBackpack then
- category = QuickLootCategory.UnassignedLoot
- definedBackpack = backpacks[category]
- end
-
- local destination = false
-
-
- -- If there is no UnassignedLoot backpack defined or the player don't have the backpack in their inventory, set destination as the mainBp if fallback is enabled
- if not definedBackpack or not player:getItemCount(definedBackpack.sid) then
- if player:getQuickLootMainContainerFallback() == 1 then
- destination = player:getSlotItem(CONST_SLOT_BACKPACK)
- else
- return QuickLootReturn.PLAYER_HAS_NO_BP_AND_FALLBACK_DISABLED
- end
- end
-
- if not destination then
- destination = getContainerByQuickLootCategory(player, category, definedBackpack.sid)
- end
- if not destination then
- return QuickLootReturn.COULD_NOT_FIND_ANY_BP
- end
-
- -- check freeSlot (if you dont check, it will add items even being beyond backpack capacity)
- if destination:getEmptySlots() == 0 then
- -- search for another BP form MainBP like this with FreeSlots
- -- if cannot have slot to move, find next container inside selected backpack (or another container == this one in other backpack (recursive performance loss?))
- -- else if it's fully full
- -- move to UnassignedLoot (avoid redundancy checks by checking category again here, if it's already UnassignedLoot you can just go to main container)
- -- if cannot have slot to move, find next container inside UnassignedLoot backpack
- -- else if it's fully full
- -- if main container fallback is enabled, move to main cotainer
- -- else ignore (and send message to user)
- destination = getFirstFreeBPOfType(player:getSlotItem(CONST_SLOT_BACKPACK), destination.itemid)
- if not destination and not category == QuickLootCategory.UnassignedLoot then
- destination = getFirstFreeBPOfType(player:getSlotItem(CONST_SLOT_BACKPACK), backpacks[QuickLootCategory.UnassignedLoot].sid)
- end
- if not destination and player:getQuickLootMainContainerFallback() == 1 then
- destination = getFirstFreeBPOfType(player:getSlotItem(CONST_SLOT_BACKPACK), player:getSlotItem(CONST_SLOT_BACKPACK).itemid)
- end
- if not destination then
- return QuickLootReturn.NO_FREE_SLOTS_LEFT
- end
- end
-
- item:moveTo(destination)
- return QuickLootReturn.ITEM_LOOTED
-end
-
-function getFirstFreeBPOfType(rootContainer, bpSID)
- if rootContainer.itemid == bpSID and rootContainer:getEmptySlots() > 0 then
- return rootContainer
- end
-
- for i = 0, rootContainer:getSize() - 1 do
- local item = rootContainer:getItem(i)
- if item:isContainer() then
- local foundOurBP = getFirstFreeBPOfType(item, bpSID)
- if foundOurBP then
- return foundOurBP
- end
- end
- end
-
- return nil
-end
-
-function getContainerBySlot(player, containerSlot, containerIndex)
- local item
-
- local container = player:getContainerById(containerSlot - 64)
- if container then
- item = container:getItem(containerIndex)
- else
- item = player:getSlotItem(containerSlot)
- end
-
- return item
-end
-
-function getContainerByQuickLootCategory(player, categoryId, serverId)
- local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX)
- if inbox then
- local itemsCount = inbox:getItemCountById(serverId)
- if itemsCount then
- local insideInbox = checkContainerCategory(inbox, categoryId)
- if insideInbox then
- return insideInbox
- end
- end
- end
-
- local mainBp = player:getSlotItem(CONST_SLOT_BACKPACK)
- if mainBp and mainBp:hasQuickLootCategory(categoryId) then
- return mainBp
- end
-
- local itemsCount = player:getItemCount(serverId)
- if not itemsCount then -- If this player doesn't have any BP like its the set one in the inventory, use mainBP as fallback
- return nil
- end
-
- local insideBp = checkContainerCategory(mainBp, categoryId)
- if insideBp then
- return insideBp
- end
-
- return nil
-end
-
-function checkContainerCategory(containerItem, categoryId)
- if not containerItem then
- return nil
- end
-
- local container = Container(containerItem.uid)
- if container then
- if container:hasQuickLootCategory(categoryId) then
- return container
- end
-
- for i = 0, container:getSize() - 1 do
- local item = container:getItem(i)
-
- if item:isContainer() then
- local nestedContainer = checkContainerCategory(item, categoryId)
- if nestedContainer then
- return nestedContainer
- end
- end
- end
- end
-
- return nil
-end
-
--- Container Methods
-function Container.hasQuickLootCategory(self, categoryId)
- return self:getCustomAttribute(string.format("%s%d", QUICKLOOT_CATEGORY_ATTRIBUTE, categoryId)) == 1
-end
-
-function Container.addQuickLootCategory(self, categoryId)
- self:setCustomAttribute(string.format("%s%d", QUICKLOOT_CATEGORY_ATTRIBUTE, categoryId), 1)
-end
-
-function Container.removeQuickLootCategory(self, categoryId)
- self:removeCustomAttribute(string.format("%s%d", QUICKLOOT_CATEGORY_ATTRIBUTE, categoryId))
-end
-
--- Player Methods
-function Player.sendLootBackpacks(self)
-
- local playerId = self:getGuid()
- local containers = {}
- local count = 0
- local rows = db.storeQuery("SELECT `category_id`, `cid`, `sid` FROM `quickloot_containers` WHERE player_id = " .. playerId)
-
- if rows then
- repeat
- local categoryId = result.getNumber(rows, "category_id")
- local clientId = result.getNumber(rows, "cid")
- local serverId = result.getNumber(rows, "sid")
-
- if getContainerByQuickLootCategory(self, categoryId, serverId) then
- count = count + 1
- containers[categoryId] = clientId
- end
- until not result.next(rows)
-
- result.free(rows)
- end
-
- local msg = NetworkMessage()
-
- msg:addByte(ServerPackets.SendBackpack)
- msg:addByte(self:getQuickLootMainContainerFallback() or 1)
- msg:addByte(count)
-
- for categoryId, clientId in pairs(containers) do
- msg:addByte(categoryId)
- -- if categoryId == QuickLootCategory.UnassignedLoot and not clientId then
- --clientId =
- -- end
- msg:addU16(clientId)
- end
-
- msg:sendToPlayer(self)
-end
-
-function Player.setQuickLootBackpack(self, categoryId, containerSlot, containerPosition, containerId)
- local playerId = self:getGuid()
-
- -- if is just remove instead replace
- if not containerSlot then
- local oldContainerQuery = db.storeQuery("SELECT `sid` FROM `quickloot_containers` WHERE player_id = " .. playerId .. " and category_id = " .. categoryId)
- if oldContainerQuery then
- local serverId = result.getNumber(oldContainerQuery, "sid")
- local oldContainer = getContainerByQuickLootCategory(self, categoryId, serverId)
- if oldContainer then
- oldContainer:removeQuickLootCategory(categoryId)
- end
- end
-
- result.free(oldContainerQuery)
- db.query("DELETE FROM `quickloot_containers` WHERE `player_id` = " .. playerId .. " AND `category_id` = " .. categoryId)
- return
- end
-
- -- check if already exists
- local query = db.storeQuery("SELECT COUNT(category_id) as c FROM `quickloot_containers` WHERE player_id = " .. playerId .. " AND `category_id` = " .. categoryId)
- local count = result.getNumber(query, "c")
- result.free(query)
-
- local container = getContainerBySlot(self, containerSlot, containerPosition)
- if not container then
- return
- end
-
- if container.itemid == ITEM_GOLD_POUCH and categoryId ~= QuickLootCategory.Gold then
- self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
- return
- end
-
- -- if exists another value, remove custom attribute
- local oldServerId = container.itemid
- local oldContainer = getContainerByQuickLootCategory(self, categoryId, oldServerId)
- if oldContainer then
- oldContainer:removeQuickLootCategory(categoryId)
- end
-
- -- and add custom attribute to new container
- local serverId = container.itemid
-
- if not container:hasQuickLootCategory(categoryId) then
- container:addQuickLootCategory(categoryId)
- end
-
- if count == 0 then
- db.query("INSERT INTO `quickloot_containers` (`player_id`, `category_id`, `cid`, `sid`) VALUES (" .. playerId .. ", " .. categoryId .. ", " .. containerId .. ", " .. serverId .. ");")
- return
- end
-
- db.query('UPDATE `quickloot_containers` SET `cid` = ' .. containerId .. ', `sid` = ' .. serverId.. ' WHERE `player_id` = ' .. playerId .. ' AND `category_id` = ' .. categoryId .. '')
-end
-
-function Player.getQuickLootBackpacks(self)
- local playerId = self:getGuid()
- local query = db.storeQuery("SELECT `category_id`, `cid`, `sid` FROM `quickloot_containers` WHERE player_id = " .. playerId)
- local containers = {}
-
- if query then
- repeat
- local categoryId = result.getNumber(query, "category_id")
- local clientId = result.getNumber(query, "cid")
- local serverId = result.getNumber(query, "sid")
-
- containers[categoryId] = {
- cid = clientId,
- sid = serverId,
- }
- until not result.next(query)
-
- result.free(query)
- end
-
- return containers
-end
-
-function Player.resetQuickLootItems(self)
- self:setQuickLootItems({})
-end
-
-function Player.getQuickLootMode(self)
- return self:getStorageValue(StorageQuickLoot.LootMode)
-end
-
-function Player.getQuickLootMainContainerFallback(self)
- return self:getStorageValue(StorageQuickLoot.MainContainerFallback)
-end
-
-function Player.setQuickLootMode(self, check)
- self:setStorageValue(StorageQuickLoot.LootMode, check or 0)
-end
-
-function Player.setQuickLootMainContainerFallback(self, check)
- self:setStorageValue(StorageQuickLoot.MainContainerFallback, check or 0)
-end
-
-function Player.setQuickLootItems(self, items)
- if type(items) ~= "table" then
- items = {}
- end
-
- self:setSpecialStorage(StorageQuickLoot.ItemsToLoot, items)
-end
-
-function Player.getQuickLootItems(self)
- local value = self:getSpecialStorage(StorageQuickLoot.ItemsToLoot)
- if not value then
- return {}
- end
-
- return value
-end
-
-function Player.updateQuickLootContainers(self)
- -- local quickLootCategories = self:getQuickLootBackpacks()
- -- for i = QuickLootCategory.Armors, QuickLootCategory.StashRetrieve do
- -- getContainerByQuickLootCategory(self, i, )
- -- end
-end
-
-function setupDatabase()
- db.query([[CREATE TABLE IF NOT EXISTS `quickloot_containers` (
- `player_id` INT NOT NULL,
- `category_id` INT UNSIGNED NOT NULL,
- `cid` INT UNSIGNED NOT NULL,
- `sid` INT UNSIGNED NOT NULL,
-
- CONSTRAINT `fk_quickloot_containers_player_id` FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
- )]])
-end
diff --git a/schema.sql b/schema.sql
index df2ad4861a..e912bb91cb 100644
--- a/schema.sql
+++ b/schema.sql
@@ -152,6 +152,7 @@ CREATE TABLE IF NOT EXISTS `players` (
`marriage_status` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
`marriage_spouse` int(11) NOT NULL DEFAULT '-1',
`bonus_rerolls` bigint(21) NOT NULL DEFAULT '0',
+ `quickloot_fallback` tinyint(1) DEFAULT '0',
INDEX `account_id` (`account_id`),
INDEX `vocation` (`vocation`),
CONSTRAINT `players_pk` PRIMARY KEY (`id`),
diff --git a/src/const.h b/src/const.h
index cbfb9d40cd..b8203a9531 100644
--- a/src/const.h
+++ b/src/const.h
@@ -394,39 +394,6 @@ enum Icons_t {
ICON_BLEEDING = 1 << 15,
};
-enum QuickLootCategory_t : uint8_t {
- LOOT_NONE = 0,
- LOOT_ARMOR = 1,
- LOOT_AMULET = 2,
- LOOT_BOOTS = 3,
- LOOT_CONTAINER = 4,
- LOOT_DECORATION = 5,
- LOOT_FOOD = 6,
- LOOT_HELMET = 7,
- LOOT_LEGS = 8,
- LOOT_OTHER = 9,
- LOOT_POTION = 10,
- LOOT_RING = 11,
- LOOT_RUNE = 12,
- LOOT_SHIELD = 13,
- LOOT_TOOL = 14,
- LOOT_VALUABLE = 15,
- LOOT_WEAPON_AMMO = 16,
- LOOT_WEAPON_AXE = 17,
- LOOT_WEAPON_CLUB = 18,
- LOOT_WEAPON_DISTANCE = 19,
- LOOT_WEAPON_SWORD = 20,
- LOOT_WEAPON_WAND = 21,
- LOOT_CREATURE_PRODUCT = 24,
- LOOT_STASH_RETRIEVE = 27,
- LOOT_GOLD = 30,
- LOOT_UNASSIGNED = 31,
-
- LOOT_START = LOOT_ARMOR,
- LOOT_END = LOOT_UNASSIGNED
-
-};
-
enum WeaponType_t : uint8_t {
WEAPON_NONE,
WEAPON_SWORD,
diff --git a/src/enums.h b/src/enums.h
index 73bfd154ce..57fe092917 100644
--- a/src/enums.h
+++ b/src/enums.h
@@ -94,6 +94,7 @@ enum itemAttrTypes : uint32_t {
ITEM_ATTRIBUTE_SPECIAL = 1 << 23,
ITEM_ATTRIBUTE_IMBUINGSLOTS = 1 << 24,
ITEM_ATTRIBUTE_OPENCONTAINER = 1 << 25,
+ ITEM_ATTRIBUTE_QUICKLOOTCONTAINER = 1 << 26,
ITEM_ATTRIBUTE_CUSTOM = 1U << 31
};
@@ -533,6 +534,47 @@ enum MapMark_t
MAPMARK_GREENSOUTH = 19,
};
+enum QuickLootFilter_t
+{
+ QUICKLOOTFILTER_SKIPPEDLOOT = 0,
+ QUICKLOOTFILTER_ACCEPTEDLOOT = 1,
+};
+
+enum ObjectCategory_t
+{
+ OBJECTCATEGORY_NONE = 0,
+ OBJECTCATEGORY_ARMORS = 1,
+ OBJECTCATEGORY_NECKLACES = 2,
+ OBJECTCATEGORY_BOOTS = 3,
+ OBJECTCATEGORY_CONTAINERS = 4,
+ OBJECTCATEGORY_DECORATION = 5,
+ OBJECTCATEGORY_FOOD = 6,
+ OBJECTCATEGORY_HELMETS = 7,
+ OBJECTCATEGORY_LEGS = 8,
+ OBJECTCATEGORY_OTHERS = 9,
+ OBJECTCATEGORY_POTIONS = 10,
+ OBJECTCATEGORY_RINGS = 11,
+ OBJECTCATEGORY_RUNES = 12,
+ OBJECTCATEGORY_SHIELDS = 13,
+ OBJECTCATEGORY_TOOLS = 14,
+ OBJECTCATEGORY_VALUABLES = 15,
+ OBJECTCATEGORY_AMMO = 16,
+ OBJECTCATEGORY_AXES = 17,
+ OBJECTCATEGORY_CLUBS = 18,
+ OBJECTCATEGORY_DISTANCEWEAPONS = 19,
+ OBJECTCATEGORY_SWORDS = 20,
+ OBJECTCATEGORY_WANDS = 21,
+ OBJECTCATEGORY_PREMIUMSCROLLS = 22, // not used in quickloot
+ OBJECTCATEGORY_TIBIACOINS = 23, // not used in quickloot
+ OBJECTCATEGORY_CREATUREPRODUCTS = 24,
+ OBJECTCATEGORY_STASHRETRIEVE = 27,
+ OBJECTCATEGORY_GOLD = 30,
+ OBJECTCATEGORY_DEFAULT = 31, // unassigned loot
+
+ OBJECTCATEGORY_FIRST = OBJECTCATEGORY_ARMORS,
+ OBJECTCATEGORY_LAST = OBJECTCATEGORY_DEFAULT,
+};
+
struct Outfit_t {
uint16_t lookType = 0;
uint16_t lookTypeEx = 0;
diff --git a/src/game.cpp b/src/game.cpp
index ae1fd18cee..9467afdc68 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -313,17 +313,18 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
break;
}
- case STACKPOS_FIND_THING: {
- thing = tile->getUseItem(index);
- if (!thing) {
- thing = tile->getDoorItem();
- }
-
- if (!thing) {
- thing = tile->getTopDownItem();
- }
- break;
- }
+ case STACKPOS_FIND_THING: {
+ thing = tile->getUseItem(index);
+ if (!thing) {
+ thing = tile->getDoorItem();
+ }
+
+ if (!thing) {
+ thing = tile->getTopDownItem();
+ }
+
+ break;
+ }
default: {
thing = nullptr;
@@ -1823,6 +1824,316 @@ ReturnValue Game::internalTeleport(Thing* thing, const Position& newPos, bool pu
return RETURNVALUE_NOTPOSSIBLE;
}
+void Game::internalQuickLootCorpse(Player* player, Container* corpse)
+{
+ if (!player || !corpse) {
+ return;
+ }
+
+ std::vector- itemList;
+ bool ignoreListItems = (player->quickLootFilter == QUICKLOOTFILTER_SKIPPEDLOOT);
+
+ bool missedAnyGold = false;
+ bool missedAnyItem = false;
+
+ for (ContainerIterator it = corpse->iterator(); it.hasNext(); it.advance()) {
+ Item* item = *it;
+ bool listed = player->isQuickLootListedItem(item);
+ if ((listed && ignoreListItems) || (!listed && !ignoreListItems)) {
+ if (item->getWorth() != 0) {
+ missedAnyGold = true;
+ } else {
+ missedAnyItem = true;
+ }
+ continue;
+ }
+
+ itemList.push_back(item);
+ }
+
+ bool shouldNotifyCapacity = false;
+ ObjectCategory_t shouldNotifyNotEnoughRoom = OBJECTCATEGORY_NONE;
+
+ uint32_t totalLootedGold = 0;
+ uint32_t totalLootedItems = 0;
+ for (Item* item : itemList) {
+ uint32_t worth = item->getWorth();
+ uint16_t baseCount = item->getItemCount();
+ ObjectCategory_t category = getObjectCategory(item);
+
+ ReturnValue ret = internalQuickLootItem(player, item, category);
+ if (ret == RETURNVALUE_NOTENOUGHCAPACITY) {
+ shouldNotifyCapacity = true;
+ } else if (ret == RETURNVALUE_CONTAINERNOTENOUGHROOM) {
+ shouldNotifyNotEnoughRoom = category;
+ }
+
+ bool success = ret == RETURNVALUE_NOERROR;
+ if (worth != 0) {
+ missedAnyGold = missedAnyGold || !success;
+ if (success) {
+ player->sendLootStats(item);
+ totalLootedGold += worth;
+ } else {
+ // item is not completely moved
+ totalLootedGold += worth - item->getWorth();
+ }
+ } else {
+ missedAnyItem = missedAnyItem || !success;
+ if (success || item->getItemCount() != baseCount) {
+ totalLootedItems++;
+ player->sendLootStats(item);
+ }
+ }
+ }
+
+ std::stringstream ss;
+ if (totalLootedGold != 0 || missedAnyGold || totalLootedItems != 0 || missedAnyItem) {
+ bool lootedAllGold = totalLootedGold != 0 && !missedAnyGold;
+ bool lootedAllItems = totalLootedItems != 0 && !missedAnyItem;
+ if (lootedAllGold) {
+ if (totalLootedItems != 0 || missedAnyItem) {
+ ss << "You looted the complete " << totalLootedGold << " gold";
+
+ if (lootedAllItems) {
+ ss << " and all dropped items";
+ } else if (totalLootedItems != 0) {
+ ss << ", but you only looted some of the items";
+ } else if (missedAnyItem) {
+ ss << " but none of the dropped items";
+ }
+ } else {
+ ss << "You looted " << totalLootedGold << " gold";
+ }
+ } else if (lootedAllItems) {
+ if (totalLootedItems == 1) {
+ ss << "You looted 1 item";
+ } else if (totalLootedGold != 0 || missedAnyGold) {
+ ss << "You looted all of the dropped items";
+ } else {
+ ss << "You looted all items";
+ }
+
+ if (totalLootedGold != 0) {
+ ss << ", but you only looted " << totalLootedGold << " of the dropped gold";
+ } else if (missedAnyGold) {
+ ss << " but none of the dropped gold";
+ }
+ } else if (totalLootedGold != 0) {
+ ss << "You only looted " << totalLootedGold << " of the dropped gold";
+ if (totalLootedItems != 0) {
+ ss << " and some of the dropped items";
+ } else if (missedAnyItem) {
+ ss << " but none of the dropped items";
+ }
+ } else if (totalLootedItems != 0) {
+ ss << "You looted some of the dropped items";
+ if (missedAnyGold) {
+ ss << " but none of the dropped gold";
+ }
+ } else if (missedAnyGold) {
+ ss << "You looted none of the dropped gold";
+ if (missedAnyItem) {
+ ss << " and none of the items";
+ }
+ } else if (missedAnyItem) {
+ ss << "You looted none of the dropped items";
+ }
+ } else {
+ ss << "No loot";
+ }
+
+ ss << ".";
+ player->sendTextMessage(MESSAGE_LOOT, ss.str());
+
+ if (shouldNotifyCapacity) {
+ ss.str(std::string());
+ ss << "Attention! The loot you are trying to pick up is too heavy for you to carry.";
+ } else if (shouldNotifyNotEnoughRoom != OBJECTCATEGORY_NONE) {
+ ss.str(std::string());
+ ss << "Attention! The container assigned to category " << getObjectCategoryName(shouldNotifyNotEnoughRoom) << " is full.";
+ } else {
+ return;
+ }
+
+ if (player->lastQuickLootNotification + 15000 < OTSYS_TIME()) {
+ player->sendTextMessage(MESSAGE_STATUS_WARNING, ss.str());
+ } else {
+ player->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
+ }
+
+ player->lastQuickLootNotification = OTSYS_TIME();
+}
+
+ReturnValue Game::internalQuickLootItem(Player* player, Item* item, ObjectCategory_t category /* = OBJECTCATEGORY_DEFAULT*/)
+{
+ if (!player || !item) {
+ return RETURNVALUE_NOTPOSSIBLE;
+ }
+
+ bool fallbackConsumed = false;
+ uint16_t baseId = 0;
+
+ Container* lootContainer = player->getLootContainer(category);
+ if (!lootContainer) {
+ if (player->quickLootFallbackToMainContainer) {
+ Item* fallbackItem = player->getInventoryItem(CONST_SLOT_BACKPACK);
+
+ if (fallbackItem) {
+ Container* mainBackpack = fallbackItem->getContainer();
+ if (mainBackpack && !fallbackConsumed) {
+ player->setLootContainer(OBJECTCATEGORY_DEFAULT, mainBackpack);
+ player->sendInventoryItem(CONST_SLOT_BACKPACK, player->getInventoryItem(CONST_SLOT_BACKPACK));
+ }
+ }
+
+ lootContainer = fallbackItem ? fallbackItem->getContainer() : nullptr;
+ fallbackConsumed = true;
+ } else {
+ return RETURNVALUE_NOTPOSSIBLE;
+ }
+ } else {
+ baseId = lootContainer->getID();
+ }
+
+ if (!lootContainer) {
+ return RETURNVALUE_NOTPOSSIBLE;
+ }
+
+ Container* lastSubContainer = nullptr;
+ uint32_t remainderCount = item->getItemCount();
+ ContainerIterator it = lootContainer->iterator();
+
+ ReturnValue ret;
+ do {
+ Item* moveItem = nullptr;
+ ret = internalMoveItem(item->getParent(), lootContainer, INDEX_WHEREEVER, item, item->getItemCount(), &moveItem, 0, player);
+ if (moveItem) {
+ remainderCount -= moveItem->getItemCount();
+ }
+
+ if (ret != RETURNVALUE_CONTAINERNOTENOUGHROOM) {
+ break;
+ }
+
+ // search for a sub container
+ bool obtainedNewContainer = false;
+ while (it.hasNext()) {
+ Item* cur = *it;
+ Container* subContainer = cur ? cur->getContainer() : nullptr;
+ it.advance();
+
+ if (subContainer) {
+ lastSubContainer = subContainer;
+ lootContainer = subContainer;
+ obtainedNewContainer = true;
+ break;
+ }
+ }
+
+ // a hack to fix last empty sub-container
+ if (!obtainedNewContainer && lastSubContainer && lastSubContainer->size() > 0) {
+ Item* cur = lastSubContainer->getItemByIndex(lastSubContainer->size() - 1);
+ Container* subContainer = cur ? cur->getContainer() : nullptr;
+
+ if (subContainer) {
+ lootContainer = subContainer;
+ obtainedNewContainer = true;
+ }
+
+ lastSubContainer = nullptr;
+ }
+
+ // consumed all sub-container & there is simply no more containers to iterate over.
+ // check if fallback should be used and if not, then break
+ bool quickFallback = (player->quickLootFallbackToMainContainer);
+ bool noFallback = fallbackConsumed || !quickFallback;
+ if (noFallback && (!lootContainer || !obtainedNewContainer)) {
+ break;
+ } else if (!lootContainer || !obtainedNewContainer) {
+ Item* fallbackItem = player->getInventoryItem(CONST_SLOT_BACKPACK);
+ if (!fallbackItem || !fallbackItem->getContainer()) {
+ break;
+ }
+
+ lootContainer = fallbackItem->getContainer();
+ it = lootContainer->iterator();
+
+ fallbackConsumed = true;
+ }
+ } while (remainderCount != 0);
+ return ret;
+}
+
+ObjectCategory_t Game::getObjectCategory(const Item* item)
+{
+ ObjectCategory_t category = OBJECTCATEGORY_DEFAULT;
+ if (!item) {
+ return OBJECTCATEGORY_NONE;
+ }
+
+ const ItemType& it = Item::items[item->getID()];
+ if (item->getWorth() != 0) {
+ category = OBJECTCATEGORY_GOLD;
+ } else if (it.weaponType != WEAPON_NONE) {
+ switch (it.weaponType) {
+ case WEAPON_SWORD:
+ category = OBJECTCATEGORY_SWORDS;
+ break;
+ case WEAPON_CLUB:
+ category = OBJECTCATEGORY_CLUBS;
+ break;
+ case WEAPON_AXE:
+ category = OBJECTCATEGORY_AXES;
+ break;
+ case WEAPON_SHIELD:
+ category = OBJECTCATEGORY_SHIELDS;
+ break;
+ case WEAPON_DISTANCE:
+ category = OBJECTCATEGORY_DISTANCEWEAPONS;
+ break;
+ case WEAPON_WAND:
+ category = OBJECTCATEGORY_WANDS;
+ break;
+ case WEAPON_AMMO:
+ category = OBJECTCATEGORY_AMMO;
+ break;
+ default:
+ break;
+ }
+ } else if (it.slotPosition != SLOTP_HAND) { // if it's a weapon/shield should have been parsed earlier
+ if ((it.slotPosition & SLOTP_HEAD) != 0) {
+ category = OBJECTCATEGORY_HELMETS;
+ } else if ((it.slotPosition & SLOTP_NECKLACE) != 0) {
+ category = OBJECTCATEGORY_NECKLACES;
+ } else if ((it.slotPosition & SLOTP_BACKPACK) != 0) {
+ category = OBJECTCATEGORY_CONTAINERS;
+ } else if ((it.slotPosition & SLOTP_ARMOR) != 0) {
+ category = OBJECTCATEGORY_ARMORS;
+ } else if ((it.slotPosition & SLOTP_LEGS) != 0) {
+ category = OBJECTCATEGORY_LEGS;
+ } else if ((it.slotPosition & SLOTP_FEET) != 0) {
+ category = OBJECTCATEGORY_BOOTS;
+ } else if ((it.slotPosition & SLOTP_RING) != 0) {
+ category = OBJECTCATEGORY_RINGS;
+ }
+ } else if (it.type == ITEM_TYPE_RUNE) {
+ category = OBJECTCATEGORY_RUNES;
+ } else if (it.type == ITEM_TYPE_CREATUREPRODUCT) {
+ category = OBJECTCATEGORY_CREATUREPRODUCTS;
+ } else if (it.type == ITEM_TYPE_FOOD) {
+ category = OBJECTCATEGORY_FOOD;
+ } else if (it.type == ITEM_TYPE_VALUABLE) {
+ category = OBJECTCATEGORY_VALUABLES;
+ } else if (it.type == ITEM_TYPE_POTION) {
+ category = OBJECTCATEGORY_POTIONS;
+ } else {
+ category = OBJECTCATEGORY_OTHERS;
+ }
+
+ return category;
+}
+
Item* searchForItem(Container* container, uint16_t itemId)
{
for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) {
@@ -3287,6 +3598,259 @@ void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
g_events->eventPlayerOnLookInBattleList(player, creature, lookDistance);
}
+void Game::playerQuickLoot(uint32_t playerId, const Position& pos, uint16_t spriteId, uint8_t stackPos, Item* defaultItem)
+{
+ Player* player = getPlayerByID(playerId);
+ if (!player) {
+ return;
+ }
+
+ if (!player->canDoAction()) {
+ uint32_t delay = player->getNextActionTime();
+ SchedulerTask* task = createSchedulerTask(delay, std::bind(&Game::playerQuickLoot,
+ this, player->getID(), pos, spriteId, stackPos, defaultItem));
+ player->setNextActionTask(task);
+ return;
+ }
+
+ if (pos.x != 0xffff) {
+ if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) {
+ //need to walk to the corpse first before looting it
+ std::forward_list listDir;
+ if (player->getPathTo(pos, listDir, 0, 1, true, true)) {
+ g_dispatcher.addTask(createTask(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir)));
+ SchedulerTask* task = createSchedulerTask(0, std::bind(&Game::playerQuickLoot,
+ this, player->getID(), pos, spriteId, stackPos, defaultItem));
+ player->setNextWalkActionTask(task);
+ } else {
+ player->sendCancelMessage(RETURNVALUE_THEREISNOWAY);
+ }
+
+ return;
+ }
+ } else if (!player->isPremium()) {
+ player->sendCancelMessage("You must be premium.");
+ return;
+ }
+
+ player->setNextActionTask(nullptr);
+
+ Item* item = nullptr;
+ if (!defaultItem) {
+ Thing* thing = internalGetThing(player, pos, stackPos, spriteId, STACKPOS_FIND_THING);
+ if (!thing) {
+ player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
+ return;
+ }
+
+ item = thing->getItem();
+ } else {
+ item = defaultItem;
+ }
+
+ if (!item || !item->getParent()) {
+ player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
+ return;
+ }
+
+ Container* corpse = nullptr;
+ if (pos.x == 0xffff) {
+ corpse = item->getParent()->getContainer();
+ } else {
+ corpse = item->getContainer();
+ }
+
+ if (!corpse || corpse->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID) || corpse->hasAttribute(ITEM_ATTRIBUTE_ACTIONID)) {
+ player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
+ return;
+ }
+
+ if (!corpse->isRewardCorpse()) {
+ uint32_t corpseOwner = corpse->getCorpseOwner();
+ if (corpseOwner != 0 && !player->canOpenCorpse(corpseOwner)) {
+ player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
+ return;
+ }
+ }
+
+ if (pos.x == 0xffff) {
+ uint32_t worth = item->getWorth();
+ ObjectCategory_t category = getObjectCategory(item);
+ ReturnValue ret = internalQuickLootItem(player, item, category);
+
+ std::stringstream ss;
+ if (ret == RETURNVALUE_NOTENOUGHCAPACITY) {
+ ss << "Attention! The loot you are trying to pick up is too heavy for you to carry.";
+ } else if (ret == RETURNVALUE_CONTAINERNOTENOUGHROOM) {
+ ss << "Attention! The container for " << getObjectCategoryName(category) << " is full.";
+ } else {
+ if (ret == RETURNVALUE_NOERROR) {
+ player->sendLootStats(item);
+ ss << "You looted ";
+ } else {
+ ss << "You could not loot ";
+ }
+
+ if (worth != 0) {
+ ss << worth << " gold.";
+ } else {
+ ss << "1 item.";
+ }
+
+ player->sendTextMessage(MESSAGE_LOOT, ss.str());
+ return;
+ }
+
+ if (player->lastQuickLootNotification + 15000 < OTSYS_TIME()) {
+ player->sendTextMessage(MESSAGE_STATUS_WARNING, ss.str());
+ } else {
+ player->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
+ }
+
+ player->lastQuickLootNotification = OTSYS_TIME();
+ } else {
+ if (corpse->isRewardCorpse()) {
+ g_actions->useItem(player, pos, 0, corpse, false);
+ } else {
+ internalQuickLootCorpse(player, corpse);
+ }
+ }
+
+ return;
+}
+
+void Game::playerSetLootContainer(uint32_t playerId, ObjectCategory_t category, const Position& pos, uint16_t spriteId, uint8_t stackPos)
+{
+ Player* player = getPlayerByID(playerId);
+ if (!player || pos.x != 0xffff) {
+ return;
+ }
+
+ Thing* thing = internalGetThing(player, pos, stackPos, spriteId, STACKPOS_USEITEM);
+ if (!thing) {
+ player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
+ return;
+ }
+
+ Container* container = thing->getContainer();
+ if (!container) {
+ player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
+ return;
+ }
+
+ if (container->getHoldingPlayer() != player) {
+ player->sendCancelMessage("You must be holding the container to set it as a loot container.");
+ return;
+ }
+
+ Container* previousContainer = player->setLootContainer(category, container);
+ player->sendLootContainers();
+
+ Cylinder* parent = container->getParent();
+ if (parent) {
+ parent->updateThing(container, container->getID(), container->getItemCount());
+ }
+
+ if (previousContainer != nullptr) {
+ parent = previousContainer->getParent();
+ if (parent) {
+ parent->updateThing(previousContainer, previousContainer->getID(), previousContainer->getItemCount());
+ }
+ }
+}
+
+void Game::playerClearLootContainer(uint32_t playerId, ObjectCategory_t category)
+{
+ Player* player = getPlayerByID(playerId);
+ if (!player) {
+ return;
+ }
+
+ Container* previousContainer = player->setLootContainer(category, nullptr);
+ player->sendLootContainers();
+
+ if (previousContainer != nullptr) {
+ Cylinder* parent = previousContainer->getParent();
+ if (parent) {
+ parent->updateThing(previousContainer, previousContainer->getID(), previousContainer->getItemCount());
+ }
+ }
+}
+
+void Game::playerOpenLootContainer(uint32_t playerId, ObjectCategory_t category)
+{
+ Player* player = getPlayerByID(playerId);
+ if (!player) {
+ return;
+ }
+
+ Container* container = player->getLootContainer(category);
+ if (!container) {
+ return;
+ }
+
+ player->sendContainer(container->getClientID(), container, container->hasParent(), 0);
+}
+
+
+void Game::playerSetQuickLootFallback(uint32_t playerId, bool fallback)
+{
+ Player* player = getPlayerByID(playerId);
+ if (!player) {
+ return;
+ }
+
+ player->quickLootFallbackToMainContainer = fallback;
+}
+
+void Game::playerQuickLootBlackWhitelist(uint32_t playerId, QuickLootFilter_t filter, std::vector clientIds)
+{
+ Player* player = getPlayerByID(playerId);
+ if (!player) {
+ return;
+ }
+
+ player->quickLootFilter = filter;
+ player->quickLootListClientIds = clientIds;
+}
+
+void Game::playerRequestLockFind(uint32_t playerId)
+{
+ Player* player = getPlayerByID(playerId);
+ if (!player) {
+ return;
+ }
+
+ std::map itemMap;
+ uint16_t count = 0;
+ DepotLocker* depotLocker = player->getDepotLocker(player->getLastDepotId());
+ if (!depotLocker) {
+ return;
+ }
+
+ for (Item* locker : depotLocker->getItemList()) {
+ Container* c = locker->getContainer();
+ if (c && c->empty()) {
+ continue;
+ }
+
+ if (c) {
+ for (ContainerIterator it = c->iterator(); it.hasNext(); it.advance()) {
+ auto itt = itemMap.find((*it)->getID());
+ if (itt == itemMap.end()) {
+ itemMap[(*it)->getID()] = Item::countByType((*it), -1);
+ count++;
+ } else {
+ itemMap[(*it)->getID()] += Item::countByType((*it), -1);
+ }
+ }
+ }
+ }
+
+ player->sendLockerItems(itemMap, count);
+ return;
+}
+
void Game::playerCancelAttackAndFollow(uint32_t playerId)
{
Player* player = getPlayerByID(playerId);
diff --git a/src/game.h b/src/game.h
index 39fcfb65f3..64a7aa0157 100644
--- a/src/game.h
+++ b/src/game.h
@@ -319,6 +319,25 @@ class Game
bool internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
bool ghostMode, SpectatorHashSet* spectatorsPtr = nullptr, const Position* pos = nullptr);
+ /**
+ * Player wants to loot a corpse
+ * \param player Player pointer
+ * \param corpse Container pointer to be looted
+ */
+ void internalQuickLootCorpse(Player* player, Container* corpse);
+
+ /**
+ * Player wants to loot a single item
+ * \param player Player pointer
+ * \param item Item pointer to be looted
+ * \param category Category of the item
+ * \returns true if the looting was successful
+ */
+ ReturnValue internalQuickLootItem(Player* player, Item* item,
+ ObjectCategory_t category = OBJECTCATEGORY_DEFAULT);
+
+ ObjectCategory_t getObjectCategory(const Item* item);
+
void loadPlayersRecord();
void checkPlayersRecord();
@@ -379,7 +398,7 @@ class Game
void playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
bool ignoreCap = false, bool inBackpacks = false);
void playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count,
- uint8_t amount, bool ignoreEquipped = false);
+ uint8_t amount, bool ignoreEquipped = false);
void playerCloseShop(uint32_t playerId);
void playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count);
void playerCloseTrade(uint32_t playerId);
@@ -389,6 +408,16 @@ class Game
void playerSetFightModes(uint32_t playerId, fightMode_t fightMode, bool chaseMode, bool secureMode);
void playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos);
void playerLookInBattleList(uint32_t playerId, uint32_t creatureId);
+ void playerQuickLoot(uint32_t playerId, const Position& pos,
+ uint16_t spriteId, uint8_t stackPos, Item* defaultItem = nullptr);
+ void playerSetLootContainer(uint32_t playerId, ObjectCategory_t category,
+ const Position& pos, uint16_t spriteId, uint8_t stackPos);
+ void playerClearLootContainer(uint32_t playerId, ObjectCategory_t category);;
+ void playerOpenLootContainer(uint32_t playerId, ObjectCategory_t category);
+ void playerSetQuickLootFallback(uint32_t playerId, bool fallback);
+ void playerQuickLootBlackWhitelist(uint32_t playerId,
+ QuickLootFilter_t filter, std::vector clientIds);
+ void playerRequestLockFind(uint32_t playerId);
void playerRequestAddVip(uint32_t playerId, const std::string& name);
void playerRequestRemoveVip(uint32_t playerId, uint32_t guid);
void playerRequestEditVip(uint32_t playerId, uint32_t guid, const std::string& description, uint32_t icon, bool notify);
diff --git a/src/iologindata.cpp b/src/iologindata.cpp
index 049d7439dd..339d100462 100644
--- a/src/iologindata.cpp
+++ b/src/iologindata.cpp
@@ -154,7 +154,7 @@ bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
{
Database& db = Database::getInstance();
std::ostringstream query;
- query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings1`, `blessings2`, `blessings3`, `blessings4`, `blessings5`, `blessings6`, `blessings7`, `blessings8`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `prey_stamina_1`, `prey_stamina_2`, `prey_stamina_3`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`, `skill_critical_hit_chance`, `skill_critical_hit_chance_tries`, `skill_critical_hit_damage`, `skill_critical_hit_damage_tries`, `skill_life_leech_chance`, `skill_life_leech_chance_tries`, `skill_life_leech_amount`, `skill_life_leech_amount_tries`, `skill_mana_leech_chance`, `skill_mana_leech_chance_tries`, `skill_mana_leech_amount`, `skill_mana_leech_amount_tries`, `xpboost_value`, `xpboost_stamina`, `bonus_rerolls` FROM `players` WHERE `id` = " << id;
+ query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings1`, `blessings2`, `blessings3`, `blessings4`, `blessings5`, `blessings6`, `blessings7`, `blessings8`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `prey_stamina_1`, `prey_stamina_2`, `prey_stamina_3`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`, `skill_critical_hit_chance`, `skill_critical_hit_chance_tries`, `skill_critical_hit_damage`, `skill_critical_hit_damage_tries`, `skill_life_leech_chance`, `skill_life_leech_chance_tries`, `skill_life_leech_amount`, `skill_life_leech_amount_tries`, `skill_mana_leech_chance`, `skill_mana_leech_chance_tries`, `skill_mana_leech_amount`, `skill_mana_leech_amount_tries`, `xpboost_value`, `xpboost_stamina`, `bonus_rerolls`, `quickloot_fallback` FROM `players` WHERE `id` = " << id;
return loadPlayer(player, db.storeQuery(query.str()));
}
@@ -267,7 +267,7 @@ bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
{
Database& db = Database::getInstance();
std::ostringstream query;
- query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings1`, `blessings2`, `blessings3`, `blessings4`, `blessings5`, `blessings6`, `blessings7`, `blessings8`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `prey_stamina_1`, `prey_stamina_2`, `prey_stamina_3`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`, `skill_critical_hit_chance`, `skill_critical_hit_chance_tries`, `skill_critical_hit_damage`, `skill_critical_hit_damage_tries`, `skill_life_leech_chance`, `skill_life_leech_chance_tries`, `skill_life_leech_amount`, `skill_life_leech_amount_tries`, `skill_mana_leech_chance`, `skill_mana_leech_chance_tries`, `skill_mana_leech_amount`, `skill_mana_leech_amount_tries`, `xpboost_stamina`, `xpboost_value` FROM `players` WHERE `name` = " << db.escapeString(name);
+ query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings1`, `blessings2`, `blessings3`, `blessings4`, `blessings5`, `blessings6`, `blessings7`, `blessings8`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `prey_stamina_1`, `prey_stamina_2`, `prey_stamina_3`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`, `skill_critical_hit_chance`, `skill_critical_hit_chance_tries`, `skill_critical_hit_damage`, `skill_critical_hit_damage_tries`, `skill_life_leech_chance`, `skill_life_leech_chance_tries`, `skill_life_leech_amount`, `skill_life_leech_amount_tries`, `skill_mana_leech_chance`, `skill_mana_leech_chance_tries`, `skill_mana_leech_amount`, `skill_mana_leech_amount_tries`, `xpboost_stamina`, `xpboost_value`, `quickloot_fallback` FROM `players` WHERE `name` = " << db.escapeString(name);
return loadPlayer(player, db.storeQuery(query.str()));
}
@@ -308,6 +308,8 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
player->setBankBalance(result->getNumber("balance"));
+ player->quickLootFallbackToMainContainer = result->getNumber("quickloot_fallback");
+
player->setSex(static_cast(result->getNumber("sex")));
player->level = std::max(1, result->getNumber("level"));
@@ -335,10 +337,10 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
player->addBlessing(i, result->getNumber(ss.str()));
}
- unsigned long conditionsSize;
- const char* conditions = result->getStream("conditions", conditionsSize);
+ unsigned long attrSize;
+ const char* attr = result->getStream("conditions", attrSize);
PropStream propStream;
- propStream.init(conditions, conditionsSize);
+ propStream.init(attr, attrSize);
Condition* condition = Condition::createCondition(propStream);
while (condition) {
@@ -517,15 +519,6 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
const std::pair
- & pair = it->second;
Item* item = pair.first;
int32_t pid = pair.second;
-
- Container* itemContainer = item->getContainer();
- if (itemContainer) {
- uint8_t cid = item->getIntAttr(ITEM_ATTRIBUTE_OPENCONTAINER);
- if (cid > 0) {
- openContainersList.emplace_back(std::make_pair(cid, itemContainer));
- }
- }
-
if (pid >= 1 && pid <= 11) {
player->internalAddThing(pid, item);
} else {
@@ -539,6 +532,22 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
container->internalAddThing(item);
}
}
+
+ Container* itemContainer = item->getContainer();
+ if (itemContainer) {
+ uint8_t cid = item->getIntAttr(ITEM_ATTRIBUTE_OPENCONTAINER);
+ if (cid > 0) {
+ openContainersList.emplace_back(std::make_pair(cid, itemContainer));
+ }
+ if (item->hasAttribute(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER)) {
+ uint32_t flags = item->getIntAttr(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER);
+ for (uint8_t category = OBJECTCATEGORY_FIRST; category <= OBJECTCATEGORY_LAST; category++) {
+ if (hasBitSet(1 << category, flags)) {
+ player->setLootContainer((ObjectCategory_t)category, itemContainer, true);
+ }
+ }
+ }
+ }
}
}
@@ -692,6 +701,8 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList, DBInsert& query_insert, PropWriteStream& propWriteStream)
{
+ Database& db = Database::getInstance();
+
std::ostringstream ss;
using ContainerBlock = std::pair;
@@ -699,9 +710,7 @@ bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList,
int32_t runningId = 100;
- Database& db = Database::getInstance();
const auto& openContainers = player->getOpenContainers();
-
for (const auto& it : itemList) {
int32_t pid = it.first;
Item* item = it.second;
@@ -790,13 +799,13 @@ bool IOLoginData::savePlayer(Player* player)
if (player->getHealth() <= 0) {
player->changeHealth(1);
}
-
Database& db = Database::getInstance();
std::ostringstream query;
query << "SELECT `save` FROM `players` WHERE `id` = " << player->getGUID();
DBResult_ptr result = db.storeQuery(query.str());
if (!result) {
+ std::cout << player->getName() << " 01" << std::endl;
return false;
}
@@ -806,18 +815,6 @@ bool IOLoginData::savePlayer(Player* player)
return db.executeQuery(query.str());
}
- //serialize conditions
- PropWriteStream propWriteStream;
- for (Condition* condition : player->conditions) {
- if (condition->isPersistent()) {
- condition->serialize(propWriteStream);
- propWriteStream.write(CONDITIONATTR_END);
- }
- }
-
- size_t conditionsSize;
- const char* conditions = propWriteStream.getStream(conditionsSize);
-
//First, an UPDATE query to write the player itself
query.str(std::string());
query << "UPDATE `players` SET ";
@@ -856,7 +853,19 @@ bool IOLoginData::savePlayer(Player* player)
query << "`lastip` = " << player->lastIP << ',';
}
- query << "`conditions` = " << db.escapeBlob(conditions, conditionsSize) << ',';
+ //serialize conditions
+ PropWriteStream propWriteStream;
+ for (Condition* condition : player->conditions) {
+ if (condition->isPersistent()) {
+ condition->serialize(propWriteStream);
+ propWriteStream.write(CONDITIONATTR_END);
+ }
+ }
+
+ size_t attributesSize;
+ const char* attributes = propWriteStream.getStream(attributesSize);
+
+ query << "`conditions` = " << db.escapeBlob(attributes, attributesSize) << ',';
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
int64_t skullTime = 0;
@@ -914,6 +923,7 @@ bool IOLoginData::savePlayer(Player* player)
query << "`xpboost_value` = " << player->getStoreXpBoost() << ',';
query << "`xpboost_stamina` = " << player->getExpBoostStamina() << ',';
query << "`bonus_rerolls` = " << player->getPreyBonusRerolls() << ',';
+ query << "`quickloot_fallback` = " << (player->quickLootFallbackToMainContainer ? 1 : 0) << ',';
if (!player->isOffline()) {
query << "`onlinetime` = `onlinetime` + " << (time(nullptr) - player->lastLoginSaved) << ',';
@@ -977,6 +987,7 @@ bool IOLoginData::savePlayer(Player* player)
//item saving
query << "DELETE FROM `player_items` WHERE `player_id` = " << player->getGUID();
if (!db.executeQuery(query.str())) {
+ std::cout << player->getName() << " 10" << std::endl;
return false;
}
@@ -991,6 +1002,7 @@ bool IOLoginData::savePlayer(Player* player)
}
if (!saveItems(player, itemList, itemsQuery, propWriteStream)) {
+ std::cout << player->getName() << " 11" << std::endl;
return false;
}
diff --git a/src/item.cpp b/src/item.cpp
index 86887d6a18..c4355e930f 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -583,8 +583,8 @@ Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream& propStream)
}
case ATTR_OPENCONTAINER: {
- int32_t openContainer;
- if (!propStream.read(openContainer)) {
+ uint8_t openContainer;
+ if (!propStream.read(openContainer)) {
return ATTR_READ_ERROR;
}
@@ -632,6 +632,16 @@ Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream& propStream)
break;
}
+ case ATTR_QUICKLOOTCONTAINER: {
+ uint32_t flags;
+ if (!propStream.read(flags)) {
+ return ATTR_READ_ERROR;
+ }
+
+ setIntAttr(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER, flags);
+ break;
+ }
+
//these should be handled through derived classes
//If these are called then something has changed in the items.xml since the map was saved
//just read the values
@@ -829,7 +839,7 @@ void Item::serializeAttr(PropWriteStream& propWriteStream) const
if (hasAttribute(ITEM_ATTRIBUTE_OPENCONTAINER)) {
propWriteStream.write(ATTR_OPENCONTAINER);
- propWriteStream.write(getIntAttr(ITEM_ATTRIBUTE_OPENCONTAINER));
+ propWriteStream.write(getIntAttr(ITEM_ATTRIBUTE_OPENCONTAINER));
}
if (hasAttribute(ITEM_ATTRIBUTE_ARMOR)) {
@@ -864,6 +874,11 @@ void Item::serializeAttr(PropWriteStream& propWriteStream) const
entry.second.serialize(propWriteStream);
}
}
+
+ if (hasAttribute(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER)) {
+ propWriteStream.write(ATTR_QUICKLOOTCONTAINER);
+ propWriteStream.write(getQuicklootAttr());
+ }
}
bool Item::hasProperty(ITEMPROPERTY prop) const
diff --git a/src/item.h b/src/item.h
index c9260b5eed..6f8f6a03f1 100644
--- a/src/item.h
+++ b/src/item.h
@@ -105,7 +105,9 @@ enum AttrTypes_t {
ATTR_SPECIAL = 34,
ATTR_IMBUINGSLOTS = 35,
ATTR_OPENCONTAINER = 36,
- ATTR_CUSTOM_ATTRIBUTES = 37
+ ATTR_CUSTOM_ATTRIBUTES = 37,
+
+ ATTR_QUICKLOOTCONTAINER = 38
};
enum Attr_ReadValue {
@@ -500,12 +502,22 @@ class ItemAttributes
return false;
}
+ const static uint32_t intAttributeTypes = ITEM_ATTRIBUTE_ACTIONID | ITEM_ATTRIBUTE_UNIQUEID | ITEM_ATTRIBUTE_DATE
+ | ITEM_ATTRIBUTE_WEIGHT | ITEM_ATTRIBUTE_ATTACK | ITEM_ATTRIBUTE_DEFENSE | ITEM_ATTRIBUTE_EXTRADEFENSE
+ | ITEM_ATTRIBUTE_ARMOR | ITEM_ATTRIBUTE_HITCHANCE | ITEM_ATTRIBUTE_SHOOTRANGE | ITEM_ATTRIBUTE_OWNER
+ | ITEM_ATTRIBUTE_DURATION | ITEM_ATTRIBUTE_DECAYSTATE | ITEM_ATTRIBUTE_CORPSEOWNER | ITEM_ATTRIBUTE_CHARGES
+ | ITEM_ATTRIBUTE_FLUIDTYPE | ITEM_ATTRIBUTE_DOORID | ITEM_ATTRIBUTE_IMBUINGSLOTS
+ | ITEM_ATTRIBUTE_OPENCONTAINER | ITEM_ATTRIBUTE_QUICKLOOTCONTAINER;
+
+ const static uint32_t stringAttributeTypes = ITEM_ATTRIBUTE_DESCRIPTION | ITEM_ATTRIBUTE_TEXT | ITEM_ATTRIBUTE_WRITER
+ | ITEM_ATTRIBUTE_NAME | ITEM_ATTRIBUTE_ARTICLE | ITEM_ATTRIBUTE_PLURALNAME | ITEM_ATTRIBUTE_SPECIAL;
+
public:
static bool isIntAttrType(itemAttrTypes type) {
- return (type & 0x27FFE13) != 0;
+ return (type & intAttributeTypes) == type;
}
static bool isStrAttrType(itemAttrTypes type) {
- return (type & 0x8001EC) != 0;
+ return (type & stringAttributeTypes) == type;
}
inline static bool isCustomAttrType(itemAttrTypes type) {
return (type & 0x80000000) != 0;
@@ -613,29 +625,6 @@ class Item : virtual public Thing
return isLootTrackeable;
}
- uint32_t getQuickLootFlags() const
- {
- if (!attributes) {
- return 0;
- }
-
- if (!attributes->hasAttribute(ITEM_ATTRIBUTE_CUSTOM)) {
- return 0;
- }
-
- uint32_t flags = 0;
- for (uint8_t i = LOOT_START; i < LOOT_END; i++)
- {
- const ItemAttributes::CustomAttribute* attr = getCustomAttribute("quickLootCategory" + std::to_string(i));
- if (attr != nullptr) {
- flags |= (1 << i);
- continue;
- }
- }
-
- return flags;
- }
-
void removeAttribute(itemAttrTypes type) {
if (attributes) {
attributes->removeAttribute(type);
@@ -855,9 +844,6 @@ class Item : virtual public Thing
// Returns the player that is holding this item in his inventory
Player* getHoldingPlayer() const;
- QuickLootCategory_t getLootCategory() const {
- return items[id].quickLootCategory;
- }
WeaponType_t getWeaponType() const {
return items[id].weaponType;
}
@@ -917,6 +903,12 @@ class Item : virtual public Thing
}
return items[id].hitChance;
}
+ uint32_t getQuicklootAttr() const {
+ if (hasAttribute(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER)) {
+ return getIntAttr(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER);
+ }
+ return 0;
+ }
uint32_t getWorth() const;
LightInfo getLightInfo() const;
diff --git a/src/items.cpp b/src/items.cpp
index d6cdbb6aa4..c54ea96d4a 100644
--- a/src/items.cpp
+++ b/src/items.cpp
@@ -42,6 +42,45 @@ void Items::clear()
nameToItems.clear();
}
+using LootTypeNames = std::unordered_map;
+
+LootTypeNames lootTypeNames = {
+ {"armor", ITEM_TYPE_ARMOR},
+ {"amulet", ITEM_TYPE_AMULET},
+ {"boots", ITEM_TYPE_BOOTS},
+ {"container", ITEM_TYPE_CONTAINER},
+ {"decoration", ITEM_TYPE_DECORATION},
+ {"food", ITEM_TYPE_FOOD},
+ {"head", ITEM_TYPE_HELMET},
+ {"legs", ITEM_TYPE_LEGS},
+ {"other", ITEM_TYPE_OTHER},
+ {"potion", ITEM_TYPE_POTION},
+ {"ring", ITEM_TYPE_RING},
+ {"rune", ITEM_TYPE_RUNE},
+ {"shield", ITEM_TYPE_SHIELD},
+ {"tools", ITEM_TYPE_TOOLS},
+ {"valuable", ITEM_TYPE_VALUABLE},
+ {"ammo", ITEM_TYPE_AMMO},
+ {"axe", ITEM_TYPE_AXE},
+ {"club", ITEM_TYPE_CLUB},
+ {"distance", ITEM_TYPE_DISTANCE},
+ {"sword", ITEM_TYPE_SWORD},
+ {"wand", ITEM_TYPE_WAND},
+ {"creatureproduct", ITEM_TYPE_CREATUREPRODUCT},
+ {"retrieve", ITEM_TYPE_RETRIEVE},
+ {"gold", ITEM_TYPE_GOLD},
+ {"unassigned", ITEM_TYPE_UNASSIGNED},
+};
+
+ItemTypes_t Items::getLootType(const std::string& strValue)
+{
+ auto lootType = lootTypeNames.find(strValue);
+ if (lootType != lootTypeNames.end()) {
+ return lootType->second;
+ }
+ return ITEM_TYPE_NONE;
+}
+
bool Items::reload()
{
clear();
@@ -430,6 +469,14 @@ void Items::parseItemNode(const pugi::xml_node& itemNode, uint16_t id)
it.type = ITEM_TYPE_RUNE;
} else if (tmpStrValue == "supply") {
it.type = ITEM_TYPE_SUPPLY;
+ } else if (tmpStrValue == "creatureproduct") {
+ it.type = ITEM_TYPE_CREATUREPRODUCT;
+ } else if (tmpStrValue == "food") {
+ it.type = ITEM_TYPE_FOOD;
+ } else if (tmpStrValue == "valuable") {
+ it.type = ITEM_TYPE_VALUABLE;
+ } else if (tmpStrValue == "potion") {
+ it.type = ITEM_TYPE_POTION;
} else {
std::cout << "[Warning - Items::parseItemNode] Unknown type: " << valueAttribute.as_string() << std::endl;
}
@@ -552,63 +599,6 @@ void Items::parseItemNode(const pugi::xml_node& itemNode, uint16_t id)
it.maxTextLen = pugi::cast(valueAttribute.value());
} else if (tmpStrValue == "writeonceitemid") {
it.writeOnceItemId = pugi::cast(valueAttribute.value());
- } else if (tmpStrValue == "quicklootcategory") {
- tmpStrValue = asLowerCaseString(valueAttribute.as_string());
- if (tmpStrValue == "none") {
- it.quickLootCategory = LOOT_NONE;
- } else if (tmpStrValue == "unassigned") {
- it.quickLootCategory = LOOT_UNASSIGNED;
- } else if (tmpStrValue == "gold") {
- it.quickLootCategory = LOOT_GOLD;
- } else if (tmpStrValue == "armor") {
- it.quickLootCategory = LOOT_ARMOR;
- } else if (tmpStrValue == "amulet") {
- it.quickLootCategory = LOOT_AMULET;
- } else if (tmpStrValue == "boots") {
- it.quickLootCategory = LOOT_BOOTS;
- } else if (tmpStrValue == "container") {
- it.quickLootCategory = LOOT_CONTAINER;
- } else if (tmpStrValue == "creatureproduct") {
- it.quickLootCategory = LOOT_CREATURE_PRODUCT;
- } else if (tmpStrValue == "decoration") {
- it.quickLootCategory = LOOT_DECORATION;
- } else if (tmpStrValue == "food") {
- it.quickLootCategory = LOOT_FOOD;
- } else if (tmpStrValue == "helmet") {
- it.quickLootCategory = LOOT_HELMET;
- } else if (tmpStrValue == "legs") {
- it.quickLootCategory = LOOT_LEGS;
- } else if (tmpStrValue == "other") {
- it.quickLootCategory = LOOT_OTHER;
- } else if (tmpStrValue == "potion") {
- it.quickLootCategory = LOOT_POTION;
- } else if (tmpStrValue == "ring") {
- it.quickLootCategory = LOOT_RING;
- } else if (tmpStrValue == "rune") {
- it.quickLootCategory = LOOT_RUNE;
- } else if (tmpStrValue == "shield") {
- it.quickLootCategory = LOOT_SHIELD;
- } else if (tmpStrValue == "tool") {
- it.quickLootCategory = LOOT_TOOL;
- } else if (tmpStrValue == "valuable") {
- it.quickLootCategory = LOOT_VALUABLE;
- } else if (tmpStrValue == "weaponammo") {
- it.quickLootCategory = LOOT_WEAPON_AMMO;
- } else if (tmpStrValue == "weaponaxe") {
- it.quickLootCategory = LOOT_WEAPON_AXE;
- } else if (tmpStrValue == "weaponclub") {
- it.quickLootCategory = LOOT_WEAPON_CLUB;
- } else if (tmpStrValue == "weapondistance") {
- it.quickLootCategory = LOOT_WEAPON_DISTANCE;
- } else if (tmpStrValue == "weaponsword") {
- it.quickLootCategory = LOOT_WEAPON_SWORD;
- } else if (tmpStrValue == "weaponwand") {
- it.quickLootCategory = LOOT_WEAPON_WAND;
- } else if (tmpStrValue == "stashretrieve") {
- it.quickLootCategory = LOOT_STASH_RETRIEVE;
- } else {
- std::cout << "[Warning - Items::parseItemNode] Unknown quickLootCategory: " << valueAttribute.as_string() << std::endl;
- }
} else if (tmpStrValue == "weapontype") {
tmpStrValue = asLowerCaseString(valueAttribute.as_string());
if (tmpStrValue == "sword") {
@@ -676,6 +666,8 @@ void Items::parseItemNode(const pugi::xml_node& itemNode, uint16_t id)
} else {
std::cout << "[Warning - Items::parseItemNode] Unknown effect: " << valueAttribute.as_string() << std::endl;
}
+ } else if (tmpStrValue == "loottype") {
+ it.type = getLootType(valueAttribute.as_string());
} else if (tmpStrValue == "range") {
it.shootRange = pugi::cast(valueAttribute.value());
} else if (tmpStrValue == "stopduration") {
diff --git a/src/items.h b/src/items.h
index 4a9ad67acb..b3fb12f73f 100644
--- a/src/items.h
+++ b/src/items.h
@@ -57,6 +57,32 @@ enum ItemTypes_t {
ITEM_TYPE_SUPPLY,
ITEM_TYPE_REWARDCHEST,
ITEM_TYPE_CARPET,
+ ITEM_TYPE_CREATUREPRODUCT,
+ ITEM_TYPE_FOOD,
+ ITEM_TYPE_VALUABLE,
+ ITEM_TYPE_POTION,
+
+ ITEM_TYPE_ARMOR,
+ ITEM_TYPE_AMULET,
+ ITEM_TYPE_BOOTS,
+ ITEM_TYPE_DECORATION,
+ ITEM_TYPE_HELMET,
+ ITEM_TYPE_LEGS,
+ ITEM_TYPE_OTHER,
+ ITEM_TYPE_RING,
+ ITEM_TYPE_SHIELD,
+ ITEM_TYPE_TOOLS,
+ ITEM_TYPE_AMMO,
+ ITEM_TYPE_AXE,
+ ITEM_TYPE_CLUB,
+ ITEM_TYPE_DISTANCE,
+ ITEM_TYPE_SWORD,
+ ITEM_TYPE_WAND,
+
+ ITEM_TYPE_RETRIEVE,
+ ITEM_TYPE_GOLD,
+ ITEM_TYPE_UNASSIGNED,
+
ITEM_TYPE_LAST,
};
@@ -241,7 +267,6 @@ class ItemType
MagicEffectClasses magicEffect = CONST_ME_NONE;
Direction bedPartnerDir = DIRECTION_NONE;
- QuickLootCategory_t quickLootCategory = LOOT_NONE;
WeaponType_t weaponType = WEAPON_NONE;
Ammo_t ammoType = AMMO_NONE;
ShootType_t shootType = CONST_ANI_NONE;
@@ -330,6 +355,8 @@ class Items
NameMap nameToItems;
private:
+ ItemTypes_t getLootType(const std::string& strValue);
+
std::map reverseItemMap;
std::vector items;
InventoryVector inventory;
diff --git a/src/luascript.cpp b/src/luascript.cpp
index 363d6ace3d..1b94f9ae1f 100644
--- a/src/luascript.cpp
+++ b/src/luascript.cpp
@@ -1534,20 +1534,46 @@ void LuaScriptInterface::registerFunctions()
registerEnum(ITEM_ATTRIBUTE_DOORID)
registerEnum(ITEM_ATTRIBUTE_SPECIAL)
registerEnum(ITEM_ATTRIBUTE_OPENCONTAINER)
+ registerEnum(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER)
registerEnum(ITEM_TYPE_DEPOT)
registerEnum(ITEM_TYPE_REWARDCHEST)
registerEnum(ITEM_TYPE_MAILBOX)
registerEnum(ITEM_TYPE_TRASHHOLDER)
- registerEnum(ITEM_TYPE_CONTAINER)
registerEnum(ITEM_TYPE_DOOR)
registerEnum(ITEM_TYPE_MAGICFIELD)
registerEnum(ITEM_TYPE_TELEPORT)
registerEnum(ITEM_TYPE_BED)
registerEnum(ITEM_TYPE_KEY)
- registerEnum(ITEM_TYPE_RUNE)
registerEnum(ITEM_TYPE_SUPPLY)
+ // Quickloot
+ registerEnum(ITEM_TYPE_ARMOR)
+ registerEnum(ITEM_TYPE_AMULET)
+ registerEnum(ITEM_TYPE_BOOTS)
+ registerEnum(ITEM_TYPE_DECORATION)
+ registerEnum(ITEM_TYPE_CONTAINER)
+ registerEnum(ITEM_TYPE_FOOD)
+ registerEnum(ITEM_TYPE_HELMET)
+ registerEnum(ITEM_TYPE_LEGS)
+ registerEnum(ITEM_TYPE_OTHER)
+ registerEnum(ITEM_TYPE_POTION)
+ registerEnum(ITEM_TYPE_RING)
+ registerEnum(ITEM_TYPE_RUNE)
+ registerEnum(ITEM_TYPE_SHIELD)
+ registerEnum(ITEM_TYPE_TOOLS)
+ registerEnum(ITEM_TYPE_VALUABLE)
+ registerEnum(ITEM_TYPE_AMMO)
+ registerEnum(ITEM_TYPE_AXE)
+ registerEnum(ITEM_TYPE_CLUB)
+ registerEnum(ITEM_TYPE_DISTANCE)
+ registerEnum(ITEM_TYPE_SWORD)
+ registerEnum(ITEM_TYPE_WAND)
+ registerEnum(ITEM_TYPE_CREATUREPRODUCT)
+ registerEnum(ITEM_TYPE_RETRIEVE)
+ registerEnum(ITEM_TYPE_GOLD)
+ registerEnum(ITEM_TYPE_UNASSIGNED)
+
registerEnum(ITEM_BAG)
registerEnum(ITEM_SHOPPING_BAG)
registerEnum(ITEM_GOLD_COIN)
@@ -1758,34 +1784,6 @@ void LuaScriptInterface::registerFunctions()
registerEnum(TILESTATE_FLOORCHANGE_EAST_ALT)
registerEnum(TILESTATE_SUPPORTS_HANGABLE)
- registerEnum(LOOT_UNASSIGNED)
- registerEnum(LOOT_GOLD)
- registerEnum(LOOT_ARMOR)
- registerEnum(LOOT_AMULET)
- registerEnum(LOOT_BOOTS)
- registerEnum(LOOT_CONTAINER)
- registerEnum(LOOT_CREATURE_PRODUCT)
- registerEnum(LOOT_DECORATION)
- registerEnum(LOOT_FOOD)
- registerEnum(LOOT_HELMET)
- registerEnum(LOOT_LEGS)
- registerEnum(LOOT_OTHER)
- registerEnum(LOOT_POTION)
- registerEnum(LOOT_RING)
- registerEnum(LOOT_RUNE)
- registerEnum(LOOT_SHIELD)
- registerEnum(LOOT_TOOL)
- registerEnum(LOOT_VALUABLE)
- registerEnum(LOOT_WEAPON_AMMO)
- registerEnum(LOOT_WEAPON_AXE)
- registerEnum(LOOT_WEAPON_CLUB)
- registerEnum(LOOT_WEAPON_DISTANCE)
- registerEnum(LOOT_WEAPON_SWORD)
- registerEnum(LOOT_WEAPON_WAND)
- registerEnum(LOOT_STASH_RETRIEVE)
- registerEnum(LOOT_START)
- registerEnum(LOOT_END)
-
registerEnum(WEAPON_NONE)
registerEnum(WEAPON_SWORD)
registerEnum(WEAPON_CLUB)
@@ -2435,8 +2433,6 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Player", "getFreeCapacity", LuaScriptInterface::luaPlayerGetFreeCapacity);
- registerMethod("Player", "canOpenCorpse", LuaScriptInterface::luaPlayerCanOpenCorpse);
-
registerMethod("Player", "getKills", LuaScriptInterface::luaPlayerGetKills);
registerMethod("Player", "setKills", LuaScriptInterface::luaPlayerSetKills);
@@ -2848,7 +2844,6 @@ void LuaScriptInterface::registerFunctions()
registerMethod("ItemType", "getExtraDefense", LuaScriptInterface::luaItemTypeGetExtraDefense);
registerMethod("ItemType", "getImbuingSlots", LuaScriptInterface::luaItemTypeGetImbuingSlots);
registerMethod("ItemType", "getArmor", LuaScriptInterface::luaItemTypeGetArmor);
- registerMethod("ItemType", "getLootCategory", LuaScriptInterface::luaItemTypeGetLootCategory);
registerMethod("ItemType", "getWeaponType", LuaScriptInterface::luaItemTypeGetWeaponType);
registerMethod("ItemType", "getElementType", LuaScriptInterface::luaItemTypeGetElementType);
@@ -8651,24 +8646,6 @@ int LuaScriptInterface::luaPlayerGetFreeCapacity(lua_State* L)
return 1;
}
-int LuaScriptInterface::luaPlayerCanOpenCorpse(lua_State* L)
-{
- // player:canOpenCorpse(corpseOwner)
- Player* player = getUserdata(L, 1);
- if (!player) {
- lua_pushnil(L);
- return 1;
- }
- if (player) {
- uint32_t corpseOwner = getNumber(L, 2);
- pushBoolean(L, player->canOpenCorpse(corpseOwner));
- }
- else {
- lua_pushnil(L);
- }
- return 1;
-}
-
int LuaScriptInterface::luaPlayerGetKills(lua_State* L)
{
// player:getKills()
@@ -13384,18 +13361,6 @@ int LuaScriptInterface::luaItemTypeGetArmor(lua_State* L)
return 1;
}
-int LuaScriptInterface::luaItemTypeGetLootCategory(lua_State* L)
-{
- // itemType:getLootCategory()
- const ItemType* itemType = getUserdata(L, 1);
- if (itemType) {
- lua_pushnumber(L, itemType->quickLootCategory);
- } else {
- lua_pushnil(L);
- }
- return 1;
-}
-
int LuaScriptInterface::luaItemTypeGetWeaponType(lua_State* L)
{
// itemType:getWeaponType()
diff --git a/src/luascript.h b/src/luascript.h
index a419ce8934..64bfc80b11 100644
--- a/src/luascript.h
+++ b/src/luascript.h
@@ -862,8 +862,6 @@ class LuaScriptInterface
static int luaPlayerGetCapacity(lua_State* L);
static int luaPlayerSetCapacity(lua_State* L);
- static int luaPlayerCanOpenCorpse(lua_State* L);
-
static int luaPlayerGetKills(lua_State* L);
static int luaPlayerSetKills(lua_State* L);
@@ -1027,6 +1025,10 @@ class LuaScriptInterface
static int luaPlayerIsPzLocked(lua_State* L);
static int luaPlayerIsOffline(lua_State* L);
+ static int luaPlayerGetContainers(lua_State* L);
+ static int luaPlayerSetLootContainer(lua_State* L);
+ static int luaPlayerGetLootContainer(lua_State* L);
+
// New Prey
static int luaPlayerGetPreyState(lua_State * L);
static int luaPlayerGetPreyUnlocked(lua_State * L);
@@ -1267,7 +1269,6 @@ class LuaScriptInterface
static int luaItemTypeGetExtraDefense(lua_State* L);
static int luaItemTypeGetImbuingSlots(lua_State* L);
static int luaItemTypeGetArmor(lua_State* L);
- static int luaItemTypeGetLootCategory(lua_State* L);
static int luaItemTypeGetWeaponType(lua_State* L);
static int luaItemTypeGetElementType(lua_State* L);
diff --git a/src/player.cpp b/src/player.cpp
index 42819353be..c5c99dcf06 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -75,10 +75,15 @@ Player::~Player()
it.second->decrementReferenceCounter();
}
+ for (const auto& it : quickLootContainers) {
+ it.second->decrementReferenceCounter();
+ }
+
inbox->decrementReferenceCounter();
setWriteItem(nullptr);
setEditHouse(nullptr);
+ logged = false;
}
bool Player::setVocation(uint16_t vocId)
@@ -795,6 +800,94 @@ void Player::onReceiveMail() const
}
}
+Container* Player::setLootContainer(ObjectCategory_t category, Container* container, bool loading /* = false*/)
+{
+ Container* previousContainer = nullptr;
+ auto it = quickLootContainers.find(category);
+ if (it != quickLootContainers.end() && !loading) {
+ previousContainer = (*it).second;
+ uint32_t flags = previousContainer->getIntAttr(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER);
+ flags &= ~(1 << category);
+ if (flags == 0) {
+ previousContainer->removeAttribute(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER);
+ } else {
+ previousContainer->setIntAttr(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER, flags);
+ }
+
+ previousContainer->decrementReferenceCounter();
+ quickLootContainers.erase(it);
+ }
+
+ if (container) {
+ previousContainer = container;
+ quickLootContainers[category] = container;
+
+ container->incrementReferenceCounter();
+ if (!loading) {
+ uint32_t flags = container->getIntAttr(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER);
+ container->setIntAttr(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER, flags | static_cast(1 << category));
+ }
+ }
+
+ return previousContainer;
+}
+
+Container* Player::getLootContainer(ObjectCategory_t category) const
+{
+ if (category != OBJECTCATEGORY_DEFAULT && !isPremium()) {
+ category = OBJECTCATEGORY_DEFAULT;
+ }
+
+ auto it = quickLootContainers.find(category);
+ if (it != quickLootContainers.end()) {
+ return (*it).second;
+ }
+
+ if (category != OBJECTCATEGORY_DEFAULT) {
+ // firstly, fallback to default
+ return getLootContainer(OBJECTCATEGORY_DEFAULT);
+ }
+
+ return nullptr;
+}
+
+void Player::checkLootContainers(const Item* item)
+{
+ if (!item) {
+ return;
+ }
+
+ const Container* container = item->getContainer();
+ if (!container) {
+ return;
+ }
+
+ bool shouldSend = false;
+
+ auto it = quickLootContainers.begin();
+ while (it != quickLootContainers.end()) {
+ Container* lootContainer = (*it).second;
+
+ bool remove = false;
+ if (item->getHoldingPlayer() != this && (item == lootContainer || container->isHoldingItem(lootContainer))) {
+ remove = true;
+ }
+
+ if (remove) {
+ shouldSend = true;
+ it = quickLootContainers.erase(it);
+ lootContainer->decrementReferenceCounter();
+ lootContainer->removeAttribute(ITEM_ATTRIBUTE_QUICKLOOTCONTAINER);
+ } else {
+ ++it;
+ }
+ }
+
+ if (shouldSend) {
+ sendLootContainers();
+ }
+}
+
bool Player::isNearDepotBox() const
{
const Position& pos = getPosition();
@@ -1142,6 +1235,8 @@ void Player::onRemoveTileItem(const Tile* fromTile, const Position& pos, const I
}
}
}
+
+ checkLootContainers(item);
}
void Player::onCreatureAppear(Creature* creature, bool isLogin)
@@ -1188,7 +1283,7 @@ void Player::onCreatureAppear(Creature* creature, bool isLogin)
}
}
- g_game.checkPlayersRecord();
+ g_game.checkPlayersRecord();
IOLoginData::updateOnlineStatus(guid, true);
}
}
@@ -1432,6 +1527,8 @@ void Player::onRemoveContainerItem(const Container* container, const Item* item)
}
}
}
+
+ checkLootContainers(item);
}
void Player::onCloseContainer(const Container* container)
@@ -1486,6 +1583,8 @@ void Player::onRemoveInventoryItem(Item* item)
}
}
}
+
+ checkLootContainers(item);
}
void Player::checkTradeState(const Item* item)
@@ -3208,6 +3307,8 @@ void Player::postRemoveNotification(Thing* thing, const Cylinder* newParent, int
if (const Item* item = thing->getItem()) {
if (const Container* container = item->getContainer()) {
+ checkLootContainers(container);
+
if (container->isRemoved() || !Position::areInRange<1, 1, 0>(getPosition(), container->getPosition())) {
autoCloseContainers(container);
} else if (container->getTopParent() == this) {
diff --git a/src/player.h b/src/player.h
index 4bfa9756a2..b4b7ac7072 100644
--- a/src/player.h
+++ b/src/player.h
@@ -626,6 +626,9 @@ class Player final : public Creature, public Cylinder
void onReceiveMail() const;
bool isNearDepotBox() const;
+ Container* setLootContainer(ObjectCategory_t category, Container* container, bool loading = false);
+ Container* getLootContainer(ObjectCategory_t category) const;
+
bool canSee(const Position& pos) const override;
bool canSeeCreature(const Creature* creature) const override;
@@ -968,6 +971,11 @@ class Player final : public Creature, public Cylinder
}
//inventory
+ void sendLockerItems(std::map itemMap, uint16_t count) {
+ if (client) {
+ client->sendLockerItems(itemMap, count);
+ }
+ }
void sendCoinBalance() {
if (client) {
client->sendCoinBalance();
@@ -1022,6 +1030,18 @@ class Player final : public Creature, public Cylinder
}
}
+ // Quickloot
+ void sendLootContainers() {
+ if (client) {
+ client->sendLootContainers();
+ }
+ }
+ void sendLootStats(Item* item) {
+ if (client) {
+ client->sendLootStats(item);
+ }
+ }
+
//event methods
void onUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem,
const ItemType& oldType, const Item* newItem, const ItemType& newType) override;
@@ -1398,6 +1418,15 @@ class Player final : public Creature, public Cylinder
lastMarketInteraction = OTSYS_TIME();
}
+ bool isQuickLootListedItem(const Item* item) const {
+ if (!item) {
+ return false;
+ }
+
+ auto it = std::find(quickLootListClientIds.begin(), quickLootListClientIds.end(), item->getClientID());
+ return it != quickLootListClientIds.end();
+ }
+
bool updateKillTracker(Container* corpse, const std::string& playerName, const Outfit_t creatureOutfit) const
{
if (client) {
@@ -1445,6 +1474,8 @@ class Player final : public Creature, public Cylinder
void checkTradeState(const Item* item);
bool hasCapacity(const Item* item, uint32_t count) const;
+ void checkLootContainers(const Item* item);
+
void gainExperience(uint64_t exp, Creature* source);
void addExperience(Creature* source, uint64_t exp, bool sendText = false);
void removeExperience(uint64_t exp, bool sendText = false);
@@ -1500,6 +1531,9 @@ class Player final : public Creature, public Cylinder
std::map rewardMap;
+ std::map quickLootContainers;
+ std::vector quickLootListClientIds;
+
std::vector outfits;
GuildWarVector guildWarVector;
@@ -1534,6 +1568,7 @@ class Player final : public Creature, public Cylinder
int64_t lastPing;
int64_t lastPong;
int64_t nextAction = 0;
+ int64_t lastQuickLootNotification = 0;
std::vector unjustifiedKills;
@@ -1627,7 +1662,8 @@ class Player final : public Creature, public Cylinder
tradestate_t tradeState = TRADE_NONE;
fightMode_t fightMode = FIGHTMODE_ATTACK;
account::AccountType accountType =
- account::AccountType::ACCOUNT_TYPE_NORMAL;
+ account::AccountType::ACCOUNT_TYPE_NORMAL;
+ QuickLootFilter_t quickLootFilter;
bool chaseMode = false;
bool secureMode = true;
@@ -1638,6 +1674,8 @@ class Player final : public Creature, public Cylinder
bool isConnecting = false;
bool addAttackSkillPoint = false;
bool inventoryAbilities[CONST_SLOT_LAST + 1] = {};
+ bool quickLootFallbackToMainContainer = false;
+ bool logged = false;
bool scheduledSaleUpdate = false;
static uint32_t playerAutoID;
diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp
index f186faf193..cc7bcf9a77 100644
--- a/src/protocolgame.cpp
+++ b/src/protocolgame.cpp
@@ -48,6 +48,65 @@ extern Modules* g_modules;
extern Spells* g_spells;
extern Imbuements* g_imbuements;
+void ProtocolGame::AddItem(NetworkMessage& msg, uint16_t id, uint8_t count)
+{
+ const ItemType& it = Item::items[id];
+
+ msg.add(it.clientId);
+
+ if (it.stackable) {
+ msg.addByte(count);
+ } else if (it.isSplash() || it.isFluidContainer()) {
+ msg.addByte(fluidMap[count & 7]);
+ } else if (it.isContainer() && player->getOperatingSystem() <= CLIENTOS_NEW_WINDOWS) {
+ msg.addByte(0x00);
+ }
+
+ if (it.isAnimation) {
+ msg.addByte(0xFE); // random phase (0xFF for async)
+ }
+}
+
+void ProtocolGame::AddItem(NetworkMessage& msg, const Item* item)
+{
+ if (!item) {
+ return;
+ }
+
+ const ItemType& it = Item::items[item->getID()];
+
+ msg.add(it.clientId);
+
+ if (it.stackable) {
+ msg.addByte(std::min(0xFF, item->getItemCount()));
+ } else if (it.isSplash() || it.isFluidContainer()) {
+ msg.addByte(fluidMap[item->getFluidType() & 7]);
+ } else if (it.isContainer() && player->getOperatingSystem() <= CLIENTOS_NEW_WINDOWS) {
+ const Container* container = item->getContainer();
+ if (container && container->getHoldingPlayer() == player) {
+ uint32_t lootFlags = 0;
+ for (auto itt : player->quickLootContainers) {
+ if (itt.second == container) {
+ lootFlags |= 1 << itt.first;
+ }
+ }
+
+ if (lootFlags != 0) {
+ msg.addByte(0x01);
+ msg.add(lootFlags);
+ } else {
+ msg.addByte(0x00);
+ }
+ } else {
+ msg.addByte(0x00);
+ }
+ }
+
+ if (it.isAnimation) {
+ msg.addByte(0xFE); // random phase (0xFF for async)
+ }
+}
+
void ProtocolGame::release()
{
//dispatcher thread
@@ -93,8 +152,8 @@ void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingS
}
if (g_config.getBoolean(ConfigManager::ONE_PLAYER_ON_ACCOUNT)
- && player->getAccountType() < account::ACCOUNT_TYPE_GAMEMASTER
- && g_game.getPlayerByAccount(player->getAccount())) {
+ && player->getAccountType() < account::ACCOUNT_TYPE_GAMEMASTER
+ && g_game.getPlayerByAccount(player->getAccount())) {
disconnectClient("You may only login with one character\nof your account at the same time.");
return;
}
@@ -455,6 +514,10 @@ void ProtocolGame::parsePacket(NetworkMessage& msg)
case 0x8C: parseLookAt(msg); break;
case 0x8D: parseLookInBattleList(msg); break;
case 0x8E: /* join aggression */ break;
+ case 0x8F: parseQuickLoot(msg); break;
+ case 0x90: parseLootContainer(msg); break;
+ case 0x91: parseQuickLootBlackWhitelist(msg); break;
+ case 0x92: parseRequestLockItems(); break;
case 0x96: parseSay(msg); break;
case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break;
case 0x98: parseOpenChannel(msg); break;
@@ -915,6 +978,58 @@ void ProtocolGame::parseLookInBattleList(NetworkMessage& msg)
addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInBattleList, player->getID(), creatureId);
}
+void ProtocolGame::parseQuickLoot(NetworkMessage& msg)
+{
+ Position pos = msg.getPosition();
+ uint16_t spriteId = msg.get();
+ uint8_t stackpos = msg.getByte();
+ addGameTask(&Game::playerQuickLoot, player->getID(), pos, spriteId, stackpos, nullptr);
+}
+
+void ProtocolGame::parseLootContainer(NetworkMessage& msg)
+{
+ uint8_t action = msg.getByte();
+ if (action == 0) {
+ ObjectCategory_t category = (ObjectCategory_t)msg.getByte();
+ Position pos = msg.getPosition();
+ uint16_t spriteId = msg.get();
+ uint8_t stackpos = msg.getByte();
+ addGameTask(&Game::playerSetLootContainer, player->getID(), category, pos, spriteId, stackpos);
+ }
+ else if (action == 1) {
+ ObjectCategory_t category = (ObjectCategory_t) msg.getByte();
+ addGameTask(&Game::playerClearLootContainer, player->getID(), category);
+ }
+ else if (action == 2) {
+ ObjectCategory_t category = (ObjectCategory_t)msg.getByte();
+ addGameTask(&Game::playerOpenLootContainer, player->getID(), category);
+ }
+ else if (action == 3) {
+ bool useMainAsFallback = msg.getByte() == 1;
+ addGameTask(&Game::playerSetQuickLootFallback, player->getID(), useMainAsFallback);
+ }
+}
+
+void ProtocolGame::parseQuickLootBlackWhitelist(NetworkMessage& msg)
+{
+ QuickLootFilter_t filter = (QuickLootFilter_t)msg.getByte();
+ std::vector listedItems;
+
+ uint16_t size = msg.get();
+ listedItems.reserve(size);
+
+ for (int i = 0; i < size; i++) {
+ listedItems.push_back(msg.get());
+ }
+
+ addGameTask(&Game::playerQuickLootBlackWhitelist, player->getID(), filter, listedItems);
+}
+
+void ProtocolGame::parseRequestLockItems()
+{
+ addGameTask(&Game::playerRequestLockFind, player->getID());
+}
+
void ProtocolGame::parseSay(NetworkMessage& msg)
{
std::string receiver;
@@ -1766,6 +1881,40 @@ void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool h
writeToOutputBuffer(msg);
}
+void ProtocolGame::sendLootContainers()
+{
+ NetworkMessage msg;
+ msg.addByte(0xC0);
+ msg.addByte(player->quickLootFallbackToMainContainer ? 1 : 0);
+ std::map quickLoot;
+ for (auto it : player->quickLootContainers) {
+ if (it.second && !it.second->isRemoved()) {
+ quickLoot[it.first] = it.second;
+ }
+ }
+ msg.addByte(quickLoot.size());
+ for (auto it : quickLoot) {
+ msg.addByte(it.first);
+ msg.add(it.second->getClientID());
+ }
+
+ writeToOutputBuffer(msg);
+}
+
+void ProtocolGame::sendLootStats(Item* item)
+{
+ if (!item) {
+ return;
+ }
+
+ NetworkMessage msg;
+ msg.addByte(0xCF);
+ AddItem(msg, item);
+ msg.addString(item->getName());
+
+ writeToOutputBuffer(msg);
+}
+
void ProtocolGame::sendShop(Npc* npc, const ShopInfoList& itemList)
{
NetworkMessage msg;
@@ -2004,11 +2153,11 @@ void ProtocolGame::updateCoinBalance()
g_dispatcher.addTask(
createTask(std::bind([](ProtocolGame* client) {
if (client && client->player) {
- account::Account account;
- account.LoadAccountDB(client->player->getAccount());
- uint32_t coins;
- account.GetCoins(&coins);
- client->player->coinBalance = coins;
+ account::Account account;
+ account.LoadAccountDB(client->player->getAccount());
+ uint32_t coins;
+ account.GetCoins(&coins);
+ client->player->coinBalance = coins;
client->sendCoinBalance();
}
}, this))
@@ -2621,9 +2770,9 @@ void ProtocolGame::sendMagicEffect(const Position& pos, uint8_t type)
void ProtocolGame::sendCreatureHealth(const Creature* creature)
{
- if (creature->isHealthHidden()) {
- return;
- }
+ if (creature->isHealthHidden()) {
+ return;
+ }
NetworkMessage msg;
msg.addByte(0x8C);
@@ -2862,8 +3011,19 @@ void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos
}
}
- sendBasicData();
sendInventoryClientIds();
+ Item* slotItem = player->getInventoryItem(CONST_SLOT_BACKPACK);
+ if (slotItem) {
+ Container* mainBackpack = slotItem->getContainer();
+ Container* hasQuickLootContainer = player->getLootContainer(OBJECTCATEGORY_DEFAULT);
+ if (mainBackpack && !hasQuickLootContainer) {
+ player->setLootContainer(OBJECTCATEGORY_DEFAULT, mainBackpack);
+ sendInventoryItem(CONST_SLOT_BACKPACK, player->getInventoryItem(CONST_SLOT_BACKPACK));
+ }
+ }
+
+ sendLootContainers();
+ sendBasicData();
initPreyData();
player->sendClientCheck();
@@ -3676,50 +3836,6 @@ void ProtocolGame::sendImbuementWindow(Item* item)
writeToOutputBuffer(msg);
}
-void ProtocolGame::AddItem(NetworkMessage& msg, uint16_t id, uint8_t count)
-{
- const ItemType& it = Item::items[id];
-
- msg.add(it.clientId);
-
- if (it.stackable) {
- msg.addByte(count);
- } else if (it.isSplash() || it.isFluidContainer()) {
- msg.addByte(fluidMap[count & 7]);
- } else if (it.isContainer() && player->getOperatingSystem() <= CLIENTOS_NEW_WINDOWS) {
- msg.addByte(0x00);
- }
-
- if (it.isAnimation) {
- msg.addByte(0xFE); // random phase (0xFF for async)
- }
-}
-
-void ProtocolGame::AddItem(NetworkMessage& msg, const Item* item)
-{
- const ItemType& it = Item::items[item->getID()];
-
- msg.add(it.clientId);
-
- if (it.stackable) {
- msg.addByte(std::min(0xFF, item->getItemCount()));
- } else if (it.isSplash() || it.isFluidContainer()) {
- msg.addByte(fluidMap[item->getFluidType() & 7]);
- } else if (it.isContainer() && player->getOperatingSystem() <= CLIENTOS_NEW_WINDOWS) {
- uint32_t quickLootFlags = item->getQuickLootFlags();
- if (quickLootFlags > 0) {
- msg.addByte(2);
- msg.add(quickLootFlags);
- } else {
- msg.addByte(0x00);
- }
- }
-
- if (it.isAnimation) {
- msg.addByte(0xFE); // random phase (0xFF for async)
- }
-}
-
void ProtocolGame::AddWorldLight(NetworkMessage& msg, LightInfo lightInfo)
{
msg.addByte(0x82);
@@ -3970,3 +4086,17 @@ void ProtocolGame::reloadCreature(const Creature* creature)
writeToOutputBuffer(msg);
}
+
+void ProtocolGame::sendLockerItems(std::map itemMap, uint16_t count)
+{
+ NetworkMessage msg;
+ msg.addByte(0x94);
+
+ msg.add(count);
+ for (const auto& it : itemMap) {
+ msg.addItemId(it.first);
+ msg.add(it.second);
+ }
+
+ writeToOutputBuffer(msg);
+}
diff --git a/src/protocolgame.h b/src/protocolgame.h
index bab069661d..383212d419 100644
--- a/src/protocolgame.h
+++ b/src/protocolgame.h
@@ -73,6 +73,8 @@ class ProtocolGame final : public Protocol
void AddItem(NetworkMessage& msg, const Item* item);
void AddItem(NetworkMessage& msg, uint16_t id, uint8_t count);
+ void sendLockerItems(std::map itemMap, uint16_t count);
+
uint16_t getVersion() const {
return version;
}
@@ -104,6 +106,12 @@ class ProtocolGame final : public Protocol
void parseSay(NetworkMessage& msg);
void parseLookAt(NetworkMessage& msg);
void parseLookInBattleList(NetworkMessage& msg);
+
+ void parseQuickLoot(NetworkMessage& msg);
+ void parseLootContainer(NetworkMessage& msg);
+ void parseQuickLootBlackWhitelist(NetworkMessage& msg);
+ void parseRequestLockItems();
+
void parseFightModes(NetworkMessage& msg);
void parseAttack(NetworkMessage& msg);
void parseFollow(NetworkMessage& msg);
@@ -305,6 +313,10 @@ class ProtocolGame final : public Protocol
void sendContainer(uint8_t cid, const Container* container, bool hasParent, uint16_t firstIndex);
void sendCloseContainer(uint8_t cid);
+ //quickloot
+ void sendLootContainers();
+ void sendLootStats(Item* item);
+
//inventory
void sendInventoryItem(slots_t slot, const Item* item);
void sendInventoryClientIds();
diff --git a/src/tile.cpp b/src/tile.cpp
index e538b98508..8134600200 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -1652,17 +1652,17 @@ Item* Tile::getDoorItem() const
{
const TileItemVector* items = getItemList();
if (!items || items->size() == 0) {
- return ground;
- }
-
- if (items) {
- for (Item* item : *items) {
- const ItemType& it = Item::items[item->getID()];
- if (it.isDoor()) {
- return item;
- }
- }
- }
+ return ground;
+ }
+
+ if (items) {
+ for (Item* item : *items) {
+ const ItemType& it = Item::items[item->getID()];
+ if (it.isDoor()) {
+ return item;
+ }
+ }
+ }
return nullptr;
}
diff --git a/src/tile.h b/src/tile.h
index abd6b391b1..cc89892eb3 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -267,8 +267,8 @@ class Tile : public Cylinder
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override final;
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override final;
- void internalAddThing(Thing* thing) override final;
- void internalAddThing(uint32_t index, Thing* thing) override;
+ void internalAddThing(Thing* thing) override;
+ void virtual internalAddThing(uint32_t index, Thing* thing) override;
const Position& getPosition() const override final {
return tilePos;
@@ -279,7 +279,7 @@ class Tile : public Cylinder
}
Item* getUseItem(int32_t index) const;
- Item* getDoorItem() const;
+ Item* getDoorItem() const;
Item* getGround() const {
return ground;
diff --git a/src/tools.cpp b/src/tools.cpp
index 2e5511b109..c7ecde5e4c 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -1371,4 +1371,38 @@ bool isCaskItem(uint16_t itemId)
return (itemId >= ITEM_HEALTH_CASK_START && itemId <= ITEM_HEALTH_CASK_END) ||
(itemId >= ITEM_MANA_CASK_START && itemId <= ITEM_MANA_CASK_END) ||
(itemId >= ITEM_SPIRIT_CASK_START && itemId <= ITEM_SPIRIT_CASK_END);
-}
\ No newline at end of file
+}
+
+std::string getObjectCategoryName(ObjectCategory_t category)
+{
+ switch (category) {
+ case OBJECTCATEGORY_ARMORS: return "Armors";
+ case OBJECTCATEGORY_NECKLACES: return "Amulets";
+ case OBJECTCATEGORY_BOOTS: return "Boots";
+ case OBJECTCATEGORY_CONTAINERS: return "Containers";
+ case OBJECTCATEGORY_DECORATION: return "Decoration";
+ case OBJECTCATEGORY_FOOD: return "Food";
+ case OBJECTCATEGORY_HELMETS: return "Helmets";
+ case OBJECTCATEGORY_LEGS: return "Legs";
+ case OBJECTCATEGORY_OTHERS: return "Others";
+ case OBJECTCATEGORY_POTIONS: return "Potions";
+ case OBJECTCATEGORY_RINGS: return "Rings";
+ case OBJECTCATEGORY_RUNES: return "Runes";
+ case OBJECTCATEGORY_SHIELDS: return "Shields";
+ case OBJECTCATEGORY_TOOLS: return "Tools";
+ case OBJECTCATEGORY_VALUABLES: return "Valuables";
+ case OBJECTCATEGORY_AMMO: return "Weapons: Ammunition";
+ case OBJECTCATEGORY_AXES: return "Weapons: Axes";
+ case OBJECTCATEGORY_CLUBS: return "Weapons: Clubs";
+ case OBJECTCATEGORY_DISTANCEWEAPONS: return "Weapons: Distance";
+ case OBJECTCATEGORY_SWORDS: return "Weapons: Swords";
+ case OBJECTCATEGORY_WANDS: return "Weapons: Wands";
+ case OBJECTCATEGORY_PREMIUMSCROLLS: return "Premium Scrolls";
+ case OBJECTCATEGORY_TIBIACOINS: return "Tibia Coins";
+ case OBJECTCATEGORY_CREATUREPRODUCTS: return "Creature Products";
+ case OBJECTCATEGORY_STASHRETRIEVE: return "Stash Retrieve";
+ case OBJECTCATEGORY_GOLD: return "Gold";
+ case OBJECTCATEGORY_DEFAULT: return "Unassigned Loot";
+ default: return std::string();
+ }
+}
diff --git a/src/tools.h b/src/tools.h
index f77d192077..3d83411b66 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -100,6 +100,8 @@ NameEval_t validateName(const std::string &name);
bool isCaskItem(uint16_t itemId);
+std::string getObjectCategoryName(ObjectCategory_t category);
+
int64_t OTSYS_TIME();
SpellGroup_t stringToSpellGroup(std::string value);