• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[TFS 1.2] Modal Window Helper Lib

Non Sequitur

Well-Known Member
Joined
Dec 1, 2015
Messages
84
Best answers
0
Reaction score
76
Location
Brazil
Reasoning
The current way we can implement modal windows is quite cumbersome in my opinion, having to create it somewhere, register an event, add buttons in some weird order to make it work and having to take account of window ids, button ids, choice ids in a complete different file than the one you've created the modal window. That is not optimal so I've created this helper library to help with that.

What you can do with it
Lua:
-- The helper lib is used by passing a table value to the ModalWindow function
local window = ModalWindow {
    title = 'Title',
    message = 'Please, choose the lowest number and press [Ok]'
}

local lowestChoice
for i = 1, 5 do
    local value = math.random(1, 100)
    -- modalWindow:addChoice() returns the choice object that will be passed to the callbacks
    local choice = window:addChoice(value)
    -- This way we can pass extra information to the callback
    choice.value = value
    if not lowestChoice or lowestChoice.value > value then
        lowestChoice = choice
    end
end

lowestChoice.correct = true

-- Add a button with a specific callback
window:addButton('Ok',
    function(button, choice)
        if choice.correct then
            print('Player selected the correct option.')
        else
            print('Player selected the incorrect option.')
        end
    end
)
-- Set this button as the default enter button
window:setDefaultEnterButton('Ok')

-- Add a button without a specific callback
window:addButton('Close')
window:setDefaultEscapeButton('Close')

-- If a button without a specific callback is pressed, this fucntion will be called
window:setDefaultCallback(
    function(button, choice)
        print('Default callback, button pressed: ' .. button.text .. ' player choice: ' .. choice.text)
    end
)

window:sendToPlayer(player)
You can use this example in a talkaction and test it for yourself (check the output on your server console). Other than what is shown in the above code, you can also use modalWindow:addButtons(...) and modalWindow:addChoices(...) to add multiple buttons/choices at once.

