Jump to content

I need some help with my character mod


Recommended Posts

Hello everyone! I created a character mod (Popuko in the workshop) and I wanted to add a perk to her, but I really don't know how

 

If it's possible, I want her to gain a bit of sanity each time an ally gets hurt near her

 

thanks in advance!!

Link to comment
Share on other sites

The solution that comes to mind is to create an AddComponentPostInit in your modmain.lua file, modifying either Combat:GetAttacked or Health:DoDelta depending on how generous you want to be with characters getting hurt (i.e. attacked by a spider vs. eating a Red Mushroom). You can add a snippet of code that checks for nearby allied players whenever a player is attacked, and if Popuko is found, then restore some of her Sanity.

VERY, VERY rough code. Quick 10-minute thing, please look it over/modify before copy/pasting this... just an example.

AddComponentPostInit("combat", function(self)
	if not GLOBAL.TheWorld.ismastersim then 
		return end
		
    local _oldfunction = self.GetAttacked --Save existing function so you can refer to it
	
	function self:GetAttacked(attacker, damage, weapon, stimuli)
		_oldfunction (self, attacker, damage, weapon, stimuli)
      
      	if not self.inst:HasTag("player") then return end
      
		local ents = TheSim:FindEntities(x, y, z, range, { "player" }, excludetags)
		for i, ent in ipairs(ents) do
        	if ent.components.sanity ~= nil
          	and ent:HasTag("someidentifyingtaghere") --**or other method of identifying your character, could be a variable. I hear that's good practice since there's a tag limit.
          	and self.inst.components.combat:IsAlly(ent) then	-- Optional - identify if your character is an ally to the person who got attacked
        		ent.components.sanity:DoDelta (9999)
          	end
        end
	end
end)

 

Edited by ShinyMoogle
Link to comment
Share on other sites

Some pretty good code there :) If OP ends up using a tag for this, OP could just put in that tag in the FindEntities call INSTEAD of "player" to save some iterations and therefore cycles. It's minor, but I felt I had to say it. Due to the tag limit, it might be better to just add a bool variable to the player inst called iAmCharacterName and check for that. Whatever floats your boat (and works).

Edited by Ultroman
Link to comment
Share on other sites

Thank you so much for the response! I am really bad at coding, but I try my best to write some stuff for my mod

I have some questions regarding the code, they may be basic but It's simply because I don't know :?

(Correct me if I'm wrong [and please help me i'm so dumb]) So if I want Popuko to gain sanity each time a player gets hit by a monster I have to use the Combat:GetAttacked line, so in my modmain.lua I have to write:
 

AddComponentPostInit("sociopath", function(self)
	if not GLOBAL.TheWorld.ismastersim then 
		return end		
    local _oldfunction = self.GetAttacked --Save existing function so you can refer to it
	
	function self:GetAttacked(attacker, damage, weapon, stimuli)
		_oldfunction (self, attacker, damage, weapon, stimuli)
      
      	if not self.inst:HasTag("popu") then return end
      
		local ents = TheSim:FindEntities(x, y, z, range, { "popu" }, excludetags)
		for i, ent in ipairs(ents) do
        	if ent.components.sanity ~= nil
          	and ent:HasTag("popu") --**or other method of identifying your character, could be a variable. I hear that's good practice since there's a tag limit.
          	and self.inst.components.combat:IsAlly(ent) then	-- Optional - identify if your character is an ally to the person who got attacked
        		ent.components.sanity:DoDelta (5)
          	end
        end
	end
end)

Something like this?

Thank you again!

Link to comment
Share on other sites

A little bit off. I think it'll help to take a bit of a step back and take a moment to understand some of the data and functions involved.

DST offers several "PostInit" functions for mods to work with, which modify existing files in the game. AddComponentPostInit specifically modifies an existing component, which is basically a collection of common variables and functions that can be added to an entity in the game (a player, an item, a structure, etc.) These components, like combat and health, are then used when entites need to interact with each other. For example, if you want something to fight, then it needs the "combat" component. Once that has been added, then you know it will have a standard set of functions for determining target, attacking, getting attacked, etc. You can view all of these in the components folder.

An AddComponentPostInit can either modify one of these existing component functions, or add a brand new one. It takes two inputs (parameters): the name of the component, so in this case "combat", and a function to define a new component function or overwrite an existing one. You don't want to use "sociopath" because that does not exist in the game as a component. You're modifying the existing "combat" component, so that's what you should be telling AddComponentPostInit to do.

 

Still with me here? Okay!

Here specifically, we're modifying "GetAttacked", because anytime something is attacked, that function within its combat component is called. If you look into combat.lua, this handles a whole ton of stuff like calculating damage and making a target flinch and all sorts of other things. We don't want to touch all that, so we make sure to save that and call all that old stuff in our modified function. This is the "_oldfunction" snippet.

Next, we want to check if the target being attacked is a player - if not, nothing else happens. Right now, your code checks to see if the target being attacked is Popu... which is not what we want! GetAttacked will be called by the entity that is taking damage, not your character. We want to see if it's a player being attacked.

