Jump to content

Hound Flute


Recommended Posts

I'm working on a modification that adds to the game an instrument that can summon hounds. However, I don't know which scripts should I use to gain control over the amount of dogs. I was able to get the effect of summon, but number of hounds that appears is completely random and uncontrolled.

 

Typically, the instrument summons a dozen or twenty/twenty-five dogs, but it also happens that the number is so large that it even causes disruptions in the game mechanics. 

 

I put screenshots and prefab file into this post. I hope that someone will be able to help, because as a beginner I may not be able to solve this problem by myself.

 

PREFAB:

 

local assets=
{
Asset("ANIM", "anim/bone_flute.zip"),
Asset("ATLAS", "images/inventoryimages/bone_flute.xml"),
Asset("IMAGE", "images/inventoryimages/bone_flute.tex"),
}

local prefabs =
{
"hound",
"icehound",
"yellowhound",
"firehound"
}


local function onfinished(inst)
inst:Remove()
end

local function HearBoneFlute(inst, musician, instrument)
local pt = Vector3(GetPlayer().Transform:GetWorldPosition())

local spawn_pt = GetSpawnPoint(pt)

if spawn_pt then
local prefab = "hound"
local special_hound_chance = GetSpecialHoundChance()
if math.random() < special_hound_chance then
if GetSeasonManager():IsWinter() or GetSeasonManager():IsSpring() then
prefab = "icehound"
end
end

if math.random() < special_hound_chance then
if GetSeasonManager():IsSummer() then
prefab = "firehound"
end
end

if math.random() < special_hound_chance then
if GetSeasonManager():IsAutumn() then
prefab = "yellowhound"
end
end

local hound = SpawnPrefab(prefab)
if hound then
hound.Physics:Teleport(spawn_pt:Get())
hound:FacePoint(pt)
return hound
end

end

end

function GetSpecialHoundChance()
local day = GetClock():GetNumCycles()
local chance = 0
for k,v in ipairs(TUNING.HOUND_SPECIAL_CHANCE) do
if day > v.minday then
chance = v.chance
elseif day <= v.minday then
return chance
end
end

return chance
end


function GetSpawnPoint(pt)

local theta = math.random() * 2 * PI
local radius = (30)

local offset = FindWalkableOffset(pt, theta, radius, 5, true)
if offset then
local pos = pt + offset
return pt+offset
end
end


local function fn(Sim)
local inst = CreateEntity()
inst.entity:AddTransform()
inst.entity:AddAnimState()

inst:AddTag("flute")

inst.AnimState:SetBank("pan_flute")
inst.AnimState:SetBuild("bone_flute")
inst.AnimState:PlayAnimation("idle")
MakeInventoryPhysics(inst)

inst:AddComponent("inspectable")
inst:AddComponent("instrument")
inst.components.instrument:SetOnHeardFn(HearBoneFlute)

inst:AddComponent("tool")
inst.components.tool:SetAction(ACTIONS.PLAY)

inst:AddComponent("finiteuses")
inst.components.finiteuses:SetMaxUses(3)
inst.components.finiteuses:SetUses(3)
inst.components.finiteuses:SetOnFinished( onfinished)
inst.components.finiteuses:SetConsumption(ACTIONS.PLAY, 1)

inst:AddComponent("inventoryitem")
inst.components.inventoryitem.atlasname = "images/inventoryimages/bone_flute.xml"

return inst
end

return Prefab( "common/inventory/bone_flute", fn, assets)

post-381792-0-15559500-1404921428_thumb.

post-381792-0-87279100-1404921448_thumb.

Link to comment
Share on other sites

All these hounds won't have any chance to beat dragonfly after all. He will smash them with single area attack.

Also if you use BushHat after using Bone Flute, Hounds won't attack you and also I added special Hat that make you hound's friend.

 

But the game is super slow when they appear in such quantity. That's too much after all.

Link to comment
Share on other sites

But I was able to do it only with GodModeMod. I'm still working on it and there is small progress. 

 

Now I'm using this code:

 

local numhounds = 1

 

but it seems that "1" means "22" for hounds oO

Link to comment
Share on other sites

It's better with this code:

 

 

local function HearBoneFlute(inst, musician, instrument)
local pt = Vector3(musician.Transform:GetWorldPosition())

local numhounds = 1

musician:StartThread(function()
for k = 1, numhounds do

local theta = math.random() * 2 * PI
local radius = math.random(3, 8)

-- we have to special case this one because birds can't land on creep
local result_offset = FindValidPositionByFan(theta, radius, 12, function(offset)
local x,y,z = (pt + offset):Get()
local ents = TheSim:FindEntities(x,y,z , 1)
return not next(ents)
end)

if result_offset then
local hound = SpawnPrefab("hound")
end
end
end)
return true
end

 

But still twenty and even more hounds appear.

Link to comment
Share on other sites

