Jump to content

Recommended Posts

I'd like an ability on a charter to turn on/off when I press a key.

I've seen mods that have such an ability, but don't understand how it works in the code.

Here's a mod where pressing R causes them to go into a 'bundle'.
https://steamcommunity.com/sharedfiles/filedetails/?id=699268081

In the configurable options, they set the key:

configuration_options = {
 {
        name = "key_bundle",
        label = "Tail Wrap Key",
        hover = "Key binding for bundling in tails.",
        options =
        {
            {description="TAB", data = 9},
            {description="KP_PERIOD", data = 266},
            {description="KP_DIVIDE", data = 267},
            {description="KP_MULTIPLY", data = 268},
            {description="KP_MINUS", data = 269},
            {description="KP_PLUS", data = 270},
            {description="KP_ENTER", data = 271},
            {description="KP_EQUALS", data = 272},
            {description="MINUS", data = 45},
            {description="EQUALS", data = 61},
            {description="SPACE", data = 32},
            {description="ENTER", data = 13},
            {description="ESCAPE", data = 27},
            {description="HOME", data = 278},
            {description="INSERT", data = 277},
            {description="DELETE", data = 127},
            {description="END", data   = 279},
            {description="PAUSE", data = 19},
            {description="PRINT", data = 316},
            {description="CAPSLOCK", data = 301},
            {description="SCROLLOCK", data = 302},
            {description="RSHIFT", data = 303}, -- use SHIFT instead
            {description="LSHIFT", data = 304}, -- use SHIFT instead
            {description="RCTRL", data = 305}, -- use CTRL instead
            {description="LCTRL", data = 306}, -- use CTRL instead
            {description="RALT", data = 307}, -- use ALT instead
            {description="LALT", data = 308}, -- use ALT instead
            {description="ALT", data = 400},
            {description="CTRL", data = 401},
            {description="SHIFT", data = 402},
            {description="BACKSPACE", data = 8},
            {description="PERIOD", data = 46},
            {description="SLASH", data = 47},
            {description="LEFTBRACKET", data     = 91},
            {description="BACKSLASH", data     = 92},
            {description="RIGHTBRACKET", data = 93},
            {description="TILDE", data = 96},
            {description="A", data = 97},
            {description="B", data = 98},
            {description="C", data = 99},
            {description="D", data = 100},
            {description="E", data = 101},
            {description="F", data = 102},
            {description="G", data = 103},
            {description="H", data = 104},
            {description="I", data = 105},
            {description="J", data = 106},
            {description="K", data = 107},
            {description="L", data = 108},
            {description="M", data = 109},
            {description="N", data = 110},
            {description="O", data = 111},
            {description="P", data = 112},
            {description="Q", data = 113},
            {description="R", data = 114},
            {description="S", data = 115},
            {description="T", data = 116},
            {description="U", data = 117},
            {description="V", data = 118},
            {description="W", data = 119},
            {description="X", data = 120},
            {description="Y", data = 121},
            {description="Z", data = 122},
            {description="F1", data = 282},
            {description="F2", data = 283},
            {description="F3", data = 284},
            {description="F4", data = 285},
            {description="F5", data = 286},
            {description="F6", data = 287},
            {description="F7", data = 288},
            {description="F8", data = 289},
            {description="F9", data = 290},
            {description="F10", data = 291},
            {description="F11", data = 292},
            {description="F12", data = 293},
 
            {description="UP", data = 273},
            {description="DOWN", data = 274},
            {description="RIGHT", data = 275},
            {description="LEFT", data = 276},
            {description="PAGEUP", data = 280},
            {description="PAGEDOWN", data = 281},
 
            {description="0", data = 48},
            {description="1", data = 49},
            {description="2", data = 50},
            {description="3", data = 51},
            {description="4", data = 52},
            {description="5", data = 53},
            {description="6", data = 54},
            {description="7", data = 55},
            {description="8", data = 56},
            {description="9", data = 57},
        },
        default = 114, -- R key
    },
}

Which shows up in ModMain:

