sman1975
Emperor
Hi,
I'm working on a LUA function that wants to attempt to destroy a building in an enemy city. Part of that process is to popup a window that contains a menu listing all the non-wonder buildings in the city. The goal is to let the player select a building from that list, then once the selection is made, continue the main function to determine if the attempt was successful or not.
Unfortunately, I'm having an issue with the timing - the "main process" code is obviously procedural (top to bottom) in nature, but waiting for the GUI to return a building ID value is not. I've tried several ways to synchronize these two functions, but so far getting no where.
Since a picture is worth a 1000 words...
The Main Process code works - the popup window is called and does display and work properly. However, the Main Process code immediately proceeds to the "print" statement and continues executing normally, even though no real action has occurred between the player and the "Select Building" popup.
I realize there needs to be some kind of feature/design approach - that will "force" the Main Process to wait on a proper value returned from the popup. Unfortunately, everything I've tried so far just hasn't worked.
Actual code for the "Select Building" popup:
Obviously, there's a design approach to handle these kinds of problems - I'm just somehow completely missing the boat on how it's done.
Thanks!
I'm working on a LUA function that wants to attempt to destroy a building in an enemy city. Part of that process is to popup a window that contains a menu listing all the non-wonder buildings in the city. The goal is to let the player select a building from that list, then once the selection is made, continue the main function to determine if the attempt was successful or not.
Unfortunately, I'm having an issue with the timing - the "main process" code is obviously procedural (top to bottom) in nature, but waiting for the GUI to return a building ID value is not. I've tried several ways to synchronize these two functions, but so far getting no where.
Since a picture is worth a 1000 words...
The Main Process code works - the popup window is called and does display and work properly. However, the Main Process code immediately proceeds to the "print" statement and continues executing normally, even though no real action has occurred between the player and the "Select Building" popup.
I realize there needs to be some kind of feature/design approach - that will "force" the Main Process to wait on a proper value returned from the popup. Unfortunately, everything I've tried so far just hasn't worked.
Actual code for the "Select Building" popup:
Code:
-- ====================================================================================================================================
-- Select Building popup - returns a building ID or -1 (random building)
local g_SortTable -- Global table used in sort function
function OnCOSBOK() -- "Confirm" button pressed, building selection is final
Controls.COSBPopup:SetHide(true) -- Close the popup
if (not g_SelectedBuildingID) or (not g_SelectedBuilding) or (g_SelectedBuilding == "") then -- If there's ANY problem with the selected building, return "random building"
g_SelectedBuildingID = -1 -- Random building "ID"
end
print("Exiting menu. Selected building ID: " .. g_SelectedBuildingID) -- Display the selected building ID
end
Controls.COSBOK:RegisterCallback(Mouse.eLClick, OnCOSBOK) -- Register the callback
function SortByName(a, b) -- QUAD sort function
local sNameA = g_SortTable[tostring(a)].Name
local sNameB = g_SortTable[tostring(b)].Name
return sNameA < sNameB
end
function OnBuildingSelected(iBuildingID) -- "Building has been selected" callback - "selected" but not confirmed!
local sBuildingName = "Random Building" -- Default selected building name is "Random"
if not iBuildingID then iBuildingID = -1 end -- If not a good ID, then force it to -1 (Random)
if iBuildingID ~= -1 then -- If the building ID isn't random, get the actual building name
sBuildingName = Locale.ConvertTextKey(GameInfo.Buildings[iBuildingID].Description) -- Localize the string
end
Controls.COSBMenu:GetButton():SetText(sBuildingName) -- Set the "button" to the building name so it displays properly
local sAtlas = "CIV_COLOR_ATLAS" -- This atlas/portrait combo is for the "Question Mark" icon
local iPortraitIDX = 23
if iBuildingID ~= -1 then -- If the building isn't random, get the actual icon for the building
sAtlas = GameInfo.Buildings[iBuildingID].IconAtlas
iPortraitIDX = GameInfo.Buildings[iBuildingID].PortraitIndex
end
IconHookup( iPortraitIDX, 128, sAtlas, Controls.SelectBuildingCenterIcon ) -- Display the building/question mark in the center of the popup
print("Selected building name: " .. sBuildingName .. " ID: " .. iBuildingID .. " Atlas: " .. sAtlas .. " Portrait Index: " .. iPortraitIDX)
g_SelectedBuildingID = iBuildingID -- Set the PROPOSED return value to the currently selected building
end
function UpdateBuildingList(pPlayer, pTargetCity) -- Construct a list of non-wonder buildings in pTargetCity
Controls.COSBMenu:ClearEntries() -- Clear any previous values that might have been there
g_SortTable = {} -- Clear the SortTable
local sCOSBTitle = Locale.ConvertTextKey("TXT_KEY_CO_COSB_MESSAGE", pTargetCity:GetName()) -- Update the "Message" on the popup (e.g. "Attack in Omaha")
Controls.COSBMessage:LocalizeAndSetText(sCOSBTitle) -- Set the title (inside top green bar) for the popup
IconHookup(23, 128, "CIV_COLOR_ATLAS", Controls.SelectBuildingCenterIcon) -- Initial center icon will be the question mark
local tEntry = {} -- Create an entry in the Pulldown Stack
Controls.COSBMenu:BuildEntry("InstanceOne", tEntry)
g_SortTable[tostring(tEntry.Button)] = {Name="Random Building"} -- Add "Random Building" to SortTable
tEntry.Button:SetVoid1(-1) -- Void1 on this entry
tEntry.Button:SetText("Random Building") -- Set the text value for the menu item
for row in GameInfo.Buildings() do -- Scroll through all buildings in the Buildings table
if pTargetCity:GetNumRealBuilding(row.ID) ~= 0 then -- If the city has more than zero of these building types, then...
local BClass = GameInfo.Buildings[row.ID].BuildingClass -- Get the Building class of the building in the city
local BWonder = GameInfo.BuildingClasses["" .. BClass .. ""].MaxGlobalInstances -- Get MGI amount; normal buildings = 0; global wonders ~= 0
local BNational = GameInfo.BuildingClasses["" .. BClass .. ""].MaxPlayerInstances -- Get MPI amount; normal buildings = 0; national wonders ~= 0
if (BWonder == -1) and (BNational == -1) then -- If not a Global or National wonder then...
local sBuildingName = Locale.ConvertTextKey(row.Description) -- Get the name of this building
local entry = {} -- Create an entry in the Pulldown Stacl
Controls.COSBMenu:BuildEntry("InstanceOne", entry)
g_SortTable[tostring(entry.Button)] = {Name=sBuildingName} -- Add this building name to the SortTable in the right location
entry.Button:SetVoid1(row.ID) -- Void1 on this entry
entry.Button:SetText(sBuildingName) -- Set the text value for the menu item
end
end
end
Controls.COSBMenuStack:SortChildren(SortByName) -- Sort items in the menu stack
Controls.COSBMenu:GetButton():LocalizeAndSetText("TXT_KEY_CO_COSB_MENU_CHOOSE") -- Prompt string for the pulldown menu
Controls.COSBMenu:CalculateInternals() -- Popup bookkeeping
Controls.COSBMenu:RegisterSelectionCallback(OnBuildingSelected) -- Register the OnBuildingSelected callback
end
function ProcessSelectBuildingPopup(pPlayer, pTargetCity) -- Return a building ID or -1 for Random Building
UpdateBuildingList(pPlayer, pTargetCity) -- Get a list of all non-wonder buildings in pTargetCity
Controls.COSBPopup:SetHide(false) -- Display the building list popup
return g_SelectedBuildingID -- THIS IS THE PROBLEM!
end
Obviously, there's a design approach to handle these kinds of problems - I'm just somehow completely missing the boat on how it's done.
Thanks!