If that's true, and a player has been attacked, then we should search for any Popu players near the player that was just attacked, verify if they're allied, and then increment that player's sanity.

 

The original code I gave you is missing some variable declarations, but should be roughly correct as far as the internal logic flow goes. Here's what it'll look like cleaned up a bit:

I left the range variable unassigned here. It's called in TheSim:FindEntities, which will look for all entities fulfilling certain conditions (in this case, being Popuko) within range of a certain point (here, anything that gets attacked). Play around with the value until you find something you're satisfied with. This is the required maximum distance a player can be from Popu for her to gain sanity when the player is hurt.

AddComponentPostInit("combat", function(self)
	if not GLOBAL.TheWorld.ismastersim then 
		return end
		
    local _oldfunction = self.GetAttacked --Save existing function so you can refer to it
	
	function self:GetAttacked(attacker, damage, weapon, stimuli)
		_oldfunction (self, attacker, damage, weapon, stimuli)
      
		if not self.inst:HasTag("player") then return end
      
		local x, y, z = self.inst.Transform:GetWorldPosition()
      
		local ents = TheSim:FindEntities(x, y, z, range, { "popu" }, nil)
		for i, ent in ipairs(ents) do
        	if ent.components.sanity ~= nil
          	and self.inst.components.combat:IsAlly(ent) then
        		ent.components.sanity:DoDelta (5)
          	end
        end
	end
end)

 

Edited by ShinyMoogle
Link to comment
Share on other sites

OH! I now understand the code a bit better, many many thanks

I have a bit of a problem now I think, so, I changed the target = ____ into 10, to see more or less if the AoE was big enough (but not so big), I tried to copy and use the code in modmain.lua and even though it didn't crash, It didn't seem to be working so I thought "Maybe I have to use it inside popuko.lua, since every other perk is in there" but when I use it in there, I open the game and host, the character select pops up for a second and the game closes, not even a crash report so I don't really know what i'm doing wrong

Link to comment
Share on other sites

PrefabPostInits do go in modmain.lua, you got that correct. Remember that the code is specifically for when a fellow player gets hurt, so you won't be seeing the effects unless you're in multiplayer.

For testing purposes, you can remove/comment out:

if not self.inst:HasTag("player") then return end

And in the FindEntities function:

and self.inst.components.combat:IsAlly(ent) 

which will remove the tests to see if the entity that got attacked is a player or ally. That should allow sanity restoration whenever anything in range gets attacked.

Edited by ShinyMoogle
Link to comment
Share on other sites

Ok, i did put it in modmain.lua and comented out

if not self.inst:HasTag("player") then return end

and

and self.inst.components.combat:IsAlly(ent) 

but nothing happens, i lured a pigman to fight spiders but it didnt give me any sanity (maybe the radius is small?)

Here's my modmain.lua, maybe i'm doing something wrong?

modmain.lua

Link to comment
Share on other sites

Ok! I did it and it works!! every time something is hit on screen she gains sanity!

Now I'm going to test it with a friend to tune the radius

 

THANK YOU SO MUCH!!

Edit: I tested with a pigman fighting a bunch of spiders and works fine commenting out the parts of the code but with a friend without removing

if not self.inst:HasTag("player") then return end

and

and self.inst.components.combat:IsAlly(ent) 

it doesnt work (It doesn't crash, my friend gets hit but Popuko doen't gain sanity)

Would it work if I exchange "and self.inst.components.combat:IsAlly(ent)" maybe for this one "and HasTag("player")" , would it target any player?

Edited by ismakenji
Link to comment
Share on other sites

It would target any player in that case, yes. Hm... Do you have PvP turned on? If you do, you can leave out "and self.inst.components.combat:IsAlly(ent)". I guess you might have it on if the perk is for when other players get hurt.

Combat:IsAlly is a function for checking to see if a particular entity is friendly to the entity calling it (here that is the thing getting attacked). One of those conditions is that both the checker and the entity in question are players and PvP is off. If PvP is on, then it'll return false and you won't get Sanity restoration.

Edited by ShinyMoogle
Link to comment
Share on other sites

Oh wait no, I misspoke! I meant it would return true for any player, but FindEntities would still only search Popuko players. You can leave that out of the for loop. Won't do anything bad specifically, just extra code that the game will run that doesn't need to be run.

Edited by ShinyMoogle
Link to comment
Share on other sites

Great! I'm glad I could help!

I forgot the code might make Popuko give herself Sanity. You can try something like this to exclude the player getting hit. This will prevent the entity calling Combat:GetAttacked from being considered for Sanity restoration.

for i, ent in ipairs(ents) do
	if self.inst ~= ent
	and ent.components.sanity ~= nil then
		ent.components.sanity:DoDelta (5)
end

 

Minor confession - I think I misremembered Combat:IsAlly(guy) since it doesn't actually check if the target is a player. It's more for checking leader/follower associations. Oops.

Edited by ShinyMoogle
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...