ismakenji Posted March 21, 2019 Share Posted March 21, 2019 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 More sharing options...
ShinyMoogle Posted March 23, 2019 Share Posted March 23, 2019 (edited) 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 March 23, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
Ultroman Posted March 23, 2019 Share Posted March 23, 2019 (edited) 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 March 23, 2019 by Ultroman Link to comment Share on other sites More sharing options...
ShinyMoogle Posted March 23, 2019 Share Posted March 23, 2019 Good catch on the tag search - I'm all in favor of trimming down redundant operations! Link to comment Share on other sites More sharing options...
ismakenji Posted March 23, 2019 Author Share Posted March 23, 2019 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 More sharing options...
ShinyMoogle Posted March 23, 2019 Share Posted March 23, 2019 (edited) 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 March 23, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
Ultroman Posted March 24, 2019 Share Posted March 24, 2019 Brilliant, m8 Link to comment Share on other sites More sharing options...
ismakenji Posted March 24, 2019 Author Share Posted March 24, 2019 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 More sharing options...
ShinyMoogle Posted March 24, 2019 Share Posted March 24, 2019 (edited) 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 March 24, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
ismakenji Posted March 24, 2019 Author Share Posted March 24, 2019 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 More sharing options...
ShinyMoogle Posted March 24, 2019 Share Posted March 24, 2019 (edited) Hm... that looks like it should work to me. Did you add the "popu" tag to your character prefab? Edited March 24, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
ismakenji Posted March 24, 2019 Author Share Posted March 24, 2019 I think so, in popuko.lua i added local prefabs = { inst:AddTag("popu") } is it correct? Link to comment Share on other sites More sharing options...
ShinyMoogle Posted March 24, 2019 Share Posted March 24, 2019 Ah, nope. The tag code is correct, but tags should get added in your character prefab's common_postinit. Link to comment Share on other sites More sharing options...
ismakenji Posted March 24, 2019 Author Share Posted March 24, 2019 (edited) 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 March 24, 2019 by ismakenji Link to comment Share on other sites More sharing options...
ShinyMoogle Posted March 24, 2019 Share Posted March 24, 2019 (edited) 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 March 24, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
ismakenji Posted March 24, 2019 Author Share Posted March 24, 2019 No, I don't have PvP turned on, that's why I don't know why it's not working, anyhow I think if it targets any player its fine so I'm going to try and use the "and HasTag("player")" and see if it works Link to comment Share on other sites More sharing options...
ShinyMoogle Posted March 24, 2019 Share Posted March 24, 2019 (edited) 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 March 24, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
ismakenji Posted March 24, 2019 Author Share Posted March 24, 2019 OK! DONE IT (it even gives Popuko sanity if she's hit, I'll tune the values so it's not overpowered) THank you so much for having so much patience with me Link to comment Share on other sites More sharing options...
ShinyMoogle Posted March 24, 2019 Share Posted March 24, 2019 (edited) 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 March 24, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
ismakenji Posted March 24, 2019 Author Share Posted March 24, 2019 Oh nice!! Now it's perfect! thanks again <3 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