Help with PLAYER_LOGIN, PLAYER_ALIVE, & other

UI and Macro
I'm developing an addon for twinks that will help make sure they don't accidentally enter a dungeon or LFD group while their XP is currently on.

This is the code I am currently using. If it's hard to read here you can read it at http://pastebin.com/3BQEMUcQ.

-- XP Checks and Safety
f:HookScript("OnEvent", function(self, event)
if (event == "PLAYER_LOGIN" and not isBG() and not isLFG() and not IsXPUserDisabled() ) then
RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Warning: Your XP is ON!", ChatTypeInfo["RAID_WARNING"])
end
if (event == "PLAYER_ALIVE" and isBG()) then
if ( IsXPUserDisabled() ) then
RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Your XP is off! Have fun!", ChatTypeInfo["RAID_WARNING"])
else
DEFAULT_CHAT_FRAME.editBox:SetText("/script LeaveBattlefield();")
ChatEdit_SendText(DEFAULT_CHAT_FRAME.editBox,0)
--LeaveBattlefield();
end
end
if (event == "PLAYER_ALIVE" and isLFG()) then
if ( IsXPUserDisabled() ) then
RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Your XP is off! Have fun!", ChatTypeInfo["RAID_WARNING"])
else
RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Your XP is ON! You have been teleported out of the dungeon.", ChatTypeInfo["RAID_WARNING"])
DEFAULT_CHAT_FRAME.editBox:SetText("/script LFGTeleport(1);")
ChatEdit_SendText(DEFAULT_CHAT_FRAME.editBox,0)
--LFGTeleport(1);
end
end
if ( event == "PLAYER_ALIVE" and isDeserter() and not IsXPUserDisabled() ) then
RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\You were recently booted from the Battleground because your XP was still on.", ChatTypeInfo["RAID_WARNING"])
end
end)