-- Tail bundle ability
local function widgette_bundle(player)
	if player.DoBundle and not player:HasTag("playerghost") then
		player:DoBundle(player)
	end
end
AddModRPCHandler(modname, "widgette_bundle", widgette_bundle)
GLOBAL.TheInput:AddKeyDownHandler(GetModConfigData("key_bundle", true), function()
    if not GLOBAL.ThePlayer or GLOBAL.ThePlayer.prefab ~= "widgette" or GLOBAL.TheFrontEnd:GetActiveScreen() ~= GLOBAL.ThePlayer.HUD then
        return
    end
    
	if GLOBAL.TheNet:GetIsServer() then
		widgette_bundle(GLOBAL.ThePlayer)
	else
		SendModRPCToServer(MOD_RPC[modname]["widgette_bundle"])
	end
end)

In the master_postinit:

	-- Tail bundle
	inst.DoBundle = DoBundle

	-- Re-override bundle when equipping/unequipping
	local inventory = inst.components.inventory
	local Equip_prev = inventory.Equip
	function inventory:Equip(item, ...)
		local equipped = Equip_prev(self, item, ...)
		if equipped and inst.isbundled then
			local equipslot = item.components.equippable.equipslot
			if equipslot == EQUIPSLOTS.BODY or equipslot == EQUIPSLOTS.NECK  or equipslot == EQUIPSLOTS.BACK then
				inst.AnimState:OverrideSymbol("swap_body", "widgette_bundle", "swap_body")
			end
		end
		return equipped
	end
	
	local Unequip_prev = inventory.Unequip
	function inventory:Unequip(equipslot, ...)
		local item = Unequip_prev(self, equipslot, ...)
		if inst.isbundled and (equipslot == EQUIPSLOTS.BODY or equipslot == EQUIPSLOTS.NECK or equipslot == EQUIPSLOTS.BACK) then
			inst.AnimState:OverrideSymbol("swap_body", "widgette_bundle", "swap_body")
		end
		return item
	end

And elsewhere in their character's PreFab file:

local WIDGETTE_BUNDLE_SANITY_RATE = 2.5/TUNING.SEG_TIME 
local WIDGETTE_BUNDLE_INSULATION = 30
local WIDGETTE_BUNDLE_SPEED_MULT = 0.6
local assets = {
    Asset("SCRIPT", "scripts/prefabs/player_common.lua"),
	Asset( "ANIM", "anim/widgette_bundle.zip" ),
}

local function OnBundle(inst)
	inst.AnimState:OverrideSymbol("swap_body", "widgette_bundle", "swap_body")
    inst.AnimState:Hide("tail")
	
	inst.components.sanity.dapperness = WIDGETTE_BUNDLE_SANITY_RATE
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "widgette_speed_mod", WIDGETTE_BUNDLE_SPEED_MULT)
    inst.components.temperature.inherentinsulation = WIDGETTE_BUNDLE_INSULATION
end
local function OnUnbundle(inst)
	inst.AnimState:ClearOverrideSymbol("swap_body")
    inst.AnimState:Show("tail")
	
	-- Restore equipped torso item
	local equippeditem = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.BODY)
		or (EQUIPSLOTS.BACK and inst.components.inventory:GetEquippedItem(EQUIPSLOTS.BACK))
		or (EQUIPSLOTS.NECK and inst.components.inventory:GetEquippedItem(EQUIPSLOTS.NECK))
	if equippeditem then
		if equippeditem.components.equippable.onunequipfn then
			equippeditem.components.equippable.onunequipfn(equippeditem, inst)
		end
		if equippeditem.components.equippable.onequipfn then
			equippeditem.components.equippable.onequipfn(equippeditem, inst)
		end
	end
	
	inst.components.sanity.dapperness = 0
	inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "widgette_speed_mod")
    inst.components.temperature.inherentinsulation = 0
end
local function DoBundle(inst)
	if inst.isbundled then
		inst.isbundled = false
		OnUnbundle(inst)
	else
		inst.isbundled = true
		OnBundle(inst)
	end
end


