Which I want to keep in that order. Add the following:
local function sortDeadByLevelAndClassAndPriority(a, b, c)
if a.level == b.level then
return (b.level < a.level) and c.priority-- highest to lowest level. think "b < a" is the same as "80 comes before 79". if equal levels, then doesn't matter
else
return (b.level < a.level) and c.priority
end
end
table.sort(self.Dead, sortDeadByLevelAndClassAndPriority)
Where self.Dead is a table containing the class and level of every dead person in the party or raid. What I want to do is keep all the level 80s together, followed by 79s, etc. So the finished, sorted self.Dead might look like the following psuedocode:
self.Dead = {
Priest, 80,
Paladin, 80,
Priest, 79,
Druid, 63,
Shaman, 60, -- because the Shaman is lower level than the Druid
Mage, 80,
Warrior, 80,
}
Maybe it's what Tekkub was pointing out, but since you have "if a.level == b.level" then having "if a.level > b.level" afterwards is pointless, since you already know they are equal.
i'm a little confused by your desired result list. are the mage and warrior not supposed to be there? or they supposed to be lower level than the shammy?
what you seem to be wanting is sort by level, if level is equal, sort by class.
pretty easy, really:
if a.level == b.level then
return a.priority < b.priority
else
return a.level > b.level
end
the sort function only takes 2 args. you might need to reverse the order (change >'s to <'s) -- i can never remember if it's true if a comes before b or true if b comes before a...
i'm a little confused by your desired result list. are the mage and warrior not supposed to be there? or they supposed to be lower level than the shammy?
I'm assuming the list's purpose is to show who to res first, and so he'd want to res other people that can res, as well.
I'm assuming the list's purpose is to show who to res first, and so he'd want to res other people that can res, as well.
that makes sense. then he needs to remove those classes that can't rez from his priority list.
then the sort function would be something like:
if a.priority and b.priority then
if a.level == b.level then
return a.priority < b.priority
else
return a.level > b.level
end
else
if a.priority then
return true
else
return false
end
end
i think that's the basic logic.
if a player is a priority target, then select them.
if they're both priority, then select the one that is higher level.
if they're the same level, then select the one that has higher priority.
I'm assuming the list's purpose is to show who to res first, and so he'd want to res other people that can res, as well.
Yes, exactly. The idea here is to res people who can res first, and I have both class and level as priorities because Blizzard made some classes better ressers than others, and obviously a higher level resser will be better than a lower level resser.
The reason the non-ressers were in my priority table was because at the end of the function, a character was returned to a button as the person you are ressing. The player does want to res everybody, just in a specific order, even Hunters. :p
@ArrowMaster: I was guessing that, but just wanted to confirm.
@lilsparky: If I remove the non-ressers, how would I eventually get to them after ressing the ressers?
@Slakah: The third arg was the whole question I am asking, and as Arrow said, I can't do what I want in the way I was thinking.
So, I am still at a loss. Is there a way I can organized self.Dead and return characters in the order I am looking for? Would it help if I posted my whole logic for you guys to analyze and point me in the correct direction?
... Or, worst case scenario, just return a random character like the original SmartRes (blah!)? I really don't want math.random to select a character.
local CLASS_PRIORITY = {
-- Higher is better
PRIEST = 100,
DRUID = 100,
-- complete with every other classes
}
local dead = {
-- sample data:
"Bob",
"Foo",
"Bar",
}
local deadLevel = {
-- sample data:
["Bob"] = 80,
["Foo"] = 80,
["Bar"] = 71,
}
local deadClass = {
-- sample data:
["Bob"] = "PRIEST",
["Foo"] = "HUNTER",
["Bar"] = "DRUID",
}
local function sortDeads(a,b)
if CLASS_PRIORITY[deadClass[a]] == CLASS_PRIORITY[deadClass[b]] then
if deadLevel[a] == deadLevel[b] then
return a < b -- arbitrary order
else
return deadLevel[a] > deadLevel[b]
end
else
return CLASS_PRIORITY[deadClass[a]] > CLASS_PRIORITY[deadClass[b]]
end
end
table.sort(dead, sortDeads)
Frankly I'd approach this in reverse. When you need to render your frames, make a table of who is dead. Iter over the list, find the top person, render the frame, remove the person. Repeat. I wouldn't even bother building all these tables and logics for how to sort, I'd just keep one simple table of names and one little function that pulls the "best" name out of the table.
Still hacking away at this. I've gone over the above answers, and there is a lot of good advice to digest. Somehow, my brain feels smaller. Anyway, I thought I'd post some code snippets that might make more sense.
First, is a res button. The Player presses this bound key and SmartRes2 picks a target based on the priority discussed above.
Then here is the whole function that I'm having issues with. Please note, this has none of the fixes posted above. I wasn't certain which suggestion would work best, and Tekkub's answer left me wondering how to do it as simply as he suggests.
and Tekkub's answer left me wondering how to do it as simply as he suggests.
He was suggesting that, because you only want the best candidate to rez, then you do not need to sort every candidate, only to keep record of the best candidate.
local CLASS_PRIORITIES = {
PRIEST = 1,
PALADIN = 2,
SHAMAN = 3,
DRUID = 4,
MAGE = 5,
WARLOCK = 6,
HUNTER = 7,
DEATHKNIGHT = 8,
ROGUE = 9,
WARRIOR = 10,
}
local function getClassOrder(unit)
local _, c = UnitClass(unit)
return CLASS_PRIORITIES[c]
end
local function compareUnit(unitId, bestUnitId)
-- bestUnitId is our best candidate yet (maybe nil if none was found yet).
-- unitId is the next candidate.
-- we return the best of the two.
if not UnitIsDead(unitId) then return bestUnitId end
if IsUnitBeingRessed(unitId) then return bestUnitId end
if UnitIsGhost(unitId) then return bestUnitId end
-- here we have a valid candidate, so check first if we already saw one to compare to.
if not bestUnitId then return unitId end
-- we have two candidates. Only change candidate if it's better than the previous one.
if getClassOrder(unitId) < getClassOrder(bestUnitId) then return unitId end
if UnitLevel(unitId) > UnitLevel(bestUnitId) then return unitId end
return bestUnitId
end
local function getBestCandidate()
local best = nil
for i = 1, GetNumRaidMembers() do
best = compareUnit("raid"..i, best)
end
if not best then
for i = 1, GetNumPartyMembers() do
best = compareUnit("party"..i, best)
end
end
return best
end
Why wouldn't it be better to have a table that you sort once than to iterate over all the dead people every rez?
Because they may be other people rezing, ghosts entering the instance, dying in the lava pool that's on the left (I TOLD THEM not to go there :-( ) You pretty much have to rescan everybody anytime you need to select which one to rez.
Because they may be other people rezing, ghosts entering the instance, dying in the lava pool that's on the left (I TOLD THEM not to go there :-( ) You pretty much have to rescan everybody anytime you need to select which one to rez.
Yes. Shortcut to Molten Core entrance... *shiver*
Hey Jerry, I'm going to use your code, since it makes sense and solves many problems in a very clean fashion.
Just two questions, just so I understand. I'll need to account for UnitInRange() and UnitIsVisable() and based on what I gather of your code, the best place to check for those would be in your compareUnit() function, correct? Looks like they would fit in right after the UnitIsGhost() checks.
I'll need to account for UnitInRange() and UnitIsVisable() and based on what I gather of your code, the best place to check for those would be in your compareUnit() function, correct?
UnitInRange() is a good check, but UnitIsVisible() isn't. It doesn't do what you think it does (LoS check), it simply check whether the Unit is in your Area of Interest (roughly the part of the game world you're in).
The second question would be where would I put the
self:Print(L["All dead units are being ressed."])
and
self:Print(L["Everybody is alive. Congratulations!"])
messages? I tried to think them through, but nothing seemed quite right.
Look at the followup pastey, http://pastey.net/120852, which gives you a solution. One thing to remember is that compareUnit() will be called a lot of time, but you only want the information message to be printed once. So you need to keep track of the state of the raid, as you are scanning. I'm using a triplet of boolean flags for this, but other solutions are possible.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
Which I want to keep in that order. Add the following:
Where self.Dead is a table containing the class and level of every dead person in the party or raid. What I want to do is keep all the level 80s together, followed by 79s, etc. So the finished, sorted self.Dead might look like the following psuedocode:
Am I on the correct track?
return (b.level < a.level) and ... <--- ALWAYS FALSE!
Ouch, ok, but that still hurts my head. Should I do one or more of the following?
what you seem to be wanting is sort by level, if level is equal, sort by class.
pretty easy, really:
the sort function only takes 2 args. you might need to reverse the order (change >'s to <'s) -- i can never remember if it's true if a comes before b or true if b comes before a...
the priority values would be assigned like this:
Heres some reading for table.sort
http://www.lua.org/pil/19.3.html
http://lua-users.org/wiki/TableLibraryTutorial
http://www.wellho.net/mouth/1697_Sorting-in-lua-specifying-your-own-sort-routine.html
Because I'm seriously confused about what your trying to do.
I'm assuming the list's purpose is to show who to res first, and so he'd want to res other people that can res, as well.
that makes sense. then he needs to remove those classes that can't rez from his priority list.
then the sort function would be something like:
i think that's the basic logic.
if a player is a priority target, then select them.
if they're both priority, then select the one that is higher level.
if they're the same level, then select the one that has higher priority.
No. Redo your entire table structure because its impossible to do what you are trying to do with a single array.
Yes, exactly. The idea here is to res people who can res first, and I have both class and level as priorities because Blizzard made some classes better ressers than others, and obviously a higher level resser will be better than a lower level resser.
The reason the non-ressers were in my priority table was because at the end of the function, a character was returned to a button as the person you are ressing. The player does want to res everybody, just in a specific order, even Hunters. :p
@ArrowMaster: I was guessing that, but just wanted to confirm.
@lilsparky: If I remove the non-ressers, how would I eventually get to them after ressing the ressers?
@Slakah: The third arg was the whole question I am asking, and as Arrow said, I can't do what I want in the way I was thinking.
So, I am still at a loss. Is there a way I can organized self.Dead and return characters in the order I am looking for? Would it help if I posted my whole logic for you guys to analyze and point me in the correct direction?
... Or, worst case scenario, just return a random character like the original SmartRes (blah!)? I really don't want math.random to select a character.
First, is a res button. The Player presses this bound key and SmartRes2 picks a target based on the priority discussed above.
http://pastey.net/120785
http://pastey.net/120786
Then here is the whole function that I'm having issues with. Please note, this has none of the fixes posted above. I wasn't certain which suggestion would work best, and Tekkub's answer left me wondering how to do it as simply as he suggests.
http://pastey.net/120783
I kind of feel like a child just learning to walk. But I suppose everybody has to start somewhere, eh?
He was suggesting that, because you only want the best candidate to rez, then you do not need to sort every candidate, only to keep record of the best candidate.
Because they may be other people rezing, ghosts entering the instance, dying in the lava pool that's on the left (I TOLD THEM not to go there :-( ) You pretty much have to rescan everybody anytime you need to select which one to rez.
Yes. Shortcut to Molten Core entrance... *shiver*
Hey Jerry, I'm going to use your code, since it makes sense and solves many problems in a very clean fashion.
Just two questions, just so I understand. I'll need to account for UnitInRange() and UnitIsVisable() and based on what I gather of your code, the best place to check for those would be in your compareUnit() function, correct? Looks like they would fit in right after the UnitIsGhost() checks.
Something like http://pastey.net/120844 I would wager.
The second question would be where would I put the and messages? I tried to think them through, but nothing seemed quite right.
UnitInRange() is a good check, but UnitIsVisible() isn't. It doesn't do what you think it does (LoS check), it simply check whether the Unit is in your Area of Interest (roughly the part of the game world you're in).
Look at the followup pastey, http://pastey.net/120852, which gives you a solution. One thing to remember is that compareUnit() will be called a lot of time, but you only want the information message to be printed once. So you need to keep track of the state of the raid, as you are scanning. I'm using a triplet of boolean flags for this, but other solutions are possible.