Jump to content

[Follower] Creature doesn't move


Recommended Posts

Hello. I have tried to make followers based on Maxwell's copies. Game doesn't crash. My followers after spawn are just idle. They can die but won't move or act in any way. I coppied maxwell's copies SG and brain so it is not problem. I also modified character and creature prefab files, so they could be troublemakers. I will appreciate every help.

Character

local MakePlayerCharacter = require "prefabs/player_common"


local assets = {
    Asset("SCRIPT", "scripts/prefabs/player_common.lua"),
}
local prefabs = {
"shadow_despawn",
"statue_transition_2",
}

-- Custom starting items
local start_inv = {         
}

-------------GRUNTS
local function squadleader(inst)
    if inst.components.leader then
        for k,v in pairs(inst.grunts) do
            if v:IsValid() then
                if v.components.follower then
                    inst.components.leader:AddFollower(v, true)
                end
            else
                inst.grunts[k] = nil
            end
        end
    end
end

local function DoEffects(pet)
    local x, y, z = pet.Transform:GetWorldPosition()
    SpawnPrefab("shadow_despawn").Transform:SetPosition(x, y, z)
    SpawnPrefab("statue_transition_2").Transform:SetPosition(x, y, z)
end

local function KillPet(pet)
    pet.components.health:Kill()
end

local function OnSpawnPet(inst, pet)   
    if pet:HasTag("grunt") then
	      pet:DoTaskInTime(0, DoEffects)

         if not (inst.components.health:IsDead() or inst:HasTag("playerghost")) then
           inst.components.sanity:AddSanityPenalty(pet, TUNING.SHADOWWAXWELL_SANITY_PENALTY[string.upper(pet.prefab)])
           inst:ListenForEvent("onremove", inst._onpetlost, pet)
        elseif pet._killtask == nil then
           pet._killtask = pet:DoTaskInTime(math.random(), KillPet)
        end
    elseif inst._OnSpawnPet ~= nil then
        inst:_OnSpawnPet(pet)
    end
end

local function OnDespawnPet(inst, pet)
    if pet:HasTag("grunt") then
        DoEffects(pet)
        pet:Remove()
    elseif inst._OnDespawnPet ~= nil then
        inst:_OnDespawnPet(pet)
    end
end

local function OnDeath(inst)
    for k, v in pairs(inst.components.petleash:GetPets()) do
        if v:HasTag("grunt") and v._killtask == nil then
            v._killtask = v:DoTaskInTime(math.random(), KillPet)
        end
    end
end

--------------------------
-- When the character is revived from human
local function onbecamehuman(inst)
	-- Set speed when reviving from ghost (optional)
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "taern_speed_mod", 1.4)
end

local function onbecameghost(inst)
	-- Remove speed modifier when becoming a ghost
   inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "taern_speed_mod")
end

-- When loading or spawning the character
local function onload(inst)
    inst:ListenForEvent("ms_respawnedfromghost", onbecamehuman)
    inst:ListenForEvent("ms_becameghost", onbecameghost)

    if inst:HasTag("playerghost") then
        onbecameghost(inst)
    else
        onbecamehuman(inst)
    end
end


-- This initializes for both the server and client. Tags can be added here.
local common_postinit = function(inst) 
	-- Minimap icon
	inst.MiniMapEntity:SetIcon( "taern.tex" )
end

-- This initializes for the server only. Components are added here.
local master_postinit = function(inst)
	-- choose which sounds this character will play
	inst.soundsname = "wolfgang"
	
	-- Uncomment if "wathgrithr"(Wigfrid) or "webber" voice is used
    --inst.talker_path_override = "dontstarve_DLC001/characters/"
	
	-- Stats	
	inst.components.health:SetMaxHealth(100)
	inst.components.hunger:SetMax(200)
	inst.components.sanity:SetMax(200)
	
	-- Damage multiplier (optional)
    inst.components.combat.damagemultiplier = 1.5
	
	-- Hunger rate (optional)
	inst.components.hunger.hungerrate = 0.65 * TUNING.WILSON_HUNGER_RATE
	
	-----GRUNTS
	inst:AddComponent("petleash")
    inst.components.petleash:SetOnSpawnFn(OnSpawnPet)
    inst.components.petleash:SetOnDespawnFn(OnDespawnPet)
    inst.components.petleash:SetMaxPets(3)
	
	--Campfire made by K1NGT1GER609 <- this guy is amazing !
	local function fireheal(inst)