First off, I believe the instrument code is the wrong code for you.  The instrument code will search the range that you set for entities.  Not a specific type of entity, just entities.  It will then proceed to execute the onheard command for every single entity within the range.  In other words, one hound is being spawned per entity in the assigned range, which is a lot especially when you remember that an entity is pretty much any object in the world.  The default range is not too big (15), but when you play it multiple times in a row, it will get catastrophic because it will effectively double the amount of hounds it spawns every time.  I would suggest making a new component that sends the player to the same state as the horn does, but you can set the function that will be executed whenever you play it.

 

I hope this helps you solve your problem.  If it doesn't, feel free to ask and I'd be happy to help some more.

Link to comment
Share on other sites

First off, I believe the instrument code is the wrong code for you.  The instrument code will search the range that you set for entities.  Not a specific type of entity, just entities.  It will then proceed to execute the onheard command for every single entity within the range.  In other words, one hound is being spawned per entity in the assigned range, which is a lot especially when you remember that an entity is pretty much any object in the world.  The default range is not too big (15), but when you play it multiple times in a row, it will get catastrophic because it will effectively double the amount of hounds it spawns every time.  I would suggest making a new component that sends the player to the same state as the horn does, but you can set the function that will be executed whenever you play it.

 

I hope this helps you solve your problem.  If it doesn't, feel free to ask and I'd be happy to help some more.

 

This is a good clue. Now I'm using this component:

 

 

inst:AddComponent("useableitem")

inst.components.useableitem:SetCanInteractFn( CanSummon )

inst.components.useableitem:SetOnUseFn( SummonHounds )

 

 

Now I have control over the number of dogs, but the object that summons them is inexhaustible. Although I try to give durability to it, it still doesn't disappear.

 

I'm using this:

 

inst:AddComponent("finiteuses")

inst.components.finiteuses:SetMaxUses(1)

inst.components.finiteuses:SetUses(1)

inst.components.finiteuses:SetOnFinished(OnFinished)

 

and this:

 

local function OnFinished(inst)

inst:Remove()

end

 

but unsuccessfully.

Link to comment
Share on other sites

In your SummonHounds function, just put this line of code:

 

inst.components.finiteuses:Use(1)

 

That will deduct 1 point from the object's durability.  If you want to do it the proper way (I guess we can call it that), add this line of code below where you define finiteuses in the fn function:

 

inst.components.finiteuses:SetConsumption(ACTIONS.USEITEM, 1)

 

That line will make it so it consumes 1 from the durability of the item whenever you use the USEITEM action on it.

Hope this helps you!

Link to comment
Share on other sites

In your SummonHounds function, just put this line of code:

 

inst.components.finiteuses:Use(1)

 

That will deduct 1 point from the object's durability.  If you want to do it the proper way (I guess we can call it that), add this line of code below where you define finiteuses in the fn function:

 

inst.components.finiteuses:SetConsumption(ACTIONS.USEITEM, 1)

 

That line will make it so it consumes 1 from the durability of the item whenever you use the USEITEM action on it.

Hope this helps you!

 

I've tried that already. I also added to function "SummonHounds" those codes:

 

holder:RemoveItem(inst)

 

or

 

inst:Remove()

 

but this won't work too.

 

I think I'll make something like Maxwell Journal. It will be infinite but will need to use an object from your inventory.

 

Link to comment
Share on other sites

Currently it looks like this:

 

local assets =
{
Asset("ANIM", "anim/hound_salve.zip"),
Asset("ATLAS", "images/inventoryimages/hound_salve.xml"),
Asset("IMAGE", "images/inventoryimages/hound_salve.tex"),
}

local function CanSummon(inst)
local owner = inst.components.inventoryitem and inst.components.inventoryitem.owner
if owner then return true end
end

local function SummonHounds(inst)
local pt = Vector3(GetPlayer().Transform:GetWorldPosition())

local spawn_pt = GetSpawnPoint(pt)
if spawn_pt then
local prefab = "hound"
local special_hound_chance = GetSpecialHoundChance()
if math.random() < special_hound_chance then
if GetSeasonManager():IsWinter() or GetSeasonManager():IsSpring() then
prefab = "icehound"
end
end

if math.random() < special_hound_chance then
if GetSeasonManager():IsSummer() then
prefab = "firehound"
end
end

if math.random() < special_hound_chance then
if GetSeasonManager():IsAutumn() then
prefab = "yellowhound"
end
end

local hound = SpawnPrefab(prefab)
if hound then
hound.Physics:Teleport(spawn_pt:Get())
hound:FacePoint(pt)
return hound
end

end
OnFinished
end

function GetSpecialHoundChance()
local day = GetClock():GetNumCycles()
local chance = 0
for k,v in ipairs(TUNING.HOUND_SPECIAL_CHANCE) do
if day > v.minday then
chance = v.chance
elseif day <= v.minday then
return chance
end
end

return chance
end


function GetSpawnPoint(pt)

local theta = math.random() * 2 * PI
local radius = (10)

local offset = FindWalkableOffset(pt, theta, radius, 5, true)
if offset then
local pos = pt + offset
return pt+offset
end
end

