Fenris_Wolf Posted March 13, 2018 Share Posted March 13, 2018 (edited) So... you want hotkeys the player can press that does something for your mod. The problem: The player should be able to reconfigure these keys, so they don't conflict with the players existing setup or other mods they have loaded. Sure you can have these keys setup in a 'settings.lua' file the player can edit, but that leads to its own problems... If a user edits this file, and the mod is designed for multiplayer, then they'll have issues connecting to servers since the checksums won't match. Maybe you're feeling clever, and decided to write these settings into a settings.ini file instead, and just read the ini on loading (thus not having to worry about checksums), but that's a problem too....users rarely read the documentation, and hate manually editing files in notepad! So...the only real answer is to have a proper GUI where they can edit these settings, and what better GUI to use then PZ's own options screen! For this tutorial I'll explain using some work I've been doing on the ORGM mod today. I needed 3 new hotkeys: for equipping the best pistol, best rifle, and one for the best shotgun. Nice and clean there, no need to manually edit file, or screw up the luachecksums, or need to explain to users how to do it other then: 'it will be in your pz options screen' Here's our script in full: Spoiler --' We need to use the global keyBinding table, this stores all our binding values' local index = nil -- index will be the position we want to insert into the table for i,b in ipairs(keyBinding) do --' we need to find the index of the item we want to insert after -- in this case its "Equip/Unequip Stab weapon"' if b.value == "Equip/Unequip Stab weapon" then index = i --' found the index, set it and break from the loop' break end end if index then --' we got a index, first lets insert our new entries' table.insert(keyBinding, index+1, {value = "Equip/Unequip Pistol", key = 5}) table.insert(keyBinding, index+2, {value = "Equip/Unequip Rifle", key = 6}) table.insert(keyBinding, index+3, {value = "Equip/Unequip Shotgun", key = 7}) --' store the original MainOptions:create() method in a variable' local oldCreate = MainOptions.create --' overwrite it' function MainOptions:create() oldCreate(self) for _, keyTextElement in pairs(MainOptions.keyText) do repeat --' if keyTextElement is nil or doesnt have a ISLabel, break out of the -- "repeat ... until true" loop, and continue with the "for .. do ... end" -- loop' if not keyTextElement or not keyTextElement.txt then break end local label = keyTextElement.txt --' our ISLabel item is stored in keyTextElement.txt -- We need to do a few things here to prep the new entries. -- 1) We wont have a proper translation, and the translation will be set to -- "UI_optionscreen_binding_Equip/Unequip Pistol", which will look funny on the -- options screen, so we need to fix -- 2) the new translation doesnt properly adjust the x position and width, so we need to -- manually adjust these' if label.name == "Equip/Unequip Pistol" then label:setTranslation("Equip/Unequip Pistol") label:setX(label.x) label:setWidth(label.width) elseif label.name == "Equip/Unequip Rifle" then label:setTranslation("Equip/Unequip Rifle") label:setX(label.x) label:setWidth(label.width) elseif label.name == "Equip/Unequip Shotgun" then label:setTranslation("Equip/Unequip Shotgun") label:setX(label.x) label:setWidth(label.width) end until true end end end --' now add the event hook function, for this example the player just says the name of the key' Events.OnKeyPressed.Add(function(key) local player = getSpecificPlayer(0) if key == getCore():getKey("Equip/Unequip Pistol") then player:Say("Key pressed: Equip/Unequip Pistol") elseif key == getCore():getKey("Equip/Unequip Rifle") then player:Say("Key pressed: Equip/Unequip Rifle") elseif key == getCore():getKey("Equip/Unequip Shotgun") then player:Say("Key pressed: Equip/Unequip Shotgun") end end) All the key bindings listed on the options screen are stored in the global table called keyBinding First we need to find the index of the option we want to insert after: local index = nil for i,b in ipairs(keyBinding) do if b.value == "Equip/Unequip Stab weapon" then index = i break end end The next chunks of code are wrapping in a 'if index then .... end' block, but I'll omit that here just so I can break this 'if statement' into smaller pieces (you can see it in the full script in the spoiler above) Since we got our index and know our insertion point, lets insert the new options: table.insert(keyBinding, index+1, {value = "Equip/Unequip Pistol", key = 5}) table.insert(keyBinding, index+2, {value = "Equip/Unequip Rifle", key = 6}) table.insert(keyBinding, index+3, {value = "Equip/Unequip Shotgun", key = 7}) Note these keys actually correspond to 4, 5 and 6 respectively (esc is key=1, swinging weapon is key=2, firearm is key=3, and stabbing weapon is key=4) You can also use constant values for these, if you look in shared/keyBinding.lua, you'll see rack firearm is key = Keyboard.KEY_X Now we need to overwrite the MainOptions:create() method, so we can fix some translation issues: local oldCreate = MainOptions.create function MainOptions:create() oldCreate(self) for _, keyTextElement in pairs(MainOptions.keyText) do repeat if not keyTextElement or not keyTextElement.txt then break end local label = keyTextElement.txt if label.name == "Equip/Unequip Pistol" then label:setTranslation("Equip/Unequip Pistol") label:setX(label.x) label:setWidth(label.width) elseif label.name == "Equip/Unequip Rifle" then label:setTranslation("Equip/Unequip Rifle") label:setX(label.x) label:setWidth(label.width) elseif label.name == "Equip/Unequip Shotgun" then label:setTranslation("Equip/Unequip Shotgun") label:setX(label.x) label:setWidth(label.width) end until true end end Notice the first thing in that block is we store the original MainOptions:create() method in a variable, and call it first thing in our overwrite. By doing this we're just basically appending our new code to the end of the original function. The problem is if we don't do this, our options will appear as "UI_optionscreen_binding_Equip/Unequip Pistol" on the screen, unless you have a proper translation entry. Since we dont, we need to change the label translations so we don't have that "UI_optionscreen_binding_" prefix. As well as changing the text that gets shown, we need to reset the x position, and the width of the label or they'll still be positioned too far off. By calling label:setTranslation() it fixes the label.x and label.width variables, but doesn't actually adjust the positions so we need to call label:setX() and label:setWidth() manually. And thats it for the options screen...all you need to do to have the custom keys show up and be configurable. This is where our 'if index then .... end' block actually ends. Note you'll still have the translation problem when the user clicks to change the key to something else, the popup will need fixing.... you have to overwrite MainOptions:render() for that, I won't be covering that here since its a minor issue, and doing that might be incompatible if 2 mods use this same technique. The code above can be used by multiple mods at the same time without issue, even with our overwrite: If your mod overwrites MainOptions:create(), and another mod loads after and uses the same technique, then their overwrite ends up calling yours, and yours then calls the original function. Now for the final piece, the event hook when the player presses a key: Events.OnKeyPressed.Add(function(key) local player = getSpecificPlayer(0) if key == getCore():getKey("Equip/Unequip Pistol") then player:Say("Key pressed: Equip/Unequip Pistol") elseif key == getCore():getKey("Equip/Unequip Rifle") then player:Say("Key pressed: Equip/Unequip Rifle") elseif key == getCore():getKey("Equip/Unequip Shotgun") then player:Say("Key pressed: Equip/Unequip Shotgun") end end) Our key presses here don't actually do much, the player just says which of the keys options got triggered. But that's all there is to it, custom user configurable keys that don't force players to manually edit files, and bypass server lua checksum comparisons. Edited March 13, 2018 by Fenris_Wolf nolanri, ElectricLimbo83 and Nebula 3 Link to comment Share on other sites More sharing options...
Fenris_Wolf Posted May 1, 2018 Author Share Posted May 1, 2018 8 hours ago, Hideki-Ishimura said: Hello I would like to start creating a simple mod in Lua, but I don't know what IDE to use, what is the IDE used by the community? Thanks! I'd imagine the most used is probably just notepad++ which is what I use, though that's not really a IDE. A real IDE is probably overkill for PZ modding, plus a lot would choke since most of the actual functions, classes and methods are in the java components. If you really want a IDE the best one for lua is probably ZeroBrane, which seems to handle PZ mod projects fairly well, though It does flag a lot of PZ's global variables and functions as possible typos since it can't look them up. Link to comment Share on other sites More sharing options...
Dr_Cox1911 Posted May 1, 2018 Share Posted May 1, 2018 I use Atom to code for PZ (and as a general text editor). Prefer it over Notepad++ but needs some love at first to run like you want it. There are a bunch of plugins for it that will customize the editor to your liking. Mainly switched to it because it is available for other operating systems as well. Link to comment Share on other sites More sharing options...
Fenris_Wolf Posted May 1, 2018 Author Share Posted May 1, 2018 3 minutes ago, Dr_Cox1911 said: Mainly switched to it because it is available for other operating systems as well. I haven't tried that one (I think, hard to remember I've burned through a lot of editors). Notepad++'s 'windows only' is a real downside, on the upside, it does run flawlessly using wine, which is what I use when I need a general editor on linux systems. Link to comment Share on other sites More sharing options...
Nebula Posted May 1, 2018 Share Posted May 1, 2018 (edited) Thanks for the example! Everything worked out.But there is one problem.What about the Tooltip?It is necessary that in Tooltip_.txt - except for the text the value was displayed getCore():getKey(getText("Text"))how to do it? Edited May 1, 2018 by Nebula Link to comment Share on other sites More sharing options...
Fenris_Wolf Posted May 1, 2018 Author Share Posted May 1, 2018 7 minutes ago, Nebula said: What about the Tooltip? Not sure what you mean..tooltips aren't really used on the keybinding screen. The Tooltip_*.txt translation files are meant to used in game, when hovering the mouse over a item. Link to comment Share on other sites More sharing options...
Nebula Posted May 1, 2018 Share Posted May 1, 2018 Yes.I need to have a designated key in the tooltip, besides the usual text.So, as a TXT file, then it does not work in it to use variables from LUA how to be? Link to comment Share on other sites More sharing options...
Nebula Posted May 1, 2018 Share Posted May 1, 2018 And further...I have a button on the destination screenUI_optionscreen_binding_ As you warned, although I used the translation files ...Here is the code. local index = nil for i,b in ipairs(keyBinding) do if b.value == "Toggle UI" then index = i break end end if index then table.insert(keyBinding, index+1, {value = getText("IGUI_Show_window_of_equipped_items"), key = 24}) local oldCreate = MainOptions.create function MainOptions:create() oldCreate(self) for _, keyTextElement in pairs(MainOptions.keyText) do repeat if not keyTextElement or not keyTextElement.txt then break end local label = keyTextElement.txt if label.name == getText("IGUI_Show_window_of_equipped_items") then label:setTranslation(getText("IGUI_Show_window_of_equipped_items")) label:setX(label.x) label:setWidth(label.width) end until true end end end Link to comment Share on other sites More sharing options...
Fenris_Wolf Posted May 1, 2018 Author Share Posted May 1, 2018 If your going to use translation files, then most of that code becomes redundant. This tutorial is mostly outdated if your using translations. The current version I'm using is: -- Setup hotkey bindings -- We need to use the global keyBinding table, this stores all our binding values local index = nil -- index will be the position we want to insert into the table for i,b in ipairs(keyBinding) do if b.value == "Equip/Unequip Stab weapon" then index = i -- found the index, set it and break from the loop break end end if index then -- we got a index, first lets insert our new entries table.insert(keyBinding, index+1, {value = "Equip/Unequip Pistol", key = 5}) table.insert(keyBinding, index+2, {value = "Equip/Unequip Rifle", key = 6}) table.insert(keyBinding, index+3, {value = "Equip/Unequip Shotgun", key = 7}) table.insert(keyBinding, index+4, {value = "Reload Any Magazine", key = Keyboard.KEY_G }) table.insert(keyBinding, index+5, {value = "Select Fire Toggle", key = Keyboard.KEY_Z }) table.insert(keyBinding, index+6, {value = "Firearm Inspection Window", key = Keyboard.KEY_U }) end Thats the Entire lua code, overwriting MainOptions:create() is not needed with translations. Then in the UI_EN.txt I've added: UI_EN = { UI_optionscreen_binding_Equip/Unequip Pistol = "Equip/Unequip Pistol", UI_optionscreen_binding_Equip/Unequip Rifle = "Equip/Unequip Rifle", UI_optionscreen_binding_Equip/Unequip Shotgun = "Equip/Unequip Shotgun", UI_optionscreen_binding_Reload Any Magazine = "Reload Any Magazine", UI_optionscreen_binding_Select Fire Toggle = "Select Fire Toggle", UI_optionscreen_binding_Firearm Inspection Window = "Firearm Inspection Window", } And thats all of it. Nebula 1 Link to comment Share on other sites More sharing options...
Vadyanga Posted September 21, 2018 Share Posted September 21, 2018 How to add a wombo-combo-table? Like that: local full = self:addCombo(splitpoint, y, comboWidth, 20, getText("UI_optionscreen_fullscreen"), {getText("UI_Yes"), getText("UI_No")}, 1); Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now