local x,y,z = inst.Transform:GetWorldPosition()
local max_rad = 3 --you have to be close to heal from the fire
local ents = TheSim:FindEntities(x,y,z, max_rad, nil, nil, {"campfire"}) --only look for campfires not forest fires
    for k,v in pairs(ents) do
    inst.components.health:DoDelta(1,1) --heal 1
    end
end

inst:DoPeriodicTask(0.5, fireheal, nil, inst) --do the heal every 2 seconds

	inst.OnLoad = onload
    inst.OnNewSpawn = onload
	
	return inst
end

return MakePlayerCharacter("taern", prefabs, assets, common_postinit, master_postinit, start_inv)

 

Creature

require "brains/shadowwaxwellbrain"
require "stategraphs/SGshadowwaxwell"

local assets = 
{
	Asset("ANIM", "anim/swap_pickaxe.zip"),
	Asset("ANIM", "anim/swap_axe.zip"),
	Asset("ANIM", "anim/swap_nightmaresword.zip"),

}

local prefabs =
{
    "shadow_despawn",
    "statue_transition_2",
    "nightmarefuel",	
}

local brain = require "brains/shadowwaxwellbrain"
local stategraph = require "stategraphs/SGshadowwaxwell"

local function linktoplayer(inst, player)
   -- inst.components.lootdropper:SetLoot(LOOT)
    inst.persists = false
    inst._playerlink = player
    player.grunt = inst
    player.components.leader:AddFollower(inst)
    for k, v in pairs(player.grunt) do
        k:Refresh()
    end
    player:ListenForEvent("onremove", unlink, inst)
end

local function OnAttacked(inst, data)
    if inst.components.follower.leader == data.attacker then
        if data.attacker.components.petleash ~= nil and
            data.attacker.components.petleash:IsPet(inst) then
            if inst.components.lootdropper == nil then
                inst:AddComponent("lootdropper")
            end
            inst.components.lootdropper:SpawnLootPrefab("nightmarefuel", inst:GetPosition())
            data.attacker.components.petleash:DespawnPet(inst)
        elseif data.attacker.components.combat ~= nil then
            inst.components.combat:SuggestTarget(data.attacker)
        end
    end
end

local function retargetfn(inst)
    --Find things attacking leader
    local leader = inst.components.follower:GetLeader()
    return leader ~= nil
        and FindEntity(
            leader,
            TUNING.SHADOWWAXWELL_TARGET_DIST,
            function(guy)
                return guy ~= inst
                    and (guy.components.combat:TargetIs(leader) or
                        guy.components.combat:TargetIs(inst))
                    and inst.components.combat:CanTarget(guy)
            end,
            { "_combat" }, -- see entityreplica.lua
            { "playerghost", "INLIMBO" }
        )
        or nil
end

local function keeptargetfn(inst, target)
    --Is your leader nearby and your target not dead? Stay on it.
    --Match KEEP_WORKING_DIST in brain
    return inst.components.follower:IsNearLeader(14)
        and inst.components.combat:CanTarget(target)
end

local function spearfn(inst)
    inst.components.health:SetMaxHealth(100)
    inst.components.health:StartRegen(TUNING.SHADOWWAXWELL_HEALTH_REGEN, TUNING.SHADOWWAXWELL_HEALTH_REGEN_PERIOD)

    inst.components.combat:SetDefaultDamage(50)
    inst.components.combat:SetAttackPeriod(TUNING.SHADOWWAXWELL_ATTACK_PERIOD)
    inst.components.combat:SetRetargetFunction(2, retargetfn) --Look for target.
    inst.components.combat:SetKeepTargetFunction(keeptargetfn) --Keep attacking while leader is near.

    return inst
end

local function nodebrisdmg(inst, amount, overtime, cause, ignore_invincible, afflicter, ignore_absorb)
    return afflicter ~= nil and afflicter:HasTag("quakedebris")
end

local function NoHoles(pt)
    return not TheWorld.Map:IsPointNearHole(pt)
end