local function OnFinished(inst)
inst:Remove()
end

local function fn(Sim)
local inst = CreateEntity()
inst.entity:AddTransform()
inst.entity:AddAnimState()

MakeInventoryPhysics(inst)

inst.AnimState:SetBank("spider_gland_salve")
inst.AnimState:SetBuild("hound_salve")
inst.AnimState:PlayAnimation("idle")


inst:AddComponent("inspectable")

inst:AddComponent("inventoryitem")
inst.components.inventoryitem.atlasname = "images/inventoryimages/hound_salve.xml"

inst:AddComponent("finiteuses")
inst.components.finiteuses:SetMaxUses(1)
inst.components.finiteuses:SetUses(1)
inst.components.finiteuses:SetOnFinished(OnFinished)

inst:AddComponent("useableitem")
inst.components.useableitem:SetCanInteractFn( CanSummon )
inst.components.useableitem:SetOnUseFn( SummonHounds )

return inst
end

return Prefab( "common/inventory/hound_salve", fn, assets)

 

 

But when I try to do this just like Maxwell Journal it alway crashed when I try to add special hound chance.

 

Now it looks like this:

 

local assets =
{
Asset("ANIM", "anim/book_maxwell.zip"),
Asset("ATLAS", "images/inventoryimages/hound_book.xml"),
Asset("IMAGE", "images/inventoryimages/hound_book.tex"),
}

local function canread(inst)
return (inst.components.sanity:GetMaxSanity() >= TUNING.SHADOWWAXWELL_SANITY_PENALTY)
end

local function onread(inst, reader)

--Check sanity
if not canread(reader) then
if reader.components.talker then
reader.components.talker:Say(GetString(reader.prefab, "ANNOUNCE_NOSANITY"))
return true
end
end

--Check reagent
if not reader.components.inventory:Has("nightmarefuel", TUNING.SHADOWWAXWELL_FUEL_COST) then
if reader.components.talker then
reader.components.talker:Say(GetString(reader.prefab, "ANNOUNCE_NOFUEL"))
return true
end
end

reader.components.inventory:ConsumeByName("nightmarefuel", TUNING.SHADOWWAXWELL_FUEL_COST)

--Ok you had everything. Make the image.
local theta = math.random() * 2 * PI
local pt = inst:GetPosition()
local radius = math.random(3, 6)
local offset = FindWalkableOffset(pt, theta, radius, 12, true)
local numhounds = 5

reader:StartThread(function()
for k = 1, numhounds do

local theta = math.random() * 2 * PI
local radius = math.random(3, 8)
local prefab = "hound"

local result_offset = FindValidPositionByFan(theta, radius, 12, function(offset)
local x,y,z = (pt + offset):Get()
local ents = TheSim:FindEntities(x,y,z , 1)
return not next(ents)
end)


if result_offset then
local hound = SpawnPrefab("prefab")
hound.Transform:SetPosition((pt + result_offset):Get())

end

local special_hound_chance = GetSpecialHoundChance()
if math.random() < special_hound_chance then
if GetSeasonManager():IsWinter() or GetSeasonManager():IsSpring() then
prefab = "icehound"
end
end

if math.random() < special_hound_chance then
if GetSeasonManager():IsSummer() then
prefab = "firehound"
end
end

if math.random() < special_hound_chance then
if GetSeasonManager():IsAutumn() then
prefab = "yellowhound"
end
end


local hound = SpawnPrefab(prefab)
if hound then
hound.Physics:Teleport(spawn_pt:Get())
hound:FacePoint(pt)
return hound
end

end
end)
return true

end


function GetSpecialHoundChance()
local day = GetClock():GetNumCycles()
local chance = 0
for k,v in ipairs(TUNING.HOUND_SPECIAL_CHANCE) do
if day > v.minday then
chance = v.chance
elseif day <= v.minday then
return chance
end
end

return chance
end


local function fn()
local inst = CreateEntity()
local trans = inst.entity:AddTransform()
local anim = inst.entity:AddAnimState()
local sound = inst.entity:AddSoundEmitter()

anim:SetBank("book_maxwell")
anim:SetBuild("hound_book")
anim:PlayAnimation("idle")

MakeInventoryPhysics(inst)

inst:AddComponent("inventoryitem")

-----------------------------------
inst:AddComponent("inspectable")
inst:AddComponent("book")
inst.components.book.onread = onread

inst:AddComponent("inventoryitem")
inst.components.inventoryitem.atlasname = "images/inventoryimages/hound_book.xml"

MakeSmallBurnable(inst)
MakeSmallPropagator(inst)

return inst
end

return Prefab("common/hound_book", fn, assets)

Link to comment
Share on other sites

It isn't supposed to play the animation.  It you want it to, you need to send the player to a different stategraph state.  I did manage to get your code working (if you want to do it just using the inst:Remove() in the summonhounds function).  The problem was your return statement at the end of that function.  It isn't supposed to return anything.  Try it after removing the return statement and see if it gives you trouble.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...