Installing

  • In data/lib/lib.lua
    Lua:
    dofile('data/lib/modalwindow.lua')
  • Create the file data/lib/modalwindow.lua
    Lua:
    if not modalWindows then
        modalWindows = {
            modalWindowConstructor = ModalWindow,
            nextFreeId = 500,
    
            windows = {}
        }
    end
    
    local MT = {}
    MT.__index = MT
    
    function ModalWindow(...)
        local args = {...}
        if type(args[1]) == 'table' then
            local self = setmetatable(args[1], MT)
            local id = modalWindows.nextFreeId        
            self.id = id
            self.buttons = {}
            self.choices = {}
            self.players = {}
            self.created = false
    
            modalWindows.nextFreeId = id + 1
            table.insert(modalWindows.windows, self)
            return self
        end
    
        return modalWindows.modalWindowConstructor(...)
    end
    
    function MT:setDefaultCallback(callback)
        self.defaultCallback = callback
    end
    
    function MT:addButton(text, callback)
        local button = {text = tostring(text), callback = callback}
        table.insert(self.buttons, button)
        return button
    end
    
    function MT:addButtons(...)
        for _, text in ipairs({...}) do
            table.insert(self.buttons, {text = tostring(text)})
        end
    end
    
    function MT:addChoice(text)
        local choice = {text = tostring(text)}
        table.insert(self.choices, choice)
        return choice
    end
    
    function MT:addChoices(...)
        for _, text in ipairs({...}) do
            table.insert(self.choices, {text = tostring(text)})
        end
    end
    
    function MT:setDefaultEnterButton(text)
        self.defaultEnterButton = text
    end
    
    function MT:setDefaultEscapeButton(text)
        self.defaultEscapeButton = text
    end
    
    function MT:setTitle(title)
        self.title = tostring(title)
    end
    
    function MT:setMessage(message)
        self.message = tostring(message)
    end
    
    local buttonOrder = {
        [4] = {3, 4, 2, 1},
        [3] = {2, 3, 1},
        [2] = {1, 2},
        [1] = {1}
    }
    function MT:create()
        local modalWindow = modalWindows.modalWindowConstructor(self.id, self.title, self.message)
        local order = buttonOrder[math.min(#self.buttons, 4)]
    
        if order then
            for _, i in ipairs(order) do
                local button = self.buttons[i]
                modalWindow:addButton(i, button.text)
                button.id = i
    
                if button.text == self.defaultEnterButton then
                    modalWindow:setDefaultEnterButton(i)
                elseif button.text == self.defaultEscapeButton then
                    modalWindow:setDefaultEscapeButton(i)
                end
            end
        end
    
        for _, choice in ipairs(self.choices) do
            modalWindow:addChoice(_, choice.text)
            choice.id = _
        end
    
        self.modalWindow = modalWindow
    end
    
    function MT:sendToPlayer(player)
        if not self.modalWindow then
            self:create()
        end
    
        player:registerEvent('ModalWindowHelper')
        self.players[player:getId()] = true
        return self.modalWindow:sendToPlayer(player)
    end
  • In data/creaturescripts/creaturescripts.xml
    XML:
    <event type="modalwindow" name="ModalWindowHelper" script="modalwindowhelper.lua" />
  • Create the file data/creaturescripts/scripts/modalwindowhelper.lua
    Lua:
    function onModalWindow(player, modalWindowId, buttonId, choiceId)
    	local modalWindow 
    	for _, window in ipairs(modalWindows.windows) do
    		if window.id == modalWindowId then
    			modalWindow = window
    			break
    		end
    	end
    
    	if not modalWindow then
    		return true
    	end
    
    	local playerId = player:getId()
    	if not modalWindow.players[playerId] then
    		return true
    	end
    	modalWindow.players[playerId] = nil
    
    	local choice = modalWindow.choices[choiceId]
    
    	for _, button in ipairs(modalWindow.buttons) do
    		if button.id == buttonId then
    			local callback = button.callback or modalWindow.defaultCallback
    			if callback then
    				callback(button, choice)
    				break
    			end
    		end
    	end
    
    	return true
    end
The end

That's it. Later today I will post a !rank talkaction I've made using this library.

EDIT: Here it is.
 
Last edited by a moderator:

zbizu

Legendary OT User
Joined
Nov 22, 2010
Messages
2,629
Best answers
3
Reaction score
1,572
Location
Poland
so... what is the point of that verification?
 

zbizu

Legendary OT User
Joined
Nov 22, 2010
Messages
2,629
Best answers
3
Reaction score
1,572
Location
Poland
print('Player selected the correct option.')
else
print('Player selected the incorrect option.')
 
OP
Non Sequitur

Non Sequitur

Well-Known Member
Joined
Dec 1, 2015
Messages
84
Best answers
0
Reaction score
76
Location
Brazil
That is just a sample code, and it's on the button callback, so the player may choose the wrong option and choice.correct will be nil, not true.
 

strutZ

Australian OT Member {AKA Beastn}
Joined
Nov 16, 2014
Messages
1,347
Best answers
6
Reaction score
484
This is great now that i know how to use it lol question though how does one use
Code:
getChoiceCount()
Is there another way to use it?

EDIT:
Ran into another issue.. Converting my addon doll script, I am hiding already unlocked outfits/addons from the choices my command
Code:
self:addOutfitAddon(outfits[choice.id].male, 3)
is wrong because choice ID 1 will always being citizen... so when i unlock that and it hides the top addon changes to choice ID one so BAM! i get citizen again >.<
 
Last edited:

Colors

Joined
Mar 22, 2013
Messages
935
Best answers
3
Reaction score
251
If I create a ModalWindow, but I don't use it for x reason, do I need to destroy the object to avoid memory leaks? Or it doesn't matter?
 

adahum

New Member
Joined
Feb 28, 2015
Messages
13
Best answers
0
Reaction score
0
Reasoning
The current way we can implement modal windows is quite cumbersome in my opinion, having to create it somewhere, register an event, add buttons in some weird order to make it work and having to take account of window ids, button ids, choice ids in a complete different file than the one you've created the modal window. That is not optimal so I've created this helper library to help with that.

What you can do with it
Code:
-- The helper lib is used by passing a table value to the ModalWindow function
local window = ModalWindow {
    title = 'Title',
    message = 'Please, choose the lowest number and press [Ok]'
}

local lowestChoice
for i = 1, 5 do
    local value = math.random(1, 100)
    -- modalWindow:addChoice() returns the choice object that will be passed to the callbacks
    local choice = window:addChoice(value)
    -- This way we can pass extra information to the callback
    choice.value = value
    if not lowestChoice or lowestChoice.value > value then
        lowestChoice = choice
    end
end

lowestChoice.correct = true

-- Add a button with a specific callback
window:addButton('Ok',
    function(button, choice)
        if choice.correct then
            print('Player selected the correct option.')
        else
            print('Player selected the incorrect option.')
        end
    end
)
-- Set this button as the default enter button
window:setDefaultEnterButton('Ok')

-- Add a button without a specific callback
window:addButton('Close')
window:setDefaultEscapeButton('Close')

-- If a button without a specific callback is pressed, this fucntion will be called
window:setDefaultCallback(
    function(button, choice)
        print('Default callback, button pressed: ' .. button.text .. ' player choice: ' .. choice.text)
    end
)

window:sendToPlayer(player)
You can use this example in a talkaction and test it for yourself (check the output on your server console). Other than what is shown in the above code, you can also use modalWindow:addButtons(...) and modalWindow:addChoices(...) to add multiple buttons/choices at once.

Installing

  • In data/lib/lib.lua
    Code:
    dofile('data/lib/modalwindow.lua')
The end

That's it. Later today I will post a !rank talkaction I've made using this library.

EDIT: Here it is.


i did exactly what u say to do but for some reason, appears it when i start my server:

[9:57:14.242] data/lib/modalwindow.lua:83: attempt to call field 'modalWindowConstructor' (a nil value)
[9:57:14.242] [Warning - Event::loadScript] Cannot load script (data/talkactions/scripts/bests.lua)

[9:57:14.285] [Error - CreatureEvent::configureEvent] No valid type for creature event.modalwindow
[9:57:14.285] [Warning - BaseEvents::loadFromXml] Cannot configure an event




i dont know how fix it. my server is 8.60
 

Infernum

Asshole
Support Team
Joined
Feb 14, 2015
Messages
5,384
Best answers
531
Reaction score
3,156
i did exactly what u say to do but for some reason, appears it when i start my server:

[9:57:14.242] data/lib/modalwindow.lua:83: attempt to call field 'modalWindowConstructor' (a nil value)
[9:57:14.242] [Warning - Event::loadScript] Cannot load script (data/talkactions/scripts/bests.lua)

[9:57:14.285] [Error - CreatureEvent::configureEvent] No valid type for creature event.modalwindow
[9:57:14.285] [Warning - BaseEvents::loadFromXml] Cannot configure an event




i dont know how fix it. my server is 8.60
you can't use modalwindows for 8.6, they were implemented in 9.6+
 

Infernum

Asshole
Support Team
Joined
Feb 14, 2015
Messages
5,384
Best answers
531
Reaction score
3,156
there's no one version to 8.60?nothing? :( thats so bad.
that's what i just said

you could use otclient but i have no idea how to implement modalwindows for it
would probably just be easier to move to a higher client version
 

Dbzl

New Member
Joined
Jan 22, 2017
Messages
34
Best answers
0
Reaction score
1
Can anyone help me with a problem using this lib?
I will post the code below, but firstly, let me explain the problem:
I'm creating a couple windows that are called from the main window.
A few of these created windows, got own player's information.
When a first player trigger this code, it runs with no problem. But when a second player tries to run, somehow the one that receives the window is the first player.
It seems weird, right?
Literally it's what happens.
>first player uses the windows with no problems
>first player closes every window and stay still
>second player tries to open the main window
>don't work on second player
>check first player
>the window was open there

And not if it was the only problem, if you manage to log off from first player, when the second player tries to open the main window, the informations there are doubled.
Anyway, you can always check this ingame to make things clear with the code below.
By the way, I've only experienced this thing with Action codes. I've created a couple talkActions and never had any problem like that.

If anyone knows how to fix this, pleaase, let me know!

Code:
local window = 0
local window2v2 = 0
local window2v2_info = 0
local window3v3 = 0
local window3v3_info = 0

function createWindows(player)
    window = ModalWindow {
       title = "Arena Window",
       message = "Please choose the PVP mode below:"
    }

    window2v2 = ModalWindow {
       title = "2v2 Window",
       message = "Please choose a 2v2 option below:"
    }

    window3v3 = ModalWindow {
       title = "3v3 Window",
       message = "Please choose a 3v3 option below:"
    }

    window2v2_info = ModalWindow {
       title = "2v2 Player Info",
       message = ""
    }

    window3v3_info = ModalWindow {
       title = "3v3 Player Info",
       message = ""
    }

    window:addChoice("2v2")
    window:addChoice("3v3")

    window2v2:addChoice("Join 2v2 Queue")
    window2v2:addChoice("Player Info")

    window3v3:addChoice("Join 3v3 Queue")
    window3v3:addChoice("Player Info")

    window2v2_info.title = player:getName().. "'s info"
    window2v2_info:addChoice("Total Games: 0")
    window2v2_info:addChoice("Win Rate: 0%")
    window2v2_info:addChoice("Elo Points: 0")
    window2v2_info:addChoice("Total Medals: 0")

    window3v3_info.title = player:getName().. "'s info"
    window3v3_info:addChoice("Total Games: 0")
    window3v3_info:addChoice("Win Rate: 0%")
    window3v3_info:addChoice("Elo Points: 0")
    window3v3_info:addChoice("Total Medals: 0")

    -- Main Window
    window:addButton("Select",
       function(button, choice)
            if choice.text == "2v2" then
                window2v2:sendToPlayer(player)
            elseif choice.text == "3v3" then
                window3v3:sendToPlayer(player)
           end
       end
    )
    window:setDefaultEnterButton("Select")
    window:addButton('Close')
    window:setDefaultEscapeButton('Close')

    -- 2v2 Window
    window2v2:addButton("Select",
       function(button, choice)
            if choice.text == "Join Queue" then
            elseif choice.text == "Player Info" then
                window2v2_info:sendToPlayer(player)
           end
       end
    )
    window2v2:setDefaultEnterButton("Select")
    window2v2:addButton('Ranking')
    window2v2:addButton("Back",
       function(button, choice)
            window:sendToPlayer(player)
       end
    )
    window2v2:setDefaultEscapeButton('Back')

    -- 3v3 Window
    window3v3:addButton("Select",
       function(button, choice)
            if choice.text == "Join Queue" then
            elseif choice.text == "Player Info" then
                window3v3_info:sendToPlayer(player)
           end
       end
    )
    window3v3:setDefaultEnterButton("Select")
    window3v3:addButton("Ranking")
    window3v3:addButton("Back",
       function(button, choice)
            window:sendToPlayer(player)
       end
    )
    window3v3:setDefaultEscapeButton("Back")

    -- 2v2 Info Window
    window2v2_info:addButton("Select",
       function(button, choice)
            window2v2_info:sendToPlayer(player)
       end
    )
    window2v2_info:setDefaultEnterButton("Select")
    window2v2_info:addButton("Back",
       function(button, choice)
            window2v2:sendToPlayer(player)
       end
    )
    window2v2_info:setDefaultEscapeButton("Back")

    -- 3v3 Info Window
    window3v3_info:addButton("Select",
       function(button, choice)
            window3v3_info:sendToPlayer(player)
       end
    )
    window3v3_info:setDefaultEnterButton("Select")
    window3v3_info:addButton("Back",
       function(button, choice)
            window3v3:sendToPlayer(player)
       end
    )
    window3v3_info:setDefaultEscapeButton("Back")
    return true
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    createWindows(player)

    window:sendToPlayer(player)
    return true
end

[/CODE~

The code is totally weird, I was just trying to make it work firstly.
Don't take it serious =p
 

Dbzl

New Member
Joined
Jan 22, 2017
Messages
34
Best answers
0
Reaction score
1
I messed up pretty bad the /CODE last part. If any mod can edit my post to fix this problem, Thanks.
Also, please delete this one post after fixing the text error xD
 

Dbzl

New Member
Joined
Jan 22, 2017
Messages
34
Best answers
0
Reaction score
1
I've discovered that, if I reload actions after the first player finishes what he was doing in the window, the second player can normally open and use the window.
But it requires a reload everytime the main window is closed. (when the script finishes, in this case)

Anyone? x_x
 

Evil Hero

Legacy Member
TFS Developer
Joined
Dec 12, 2007
Messages
1,205
Best answers
20
Reaction score
576
Location
Germany
I've discovered that, if I reload actions after the first player finishes what he was doing in the window, the second player can normally open and use the window.
But it requires a reload everytime the main window is closed. (when the script finishes, in this case)

Anyone? x_x
that's easily explained, you basicly have to keep a save for every different player on modal windows, it keeps showing first player only because you do only save that one
here is a code snippet from my old ingame manager where it shows how you can do it.
Code:
if state[player:getId()] == nil then
       state[player:getId()] = 1
   end
   --######Management######--
   if modalWindowId == windows.Management then
       state[player:getId()] = 1
       if buttonId == 0x00 then
           if choiceId == managementOptions.Player[1] then -- Players
               state[player:getId()] = 1
               if Game.getPlayerCount() > 0 then
                   playerChoices = {}
                   onlinePlayers = {}
                   for k, v in pairs(getOnlinePlayers()) do
                       table.insert(onlinePlayers, v)
                   end
                   table.sort(onlinePlayers)
                   playerChoices = cacheData1(onlinePlayers, state[player:getId()])
                   createWindowWithButtons(player, players, windows.Management_Players, "Players List", "Select Player", preButtons, playerChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.NPC[1] then -- NPCs
               if Game.getNpcCount() > 0 then
                   npcChoices = {}
                   onlineNpcs = {}
                   npcButtons = {{id = 0x00, text = "Select", enter = false, escape = false}, {id = 0x01, text = "End", enter = false, escape = true}, {id = 0x02, text = "Back", enter = false, escape = false}, {id = 0x03, text = "TP", enter = true, escape = false}}
                   for k, v in pairs(getOnlineNpcs()) do
                       onlineNpcs[#onlineNpcs == nil and 1 or #onlineNpcs + 1] = {}
                       onlineNpcs[#onlineNpcs][1] = v[1]
                       onlineNpcs[#onlineNpcs][2] = v[2]
                   end
                   npcChoices = cacheData2(onlineNpcs, state[player:getId()])
                   createWindowWithButtons(player, npcs, windows.Management_NPC, "NPC List", "Select NPC", npcButtons, npcChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.Monster_Type[1] then -- Monsters
               if Game.getMonsterCount() > 0 then
                   monsterTypeChoices = {}
                   monsterType = {}
                   for k,v in pairs(monsters) do
                       table.insert(monsterType, k)
                   end
                   table.sort(monsterType)
                   monsterTypeChoices = cacheData1(monsterType, state[player:getId()])
                   createWindowWithButtons(player, monsters1, windows.Management_Monster_Type, "Monster Type List", "Select Monster Type", preButtons, monsterTypeChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.Tp_Players_To_Temple[1] then -- teleport all players to temple
               local online = getOnlinePlayers()
               local counter = 0
               for k,v in pairs(online) do
                   local tpPlayer = Player(v)
                   if tpPlayer then
                       doTeleportThing(tpPlayer, tpPlayer:getTown():getTemplePosition(), true)
                       tpPlayer:sendTextMessage(22, "You have been teleported to temple")
                       counter = counter + 1
                   end
               end
               player:sendTextMessage(22, "You have successfully teleported ".. counter .."/".. #online .." players to temple")
               createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
           end
       end
   end
Code:
state[player:getId()]
is what you should take a closer look on.
 

Dbzl

New Member
Joined
Jan 22, 2017
Messages
34
Best answers
0
Reaction score
1
that's easily explained, you basicly have to keep a save for every different player on modal windows, it keeps showing first player only because you do only save that one
here is a code snippet from my old ingame manager where it shows how you can do it.
Code:
if state[player:getId()] == nil then
       state[player:getId()] = 1
   end
   --######Management######--
   if modalWindowId == windows.Management then
       state[player:getId()] = 1
       if buttonId == 0x00 then
           if choiceId == managementOptions.Player[1] then -- Players
               state[player:getId()] = 1
               if Game.getPlayerCount() > 0 then
                   playerChoices = {}
                   onlinePlayers = {}
                   for k, v in pairs(getOnlinePlayers()) do
                       table.insert(onlinePlayers, v)
                   end
                   table.sort(onlinePlayers)
                   playerChoices = cacheData1(onlinePlayers, state[player:getId()])
                   createWindowWithButtons(player, players, windows.Management_Players, "Players List", "Select Player", preButtons, playerChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.NPC[1] then -- NPCs
               if Game.getNpcCount() > 0 then
                   npcChoices = {}
                   onlineNpcs = {}
                   npcButtons = {{id = 0x00, text = "Select", enter = false, escape = false}, {id = 0x01, text = "End", enter = false, escape = true}, {id = 0x02, text = "Back", enter = false, escape = false}, {id = 0x03, text = "TP", enter = true, escape = false}}
                   for k, v in pairs(getOnlineNpcs()) do
                       onlineNpcs[#onlineNpcs == nil and 1 or #onlineNpcs + 1] = {}
                       onlineNpcs[#onlineNpcs][1] = v[1]
                       onlineNpcs[#onlineNpcs][2] = v[2]
                   end
                   npcChoices = cacheData2(onlineNpcs, state[player:getId()])
                   createWindowWithButtons(player, npcs, windows.Management_NPC, "NPC List", "Select NPC", npcButtons, npcChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.Monster_Type[1] then -- Monsters
               if Game.getMonsterCount() > 0 then
                   monsterTypeChoices = {}
                   monsterType = {}
                   for k,v in pairs(monsters) do
                       table.insert(monsterType, k)
                   end
                   table.sort(monsterType)
                   monsterTypeChoices = cacheData1(monsterType, state[player:getId()])
                   createWindowWithButtons(player, monsters1, windows.Management_Monster_Type, "Monster Type List", "Select Monster Type", preButtons, monsterTypeChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.Tp_Players_To_Temple[1] then -- teleport all players to temple
               local online = getOnlinePlayers()
               local counter = 0
               for k,v in pairs(online) do
                   local tpPlayer = Player(v)
                   if tpPlayer then
                       doTeleportThing(tpPlayer, tpPlayer:getTown():getTemplePosition(), true)
                       tpPlayer:sendTextMessage(22, "You have been teleported to temple")
                       counter = counter + 1
                   end
               end
               player:sendTextMessage(22, "You have successfully teleported ".. counter .."/".. #online .." players to temple")
               createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
           end
       end
   end
Code:
state[player:getId()]
is what you should take a closer look on.
Thank you very much for your help. As soon as I'm able to, I will read it and try changing my code!
 

Dbzl

New Member
Joined
Jan 22, 2017
Messages
34
Best answers
0
Reaction score
1
that's easily explained, you basicly have to keep a save for every different player on modal windows, it keeps showing first player only because you do only save that one
here is a code snippet from my old ingame manager where it shows how you can do it.
Code:
if state[player:getId()] == nil then
       state[player:getId()] = 1
   end
   --######Management######--
   if modalWindowId == windows.Management then
       state[player:getId()] = 1
       if buttonId == 0x00 then
           if choiceId == managementOptions.Player[1] then -- Players
               state[player:getId()] = 1
               if Game.getPlayerCount() > 0 then
                   playerChoices = {}
                   onlinePlayers = {}
                   for k, v in pairs(getOnlinePlayers()) do
                       table.insert(onlinePlayers, v)
                   end
                   table.sort(onlinePlayers)
                   playerChoices = cacheData1(onlinePlayers, state[player:getId()])
                   createWindowWithButtons(player, players, windows.Management_Players, "Players List", "Select Player", preButtons, playerChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.NPC[1] then -- NPCs
               if Game.getNpcCount() > 0 then
                   npcChoices = {}
                   onlineNpcs = {}
                   npcButtons = {{id = 0x00, text = "Select", enter = false, escape = false}, {id = 0x01, text = "End", enter = false, escape = true}, {id = 0x02, text = "Back", enter = false, escape = false}, {id = 0x03, text = "TP", enter = true, escape = false}}
                   for k, v in pairs(getOnlineNpcs()) do
                       onlineNpcs[#onlineNpcs == nil and 1 or #onlineNpcs + 1] = {}
                       onlineNpcs[#onlineNpcs][1] = v[1]
                       onlineNpcs[#onlineNpcs][2] = v[2]
                   end
                   npcChoices = cacheData2(onlineNpcs, state[player:getId()])
                   createWindowWithButtons(player, npcs, windows.Management_NPC, "NPC List", "Select NPC", npcButtons, npcChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.Monster_Type[1] then -- Monsters
               if Game.getMonsterCount() > 0 then
                   monsterTypeChoices = {}
                   monsterType = {}
                   for k,v in pairs(monsters) do
                       table.insert(monsterType, k)
                   end
                   table.sort(monsterType)
                   monsterTypeChoices = cacheData1(monsterType, state[player:getId()])
                   createWindowWithButtons(player, monsters1, windows.Management_Monster_Type, "Monster Type List", "Select Monster Type", preButtons, monsterTypeChoices, true, false)
               else
                   createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
               end
           elseif choiceId == managementOptions.Tp_Players_To_Temple[1] then -- teleport all players to temple
               local online = getOnlinePlayers()
               local counter = 0
               for k,v in pairs(online) do
                   local tpPlayer = Player(v)
                   if tpPlayer then
                       doTeleportThing(tpPlayer, tpPlayer:getTown():getTemplePosition(), true)
                       tpPlayer:sendTextMessage(22, "You have been teleported to temple")
                       counter = counter + 1
                   end
               end
               player:sendTextMessage(22, "You have successfully teleported ".. counter .."/".. #online .." players to temple")
               createWindowWithButtons(player, management, windows.Management, "Management", "Ingame Administration Tool:\nCreated by Evil Hero @ otland", managementButtons, managementChoices, true, false)
           end
       end
   end
Code:
state[player:getId()]
is what you should take a closer look on.
Thanks for the code.
I kinda understood what was the point of my problem, but I don't know I understood how to exactly replicate.
That's what I tried:

Code:
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if player_modal_save[player:getId()] == nil then
        player_modal_save[player:getId()] = {}
    end

    player_modal_save[player:getId()].name = player:getName()

    createWindows(player)
    window:sendToPlayer(player)
    return true
end
I created a table for each player that used the modal window. Then I inserted there some infos I would use from these players.
Like name, some storages, etc.
At first, it does work. But when both the players try to reload the window, here:

Code:
    window2v2_info:addButton("Select",
       function(button, choice)
            window2v2_info:sendToPlayer(player)
       end
    )
It updates with the other player's info (the one that opened the modal after he did)

Then I tried updating inside the code above, every information, to check if it would remain with the own player's information, like that:

Code:
    window2v2_info:addButton("Select",
       function(button, choice)
            player_modal_save[player:getId()].name = player:getName()
            window2v2_info:sendToPlayer(player)
       end
    )
But it didn't work.
Have you got any idea what am I doing wrong? x_x
 

Mkalo

ボーカロイド
Joined
Jun 1, 2011
Messages
1,118
Best answers
54
Reaction score
900
Location
Japan
Thanks for the code.
I kinda understood what was the point of my problem, but I don't know I understood how to exactly replicate.
That's what I tried:

Code:
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if player_modal_save[player:getId()] == nil then
        player_modal_save[player:getId()] = {}
    end

    player_modal_save[player:getId()].name = player:getName()

    createWindows(player)
    window:sendToPlayer(player)
    return true
end
I created a table for each player that used the modal window. Then I inserted there some infos I would use from these players.
Like name, some storages, etc.
At first, it does work. But when both the players try to reload the window, here:

Code:
    window2v2_info:addButton("Select",
       function(button, choice)
            window2v2_info:sendToPlayer(player)
       end
    )
It updates with the other player's info (the one that opened the modal after he did)

Then I tried updating inside the code above, every information, to check if it would remain with the own player's information, like that:

Code:
    window2v2_info:addButton("Select",
       function(button, choice)
            player_modal_save[player:getId()].name = player:getName()
            window2v2_info:sendToPlayer(player)
       end
    )
But it didn't work.
Have you got any idea what am I doing wrong? x_x
Firstly, when using this lib you shouldn't ever assume that the userdata will be in a valid state when the callback function get called, so you should never use any userdata upvalue inside the callback functions.

Now to your problem, I couldn't really understand what you want exactly, can you tell exactly how the navigation between modal windows should work?
 

Dbzl

New Member
Joined
Jan 22, 2017
Messages
34
Best answers
0
Reaction score
1
Firstly, when using this lib you shouldn't ever assume that the userdata will be in a valid state when the callback function get called, so you should never use any userdata upvalue inside the callback functions.

Now to your problem, I couldn't really understand what you want exactly, can you tell exactly how the navigation between modal windows should work?
Maybe it would be better to don't use this lib, then

This modal window is supposed to have two functions: get inside a player queue or checking your own info.
It would be something like that:
If the player wants to simply join a queue, he will just select this first option and enter the queue.
This should be easy, if there were not the problem I will describe below.
(1)

If the player wants to check it's info, he will receive this:
(2)

The main problem is the userdata is changed whenever a new player opens the modal window, for every player with it opened.
If I have this window opened, like you can see at (2)
And the character Test Character 1, opens it, it will update Gamemaster's info to Test Character 1's info.

Evil Hero said, as you can see in his post, that I needed to keep a "save" for each player that uses the modal window.
I've tried, actually, inserting the player's info inside a global table, where I would access it whenever I needed.
But since the userdata gets replaced, it changes from every other windows opened.

x_x
 
Top