Jump to content

[ Solved ] External Damage Taken Multiplier code help.


Recommended Posts

Hey, its me again.

So, I'm now working on the 'Monstrous!' update to Wanon's mod. To do this, I'm using this code in order to pull in builds. Both forms have completed art and are loading properly into the game upon certain conditions met.

As of now, all important components of this update are complete. The final thing I'm doing is adding a bit of pizzazz to the mod to make it feel extra special. Thank you to everyone who helped me for this update! You're all wonderful!!

Things that are currently working:
Art for both forms 100% complete
He 'transforms' to Fearsome at 50% sanity. Damage modifier works.
He 'transforms' from Fearsome to Monstrous at 5% sanity. Damage modifier works.
Adds 'monster' and 'playermonster' tags at 5% sanity. Removes at above 50%.
Fire-Pit fuel sound plays upon all three transformations
Animation plays upon all three transformations
Combat coding for increasing damage-taken multiplier is done (Thank you penguin0616!!!)

Things that I am currently working on:
Sanity Auras (Currently preparing to update current version of mod on Workshop to test this)

Not yet implemented in the code/tested:
-- For the third form specifically, removing his usual speech file and adding a pool of ~10 random garbled messages that will be used when inspecting any item/announcing any event. (This isn't 100% necessary, but I feel it makes the mod more interesting and adds a level of challenge to playing him while insane)



I attached warlock.lua to this post, will always update it once I have a 'current' version upon each major update.

I'm open to any and all suggestions, since maybe I'm using faulty code or there's insight into a better set sanity than what I have him at.

All of this is outside of master_postinit and common_postinit, and I'll post the code here as well just in case you don't want to do:wnload

Spoiler

------- This is for the Sanity Transformations --------
local currentForm = nil

-- logic consistent across all forms
local forms = {
	normal = {
		damage_multiplier = 1.05,
		external_damage_taken_multiplier = 1
	},
	fearsome = {
		damage_multiplier = 1.15,
		external_damage_taken_multiplier = 1.10
	},
	monstrous = {
		damage_multiplier = 1.20,
		external_damage_taken_multiplier = 1.15
	}
}

local function SetForm(inst, str)
	assert(forms[str], "Trying to SetForm with invalid name.")
	currentForm = str
	
	local data = forms[currentForm]
	inst.components.combat.damagemultiplier = data.damage_multiplier
	inst.components.combat.externaldamagetakenmultipliers:SetModifier(inst, data.external_damage_taken_multiplier)
	
	-- specialized logic per form, could put it in the form table above but too complex for this example
	if currentForm == "normal" then
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	elseif currentForm == "fearsome" then
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	elseif currentForm == "monstrous" then
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	end
end

local function OnSanityDrop(inst, data)
	-- Make sure not to react while the player is dead.
    if inst:HasTag("playerghost") or inst.components.health and inst.components.health:IsDead() then
        return
    end
	
	if currentForm == "normal" and inst.components.sanity.current < 50 then
		SetForm(inst, "fearsome")
		inst.AnimState:SetBuild("warlock_fearsome")
	elseif currentForm == "fearsome" and inst.components.sanity.current < 5 then
		SetForm(inst, "monstrous")
		inst:AddTag("monster")
		inst:AddTag("playermonster")
		inst.AnimState:SetBuild("warlock_monstrous")
	elseif currentForm == "fearsome" and inst.components.sanity.current > 50 then
		SetForm(inst, "normal")
		inst.AnimState:SetBuild("warlock")
	elseif currentForm == "monstrous" and inst.components.sanity.current > 50 then
		SetForm(inst, "normal")
		inst.AnimState:SetBuild("warlock")
	end
	-- removes the unwanted tags
	if inst.components.sanity.current > 50 then
	inst:RemoveTag("monster")
	inst:RemoveTag("playermonster")
	end
	
end

local function sanityaurafn(inst, observer)
    -- Create a temporary variable with the current value, so we don't call GetPercent() a million times.
    local currentSanity = inst.components.sanity:GetPercent()
    
    if currentSanity > 0.5 then
		return
	elseif currentSanity < 0.05 then
        return -TUNING.SANITYAURA_LARGE
    elseif currentSanity < 0.5 then
        return -TUNING.SANITYAURA_MED
    end
end

 




 

 

 

 

 

 

 

 

 

 

warlock.lua

Edited by WesisBless
Updating current info as not to flood this thread with various this and thats.
Link to comment
Share on other sites

So I was able to fix the above error by removing the 'add tags' code for the third form, and I tweaked a few things... but now he flickers between the sprite for his third form and the sprite for his second... this has been an interesting journey so far.

No longer relevant, have edited title to reflect current needed help.

Edited by WesisBless
Removed out of date information.
Link to comment
Share on other sites

This is likely 100% an instance of me having no idea what I'm doing but trying to learn. I've been toying around with some of the combat components to take more damage when in his Fearsome/Monstrous forms... but I'm really struggling out in this sea on my own. Here's what's currently going on, because I'm going to take a break from this for a little bit to clear my head.
The code in question:

local function Combat:CalcDamage(target, weapon, multiplier)
	local externaldamagetakenmultipliers = self.externaldamagetakenmultipliers
	if not isInSecondForm or not isInThirdForm then
	return
	elseif isInSecondForm then
	inst.components.combat.externaldamagetakenmultipliers = 1.10
	elseif isInThirdForm then
	inst.components.combat.externaldamagetakenmultipliers = 1.15
	end
end

What happened after I utilized it:2039474108_Screenshot2020-11-10164012.thumb.png.c0d4a7f87e76645338bd8e0ced05a777.png
So I'm certain I'm just doing something very, very wrong. I'm attaching a to-date version of the warlock.lua as well, along with updating what is in the original post for this so people aren't confused by my scatterbrained attempt at coding this mod.

Link to comment
Share on other sites

Colons are lua shorthand for methods and they require the thing before the colon to already exist.

Inside a prefab file, the game won't have loaded components/combat.lua unless you specifically tell it to do so.

Running a simple require "components/combat.lua" at the top should fix it. I think modimport should as well, but I'm not that versed in Lua hierarchy.

  • Like 1
Link to comment
Share on other sites

12 hours ago, penguin0616 said:

#2: Deal with the externaldamagetakenmultiplier in your transformer.

So I have tried a few things, but it really doesn't like the 'self' part of the external damage multiplier code and I don't know how to mess with it appropriately to get it to work right. I have tried a workaround that someone else was doing for another mod but the way they coded it was not agreeing with my code either and caused crash after crash, I'm not well-versed enough to clean it up. Anyways, I'll show you what I've got as of right now while I go combing through the forms for any other clues on what to do here.
 

Spoiler

local isInSecondForm = false
local isInThirdForm = false
local externaldamagetakenmultipliers = self.externaldamagetakenmultipliers

local function TurnBackToNormal(inst)
	inst.components.combat.damagemultiplier = 1.05
	inst.components.combat.externaldamagetakenmultipliers = 1
	inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
    inst.AnimState:SetBuild("warlock")
	SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
    isInSecondForm = false
	isInThirdForm = false
end

local function TurnIntoSecondForm(inst)
    inst.components.combat.damagemultiplier = 1.15
	inst.components.combat.externaldamagetakenmultipliers = 1.10
    inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
    inst.AnimState:SetBuild("warlock_fearsome")
	SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
    isInSecondForm = true
end

local function TurnIntoThirdForm(inst)
    inst.components.combat.damagemultiplier = 1.20
	inst.components.combat.externaldamagetakenmultipliers = 1.15
	inst:AddTag("monster")
	inst:AddTag("playermonster")
    inst.AnimState:SetBuild("warlock_monstrous")
    isInThirdForm = true
end

local function OnSanityDrop(inst, data)
    -- Make sure not to react while the player is dead.
    if inst:HasTag("playerghost") or inst.components.health and inst.components.health:IsDead() then
        return
    end
    -- If sanity drops below 50, become the second form.
    if not isInSecondForm and inst.components.sanity.current < 50 then  
        TurnIntoSecondForm(inst)
    -- This should enter 'monsterous' stage.
    elseif isInSecondForm and inst.components.sanity.current < 5 then
        TurnIntoThirdForm(inst)
    -- This should turn me back into normal, I hope.
    elseif isInSecondForm and inst.components.sanity.current > 50 then
        TurnBackToNormal(inst)
    end
	-- removes the unwanted tags
	if inst.components.sanity.current > 50 then
	inst:RemoveTag("monster")
	inst:RemoveTag("playermonster")
	end
	
end

 

Sorry for my messy hodge-podge of code, I wish I was better adapted so I could clean this up nice and neat. Someone else was suggesting something like it'd "be easier to have the state of each form in a single variable so you don't have to reset each one but just replace one" but I have no clue how to do that since I'm following someone else's code for this save having shoved a third form into it. That same person also said "also you should probably have the change in form function happen when you load in or something so it can apply the form when you join" which I wasn't sure what they were meaning by that and if it is better than what I have right now.

Link to comment
Share on other sites

Quote

local externaldamagetakenmultipliers = self.externaldamagetakenmultipliers

That would error because there is no "self" to reference. You can get rid of that line entirely, since it doesn't really help you.

2 hours ago, WesisBless said:

Someone else was suggesting something like it'd "be easier to have the state of each form in a single variable so you don't have to reset each one but just replace one"

Not completely sure what they meant, but this is roughly the approach I would take (and I believe is what they meant).

local currentForm = nil

-- logic consistent across all forms
local forms = {
	normal = {
		damage_multiplier = 1.05,
		external_damage_taken_multiplier = 1
	},
	second = {
		damage_multiplier = 1.15,
		external_damage_taken_multiplier = 1.10
	},
	third = {
		damage_multiplier = 1.20,
		external_damage_taken_multiplier = 1.15
	}
}

local function SetForm(inst, str)
	assert(forms[str], "Trying to SetForm with invalid name.")
	currentForm = str
	
	local data = forms[currentForm]
	inst.components.combat.damagemultiplier = data.damage_multiplier
	inst.components.combat.externaldamagetakenmultiplier = data.external_damage_taken_multiplier
	
	-- specialized logic per form, could put it in the form table above but too complex for this example
	if currentForm == "normal" then
		-- blah
	elseif currentForm == "second" then
		-- blah
	elseif currentForm == "third" then
		-- blah
	end
end

local function OnSanityDrop(inst, data)
	-- blah
	
	if currentForm == "SOMETHING" and inst.components.sanity.current < SOMETHING then
		SetForm(inst, "SOMETHING")
	end
	
	-- blah
end

 

Edited by penguin0616
  • Like 1
  • Big Ups 1
Link to comment
Share on other sites

24 minutes ago, penguin0616 said:

local forms = { normal = { damage_multiplier = 1.05 external_damage_taken_multiplier = 1 }, second = { damage_multiplier = 1.15, external_damage_taken_multiplier = 1.10 }, third = { damage_multiplier = 1.20, external_damage_taken_multiplier = 1.15 } }

This whole thing looks so much better, and I'm going to implement it myself, however when I went to test and see if I modified everything correctly it yelled at me about the normal = { line.
Here's the crash screen:636319909_Screenshot2020-11-1174829472234.thumb.png.159963799a9af166a984dbaad96c0f16.png
And just so you can look and see my attempt at adding what I wanted and making sure things are where they should go:
 

------- This is for the Sanity Transformations --------
local currentForm = nil

-- logic consistent across all forms
local forms = {
	normal = {
		damage_multiplier = 1.05
		external_damage_taken_multiplier = 1
	},
	fearsome = {
		damage_multiplier = 1.15,
		external_damage_taken_multiplier = 1.10
	},
	monstrous = {
		damage_multiplier = 1.20,
		external_damage_taken_multiplier = 1.15
	}
}

local function SetForm(inst, str)
	assert(forms[str], "Trying to SetForm with invalid name.")
	currentForm = str
	
	local data = forms[currentForm]
	inst.components.combat.damagemultiplier = data.damage_multiplier
	inst.components.combat.externaldamagetakenmultiplier = data.external_damage_taken_multiplier
	
	-- specialized logic per form, could put it in the form table above but too complex for this example
	if currentForm == "normal" then
		inst.AnimState:SetBuild("warlock")
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	elseif currentForm == "fearsome" then
		inst.AnimState:SetBuild("warlock_fearsome")
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	elseif currentForm == "monstrous" then
		inst.AnimState:SetBuild("warlock_monstrous")
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	end
end

local function OnSanityDrop(inst, data)
	-- blah
	
	if currentForm == "normal" and inst.components.sanity.current < 50 then
		SetForm(inst, "fearsome")
	elseif currentForm == "fearsome" and inst.components.sanity.current < 5 then
		SetForm(inst, "monstrous")
		inst:AddTag("monster")
		inst:AddTag("playermonster")
	elseif currentForm == "monstrous" and inst.components.sanity.current > 50 then
		SetForm(inst, "normal")
	end
	-- removes the unwanted tags
	if inst.components.sanity.current > 50 then
	inst:RemoveTag("monster")
	inst:RemoveTag("playermonster")
	
end

 

Link to comment
Share on other sites

2 minutes ago, penguin0616 said:

You forgot the comma after 1.05

Oh! Hahaha! It's always little things like that, isn't it? Thanks, I would have gone half mad before noticing that.

Good news: No crashes!
Bad news: Seems entering different sanity levels doesn't cause the form shift, I've moved the 'AnimState:SetBuild' to happen on the sanity drop instead of being in the specialized strings and that didn't change anything. I do have this in master_postinit:
 

-- Listen for sanity drop for transformation
	inst:ListenForEvent("sanitydelta", OnSanityDrop)

I'm going to mess around and see if I can't figure it on my own, but just in case you might figure it out before I do I'll post it here anyways.

warlock.lua

Link to comment
Share on other sites

I'm not sure about dealing with animations, but glancing over your code reveals an issue with sanityaurafn.

Since you check currentSanity < 0.5 before < 0.05, it will never reach -TUNING.SANITYAURA_LARGE

You'll want to revise your if-statement order.

For debugging your failed transformations, I suggest you put prints at each point of the process to see where it fails at. Hasn't failed me yet.

  • Like 1
Link to comment
Share on other sites

7 minutes ago, penguin0616 said:

glancing over your code reveals an issue with sanityaurafn.

Fixed it, thanks! I was hoping someone would double-check that for me since I won't be able to test it reliably until I make this thing live to test the multiplayer aspects.
As for testing the transformations, could you elaborate on what you mean by 'prints'? I haven't heard that term used yet so I don't know what it means, hah!

Link to comment
Share on other sites

4 minutes ago, WesisBless said:

As for testing the transformations, could you elaborate on what you mean by 'prints'?

The function print, built-in to Lua. 

Takes any number of arguments, concatenates them as a string, and displays the result.

https://www.lua.org/pil/5.1.html

Adding more than one print means you can call them prints.

  • Like 1
Link to comment
Share on other sites

I'm really thankful for your patience with me, since I'm really still quite new to this. Just to make sure that I'm utilizing the prints correctly, this is what I've got in the code:
 

local currentForm = nil
print("currentForm was called")
-- logic consistent across all forms
local forms = {
	normal = {
		damage_multiplier = 1.05,
		external_damage_taken_multiplier = 1
	},
	fearsome = {
		damage_multiplier = 1.15,
		external_damage_taken_multiplier = 1.10
	},
	monstrous = {
		damage_multiplier = 1.20,
		external_damage_taken_multiplier = 1.15
	}
}

local function SetForm(inst, str)
	assert(forms[str], "Trying to SetForm with invalid name.")
	currentForm = str
	
	local data = forms[currentForm]
	inst.components.combat.damagemultiplier = data.damage_multiplier
	inst.components.combat.externaldamagetakenmultiplier = data.external_damage_taken_multiplier
	
	-- specialized logic per form, could put it in the form table above but too complex for this example
	if currentForm == "normal" then
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	elseif currentForm == "fearsome" then
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	elseif currentForm == "monstrous" then
		inst.SoundEmitter:PlaySound("dontstarve/common/fireAddFuel")
		SpawnPrefab("poopcloud").Transform:SetPosition(inst.Transform:GetWorldPosition())
	end
print("SetForm was called")
end

local function OnSanityDrop(inst, data)
	-- Make sure not to react while the player is dead.
    if inst:HasTag("playerghost") or inst.components.health and inst.components.health:IsDead() then
        return
    end
	
	if currentForm == "normal" and inst.components.sanity.current < 50 then
		SetForm(inst, "fearsome")
		inst.AnimState:SetBuild("warlock_fearsome")
	elseif currentForm == "fearsome" and inst.components.sanity.current < 5 then
		SetForm(inst, "monstrous")
		inst:AddTag("monster")
		inst:AddTag("playermonster")
		inst.AnimState:SetBuild("warlock_monstrous")
	elseif currentForm == "monstrous" and inst.components.sanity.current > 50 then
		SetForm(inst, "normal")
		inst.AnimState:SetBuild("warlock")
	end
	-- removes the unwanted tags
	if inst.components.sanity.current > 50 then
	inst:RemoveTag("monster")
	inst:RemoveTag("playermonster")
	end
print("OnSanityDrop was called")
end

I can tell you with certainty that 'On sanity drop' was called. A lot. The Client Log is full of it.
Please correct me if I'm doing this wrong, I'm always ready to learn what I'm doing wrong!
 

client_log.txt

Link to comment
Share on other sites

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
 Share

×
  • Create New...