Jump to content

Recommended Posts

Hi there, I'm working on a character mod and I'm trying to make it non-stunlockable under certain circumstance. I gave it a try and got an error. Would you please point out what went wrong with my code? Thanks!

Part of the character.lua: (I referred to combat.lua for this stunlock code)

Spoiler

local function bskns(inst, attacker)
    if inst.components.health.currenthealth > 0 then
    attacker.components.combat:SetPlayerStunlock(PLAYERSTUNLOCK.NEVER)
    end
end

    inst:ListenForEvent("attacked",bskns)

These are the mod file and the server log file. This mod works just fine before this non-stunlockable stuff.

server_log.txt

 

 

Part of the server log:

Spoiler

[00:00:51]: [string "../mods/hisoka 3-9 non_stun/scripts/prefabs..."]:59: attempt to index field 'components' (a nil value)
LUA ERROR stack traceback:
../mods/hisoka 3-9 non_stun/scripts/prefabs/hisoka.lua:59 in (local) fn (Lua) <57-61>
   inst = 123462 - hisoka (valid:true)
   attacker = table: 0CADD980
scripts/entityscript.lua:1035 in (method) PushEvent (Lua) <1022-1049>
   self (valid:true) =
      DynamicShadow = DynamicShadow (375A5830)
      inlimbo = false
      GetMoistureRateScale = function - scripts/prefabs/player_common.lua:146
      SetCameraDistance = function - scripts/prefabs/player_common.lua:954
      ScreenFlash = function - scripts/prefabs/player_common.lua:1016
      player_classified = 123463 - player_classified (valid:true)
      playercolour = table: 091AAD90
      vitality = 413
      ShowWardrobePopUp = function - scripts/prefabs/player_common.lua:942
      Light = Light (375A58B0)
      _isrezattuned = false
      OnRemoveEntity = function - scripts/prefabs/player_common.lua:630
      pendingtasks = table: 07AE5218
      ShowHUD = function - scripts/prefabs/player_common.lua:936
      ShowGiftItemPopUp = function - scripts/prefabs/player_common.lua:948
      sg = sg="wilson", state="idle", time=0.47, tags = "idle,canrotate,"
      IsHUDVisible = function - scripts/prefabs/player_common.lua:926
      ApplyScale = function - scripts/prefabs/player_common.lua:1031
      SetGhostMode = function - scripts/prefabs/player_common.lua:543
      ShowActions = function - scripts/prefabs/player_common.lua:930
      OnWakeUp = function - scripts/prefabs/player_common.lua:803
      Transform = Transform (375A5610)
      actionreplica = table: 07AE49F8
      event_listening = table: 07AE54E8
      actioncomponents = table: 07AE49D0
      lower_components_shadow = table: 07AE4CC8
      GetMaxMoisture = function - scripts/prefabs/player_common.lua:136
      class_B = 1
      CanUseTouchStone = function - scripts/prefabs/player_common.lua:86
      updatecomponents = table: 08B150E0
      ShakeCamera = function - scripts/prefabs/player_common.lua:974
      OnDespawn = function - scripts/prefabs/player_common.lua:825
      persists = false
      MiniMapEntity = MiniMapEntity (375A5930)
      IsFreezing = function - scripts/prefabs/player_common.lua:106
      _OnLoad = function - ../mods/hisoka 3-9 non_stun/scripts/prefabs/hisoka.lua:26
      replica = table: 07AE4A20
      GetTemperature = function - scripts/prefabs/player_common.lua:96
      GUID = 123462
      ghostenabled = false
      EnableMovementPrediction = function - scripts/prefabs/player_common.lua:499
      worldstatewatching = table: 08B138F8
      SetCameraZoomed = function - scripts/prefabs/player_common.lua:960
      speed = 222
      Network = Network (375A5710)
      GetMoisture = function - scripts/prefabs/player_common.lua:126
      OnPreLoad = function - scripts/prefabs/player_common.lua:704
      LightWatcher = LightWatcher (375A5630)
      inherentactions = table: 1AA5C4E8
      spawntime = 0.13333334028721
      dychealthbar = 123556 - dyc_healthbar (valid:true)
      combat = false
      SnapCamera = function - scripts/prefabs/player_common.lua:966
      name = Nick
      _OnSave = function - ../mods/hisoka 3-9 non_stun/scripts/prefabs/hisoka.lua:273
      prefab = hisoka
      point = 21
      _OnPreLoad = function - ../mods/hisoka 3-9 non_stun/scripts/prefabs/hisoka.lua:207
      class_D = 3
      ScreenFade = function - scripts/prefabs/player_common.lua:1007
      OnSleepIn = function - scripts/prefabs/player_common.lua:775
      OnSave = function - scripts/prefabs/player_common.lua:678
      GetSandstormLevel = function - scripts/prefabs/player_common.lua:156
      OnLoad = function - scripts/prefabs/player_common.lua:714
      entity = Entity (08C80C48)
      ggtm = 3
      children = table: 0CFD4EE8
      IsCarefulWalking = function - scripts/prefabs/player_common.lua:160
      intelligence = 107
      AttachClassified = function - scripts/prefabs/player_common.lua:619
      strength = 426
      IsActionsVisible = function - scripts