local function onbecameghost(inst)
	if inst.isbundled then
		inst.isbundled = false
		OnUnbundle(inst)
	end
end

 

 

Most of this isn't too complex, but I don't understand the simple act of getting the game to detect when a key was pressed.

The function that detects key presses is 

GLOBAL.TheInput:AddKeyDownHandler(GetModConfigData("key_bundle", true), function()
    if not GLOBAL.ThePlayer or GLOBAL.ThePlayer.prefab ~= "widgette" or GLOBAL.TheFrontEnd:GetActiveScreen() ~= GLOBAL.ThePlayer.HUD then
        return
    end
    
	if GLOBAL.TheNet:GetIsServer() then
		widgette_bundle(GLOBAL.ThePlayer)
	else
		SendModRPCToServer(MOD_RPC[modname]["widgette_bundle"])
	end
end)

TheInput gets information from key presses on the client. AddKeyDownHandler makes a function run when a certain key is pressed.

As this is happening on the client, you need to send a RPC to get the server to do something.

  • Like 1

@Monti18
Ahh, ok, thanks!

So to do this, I'd declare a button value (similar to how they did probably), and use AddKeyDownHandler to make a function run when a specific character/player pressed that key, right?  It's still kind of complex, for such a simple action..

Do you know how this might look if I wanted to add/remove a Tag from a character?  (I'm willing to wager a guess, but figured I should ask before spamming my currently ignorant code..)

The button values can be found in constants.lua of the base game there you can which value corresponds which key. 

It's complex, that's right, but all things that have to so with client server connection are complex unfortunaly. If you want to have it a bit easier, try the keyhandler component by kzisor. 

The best way to learn is to try and fail, so post your guess and I will help you :D

  • Like 2

@Monti18
This is in ModInfo:

configuration_options = {
 {
        name = "key_to_swim",
        label = "Key to toggle Swim-Mode",
        hover = "Jump into the water, only when you want to.",
        options =
        {
            {description="A", data = 97},
            {description="B", data = 98},
            {description="C", data = 99},
            {description="D", data = 100},
            {description="E", data = 101},
            {description="F", data = 102},
            {description="G", data = 103},
            {description="H", data = 104},
            {description="I", data = 105},
            {description="J", data = 106},
            {description="K", data = 107},
            {description="L", data = 108},
            {description="M", data = 109},
            {description="N", data = 110},
            {description="O", data = 111},
            {description="P", data = 112},
            {description="Q", data = 113},
            {description="R", data = 114},
            {description="S", data = 115},
            {description="T", data = 116},
            {description="U", data = 117},
            {description="V", data = 118},
            {description="W", data = 119},
            {description="X", data = 120},
            {description="Y", data = 121},
            {description="Z", data = 122},
            {description="F1", data = 282},
            {description="F2", data = 283},
            {description="F3", data = 284},
            {description="F4", data = 285},
            {description="F5", data = 286},
            {description="F6", data = 287},
            {description="F7", data = 288},
            {description="F8", data = 289},
            {description="F9", data = 290},
            {description="F10", data = 291},
            {description="F11", data = 292},
            {description="F12", data = 293},
 
            {description="UP", data = 273},
            {description="DOWN", data = 274},
            {description="RIGHT", data = 275},
            {description="LEFT", data = 276},
            {description="PAGEUP", data = 280},
            {description="PAGEDOWN", data = 281},
 
            {description="0", data = 48},
            {description="1", data = 49},
            {description="2", data = 50},
            {description="3", data = 51},
            {description="4", data = 52},
            {description="5", data = 53},
            {description="6", data = 54},
            {description="7", data = 55},
            {description="8", data = 56},
            {description="9", data = 57},
        },
        default = 114, -- R key
    },
}

These are in ModMain:

-- Tail bundle ability
local function ___UNKNOWN___(player)
	if player.WILL_SWIM and not player:HasTag("playerghost") then  --Note: I think I edited this incorrectly, and likely broke a key component of the code.
		player:WILL_SWIM(player)
	end
end
GLOBAL.TheInput:AddKeyDownHandler(GetModConfigData("key_to_swim", true), function()
    if not GLOBAL.ThePlayer or GLOBAL.ThePlayer.prefab ~= "CHARACTER'S_PREFAB_NAME" or GLOBAL.TheFrontEnd:GetActiveScreen() ~= GLOBAL.ThePlayer.HUD then
        return
    end
    
	if GLOBAL.TheNet:GetIsServer() then
		widgette_bundle(GLOBAL.ThePlayer)
	else
		SendModRPCToServer(MOD_RPC[modname]["___UNKNOWN___"])  --I don't know what this is for or how it works.
	end
end)

In the character's Master_PostInIt:

	-- Swim Mode
	inst.SwimMode = SwimMode  --Note: I believe I no longer use this variable, and should not include it.

In the character's PreFab:

local function DoBundle(inst)
	if inst:HasTag("WILLING_TO_SWIM") then
		WILL_NOT_SWIM(inst)
	else
		inst:HasTag("WILLING_TO_SWIM") = true
		WILL_SWIM(inst)
	end
end


local function onbecameghost(inst)
	if inst:HasTag("WILLING_TO_SWIM") then
		WILL_NOT_SWIM(inst)
	end
end
local function WILL_SWIM(inst)
	inst:AddTag("WILLING_TO_SWIM")
	player.components.talker:Say("Time for a swim!")
end
local function WILL_NOT_SWIM(inst)
	inst:RemoveTag("WILLING_TO_SWIM")
	player.components.talker:Say("I don't feellike getting wet..")
end


Thoughts?

Edited by FurryEskimo

A few things:

-ModInfo is fine.

-Modmain:

When sending a RPC to the server, you need to save the function you want to send as AddModRPCHandler

-- Tail bundle ability
local function ___UNKNOWN___(player)
	if player.WILL_SWIM and not player:HasTag("playerghost") then  --Note: I think I edited this incorrectly, and likely broke a key component of the code.
		player:WILL_SWIM(player)
	end
end

So after this function, you add

AddModRPCHandler("yourmodname","__UNKNOWN__",__UNKNOWN__)

and change 

SendModRPCToServer(MOD_RPC[modname]["___UNKNOWN___"])  --I don't know what this is for or how it works.

to

SendModRPCToServer(MOD_RPC["yourmodname]["___UNKNOWN___"])  

SendModRPCToServer sends your function __UNKNOWN__ to the server so that it cn be run on the server.

-Charater prefab:

You call in your __UNKNOWN__ function player.WILL_SWIM. The problem is, the game doesn't know this function, as you saved it as a local function that can only be accessed in your character prefab.

To solve this, add this to your MasterPostinit:

inst.WILL_SWIM = WILL_SWIM

I'm not quite sure what your DoBundle function does, as you never call it anywhere, which also renders WILL_NOT_SWIM useless.

Also you can not say inst:HasTag("WILLING_TO_SWIM") = true, you need to write inst:AddTag("WILLING_TO_SWIM")

What exactly do you want to do when pressing the key?

  • Like 1
  • Thanks 1
  • Health 1

@Monti18

Thanks!  I’ll give this a try tonight, once I’m out of work.

I have a character who can dump into and out of the water, but some people have said it can be frustrating, since it happens automatically once you stand next to the shore.  I figured I’d add/remove a tag that would allow/prevent the player entering the water.

@Monti18
Unfortunately it doesn't appear to be working yet.  I've uploaded my error log. 

What I added to ModInfo:

{
	name = "key_to_swim",
	label = "Key to toggle Swim-Mode",
	hover = "Jump into the water, only when you want to.",
	options =
		{
			{description="A", data = 97},
			{description="B", data = 98},
			{description="C", data = 99},
			{description="D", data = 100},
			{description="E", data = 101},
			{description="F", data = 102},
			{description="G", data = 103},
			{description="H", data = 104},
			{description="I", data = 105},
			{description="J", data = 106},
			{description="K", data = 107},
			{description="L", data = 108},
			{description="M", data = 109},
			{description="N", data = 110},
			{description="O", data = 111},
			{description="P", data = 112},
			{description="Q", data = 113},
			{description="R", data = 114},
			{description="S", data = 115},
			{description="T", data = 116},
			{description="U", data = 117},
			{description="V", data = 118},
			{description="W", data = 119},
			{description="X", data = 120},
			{description="Y", data = 121},
			{description="Z", data = 122},
			{description="F1", data = 282},
			{description="F2", data = 283},
			{description="F3", data = 284},
			{description="F4", data = 285},
			{description="F5", data = 286},
			{description="F6", data = 287},
			{description="F7", data = 288},
			{description="F8", data = 289},
			{description="F9", data = 290},
			{description="F10", data = 291},
			{description="F11", data = 292},
			{description="F12", data = 293},

			{description="UP", data = 273},
			{description="DOWN", data = 274},
			{description="RIGHT", data = 275},
			{description="LEFT", data = 276},
			{description="PAGEUP", data = 280},
			{description="PAGEDOWN", data = 281},

			{description="0", data = 48},
			{description="1", data = 49},
			{description="2", data = 50},
			{description="3", data = 51},
			{description="4", data = 52},
			{description="5", data = 53},
			{description="6", data = 54},
			{description="7", data = 55},
			{description="8", data = 56},
			{description="9", data = 57},
		},
		default = 114, -- R key
	},

What I added to ModMain:

--Toggle swimming ability
local function WILL_SWIM (player)
	if player.WILL_SWIM and not player:HasTag("playerghost") then  --Note: I think I edited this incorrectly, and likely broke a key component of the code.
		player:WILL_SWIM(player)
	end
end

AddModRPCHandler("The Wild Child  -Ver. 1.3.4.7","WILL_SWIM ",WILL_SWIM )

SendModRPCToServer(MOD_RPC["The Wild Child  -Ver. 1.3.4.7]["WILL_SWIM "])

What I added to the character's Master_PostInIt:

inst.WILL_SWIM = WILL_SWIM  --Used to help toggle the swimming ability.

What added to the character's PreFab:

(Nothing yet)

server_log_2021-06-07-19-04-52.txt

Try to learn to read your logs, then you can solve issues you have more easily.

For example, in your log,there is these lines:

[00:00:09]: Mod: workshop-2238207705 (The Wild Child  -Ver. 1.3.4.7)	  Error loading mod!
[string "../mods/workshop-2238207705/modmain.lua"]:280: ']' expected near 'WILL_SWIM'

So line 280 in your modmain has an error, I will guess that it's this line:

SendModRPCToServer(MOD_RPC["The Wild Child  -Ver. 1.3.4.7]["WILL_SWIM "])

You forgot a " after your modname, that's probably the cause of the error.

But even if that's correct, it wouldn't work. You need to think what you want to reach with your function, what they should do.

You detect a key press, this key press sends a function to the server, this function on the server adds a tag to the person who clicked it if they have your character.

This means, you have a TheInput:AddKeyDownHandler where you send the ModRPCHandler, you write a function that the ModRPCHandler can send and that's it already.

I will help you with the AddModRPCHandler function, as you make it more complicated than it needs to be:

local function ToogleSwimming(inst)
  if inst.prefab ~= "yourcharacter" then --check if the character who called the function is your character, if not, they don't need to run this function
    return
  end
  if inst:HasTag("WILLING_TO_SWIM")  then  --if your character has the tag, remove it, otherwise add it.
    inst:RemoveTag("WILLING_TO_SWIM")
  else
    inst:AddTag("WILLING_TO_SWIM")
  end
end

AddModRPCHandler("yourmodname","ToogleSwimming",ToogleSwimming) 

--you can now call the the RPC by using

--SendModRPCToServer(MOD_RPC["yourmodname"]["ToogleSwimming"])  

You won't need anything else in the character prefab, as these things are already in the ModRPCHandler.

Edited by Monti18
forgot "
  • Like 2

Great, thanks!

I only had a little bit of time after work to type up all the code, and I guess I overlooked that.  I'm late for work now, but I fixed the error and tested it.  The server was able to load, and I could see the custom character, but the game crashed when I selected them.  I haven't been able to review the error log yet, but I'll try and fix the code tonight.server_log_2021-06-08-06-22-59.txt

Edited by FurryEskimo

@Monti18
After some extensive testing, I'm fairly certain the issue is with:

inst.ToogleSwimming = ToogleSwimming

The mod seems to crash if that code is added to the character's Mast_PostInIt.  Without that code however, nothing appears to happen at all when the key is pressed..

Ps-  Sorry for the delay, the game weirded out and deleted my entire mod, so I had to use one of my backup copies and add back in a lot of code that was deleted..

Edited by FurryEskimo

You can't add that to the master postinit, as the function ToogleSwimming is defined in the modmain and not your character prefab, so it will always crash.

I'm sorry if I wrote it confusing, you won't need to add anything to your character prefab for this to work. You can just put everything into your modmain.

Did you just copy my code? Because I saw that I also forgot a " after yourmodname, perhaps that's the reason why. You could post your mod and I can have a look at it.

  • Like 1

@Monti18
Ok, I pulled out all the mode from the character's prefab, and while the mod doesn't crash, it doesn't appear to do anything either when R is pressed.

GLOBAL.key_to_swim = GetModConfigData("key_to_swim")

local function ToogleSwimming(inst)
	if inst.prefab ~= "wildchild" then  --check if the character who called the function is your character, if not, they don't need to run this function
		return
	end
	if inst:HasTag("WILLING_TO_SWIM")  then
		print("Not willing to swim.")
		inst:RemoveTag("WILLING_TO_SWIM")
		player.components.talker:Say("I don't feellike getting wet..")
	else
		print("Willing to swim.")
		inst:AddTag("WILLING_TO_SWIM")
		player.components.talker:Say("Time for a swim!")
	end
end

AddModRPCHandler("The Wild Child  -Ver. 1.3.4.7","ToogleSwimming",ToogleSwimming)

--inst.ToogleSwimming = ToogleSwimming
{
	name = "key_to_swim",
	label = "Key to toggle Swim-Mode",
	hover = "Jump into the water, only when you want to.",
	options =
		{
			{description="A", data = 97},
			{description="B", data = 98},
			{description="C", data = 99},
			{description="D", data = 100},
			{description="E", data = 101},
			{description="F", data = 102},
			{description="G", data = 103},
			{description="H", data = 104},
			{description="I", data = 105},
			{description="J", data = 106},
			{description="K", data = 107},
			{description="L", data = 108},
			{description="M", data = 109},
			{description="N", data = 110},
			{description="O", data = 111},
			{description="P", data = 112},
			{description="Q", data = 113},
			{description="R", data = 114},
			{description="S", data = 115},
			{description="T", data = 116},
			{description="U", data = 117},
			{description="V", data = 118},
			{description="W", data = 119},
			{description="X", data = 120},
			{description="Y", data = 121},
			{description="Z", data = 122},
			{description="F1", data = 282},
			{description="F2", data = 283},
			{description="F3", data = 284},
			{description="F4", data = 285},
			{description="F5", data = 286},
			{description="F6", data = 287},
			{description="F7", data = 288},
			{description="F8", data = 289},
			{description="F9", data = 290},
			{description="F10", data = 291},
			{description="F11", data = 292},
			{description="F12", data = 293},

			{description="UP", data = 273},
			{description="DOWN", data = 274},
			{description="RIGHT", data = 275},
			{description="LEFT", data = 276},
			{description="PAGEUP", data = 280},
			{description="PAGEDOWN", data = 281},

			{description="0", data = 48},
			{description="1", data = 49},
			{description="2", data = 50},
			{description="3", data = 51},
			{description="4", data = 52},
			{description="5", data = 53},
			{description="6", data = 54},
			{description="7", data = 55},
			{description="8", data = 56},
			{description="9", data = 57},
		},
		default = 114,  --The R key
	},

I'll see what I can do about getting you access to the mod's current status.

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...