Skip to content

Instantly share code, notes, and snippets.

@Novaras
Created February 9, 2022 02:41
Show Gist options
  • Save Novaras/0c27769f31a6bfdf55720e89aa14cf13 to your computer and use it in GitHub Desktop.
Save Novaras/0c27769f31a6bfdf55720e89aa14cf13 to your computer and use it in GitHub Desktop.

wow

The problem:

There is no way to share any variables or state with other LUA scopes which may be running alongside the current one.

For exmaple, a script running the mission rules will be running during gametime, and so will ship customcode scripts, but they have no way to communicate with eachother!.

In order to overcome this, we can write to the UI in a very specific way and keep a string representation of a lua table there!

Implementation

-- scripts/state_scope.lua

function makeStateHandle(screen_name, dropdown_host_el)
	screen_name = screen_name or "DefaultStateScreen";
	dropdown_host_el = dropdown_host_el or "host_dropdown";

	if (UI_GetElementCustomData(screen_name, dropdown_host_el) ~= 1) then
		UI_AddDropDownListboxItem(screen_name, dropdown_host_el, "_", "", 0, "{}");
		UI_SetElementCustomData(screen_name, dropdown_host_el, 1); -- 1 = init
	end

	return function(new_state, overwrite)
		UI_SelectDropDownListboxItemIndex(%screen_name, %dropdown_host_el, 0);
		local current_state = dostring("return " .. (UI_GetDropdownListBoxSelectedCustomDataString(%screen_name, %dropdown_host_el) or "{}"));

		if (new_state) then
			UI_ClearDropDownListbox(%screen_name, %dropdown_host_el);

			if (overwrite) then
				current_state = new_state;
			else
				current_state = modkit.table:merge(current_state, new_state);
			end

			local asStr = function (v, tblParser)
				if (type(v) == "table") then
					local out = "{";
					for k, v in v do
						out = out .. k .. "=" .. tblParser(v) .. ",";
					end
					out = out .. "}";
					return out;
				elseif (type(v) == "string") then
					return "\"" .. v .. "\"";
				else
					return tostring(v);
				end
			end

			local state_str = asStr(current_state, asStr);
			UI_AddDropDownListboxItem(%screen_name, %dropdown_host_el, "_", "", 0, state_str);
		end

		return current_state;
	end
end

The host screen:

-- ui/newui/defaultstatescreen.lua

dofilepath("data:ui/newui/Styles/HWRM_Style/HWRMDefines.lua");

DefaultStateScreen = {
	size = { 0, 0, 0, 0 },
	stylesheet = "HW2StyleSheet"
	;
	{
		type = "Frame"
		;
		{
			type = "DropDownListBox",
			name  = "host_dropdown",
			dropDownListBoxStyle = "IGDropDownListBoxStyle",
			autosize = 1,
			ListBox = {
				type = "ListBox",
				name = "host_dropdown_listbox",
				ItemToClone = {
					type = "TextListBoxItem",
					resizeToListBox = 1,
					Text = {
						text = ""
					}
				},
			}
		}
	}
};

You also need to register the screen in uisettings.lua (which is a stock file, make sure to paste what's in here first and just add a new entry):

{
    name = "DefaultStateScreen",
    filename = "data:\\ui\\newui\\defaultstatescreen.lua",
    activated = 0
},

Usage

-- some scope, perhaps:
-- leveldata/campaign/my_campaign/my_mission.lua

dofilepath("data:scripts/state_scope.lua");

local state = makeStateHandle("my_screen", "my_dropdown_el");
state({ a = "foo", b = 10 });
-- some other scope, i.e:
-- ships/hgn_mothership/hgn_mothership.lua

dofilepath("data:scripts/state_scope.lua");

local state = makeStateHandle("my_screen", "my_dropdown_el");
-- prints:
-- a: foo
-- b: 10
for k, v in state() do
    print(k .. ": " .. tostring(v);
end

You can get and set the state from any runtime scope (any scope with access to UI_ calls).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment