Skip to content

Commit

Permalink
Initial work.
Browse files Browse the repository at this point in the history
Added LootStatus definition in GroupLoot.
  • Loading branch information
evil-morfar committed Sep 4, 2024
1 parent 82d7d1b commit 430d712
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 92 deletions.
270 changes: 178 additions & 92 deletions .specs/Classes/Utils/GroupLoot.spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,98 +13,98 @@ local GroupLoot = addon.Require "Utils.GroupLoot"
addon:InitLogging()
addon.Print = function() end --noop
describe("#GroupLoot", function()
-- describe("#Basic", function()
-- it("should need on items when we're ML and item can be needed", function()
-- stub(_G, "GetLootRollItemInfo", function()
-- return nil,nil,nil,nil,nil,1 -- canNeed = true
-- end)
-- local s = spy.on(GroupLoot, "RollOnLoot")
-- SetupML()
-- GroupLoot:OnStartLootRoll(nil, 1)
-- assert.spy(s).was_called(1)
-- assert.spy(s).was_called_with(GroupLoot, 1, 1)
-- _G.GetLootRollItemInfo:revert()
-- end)
-- it("should greed on loot when we're ML", function()
-- local s = spy.on(GroupLoot, "RollOnLoot")
-- SetupML()
-- GroupLoot:OnStartLootRoll(nil, 1)
-- assert.spy(s).was_called(1)
-- assert.spy(s).was_called_with(GroupLoot, 1, 2)
-- end)
-- it("should pass on loot by default", function()
-- local s = spy.on(GroupLoot, "RollOnLoot")
-- SetupML()
-- addon.isMasterLooter = false
-- addon.isInGuildGroup = false
-- GroupLoot:OnStartLootRoll(nil, 1)
-- GroupLoot:OnStartLootRoll(nil, 2)
-- assert.spy(s).was_called(0)
-- end)

-- it("should not do anything when addon isn't in use", function()
-- local s = spy.on(GroupLoot, "RollOnLoot")
-- addon.handleLoot = false
-- GroupLoot:OnStartLootRoll(nil, 3)
-- assert.spy(s).was_called(0)
-- end)

-- it("should not do anything when addon is disabled", function()
-- local s = spy.on(GroupLoot, "RollOnLoot")
-- addon.enabled = false
-- GroupLoot:OnStartLootRoll(nil, 3)
-- assert.spy(s).was_called(0)
-- end)
-- end)

-- describe("#autoGroupLootGuildGroupOnly ", function()
-- local s
-- before_each(function()
-- s = spy.on(GroupLoot, "RollOnLoot")
-- addon.enabled = true
-- SetupML()
-- addon.isMasterLooter = false
-- end)
-- describe("enabled", function()
-- it("should pass on loot if in guild group", function()
-- addon.isInGuildGroup = true
-- GroupLoot:OnStartLootRoll(nil, 1)
-- GroupLoot:OnStartLootRoll(nil, 2)
-- assert.spy(s).was_called(2)
-- assert.spy(s).was_called_with(GroupLoot, 1, 0)
-- assert.spy(s).was_called_with(GroupLoot, 2, 0)
-- end)

-- it("should not pass on loot if not in guild group", function()
-- addon.isInGuildGroup = false
-- GroupLoot:OnStartLootRoll(nil, 1)
-- GroupLoot:OnStartLootRoll(nil, 2)
-- assert.spy(s).was_called(0)
-- end)
-- end)

-- describe("disabled", function()
-- addon.db.profile.autoGroupLootGuildGroupOnly = false
-- it("should pass on loot if in guild group", function()
-- addon.isInGuildGroup = true
-- GroupLoot:OnStartLootRoll(nil, 1)
-- GroupLoot:OnStartLootRoll(nil, 2)
-- assert.spy(s).was_called(2)
-- assert.spy(s).was_called_with(GroupLoot, 1, 0)
-- assert.spy(s).was_called_with(GroupLoot, 2, 0)
-- end)

-- it("should pass on loot if not in guild group", function()
-- addon.isInGuildGroup = false
-- GroupLoot:OnStartLootRoll(nil, 1)
-- GroupLoot:OnStartLootRoll(nil, 2)
-- assert.spy(s).was_called(2)
-- assert.spy(s).was_called_with(GroupLoot, 1, 0)
-- assert.spy(s).was_called_with(GroupLoot, 2, 0)
-- end)
-- end)

-- end)
describe("#Basic", function()
it("should need on items when we're ML and item can be needed", function()
stub(_G, "GetLootRollItemInfo", function()
return nil,nil,nil,nil,nil,1 -- canNeed = true
end)
local s = spy.on(GroupLoot, "RollOnLoot")
SetupML()
GroupLoot:OnStartLootRoll(nil, 1)
assert.spy(s).was_called(1)
assert.spy(s).was_called_with(GroupLoot, 1, 1)
_G.GetLootRollItemInfo:revert()
end)
it("should greed on loot when we're ML", function()
local s = spy.on(GroupLoot, "RollOnLoot")
SetupML()
GroupLoot:OnStartLootRoll(nil, 1)
assert.spy(s).was_called(1)
assert.spy(s).was_called_with(GroupLoot, 1, 2)
end)
it("should pass on loot by default", function()
local s = spy.on(GroupLoot, "RollOnLoot")
SetupML()
addon.isMasterLooter = false
addon.isInGuildGroup = false
GroupLoot:OnStartLootRoll(nil, 1)
GroupLoot:OnStartLootRoll(nil, 2)
assert.spy(s).was_called(0)
end)

it("should not do anything when addon isn't in use", function()
local s = spy.on(GroupLoot, "RollOnLoot")
addon.handleLoot = false
GroupLoot:OnStartLootRoll(nil, 3)
assert.spy(s).was_called(0)
end)

it("should not do anything when addon is disabled", function()
local s = spy.on(GroupLoot, "RollOnLoot")
addon.enabled = false
GroupLoot:OnStartLootRoll(nil, 3)
assert.spy(s).was_called(0)
end)
end)

describe("#autoGroupLootGuildGroupOnly ", function()
local s
before_each(function()
s = spy.on(GroupLoot, "RollOnLoot")
addon.enabled = true
SetupML()
addon.isMasterLooter = false
end)
describe("enabled", function()
it("should pass on loot if in guild group", function()
addon.isInGuildGroup = true
GroupLoot:OnStartLootRoll(nil, 1)
GroupLoot:OnStartLootRoll(nil, 2)
assert.spy(s).was_called(2)
assert.spy(s).was_called_with(GroupLoot, 1, 0)
assert.spy(s).was_called_with(GroupLoot, 2, 0)
end)

it("should not pass on loot if not in guild group", function()
addon.isInGuildGroup = false
GroupLoot:OnStartLootRoll(nil, 1)
GroupLoot:OnStartLootRoll(nil, 2)
assert.spy(s).was_called(0)
end)
end)

describe("disabled", function()
addon.db.profile.autoGroupLootGuildGroupOnly = false
it("should pass on loot if in guild group", function()
addon.isInGuildGroup = true
GroupLoot:OnStartLootRoll(nil, 1)
GroupLoot:OnStartLootRoll(nil, 2)
assert.spy(s).was_called(2)
assert.spy(s).was_called_with(GroupLoot, 1, 0)
assert.spy(s).was_called_with(GroupLoot, 2, 0)
end)

it("should pass on loot if not in guild group", function()
addon.isInGuildGroup = false
GroupLoot:OnStartLootRoll(nil, 1)
GroupLoot:OnStartLootRoll(nil, 2)
assert.spy(s).was_called(2)
assert.spy(s).was_called_with(GroupLoot, 1, 0)
assert.spy(s).was_called_with(GroupLoot, 2, 0)
end)
end)

end)

describe("#ignored items", function()
local s
Expand All @@ -121,6 +121,91 @@ describe("#GroupLoot", function()
end)
end)

describe("#Status", function()
--[[ Tested with integers, binary and string versions (100.000 reps):
String Time taken: 1.035
Normal Time taken: 0.819
Binary Time taken: 0.84
Binary is a bit slower than using integers, but uses less than half the size when transmitting.
]]
before_each(function()
addon.enabled = true
addon.handleLoot = false
addon.mldb = {}
addon.isMasterLooter = false
addon.masterLooter = nil
addon.isInGuildGroup = false
addon.db.profile.autoGroupLootGuildGroupOnly = true
end)
it("should return '101100000' by default", function()
local status = GroupLoot:GetInvertedStatusTable()
-- By default only GetNumGroupMembers, autoGroupLootGuildGroupOnly, and enabled are set
-- 101100000
local expected = GroupLoot:CalculateStatus("enabled", "autoGroupLootGuildGroupOnly", "numGroupMembers")
assert.equal(expected, GroupLoot:GetStatus())
end)

it("should return '101100001' when mldb is set", function()
addon.mldb = { autoGroupLoot = false, }
-- 101100001
local expected = GroupLoot:CalculateStatus("enabled", "autoGroupLootGuildGroupOnly", "numGroupMembers",
"mldb")
assert.equal(expected, GroupLoot:GetStatus())
end)
it("should return '101100011' when mldb.autoGroupLoot is enabled", function()
addon.mldb = { autoGroupLoot = true, }
-- 101100011
local expected = GroupLoot:CalculateStatus("enabled", "autoGroupLootGuildGroupOnly", "numGroupMembers",
"mldb", "mldb.autoGroupLoot")
assert.equal(expected, GroupLoot:GetStatus())
end)

it("should return '101100100' when handleLoot is enabled", function()
addon.handleLoot = true
-- 101100100
local expected = GroupLoot:CalculateStatus("enabled", "autoGroupLootGuildGroupOnly", "numGroupMembers",
"handleLoot")
assert.equal(expected, GroupLoot:GetStatus())
end)

it("should return '101111000' when someone else is ML", function()
addon.masterLooter = "Someone"
-- 101111000
local expected = GroupLoot:CalculateStatus("enabled", "autoGroupLootGuildGroupOnly", "numGroupMembers",
"masterLooter")
assert.equal(expected, GroupLoot:GetStatus())
end)

it("should return '101111000' when we're ML", function()
addon.isMasterLooter = true
addon.masterLooter = addon.player
-- 101111000
local expected = GroupLoot:CalculateStatus("enabled", "autoGroupLootGuildGroupOnly", "numGroupMembers",
"masterLooter", "isMasterLooter")
assert.equal(expected, GroupLoot:GetStatus())
end)

it("should return '111101111' when we should pass", function()
addon.mldb = { autoGroupLoot = true, }
addon.handleLoot = true
addon.masterLooter = addon.player
addon.isInGuildGroup = true
assert.is.True(GroupLoot:ShouldPassOnLoot())
assert.is.False(GroupLoot:ShouldRollOnLoot())
assert.is.Equal(0x1ef, GroupLoot:GetStatus())
end)
it("should return '111111111' when we should roll", function()
addon.mldb = { autoGroupLoot = true, }
addon.handleLoot = true
addon.masterLooter = addon.player
addon.isMasterLooter = true
addon.isInGuildGroup = true
assert.is.False(GroupLoot:ShouldPassOnLoot())
assert.is.True(GroupLoot:ShouldRollOnLoot())
assert.is.Equal(0x1ff, GroupLoot:GetStatus())
end)
end)

function _G.GetLootRollItemLink(rollID)
if GroupLoot.IgnoreList[rollID] then
return "item:" .. rollID .. ":"
Expand All @@ -129,6 +214,7 @@ describe("#GroupLoot", function()
end
end)

---@private
function _G.GetNumGroupMembers()
return 10
end
Expand Down
68 changes: 68 additions & 0 deletions Classes/Utils/GroupLoot.lua
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,79 @@ function GroupLoot:ShouldPassOnLoot()
return addon.mldb and addon.mldb.autoGroupLoot and addon.handleLoot and
addon.masterLooter and not addon.isMasterLooter and GetNumGroupMembers() > 1
and (db.autoGroupLootGuildGroupOnly and addon.isInGuildGroup or not db.autoGroupLootGuildGroupOnly)

-- return self:GetStatus() == 0x1ef -- 111101111
end

function GroupLoot:ShouldRollOnLoot()
return addon.mldb and addon.mldb.autoGroupLoot and addon.handleLoot and
addon.masterLooter and addon.isMasterLooter and GetNumGroupMembers() > 1
-- return bit.band(self:GetStatus(), 0x13f) == 0x13f -- 100111111
-- TODO Consider if we do care about the guild group thing as ML.
end

--- @enum Status
--- Table which keys is the binary representation of whether the value is true.
--- If everything but 'isMasterLooter' is true, then we pass on loot.
--- If 'isMasterLooter' is also true, then we roll on loot.
local status = {
[000000001] = "mldb",
[000000010] = "mldb.autoGroupLoot",
[000000100] = "handleLoot",
[000001000] = "masterLooter",
[000010000] = "isMasterLooter",
[000100000] = "numGroupMembers",
[001000000] = "autoGroupLootGuildGroupOnly",
[010000000] = "guildGroup",
[100000000] = "enabled",
}

local statusInverted = tInvert(status)

---@class StatusInt : integer

--- Generates the status for the current GroupLoot setting.
---@return StatusInt #The integer representation of the binary status value.
function GroupLoot:GetStatus()
local result = (addon.mldb and next(addon.mldb) and 1 or 0)
result = result + bit.lshift((addon.mldb and addon.mldb.autoGroupLoot and 1 or 0), 1)
result = result + bit.lshift((addon.handleLoot and 1 or 0), 2)
result = result + bit.lshift((addon:HasValidMasterLooter() and 1 or 0), 3)
result = result + bit.lshift((addon.isMasterLooter and 1 or 0), 4)
result = result + bit.lshift((GetNumGroupMembers() > 1 and 1 or 0), 5)
result = result + bit.lshift((addon.db.profile.autoGroupLootGuildGroupOnly and 1 or 0), 6)
result = result +
bit.lshift(((not addon.db.profile.autoGroupLootGuildGroupOnly or addon.isInGuildGroup) and 1 or 0), 7)
result = result + bit.lshift((addon.enabled and 1 or 0), 8)
return result
end

---Generates the binary version of [GroupLoot:GetStatus()](lua://Utils.GroupLoot.GetStatus)
---@return string #The binary representation of the status.
function GroupLoot:GetStatusBinary()
return addon.Utils:Int2Bin(self:GetStatus())
end

---@return enum Status The status table as-is.
function GroupLoot:GetStatusTable() return status end

---@return table<string, integer> StatusInverted The inverted status table as-is.
function GroupLoot:GetInvertedStatusTable() return statusInverted end


--- Calculates the status with one or more fields set.
--- Invalid fields will be ignored.
---@param ...Status The fields to set. Must be a valid value in [Status](lua://Status).
---@return StatusInt #The integer representation of the binary status value.
function GroupLoot:CalculateStatus(...)
local result = 0
for i = 1, select("#", ...) do
local s = select(i, ...)
if statusInverted[s] then
result = result + statusInverted[s]
end
end
return tonumber(result, 2) --[[@as StatusInt]]
end

function GroupLoot:OnLootHistoryRollChanged(event, itemId, playerId)
Expand Down
15 changes: 15 additions & 0 deletions Utils/Utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,21 @@ function Utils:GetTableDifference(base, t)
return ret
end

--- Converts an integer into a binary string
---@param n integer Number to convert
function Utils:Int2Bin(n)
local result = ""
while n ~= 0 and n do
if n % 2 == 0 then
result = "0" .. result
else
result = "1" .. result
end
n = math.floor(n / 2)
end
return string.format("%04s", result)
end

---@deprecated
---@see Utils.Item.GetTransmittableItemString
function Utils:GetTransmittableItemString(link)
Expand Down
Loading

0 comments on commit 430d712

Please sign in to comment.