Lumina Posted February 12, 2017 Share Posted February 12, 2017 I want to spawn something near the player when doing a certain action. Triggering the event is ok, but i don't know how to spawn my thing near the player but offscreen if possible, at least not "on" the player. I guess it implies code similar for warg calling help, probably like this : local function NumHoundsToSpawn(inst) local numHounds = TUNING.WARG_BASE_HOUND_AMOUNT local pt = Vector3(inst.Transform:GetWorldPosition()) local ents = TheSim:FindEntities(pt.x, pt.y, pt.z, TUNING.WARG_NEARBY_PLAYERS_DIST, {"player"}, {"playerghost"}) for i,player in ipairs(ents) do local playerAge = player.components.age:GetAgeInDays() local addHounds = math.clamp(Lerp(1, 4, playerAge/100), 1, 4) numHounds = numHounds + addHounds end local numFollowers = inst.components.leader:CountFollowers() local num = math.min(numFollowers+numHounds/2, numHounds) -- only spawn half the hounds per howl num = (math.log(num)/0.4)+1 -- 0.4 is approx log(1.5) num = RoundToNearest(num, 1) return num - numFollowers end But i'm confused about what to use and how. If someone have a clue it will be welcome Link to comment Share on other sites More sharing options...
Serpens Posted February 12, 2017 Share Posted February 12, 2017 (edited) So you have a certain action the player does and you have a function that is called when this action is made, right? And now you need code within this function, to spawn a prefab somewhere around the player, but not at exactly the same point? Is offscreen necessary? In the code you wrote, there is much more than just spawning something. Do you need all the stuff in this code? For example making them follow the leader, playerage and such stuff? Edited February 12, 2017 by Serpens Link to comment Share on other sites More sharing options...
Lumina Posted February 12, 2017 Author Share Posted February 12, 2017 1 minute ago, Serpens said: So you have a certain action the player does and you have a function that is called when this action is made, right? Yes, this part i could do. 1 minute ago, Serpens said: And now you need code within this function, to spawn a prefab somewhere around the player, but not at exactly the same point? Is offscreen necessary? Offscreen is probably more "clean", but anything that isn't "all in the same spot" will be better than now. Here is one example i plan to use it. function WargPrefabPostInit(inst) if not GLOBAL.TheWorld.ismastersim then return inst end local function SeasonHound(inst) if GLOBAL.TheWorld.state.isspring then inst.components.lootdropper:SpawnLootPrefab("hound_yellow") inst.components.lootdropper:SpawnLootPrefab("hound_yellow") local num = math.random(1, 3) if num == 3 then inst.components.lootdropper:SpawnLootPrefab("hound_yellow") end elseif GLOBAL.TheWorld.state.issummer then inst.components.lootdropper:SpawnLootPrefab("hound_orange") inst.components.lootdropper:SpawnLootPrefab("hound_orange") local num = math.random(1, 3) if num == 3 then inst.components.lootdropper:SpawnLootPrefab("hound_orange") end elseif GLOBAL.TheWorld.state.isautumn then inst.components.lootdropper:SpawnLootPrefab("hound_green") inst.components.lootdropper:SpawnLootPrefab("hound_green") local num = math.random(1, 3) if num == 3 then inst.components.lootdropper:SpawnLootPrefab("hound_green") end elseif GLOBAL.TheWorld.state.iswinter then inst.components.lootdropper:SpawnLootPrefab("hound_purple") inst.components.lootdropper:SpawnLootPrefab("hound_purple") local num = math.random(1, 3) if num == 3 then inst.components.lootdropper:SpawnLootPrefab("hound_purple") end end end inst:ListenForEvent("death", function() SeasonHound(inst) end) end AddPrefabPostInit("warg", WargPrefabPostInit) When a warg is killed, i want to spawn hounds, i manage to do it now with "spawnlootprefab" but it's not "clean" and all the hounds are spawned "on" the warg. I would like to spawn them "around" it, and if possible, far away enough so it seems that the warg "called" them. Something more natural. But anything will be better than the current state. I plan to use something similar to "spawn" a creature when the player interact with a prefab (similar to koalefant track but a LOT much simpler), with if possible the same "off screen if possible" but anything will be better than "right under the feet of the player". I hope i'm more clear. Thanks for reading. Link to comment Share on other sites More sharing options...
Serpens Posted February 12, 2017 Share Posted February 12, 2017 (edited) I already made a nice function for spawning stuff near someone/something for my teleportato mod (chests and enemies spawning around the teleportato) Maybe it is exactly what you are looking for? Spoiler local function SpawnPrefabAtLandPlotNearInst(prefab,loc,x,y,z,times,xmin,zmin) -- xmin and zmin are the mind distance it should have to the given position -- print("Spawn "..tostring(prefab).." near "..tostring(loc).." times: "..tostring(times)) if prefab==nil or loc==nil or type(prefab)~="string" then print("Adventure: Spawnprefab is "..tostring(prefab).." instead of a prefab string... and loc is "..tostring(loc)) return nil end local pos = nil if loc.prefab then pos = loc:GetPosition() else -- loc can also be a position already pos = loc end x = x or 5 y = y or 0 z = z or 5 xmin = xmin or 3 zmin = zmin or 3 local xn = 0 local zn = 0 times = times or 1 times = math.ceil(times) local found = false local tp_pos local attempts = 100 local spawn = nil for i=1,times,1 do found = false attempts = 100 --try multiple times to get a spot on ground before giving up so we don't infinite loop while attempts > 0 do xn = GetRandomWithVariance(0,x) zn = GetRandomWithVariance(0,z) xn = (xn>=0 and xn<=xmin and xn+xmin) or (xn<0 and xn>=-xmin and xn-xmin) or xn -- dont be in range of xmin zmin, cause this is too near zn = (zn>=0 and zn<=zmin and zn+zmin) or (zn<0 and zn>=-zmin and zn-zmin) or zn tp_pos = pos + Vector3(xn ,GetRandomWithVariance(0,y) ,zn ) if TheWorld.Map:IsAboveGroundAtPoint(tp_pos:Get()) then found = true break end attempts = attempts - 1 end spawn = nil if found then spawn = SpawnPrefab(prefab) if spawn then spawn.Transform:SetPosition(tp_pos:Get()) SpawnPrefab("collapse_small").Transform:SetPosition(tp_pos:Get()) -- a small puff effect else print("Adventure: Spawn of "..tostring(prefab).." failed...") end -- print("spawned "..tostring(prefab).." at "..tostring(tp_pos).." times: "..tostring(times).." spawn: "..tostring(spawn)) end end return spawn -- does only return the last spawn, if times is higher than 1 end - The prefab is what you want to spawn. - The "loc" is either a position where to spawn or an instance near to spawn. - times is the number of prefabs you want to spawn around the position/instance - x,y,z are the range within the prefab should spawn. Since y is the height, this is usually 0. - xmin and zmin are the min distance between position/instance and the prefab. This function already tests, if the random point to spawn is land. If it is blocked or water it is trying another point withing range, up to 100 times before giving up. And it also makes a small "puff" effect. Of course you can remove/change every "print" statement. They are mainly for debugging. Edited February 12, 2017 by Serpens Link to comment Share on other sites More sharing options...
Lumina Posted February 12, 2017 Author Share Posted February 12, 2017 Thanks a lot, i'll try this. Link to comment Share on other sites More sharing options...
Lumina Posted February 16, 2017 Author Share Posted February 16, 2017 @Serpens Thanks, it works fine. My first tests got crashes because i wasn't in global (this specific code is in modmain), i didn't got time to make tests until today, now i added the GLOBAL. all is working fine, i just have to tune values to see what distance will be great. Anyway, thanks because it was what i needed so it's great Link to comment Share on other sites More sharing options...
diovbc Posted March 15, 2017 Share Posted March 15, 2017 Hello. May I ask some help here, too? xD I'm trying to do something similar around my character. The line I'm trying to use is: Quote -- Spawning hounds around you! inst:DoPeriodicTask(1, function() local function SpawnPrefabAtLandPlotNearInst(prefab,loc,x,y,z,times,xmin,zmin) -- xmin and zmin are the mind distance it should have to the given position -- print("Spawn "..tostring(prefab).." near "..tostring(loc).." times: "..tostring(times)) if prefab==nil or loc==nil or type(prefab)~="string" then print("Adventure: Spawnprefab is "..tostring(prefab).." instead of a prefab string... and loc is "..tostring(loc)) return nil end local pos = nil if loc.prefab then pos = loc:GetPosition() else -- loc can also be a position already pos = loc end x = x or 10 y = y or 0 z = z or 10 xmin = xmin or 6 zmin = zmin or 6 local xn = 0 local zn = 0 times = times or 1 times = math.ceil(times) local found = false local tp_pos local attempts = 100 local spawn = nil for i=1,times,1 do found = false attempts = 100 --try multiple times to get a spot on ground before giving up so we don't infinite loop while attempts > 0 do xn = GetRandomWithVariance(0,x) zn = GetRandomWithVariance(0,z) xn = (xn>=0 and xn<=xmin and xn+xmin) or (xn<0 and xn>=-xmin and xn-xmin) or xn -- dont be in range of xmin zmin, cause this is too near zn = (zn>=0 and zn<=zmin and zn+zmin) or (zn<0 and zn>=-zmin and zn-zmin) or zn tp_pos = pos + Vector3(xn ,GetRandomWithVariance(0,y) ,zn ) if TheWorld.Map:IsAboveGroundAtPoint(tp_pos:Get()) then found = true break end attempts = attempts - 1 end spawn = nil if found then spawn = SpawnPrefab("hound") if spawn then spawn.Transform:SetPosition(tp_pos:Get()) SpawnPrefab("collapse_small").Transform:SetPosition(tp_pos:Get()) -- a small puff effect else print("Adventure: Spawn of "..tostring(prefab).." failed...") end -- print("spawned "..tostring(prefab).." at "..tostring(tp_pos).." times: "..tostring(times).." spawn: "..tostring(spawn)) end end return spawn -- does only return the last spawn, if times is higher than 1 end end) Basically I tried to use a function that every "x" time, spawns a hound near you. I tried to do 1 second for test purposes. The thing is... It is not spawning the hound. The game lags for a bit, and nothing happens. Any ideas? Thanks! Link to comment Share on other sites More sharing options...
Serpens Posted March 16, 2017 Share Posted March 16, 2017 (edited) @diovbc your code is wrong, I mean this part: inst:DoPeriodicTask(1, function() local function SpawnPrefabAtLandPlotNearInst(prefab,loc,x,y,z,times,xmin,zmin) -- print("Spawn "..tostring(prefab).." near "..tostring(loc).." times: "..tostring(times)) if prefab==nil or loc==nil or type(prefab)~="string" then print("Adventure: Spawnprefab is "..tostring(prefab).." instead of a prefab string... and loc is "..tostring(loc)) return nil end --... Please try notepad++ and do search for "inst:DoPeriodicTask" in the game files, to get some examples how to use the function. It is described here how to search:http://forums.kleientertainment.com/topic/73989-tutorial-basics-what-to-use-to-open-lua-files-and-why/#comment-865955 There are two way how it could look correct: 1) inst:DoPeriodicTask(1, function(prefab,loc,x,y,z,times,xmin,zmin) -- print("Spawn "..tostring(prefab).." near "..tostring(loc).." times: "..tostring(times)) if prefab==nil or loc==nil or type(prefab)~="string" then print("Adventure: Spawnprefab is "..tostring(prefab).." instead of a prefab string... and loc is "..tostring(loc)) return nil end --... --.. end, nil, prefab,loc,...your values) 2) local function SpawnPrefabAtLandPlotNearInst(prefab,loc,x,y,z,times,xmin,zmin) -- print("Spawn "..tostring(prefab).." near "..tostring(loc).." times: "..tostring(times)) if prefab==nil or loc==nil or type(prefab)~="string" then print("Adventure: Spawnprefab is "..tostring(prefab).." instead of a prefab string... and loc is "..tostring(loc)) return nil end --... --.. end inst:DoPeriodicTask(1, SpawnPrefabAtLandPlotNearInst,nil,prefab,loc,...your values) Of course you also need to know where to put the code. You can't put it anywhere, you need to know when this should happen. So to tell you where to put it, I would need the rest of your code or explanation when it should happen. And of course you need to stop that task sometime. This is another peace of code you have to add. Edited March 16, 2017 by Serpens Link to comment Share on other sites More sharing options...
Lumina Posted April 12, 2017 Author Share Posted April 12, 2017 (edited) @Serpens: i'm trying to use this code to spawn something when investigate a custom dirt pile, the code itself works fine but my problem is that i can't manage to remove the custom dirt pile itself when using it. local assets = { Asset("ANIM", "anim/koalefant_tracks.zip"), Asset("ANIM", "anim/smoke_puff_small.zip"), } local prefabs = { "small_puff", "hound_purple" } local AUDIO_HINT_MIN = 10 local AUDIO_HINT_MAX = 60 local function GetVerb() return "INVESTIGATE" end local function SpawnPrefabAtLandPlotNearInst(prefab,loc,x,y,z,times,xmin,zmin) -- xmin and zmin are the mind distance it should have to the given position prefab = "hound_purple" -- print("Spawn "..tostring(prefab).." near "..tostring(loc).." times: "..tostring(times)) if prefab==nil or loc==nil or type(prefab)~="string" then print("Adventure: Spawnprefab is "..tostring(prefab).." instead of a prefab string... and loc is "..tostring(loc)) return nil end local pos = nil if loc.prefab then pos = loc:GetPosition() else -- loc can also be a position already pos = loc end x = x or 5 y = y or 0 z = z or 5 xmin = xmin or 3 zmin = zmin or 3 local xn = 0 local zn = 0 times = times or 1 times = math.ceil(times) local found = false local tp_pos local attempts = 100 local spawn = nil for i=1,times,1 do found = false attempts = 100 --try multiple times to get a spot on ground before giving up so we don't infinite loop while attempts > 0 do xn = GetRandomWithVariance(0,x) zn = GetRandomWithVariance(0,z) xn = (xn>=0 and xn<=xmin and xn+xmin) or (xn<0 and xn>=-xmin and xn-xmin) or xn -- dont be in range of xmin zmin, cause this is too near zn = (zn>=0 and zn<=zmin and zn+zmin) or (zn<0 and zn>=-zmin and zn-zmin) or zn tp_pos = pos + Vector3(xn ,GetRandomWithVariance(0,y) ,zn ) if TheWorld.Map:IsAboveGroundAtPoint(tp_pos:Get()) then found = true break end attempts = attempts - 1 end spawn = nil if found then spawn = SpawnPrefab(prefab) if spawn then spawn.Transform:SetPosition(tp_pos:Get()) SpawnPrefab("collapse_small").Transform:SetPosition(tp_pos:Get()) -- a small puff effect else print("Adventure: Spawn of "..tostring(prefab).." failed...") end -- print("spawned "..tostring(prefab).." at "..tostring(tp_pos).." times: "..tostring(times).." spawn: "..tostring(spawn)) end end return spawn -- does only return the last spawn, if times is higher than 1 end -- local function OnInvestigated(inst) -- print("dirtpile - OnInvestigated") SpawnPrefabAtLandPlotNearInst PlayFX(pt, "small_puff", "smoke_puff_small", "puff", "dontstarve/common/deathpoof", nil, Vector3(216/255, 154/255, 132/255)) -- inst:Remove() -- end local function create() --print("dirtpile - create") local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() --inst.entity:AddSoundEmitter() inst.entity:AddNetwork() MakeInventoryPhysics(inst) inst:AddTag("dirtpile") inst.AnimState:SetBank("track") inst.AnimState:SetBuild("koalefant_tracks") --inst.AnimState:SetOrientation( ANIM_ORIENTATION.OnGround ) --inst.AnimState:SetLayer( LAYER_BACKGROUND ) --inst.AnimState:SetSortOrder( 3 ) inst.AnimState:SetRayTestOnBB(true) inst.AnimState:PlayAnimation("idle_pile") --inst.Transform:SetRotation(math.random(360)) inst.GetActivateVerb = GetVerb inst.entity:SetPristine() if not TheWorld.ismastersim then return inst end inst:AddComponent("inspectable") --inst.components.inspectable.getstatus = GetStatus inst:AddComponent("activatable") --set required inst.components.activatable.OnActivate = SpawnPrefabAtLandPlotNearInst -- inst.components.activatable.OnActivate = OnInvestigated inst.components.activatable.inactive = true -- inst:AddComponent("hauntable") --inst:DoTaskInTime(1, OnAudioHint) inst.persists = false return inst end return Prefab("customdirtpile", create, assets, prefabs) Here is the code i'm using. I tried to add an "inst:remove()" in the spawn code, but the variable isn't declared. If i add "inst" in the " SpawnPrefabAtLandPlotNearInst(prefab,loc,x,y,z,times,xmin,zmin)" part it doesn't work. So maybe you have an advice, even if it's not the initial use for your code ? Or another solution ? What i want is being able to spawn monter around the player when investigate a dirtpile, but without managing all the complex components of the initial koalefants tracks. But of course i could search to do something not really possible here. Edited April 12, 2017 by Lumina Link to comment Share on other sites More sharing options...
Serpens Posted April 12, 2017 Share Posted April 12, 2017 I would have to test it myself, but dont have time to do this at the momemt. But I would not advice to do inst.components.activatable.OnActivate = SpawnPrefabAtLandPlotNearInst The way with "OnInvestigated" is better. So simplify the problem: If you only have "inst.Remove()" in OnInvestigate, it is not removed? maybe try "return inst:Remove()". And if this also does not work use DoTaskIntime with a timer of 0.01. Link to comment Share on other sites More sharing options...
Lumina Posted April 13, 2017 Author Share Posted April 13, 2017 If i use " OnInvestigated", the custom dirt pile is removed, but i can't spawn the monster. If i use " SpawnPrefabAtLandPlotNearInst " i can spawn the monster but can't remove the custom dirt pile. I could do one, i could do the other, but i fail to do both at the same time. I tried to call the "SpawnPrefabAtLandPlotNearInst" function into the "OnInvestigated" function without success, i probably wasn't doing it right. Link to comment Share on other sites More sharing options...
Serpens Posted April 14, 2017 Share Posted April 14, 2017 15 hours ago, Lumina said: I tried to call the "SpawnPrefabAtLandPlotNearInst" function into the "OnInvestigated" function without success, i probably wasn't doing it right. In case your OnInvestigate function really looks like this, it of course does not work: local function OnInvestigated(inst) print("dirtpile - OnInvestigated") SpawnPrefabAtLandPlotNearInst PlayFX(pt, "small_puff", "smoke_puff_small", "puff", "dontstarve/common/deathpoof", nil, Vector3(216/255, 154/255, 132/255)) inst:Remove() end SpawnPrefab... is a function, so of course you have to call it like that: SpawnPrefabAtLandPlotNearInst("prefab",inst,...) replace prefab with your prefab (and remove your prefab change in the function itself), and replace ... with whatever you want. Link to comment Share on other sites More sharing options...
Lumina Posted April 14, 2017 Author Share Posted April 14, 2017 Thanks, i'll try it, i tried something like it without success but i misplaced the inst i think. Link to comment Share on other sites More sharing options...
Lumina Posted April 14, 2017 Author Share Posted April 14, 2017 Also, i changed prefab this way because i plan to change prefab depending of season and the only way i found at the moment is to change it with a "if season is = x then, elseif". There is probably a better way, but in the meantime this is the reason why i change it this way. Link to comment Share on other sites More sharing options...
Serpens Posted April 14, 2017 Share Posted April 14, 2017 (edited) 1 hour ago, Lumina said: Also, i changed prefab this way because i plan to change prefab depending of season and the only way i found at the moment is to change it with a "if season is = x then, elseif". There is probably a better way, but in the meantime this is the reason why i change it this way. yes, but it is better readable and more professional and everything, if you do it outside of the spawn function, so eg. like this: local function OnInvestigated(inst) print("dirtpile - OnInvestigated") prefab = "hound" if itiswinter then prefab = "winterhound" end SpawnPrefabAtLandPlotNearInst(prefab,inst,...) PlayFX(pt, "small_puff", "smoke_puff_small", "puff", "dontstarve/common/deathpoof", nil, Vector3(216/255, 154/255, 132/255)) inst:Remove() end The order of the things you pass to the spawn function must be exactly the same order like you see in the bracket of the spawnfunction, so: (prefab,loc,x,y,z,times,xmin,zmin) Edited April 14, 2017 by Serpens Link to comment Share on other sites More sharing options...
Lumina Posted April 14, 2017 Author Share Posted April 14, 2017 Thanks again I'll do it this way then. 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