[00:00:51]: [string "../mods/hisoka 3-9 non_stun/scripts/prefabs..."]:59: attempt to index field 'components' (a nil value)
LUA ERROR stack traceback:
    ../mods/hisoka 3-9 non_stun/scripts/prefabs/hisoka.lua:59 in (local) fn (Lua) <57-61>
    scripts/entityscript.lua:1035 in (method) PushEvent (Lua) <1022-1049>
    scripts/components/combat.lua:463 in () ? (Lua) <405-480>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/components/combat.lua:844 in (method) DoAttack (Lua) <794-868>
    scripts/stategraphs/SGBeefalo.lua:465 in (field) fn (Lua) <465-465>
    scripts/stategraph.lua:568 in (method) UpdateState (Lua) <536-580>
    scripts/stategraph.lua:607 in (method) Update (Lua) <599-627>
    scripts/stategraph.lua:125 in (method) Update (Lua) <109-148>
    scripts/update.lua:218 in () ? (Lua) <149-228>

 

Regards,

Edited by nicknightyx

The problem with ListenForEvents is they activate after the event has happened. In this case your character was already hit and stunned, to properly do this you'll have to do a component override for combat:GetAttacked.

--The basic premise is like this. Used in modmain.lua
AddComponentPostInit("combat", function(self)
	local oldGetAttacked = self.GetAttacked
	function self:GetAttacked(attacker, damage, weapon, stimuli)
		if self.inst.prefab == "yourchar" then
			--do something here
		end
		return oldGetAttacked(self, attacker, damage, weapon, stimuli)	
	end
end)

The Second problem is this doesn't really work against damage sources lacking the combat component. e.g. explosives, this will cause a crash.

A third problem is your code permanently sets the stunlock to never on the enemy that hits you. You'll likely want to revert it back after you are hit, as this can be wierd with multiple players.

Depending on whether you want to retain the hit animations or not, there are a few ways for you to experiment with this, one simple solution is to just blank the hit and make a fake hit with health:DoDelta and making your character play the state, instead.

Alternatively you could make a custom eventhandler copy of the "Attacked" event with modified code regarding the stunlock, then rebuild a custom getattacked function that pushes this event for your character, and return the original for any character but yourself.

There are a lot of ways to go about programming this depending on how deep you want to modify things.

Hope this helps, I don't have time right now to tinker.

Cheers,

Iron_Hunter

 

 

13 hours ago, IronHunter said:

Iron_Hunter

Thanks a ton! You don't have to tinker anything right now, I have some plain questions for you instead XD.

1. Since I'm learning coding, I want to really understand your code, would you kindly explain something to me please?

(i) The "AddComponentPostInit("combat", function(self)" is adding a component called "combat" not having to create another combat.lua under the component folder, right? But what does the "self" mean? Does it mean this component specifically works for myself? I have seen "inst:DoPeriodicTask(5,function()", so what's the difference between them?