Here's the trouble I'm having with this code:
  • PLAYER_ALIVE seems to be unreliable. It appears to trigger only upon the first time I enter an instance via LFD per session. It also doesn't seem to trigger the battleground portion of the addon at all, as there is no raid warning whatsoever. If I take out that conditional and leave isLFG() or isBG() it works fine.
  • PLAYER_LOGIN doesn't seem to be working at all, as that raid warning is never triggered.
  • PLAYER_ENTERING_WORLD seems to work, but will not trigger porting out of a dungeon or a battleground. The raid warning will pop up, however. I have also tried uncommenting the 2 direct functions for it but have had no luck with them either. Does it have something to do with lag or the order the UI is loaded?
  • LeaveBattlefield() and LFGTeleport(1) seem to barely work for me at all. It's hit and miss. Do I need to add a delay?
  • One other snippet I am having trouble with is returning whether or not I am queued for any BG. I just want to return 1 if I'm in a queue, or ready to Enter Battle (I guess inside too but that's not necessary for my purposes). I am using the following code but it isn't working at all:

    -- Are we queued for a Battlground?
    local function isQueued()
    for i=1, GetMaxBattlefieldID() do
    queued, __, __ = GetBattlefieldStatus(i);
    if ( queued == "queued" or "confirm" ) then
    return 1;
    end
    end
    end


    I'm fairly new to LUA as a whole and addon coding, so any help would be very much appreciated.
    Queued for LFR at the moment so I'm looking through this one as as I can. One thing I see immediately in your bottom code snippet:

    if ( queued == "queued" or "confirm" )

    needs to be more explicitly evaluated:

    if (queued == "queued" or queued == "confirm" )

    Right now it's evaluating the statement "if BOOLEAN or STRING" and since strings evaluate to true in Lua, it's always going to return true. Since you didn't explain what you meant by "not working at all" then this could be what you mean, but you weren't specific how it wasn't working :)

    Another small question: What frame "f" are you hooking your OnEvent script to?
    That doesn't seem to be working either. No change in functionality (or lackthereof ><)

    As for the f frame:


    local f = CreateFrame("Frame");
    That doesn't seem to be working either. No change in functionality (or lackthereof ><)
    Well, what is it doing, if anything? You don't have any returns to see so that might be a good place to start debugging. Throw a print(i) function instead of your return so that you can at least see what values of i make it through your logic.

    As far as your f:HookScript(), I don't think it's going to make a difference for your code but you probably want to use SetScript() instead. HookScript() is designed to make sure a piece of code runs after a frame's existing SetScript() method; you just want your code to run when your event fires, which means you want SetScript(). Again, I don't think it'd make a difference here, but for future reference.

    Last thing of note: you're trying to activate teleport functions based on events with the player loading into zones. From experience, those events fire much sooner than the UI is fully loaded (and can therefore process the teleport call). You may also run into a situation where some of the data you're checking for (are you in a BG? are you in an instance?) may not be available at those events, and may only be available after the UI loads.

    You're probably better off using those events to trigger a call to show a frame -- a frame whose OnUpdate call is to execute the code you're after. This way the code will only fire once the UI is loaded, because OnUpdate code only happens when the frame is shown. (After the code is finished, you have the frame hide itself so it behaves as a toggle.)
    I've been using print in another section of my code to check if it's firing the return or not. It hasn't been.

    As far as the latter part of your post:

    I thought that was the problem. I'm pretty new to LUA coding so I wouldn't have the slightest idea how to go about doing that. Is there a way to check if the UI is fully loaded? I thought PLAYER_ALIVE did that fairly well and is why I expected it to work better. Perhaps a way to call it once the BG or LFG raidframes are loaded or something?

    Again, I have no clue so any help at all would be appreciated.
    If you're confident the debug in the "other part" of your code works fine, then sure. But it's best to start at the deepest level of the code (the direct return) and test there so that you can "bubble up" to see where the problem is. The syntax looks OK assuming you've made the fix I gave you. If I get a moment to test with a queue I will.

    Incoming instructions on how to use a dummy frame to only work when things are visible...
    Looking forward to the instructions.

    Using this, it always prints Not Queued. Twice if I'm queued for 2 BGs, but once if I'm queued for one or none at all.

    local function isQueued()
    for i=1, GetMaxBattlefieldID() do
    queued, __, __ = GetBattlefieldStatus(i);
    if (queued == "queued" or queued == "confirm" ) then
    --return 1;
    print("Queued");
    else
    print("Not queued");
    end
    end
    end


    So it seems like my conditional is the problem.

    In addition, what's the best way to "escape" the loop and return 1 as soon as I get "queued"/"confirm" for a BG, to prevent it returning more than one value.

    EDIT: The last BG on my available list is AV (@ Level 50), and if I queue for it and print queued it gives me "none", instead of "queued", even though the function should stop at AV and I believe it should return "queued".
    There can only be one return. That's what "return" is - it leaves the function. So you're "escaped" as soon as you get a return.

    There's a quicker way to write that code, though. Will discuss in a bit.
    Completely forgot about the entire point of return.

    Seems I'm way out of practice.

    Still looking for some help, particularly trying to get a character ported out upon entering a LFD or BG with their XP on. ^_^
    OK looks like another pending wipe on Deathwing so!

    Shortcut for returning values based on Boolean logic:

    return (queued == "queued" or queued == "confirm")

    Note that this returns true/false instead of 1/nil like your current setup, but it's a little cleaner.

    As far as your queue issues go, once this LFR finishes...

    Finally to execute code when the UI shows:

    local function doStuffHere()
    -- Here's where your code goes that you check for status of BG / instance / etc. and teleport
    watchForUIFrame:Hide()
    end

    local watchForUIFrame = CreateFrame("Frame")
    watchForUIFrame:SetScript("OnUpdate", doStuffHere)

    local g = CreateFrame("Frame")
    g:SetScript("OnEvent", function(self, event, ...)
    watchForUiFrame:Shiow()
    end

    g:RegisterEvent(whatever events you need)


    So you register your event-handling frame for the events of P_E_W, PLAYER_ALIVE, etc. When it detects one of those events, it shows the frame "watchForUIFrame." This frame has a script, OnUpdate, which fires every time the screen redraws (i.e. it first fires when the UI is loaded). On its first execution, it does the code for checking to see if you're in a BG, instance, whatever and performs the appropriate code. Then it hides itself (otherwise it'd keep checking over and over again, since OnUpdate fires every draw).
    Is P_E_W a legitimate acronym? I've seen it used in explanations but didn't know if I could actually use it in code.

    And thanks for that code, will test and report back!

    EDIT: But if I use return (queued == "queued" or queued == "confirm"), won't it immediately escape and return false if I'm not queued for the first Battlefield ID?

    IE: I'm queued for AV, it will start by looking to check Random BG. Won't it return false there and stop?
    PLAYER_ENTERING_WORLD fired for me when entering/leaving a BG just now.

    If there's an issue of pvp/xp status not being correct when the event fires (possible), then do a one-frame delay, which is a common solution for the PLAYER_ALIVE event (which fires on initial login but not on /reloads) and stuff like talents:
    local f=CreateFrame("Frame")
    f:Hide()
    f:SetScript("OnUpdate",function(self)
    -- call your code here that you want to run after PLAYER_ENTERING_WORLD
    -- and player resumes control of their character (ie frames start running)
    self:Hide()
    end)
    f:SetScript("OnEvent",function(self)
    self:Show()
    end)
    f:RegisterEvent("PLAYER_ENTERING_WORLD")


    Many events can fire while you're zoning, even after PLAYER_ENTERING_WORLD. What this code does is create a frame with an OnUpdate. OnUpdates only run when frames are being drawn. The first frame it draws after a PLAYER_ENTERING_WORLD event (ie after all other reload/zoning/login events are done) and the client starts drawing the world again, it runs your code and immediately hides the frame to stop the OnUpdate.

    edit: Simpleton beat me to it! His method is the same. So whichever approach looks more familiar to you.
    Well I confess I'm a bit stuck here.

    I just finished the LFR, popped out and queued for 2 BGs. I ran the following code:

    /run for i = 1, GetMaxBattlefieldID() do print(GetBattlefieldStatus(i)) end

    and got the following output:

    queued The Battle for Gilneas 0 0 85 0 nil nil 1
    queued Twin Peaks 0 0 85 0 nil nil 1


    which is what I'd expect. When one popped, that entry changed to:

    confirm Twin Peaks 0 0 85 0 nil 1 nil

    which also makes sense. (The page http://wowprogramming.com/docs/api/GetBattlefieldStatus is out of date so I don't know exactly what the latter returns are for, but the first one is what we need.)
    That is odd.

    Seems I may be doing something wrong. I'll dig into my code and see if I can fix it myself.
    05/02/2012 02:35 PMPosted by Thirkfifty
    Is P_E_W a legitimate acronym? I've seen it used in explanations but didn't know if I could actually use it in code.
    No, it's just shorthand on the forums.

    EDIT: But if I use return (queued == "queued" or queued == "confirm"), won't it immediately escape and return false if I'm not queued for the first Battlefield ID?

    IE: I'm queued for AV, it will start by looking to check Random BG. Won't it return false there and stop?
    Your Battlefield IDs are not what you think they are. They're the IDs associated with BGs you're currently involved in some way in (i.e. queued for or active in). Currently your Battlefield ID can either be 1 or 2, corresponding to the first (and second, if applicable) battlefield you're queued for or participating in. So if you're not queued for AV, then there's no information about AV that will be returned by GetBattlefieldStatus().

    Edit: To be more clear, if you have a battlefield ID, you have to be queued for something or in a BG.

    05/02/2012 02:36 PMPosted by Ro
    edit: Simpleton beat me to it! His method is the same. So whichever approach looks more familiar to you.
    Ours is the same in function, if not form. Mine is a bit more verbose to give it a little more user-friendliness for someone just starting out. Ro's is more elegant, however.
    If I don't have a Battlefield ID when not queued, couldn't I just do something like this?

    if GetMaxBattlefieldID() >= 1 then

    If not, why not?

    EDIT: Woah okay, I'm confused. It seems the ID changes between 1 and 2 but queueing/leaving queue doesn't seem to always or immediately change the number. What gives? Is it something I'm doing wrong? I'm doing /reload to test this out, queueing for BGs and running /script print(GetMaxBattlefieldID());
    The MaxBattlefieldID is a constant. It's in there for future proofing; i.e. if Blizzard ever decides to change things so you can queue for three battlegrounds, then instead of going through and changing all their relevant 2s to 3s, they can just change GetMaxBattlefieldID() to return 3.

    Edit: You don't have a BattlefieldID when not queued. That's not the same as whatever the MaxBattlefieldID is :)
    I didn't get a chance to fully tweak and test the code, but now that I have it seems I can't get it to work at all.

    The following code does absolutely nothing and shows no LUA errors. :/

    local g = CreateFrame("Frame");
    g:RegisterEvent("PLAYER_ENTERING_WORLD");

    local watchForUIFrame = CreateFrame("Frame");
    watchForUIFrame:SetScript("OnUpdate", doStuffHere);

    g:SetScript("OnEvent", function(self, event, ...)
    watchForUIFrame:Show()
    end)

    -- Are we doing a Battleground?
    local function isBG()
    return select(2,IsInInstance()) == "pvp"
    end

    -- Are we doing a Dungeon?
    local function isLFG()
    return select(2,IsInInstance()) == "party"
    end

    -- Do we have deserter?
    local function isDeserter()
    local name, _, _, _, _, _, _, _ = UnitDebuff("player", "Deserter")
    if name == "Deserter" then
    return 1;
    end
    end

    -- Simpleton Frame Test
    local function doStuffHere()
    print("Works");
    RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Addon loaded!", ChatTypeInfo["RAID_WARNING"])
    if (event == "PLAYER_ENTERING_WORLD" and not isBG() and not isLFG() and not IsXPUserDisabled() ) then
    RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Warning: Your XP is ON!", ChatTypeInfo["RAID_WARNING"])
    end
    if (event == "PLAYER_ALIVE" and isBG()) then
    if ( IsXPUserDisabled() ) then
    RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Your XP is off! Have fun!", ChatTypeInfo["RAID_WARNING"])
    else
    DEFAULT_CHAT_FRAME.editBox:SetText("/script LeaveBattlefield();")
    ChatEdit_SendText(DEFAULT_CHAT_FRAME.editBox,0)
    --LeaveBattlefield();
    end
    end
    if (event == "PLAYER_ENTERING_WORLD" and isLFG()) then
    if ( IsXPUserDisabled() ) then
    RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Your XP is off! Have fun!", ChatTypeInfo["RAID_WARNING"])
    else
    RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\Your XP is ON! You have been teleported out of the dungeon.", ChatTypeInfo["RAID_WARNING"])
    DEFAULT_CHAT_FRAME.editBox:SetText("/script LFGTeleport(1);")
    ChatEdit_SendText(DEFAULT_CHAT_FRAME.editBox,0)
    --LFGTeleport(1);
    end
    end
    if ( event == "PLAYER_ALIVE" and isDeserter() and not IsXPUserDisabled() ) then
    RaidNotice_AddMessage(RaidBossEmoteFrame, "\124cFFF000FF\You were recently booted from the Battleground because your XP was still on.", ChatTypeInfo["RAID_WARNING"])
    end
    watchForUIFrame:Hide()
    end


    Pastebin for better readability - http://pastebin.com/XjMr77ZF
    watchForUIFrame:SetScript("OnUpdate", doStuffHere);
    ...
    -- Simpleton Frame Test
    local function doStuffHere()

    doStuffHere is nil when you SetScript. When it gets around to defining doStuffHere it won't go back and re-SetScript.
    Oops! Thought that was the issue. Was actually just testing out your code Ro, and it's more compact so if it works I should be set. Thanks for the quick response!

    Join the Conversation

    Return to Forum