local function onbuilt(inst, builder)
    local theta = math.random() * 2 * PI
    local pt = builder:GetPosition()
    local radius = math.random(3, 6)
    local offset = FindWalkableOffset(pt, theta, radius, 12, true, true, NoHoles)
    if offset ~= nil then
        pt.x = pt.x + offset.x
        pt.z = pt.z + offset.z
    end
    builder.components.petleash:SpawnPetAt(pt.x, 0, pt.z, inst.pettype)
    inst:Remove()
end

local function MakeBuilder(prefab)
    --These shadows are summoned this way because petleash needs to
    --be the component that summons the pets, not the builder.
    local function fn()
        local inst = CreateEntity()

        inst.entity:AddTransform()

        inst:AddTag("CLASSIFIED")

        --[[Non-networked entity]]
        inst.persists = false

        --Auto-remove if not spawned by builder
        inst:DoTaskInTime(0, inst.Remove)

        if not TheWorld.ismastersim then
            return inst
        end

        inst.pettype = prefab
        inst.OnBuiltFn = onbuilt

        return inst
    end

    return Prefab(prefab.."_builder", fn, nil, { prefab })
end

local function MakeMinion(prefab, tool, hat, master_postinit)
    local assets =
    {
        Asset("ANIM", "anim/taern.zip"),
        Asset("SOUND", "sound/maxwell.fsb"),
        Asset("ANIM", "anim/"..tool..".zip"),
    }

    local function fn()
        local inst = CreateEntity()

        inst.entity:AddTransform()
        inst.entity:AddAnimState()
        inst.entity:AddSoundEmitter()
        inst.entity:AddNetwork()

        MakeGhostPhysics(inst, 1, 0.5)

        inst.Transform:SetFourFaced(inst)

        inst.AnimState:SetBank("wilson")
        inst.AnimState:SetBuild("taern")
        inst.AnimState:PlayAnimation("idle")
       -- inst.AnimState:SetMultColour(0, 0, 0, .5)

        if tool ~= nil then
            inst.AnimState:OverrideSymbol("swap_object", tool, tool)
            inst.AnimState:Hide("ARM_normal")
        else
            inst.AnimState:Hide("ARM_carry")
        end

        if hat ~= nil then
            inst.AnimState:OverrideSymbol("swap_hat", hat, "swap_hat")
            inst.AnimState:Hide("HAIR_NOHAT")
            inst.AnimState:Hide("HAIR")
        else
            inst.AnimState:Hide("HAT")
            inst.AnimState:Hide("HAIR_HAT")
        end

        inst:AddTag("scarytoprey")
        inst:AddTag("grunt")
        inst:AddTag("NOBLOCK")

        inst:SetPrefabNameOverride("grunt")

        inst.entity:SetPristine()

        if not TheWorld.ismastersim then
            return inst
        end

        inst:AddComponent("locomotor")
        inst.components.locomotor.runspeed = TUNING.SHADOWWAXWELL_SPEED
        inst.components.locomotor.pathcaps = { ignorecreep = true }
        inst.components.locomotor:SetSlowMultiplier(.6)

        inst:AddComponent("health")
        inst.components.health:SetMaxHealth(1)
        inst.components.health.nofadeout = true
        inst.components.health.redirect = nodebrisdmg

        inst:AddComponent("combat")
        inst.components.combat.hiteffectsymbol = "torso"
        inst.components.combat:SetRange(2)

        inst:AddComponent("follower")
        inst.components.follower:KeepLeaderOnAttacked()
        inst.components.follower.keepdeadleader = true

        --inst:SetBrain("shadowwaxwellbrain")
		inst:SetBrain(brain)
        inst:SetStateGraph("SGshadowwaxwell")

        inst:ListenForEvent("attacked", OnAttacked)
		----
		inst.LinkToPlayer = linktoplayer
		
   -- inst:ListenForEvent("onbuilt", OnBuilt)
	---inst:DoTaskInTime(0.1, function() if inst.components.follower and not inst.components.follower.leader then inst:Remove() end end)
	
        if master_postinit ~= nil then
            master_postinit(inst)
        end

        return inst
    end

    return Prefab(prefab, fn, assets, prefabs)
end

return 
   MakeMinion("grunt", "swap_spear", nil, spearfn),
   MakeBuilder("grunt")

followers.zip

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