(ii) The "self" appeared 4 times, "self.GetAttacked", "function self", "self.inst.prefab", "return oldGetAttacked(self..." would you please tell me what do they mean respectively?

(iii) Lastly, why do we want to "return oldGetAttacked" ?

2. And for the second problem you mentioned, is there any way that we can fix it? Because even if I steer clear of gun powder it's pretty tough to avoid the meteorites and falling rocks in cave. Maybe something like "if not attacker.prefab == rocks then [do something] end" ? Do you think it would work?

3. For the third problem, were you saying that for example one spider hit me and I wasn't stunlocked when some requirements were met then all other spider will no longer stunlock me or other players even when those requirements are not met? Well this is really serious, I'm thinking if we can just skip the stunlock animation or "stategraph" of my character so that it can move freely when it's taking damage. Can you help?

4. What do you mean by retaining the hit animation? If I understood you correctly, the hit animation is exactly what I want to get rid of. Now that you see what I'm really trying to do here, maybe you know some more efficient ways to get there?

Really appreciate you answering some newbies like myself. God bless you.

Spoiler
28 minutes ago, nicknightyx said:

 

Thanks a ton! You don't have to tinker anything right now, I have some plain questions for you instead XD.

1. Since I'm learning coding, I want to really understand your code, would you kindly explain something to me please?

(i) The "AddComponentPostInit("combat", function(self)" is adding a component called "combat" not having to create another combat.lua under the component folder, right? But what does the "self" mean? Does it mean this component specifically works for myself? I have seen "inst:DoPeriodicTask(5,function()", so what's the difference between them?

(ii) The "self" appeared 4 times, "self.GetAttacked", "function self", "self.inst.prefab", "return oldGetAttacked(self..." would you please tell me what do they mean respectively?

(iii) Lastly, why do we want to "return oldGetAttacked" ?

2. And for the second problem you mentioned, is there any way that we can fix it? Because even if I steer clear of gun powder it's pretty tough to avoid the meteorites and falling rocks in cave. Maybe something like "if not attacker.prefab == rocks then [do something] end" ? Do you think it would work?

3. For the third problem, were you saying that for example one spider hit me and I wasn't stunlocked when some requirements were met then all other spider will no longer stunlock me or other players even when those requirements are not met? Well this is really serious, I'm thinking if we can just skip the stunlock animation or "stategraph" of my character so that it can move freely when it's taking damage. Can you help?

4. What do you mean by retaining the hit animation? If I understood you correctly, the hit animation is exactly what I want to get rid of. Now that you see what I'm really trying to do here, maybe you know some more efficient ways to get there?

Really appreciate you answering some newbies like myself. God bless you.

1(i)

Spoiler

AddComponentPostInit is a function in modutil.lua that runs a function when the chosen component is defined. Allowing you to inject or modify the component.

Self is the variable in the function we made that is passed the self variable from the combat component by default. It simply refers to the self aspect of the component. If you look at the component combat, you'll see it defines stuff as self.variablename, self can be actually anything as long as you call the variables using the same variable.

Inst:DoPeridicTask is refering to inst variable of the created entity, inst is just the name that is commonly used amongst the prefabs.

These variables act as pointers pointing at specific code for their respective files.

1(ii)

Spoiler

self.GetAttacked refers to the Getattacked function inside the combat component. We first call this to store a pointer variable to the old version of the getattacked.

function(self), is just used as a variable name to maintain conformity with the components variable name. It makes it easier to infer what it does, from the combat component.

self.inst.prefab, self.inst refers to the inst that has this component. When you AddComponent("combat") which is enabled by default for custom characters, it'll automatically assign self.inst to your character. This is again another pointer variable for easy access to data. .prefab part of this returns the prefab of self.inst for example self.inst.prefab where self.inst == wilson will return wilson.

1(iii)

Spoiler

the return oldgetAttacked is important for compatibility with other entities that use the combat component. If the if statement fails we return the oldgetattacked function which we saved a pointer variable for.

2

Spoiler

Instead of trying to change the stunlock of sources of damage, instead just change how your character handles being stunned. It is probably easier for you to make a modified copy of the getattacked function and return the old one for anything but yourself. This modified function will instead pushevent for a modified/custom eventhandler("attacked")

3

Spoiler

The problem is very noticeable against tough enemies that can easily hit multiple players, like deerclops. After he hits you he would never stunlock any other player, not just your character. If you desire that route, then you would have to do some clever hack to revert the effect before getattacked is called for other players. It'll likely have sync issues too.

4

Spoiler

If you don't care about hit animation or you don't care about being frozen in one spot after being hit?

If its the former you could just make a modified copy of getattacked that doesn't push the event "attacked", as that is what handles the animations and stunlock simultaneously.

If you prefer keeping animations but want to get rid of the frozen in one spot after being hit, because getting struck by lightning etc, then you just need to make a custom modified event handler without the stunlock portion of code. That is pushed by your custom getattacked function, instead of the old one.

Learning how to inject but not overide code is pretty important for anything but the simplest mods.

It maintains compatibility with other mods better and has less conflict.

If you have any other questions I'll do what I can to answer them.

Sorry for the wall of text, I could go into more detail if needed.

Cheers,

Iron_Hunter

 

2 hours ago, IronHunter said:

Iron_Hunter

Thanks again! I'm kind of getting your code now.

I added some conditions to the non-stunlockable code and tested it and it worked! Maybe I'm too excited but I now don't think the two problems are that big deal which are: for other players that won't be stunlocked by the enemies that has hit me and for the game will crash if I am hurt by explosives, I think I can just live with that. And I would like to retain the frozen stun and lightning stun.

Let me test if the temperature damage and monster meat damage would crash the game.

Regards,

Nick

On 3/5/2018 at 5:29 PM, IronHunter said:

Iron_Hunter

Hi Iron_Hunter,

I have another piece of code that I don't get. Would you please take a look at it? Thanks!

Spoiler

[modmain.lua]

function combat(inst)

inst.writing = false
local x,y,z = inst.Transform:GetWorldPosition()
local ents = TheSim:FindEntities(x,y,z, 1, {"_writeable"})
for k,v in pairs(ents) do
inst.writing = true
end 

if not inst.writing then 

blablabla

end

end

AddModRPCHandler("hisoka", "combat", combat)

I especially don't understand the inst.writing part, is it necessary? What does it do?

Regards,

Nick

Edited by nicknightyx
3 minutes ago, nicknightyx said:

Hi Iron_Hunter,

I have another piece of code that I don't get. Would you please take a look at it? Thanks!

  Hide contents

[modmain.lua]

function combat(inst)

inst.writing = false
local x,y,z = inst.Transform:GetWorldPosition()
local ents = TheSim:FindEntities(x,y,z, 1, {"_writeable"})
for k,v in pairs(ents) do
inst.writing = true
end 

if not inst.writing then 

blablabla

end

end

AddModRPCHandler("hisoka", "combat", combat)

I especially don't understand the inst.writing part, is it necessary? What does it do?

Regards,

Nick

Inst.writing is a variable on a entity inst. I don't know what the context of this code snippet is suppose to do. It seems really inefficient checking for all entities within 1 unit of inst position that have the "_writing" tag only to set the variable true afterward.

Could you give me more info what this is suppose to accomplish. Either link the source mod or describe it etc.

Cheers,

Iron_Hunter

4 minutes ago, IronHunter said:

Cheers,

Iron_Hunter

I got this code originally from a mod called "Musha", because I don't understand the inst.writing part, I copy it into my mod every time I want to use " inst.components.keyhandler:AddActionListener("hisoka", TUNING.HISOKA.KEY3, "combat") " in case it's important.

modmain.lua  hisoka.lua

Thanks,

3 minutes ago, nicknightyx said:

I got this code originally from a mod called "Musha", because I don't understand the inst.writing part, I copy it into my mod every time I want to use " inst.components.keyhandler:AddActionListener("hisoka", TUNING.HISOKA.KEY3, "combat") " in case it's important.

modmain.lua  hisoka.lua

Thanks,

When I get some free time I'll take a look into this.

Cheers,

Iron_Hunter

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...