Jump to content

Multiple Followers Crash


Recommended Posts

Problem with Followers.

 

 

I'm trying to implement the Damaged Chess Followers into the game, and when one spawns, it works fine

but when I spawn a second one, the first one crashes the game with the following error:

 

Note: Knight was the First follower, Bishop was the second follower.

 

Error:




[string "scripts/prefabs/knight.lua"]:75: variable 'myleader' is not declared
LUA ERROR stack traceback:
=[C]:-1 in (global) error (C) <-1--1>
scripts/strict.lua:23 in () ? (Lua) <21-26>
   t = table: 0D252968
   n = myleader
scripts/prefabs/knight.lua:75 in (local) fn (Lua) <72-81>
   guy = 116929 - bishop_nightmare (valid:true)
   myLeader = 115771 - wilson (valid:true)
   theirLeader = 115771 - wilson (valid:true)
scripts/simutil.lua:40 in (global) FindEntity (Lua) <33-45>
   inst = 116730 - knight_nightmare (valid:true)
   radius = 10
   fn = function - scripts/prefabs/knight.lua:72
   musttags = nil
   canttags = nil
   mustoneoftags = nil
   x = 394.32562255859
   y = -1.8167193971408e-008
   z = -107.9944152832
   ents = table: 2D3B8EA0
   k = 14
   v = 116929 - bishop_nightmare (valid:true)
scripts/prefabs/knight.lua:72 in (field) targetfn (Lua) <63-83>
   inst = 116730 - knight_nightmare (valid:true)
   homePos = (454.33, 0.00, -197.60)
   myPos = (394.33, -0.00, -107.99)
scripts/components/combat.lua:154 in (method) TryRetarget (Lua) <149-164>
   self =
      hiteffectsymbol = spring
      defaultdamage = 40
      keeptargetfn = function - scripts/prefabs/knight.lua:85
      inst = 116730 - knight_nightmare (valid:true)
      retargetperiod = 3
      hitrange = 3
      keeptargettimeout = 0.73333331942558
      lasttargetGUID = 116561
      pvp_damagemod = 1
      lastdoattacktime = 166.20000866801
      laststartattacktime = 165.63334197178
      retargettask = PERIODIC 116730: 3.000000
      nextbattlecrytime = 175.01722322884
      lastattacker = 116832 - hound (valid:false)
      losetargetcallback = function - scripts/components/combat.lua:235
      targetfn = function - scripts/prefabs/knight.lua:63
      _ = table: 2D102788
      playerdamagepercent = 1
scripts/components/combat.lua:146 in (field) fn (Lua) <145-147>
   inst = 116730 - knight_nightmare (valid:true)
scripts/scheduler.lua:170 in (method) OnTick (Lua) <144-199>
   self =
      running = table: 12FAF768
      waitingfortick = table: 12FAF740
      tasks = table: 12FAF6F0
      waking = table: 2D3B7CF8
      attime = table: 12FAF830
      hibernating = table: 12FAF808
   tick = 5336
   k = PERIODIC 116730: 3.000000
   v = true
   already_dead = nil
scripts/scheduler.lua:380 in (global) RunScheduler (Lua) <378-386>
   tick = 5336
scripts/update.lua:134 in () ? (Lua) <118-180>
   dt = 0.033333335071802
   tick = 5336
   i = 5336



 

Knight Code as found in the game:




local assets =
{
Asset("ANIM", "anim/knight.zip"),
Asset("ANIM", "anim/knight_build.zip"),
    Asset("ANIM", "anim/knight_nightmare.zip"),
Asset("SOUND", "sound/chess.fsb"),
}


local prefabs =
{
"gears",
    "thulecite_pieces",
    "nightmarefuel",
}


local brain = require "brains/knightbrain"


SetSharedLootTable( 'knight',
{
    {'gears',  1.0},
    {'gears',  1.0},
})


SetSharedLootTable( 'knight_nightmare',
{
    {'gears',             1.0},
    {'nightmarefuel',     0.6},
    {'thulecite_pieces',  0.5},
})


local SLEEP_DIST_FROMHOME = 1
local SLEEP_DIST_FROMTHREAT = 20
local MAX_CHASEAWAY_DIST = 40
local MAX_TARGET_SHARES = 5
local SHARE_TARGET_DIST = 40


local function ShouldSleep(inst)
    local homePos = inst.components.knownlocations:GetLocation("home")
    local myPos = Vector3(inst.Transform:GetWorldPosition() )
    if not (homePos and distsq(homePos, myPos) <= SLEEP_DIST_FROMHOME*SLEEP_DIST_FROMHOME)
       or (inst.components.combat and inst.components.combat.target)
       or (inst.components.burnable and inst.components.burnable:IsBurning() )
       or (inst.components.freezable and inst.components.freezable:IsFrozen() ) then
        return false
    end
    local nearestEnt = GetClosestInstWithTag("character", inst, SLEEP_DIST_FROMTHREAT)
    return nearestEnt == nil
end


local function ShouldWake(inst)
    local homePos = inst.components.knownlocations:GetLocation("home")
    local myPos = Vector3(inst.Transform:GetWorldPosition() )
    if (homePos and distsq(homePos, myPos) > SLEEP_DIST_FROMHOME*SLEEP_DIST_FROMHOME)
       or (inst.components.combat and inst.components.combat.target)
       or (inst.components.burnable and inst.components.burnable:IsBurning() )
       or (inst.components.freezable and inst.components.freezable:IsFrozen() ) then
        return true
    end
    local nearestEnt = GetClosestInstWithTag("character", inst, SLEEP_DIST_FROMTHREAT)
    return nearestEnt
end


local function Retarget(inst)


    local homePos = inst.components.knownlocations:GetLocation("home")
    local myPos = Vector3(inst.Transform:GetWorldPosition() )
    if (homePos and distsq(homePos, myPos) > TUNING.KNIGHT_TARGET_DIST*TUNING.KNIGHT_TARGET_DIST) and not
    (inst.components.follower and inst.components.follower.leader) then
        return
    end
    
    local newtarget = FindEntity(inst, TUNING.KNIGHT_TARGET_DIST, function(guy)
local myLeader = inst.components.follower and inst.components.follower.leader
local theirLeader = guy.components.follower and guy.components.follower.leader
local bothFollowingSamePlayer = myLeader and (myLeader == theirLeader) and myleader:HasTag("player")
            return (guy:HasTag("character") or guy:HasTag("monster") )
                   and not (guy:HasTag("chess") and (guy.components.follower and not guy.components.follower.leader))
                    and not bothFollowingSamePlayer
                   and not (inst.components.follower and inst.components.follower.leader == guy)
                   and inst.components.combat:CanTarget(guy)
    end)
    return newtarget
end


local function KeepTarget(inst, target)
    if (inst.components.follower and inst.components.follower.leader) then
        return true
    end


    local homePos = inst.components.knownlocations:GetLocation("home")
    local targetPos = Vector3(target.Transform:GetWorldPosition() )
    return homePos and distsq(homePos, targetPos) < MAX_CHASEAWAY_DIST*MAX_CHASEAWAY_DIST
end


local function OnAttacked(inst, data)
    local attacker = data and data.attacker
    if attacker and attacker:HasTag("chess") then return end
    inst.components.combat:SetTarget(attacker)
    inst.components.combat:ShareTarget(attacker, SHARE_TARGET_DIST, function(dude) return dude:HasTag("chess") end, MAX_TARGET_SHARES)
end


local function RememberKnownLocation(inst)
    inst.components.knownlocations:RememberLocation("home", Vector3(inst.Transform:GetWorldPosition()))
end


local function fn_common(build)
local inst = CreateEntity()


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


    MakeCharacterPhysics(inst, 50, .5)


    inst.DynamicShadow:SetSize(1.5, .75)
    inst.Transform:SetFourFaced()


    inst.AnimState:SetBank("knight")
    inst.AnimState:SetBuild(build)


    inst:AddTag("monster")
    inst:AddTag("hostile")
    inst:AddTag("chess")
    inst:AddTag("knight")


    if not TheWorld.ismastersim then
        return inst
    end


    inst.entity:SetPristine()


    inst.kind = ""


    inst:AddComponent("locomotor")
    inst.components.locomotor.walkspeed = TUNING.KNIGHT_WALK_SPEED


    inst:SetStateGraph("SGknight")


    inst:SetBrain(brain)


    inst:AddComponent("sleeper")
    inst.components.sleeper:SetWakeTest(ShouldWake)
    inst.components.sleeper:SetSleepTest(ShouldSleep)
    inst.components.sleeper:SetResistance(3)


    inst:AddComponent("health")
    inst:AddComponent("combat")
    inst.components.combat.hiteffectsymbol = "spring"
    inst.components.combat:SetAttackPeriod(TUNING.KNIGHT_ATTACK_PERIOD)
    inst.components.combat:SetRetargetFunction(3, Retarget)
    inst.components.combat:SetKeepTargetFunction(KeepTarget)


    inst.components.health:SetMaxHealth(TUNING.KNIGHT_HEALTH)
    inst.components.combat:SetDefaultDamage(TUNING.KNIGHT_DAMAGE)
    inst.components.combat:SetAttackPeriod(TUNING.KNIGHT_ATTACK_PERIOD)


    inst:AddComponent("lootdropper")
    inst.components.lootdropper:SetChanceLootTable('knight')


    inst:AddComponent("inspectable")
    inst:AddComponent("knownlocations")


    inst:DoTaskInTime(1*FRAMES, RememberKnownLocation)


    inst:AddComponent("follower")


    MakeMediumBurnableCharacter(inst, "spring")
    MakeMediumFreezableCharacter(inst, "spring")


    MakeHauntablePanic(inst)


    inst:ListenForEvent("attacked", OnAttacked)


    return inst
end


local function fn()
    local inst = fn_common("knight_build")


    if not TheWorld.ismastersim then
        return inst
    end


    inst.kind = ""


    return inst
end


local function nightmarefn()
    local inst = fn_common("knight_nightmare")


    if not TheWorld.ismastersim then
        return inst
    end


    inst.kind = "_nightmare"
    inst.components.lootdropper:SetChanceLootTable("knight_nightmare")
    return inst
end


return Prefab("chessboard/knight", fn, assets, prefabs),
Prefab("cave/monsters/knight_nightmare", nightmarefn, assets, prefabs)



 

Bishop Code as found in the game:




local assets =
{
Asset("ANIM", "anim/bishop.zip"),
Asset("ANIM", "anim/bishop_build.zip"),
Asset("ANIM", "anim/bishop_nightmare.zip"),
Asset("SOUND", "sound/chess.fsb"),
}


local prefabs =
{
"gears",
    "bishop_charge",
    "purplegem",
}


local brain = require "brains/bishopbrain"


SetSharedLootTable( 'bishop',
{
    {'gears',       1.0},
    {'gears',       1.0},
    {'purplegem',   1.0},
})


SetSharedLootTable( 'bishop_nightmare',
{
    {'purplegem',         1.0},
    {'nightmarefuel',     0.6},
    {'thulecite_pieces',  0.5},
})


local SLEEP_DIST_FROMHOME = 1
local SLEEP_DIST_FROMTHREAT = 20
local MAX_CHASEAWAY_DIST = 40
local MAX_TARGET_SHARES = 5
local SHARE_TARGET_DIST = 40


local function ShouldSleep(inst)
    local homePos = inst.components.knownlocations:GetLocation("home")
    local myPos = Vector3(inst.Transform:GetWorldPosition() )
    if not (homePos and distsq(homePos, myPos) <= SLEEP_DIST_FROMHOME*SLEEP_DIST_FROMHOME)
       or (inst.components.combat and inst.components.combat.target)
       or (inst.components.burnable and inst.components.burnable:IsBurning() )
       or (inst.components.freezable and inst.components.freezable:IsFrozen() ) then
        return false
    end
    local nearestEnt = GetClosestInstWithTag("character", inst, SLEEP_DIST_FROMTHREAT)
    return nearestEnt == nil
end


local function ShouldWake(inst)
    local homePos = inst.components.knownlocations:GetLocation("home")
    local myPos = Vector3(inst.Transform:GetWorldPosition() )
    if (homePos and distsq(homePos, myPos) > SLEEP_DIST_FROMHOME*SLEEP_DIST_FROMHOME)
       or (inst.components.combat and inst.components.combat.target)
       or (inst.components.burnable and inst.components.burnable:IsBurning() )
       or (inst.components.freezable and inst.components.freezable:IsFrozen() ) then
        return true
    end
    local nearestEnt = GetClosestInstWithTag("character", inst, SLEEP_DIST_FROMTHREAT)
    return nearestEnt
end


local function Retarget(inst)
    local homePos = inst.components.knownlocations:GetLocation("home")
    local myPos = Vector3(inst.Transform:GetWorldPosition() )
    if (homePos and distsq(homePos, myPos) > TUNING.BISHOP_TARGET_DIST*TUNING.BISHOP_TARGET_DIST) and not
    (inst.components.follower and inst.components.follower.leader) then
        return
    end
    
    local newtarget = FindEntity(inst, TUNING.BISHOP_TARGET_DIST, function(guy)
local myLeader = inst.components.follower and inst.components.follower.leader
local theirLeader = guy.components.follower and guy.components.follower.leader
local bothFollowingSamePlayer = myLeader and (myLeader == theirLeader) and myleader:HasTag("player")
            return (guy:HasTag("character") or guy:HasTag("monster") )
                   and not (inst.components.follower and inst.components.follower.leader == guy)
                   and not bothFollowingSamePlayer
                   and not  (guy:HasTag("chess") and (guy.components.follower and not guy.components.follower.leader))
                   and inst.components.combat:CanTarget(guy)
    end)
    return newtarget
end


local function KeepTarget(inst, target)


    if (inst.components.follower and inst.components.follower.leader) then
        return true
    end


    local homePos = inst.components.knownlocations:GetLocation("home")
    local targetPos = Vector3(target.Transform:GetWorldPosition() )
    return homePos and distsq(homePos, targetPos) < MAX_CHASEAWAY_DIST*MAX_CHASEAWAY_DIST
end


local function ShareTargetFn(dude)
    return dude:HasTag("chess")
end


local function OnAttacked(inst, data)
    local attacker = data and data.attacker
    if attacker and attacker:HasTag("chess") then
        return
    end
    inst.components.combat:SetTarget(attacker)
    inst.components.combat:ShareTarget(attacker, SHARE_TARGET_DIST, ShareTargetFn, MAX_TARGET_SHARES)
end


local function EquipWeapon(inst)
    if inst.components.inventory and not inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) then
        local weapon = CreateEntity()
        --[[Non-networked entity]]
        weapon.entity:AddTransform()
        weapon:AddComponent("weapon")
        weapon.components.weapon:SetDamage(inst.components.combat.defaultdamage)
        weapon.components.weapon:SetRange(inst.components.combat.attackrange, inst.components.combat.attackrange+4)
        weapon.components.weapon:SetProjectile("bishop_charge")
        weapon:AddComponent("inventoryitem")
        weapon.persists = false
        weapon.components.inventoryitem:SetOnDroppedFn(inst.Remove)
        weapon:AddComponent("equippable")
        
        inst.components.inventory:Equip(weapon)
    end
end


local function RememberKnownLocation(inst)
    inst.components.knownlocations:RememberLocation("home", Vector3(inst.Transform:GetWorldPosition()))
end


local function common_fn(build)
    local inst = CreateEntity()


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


    MakeCharacterPhysics(inst, 50, .5)


    inst.DynamicShadow:SetSize(1.5, .75)
    inst.Transform:SetFourFaced()


    inst.AnimState:SetBank("bishop")
    inst.AnimState:SetBuild(build)


    inst:AddTag("monster")
    inst:AddTag("hostile")
    inst:AddTag("chess")
    inst:AddTag("bishop")


    if not TheWorld.ismastersim then
        return inst
    end


    inst.entity:SetPristine()


    inst:AddComponent("lootdropper")


    inst:AddComponent("locomotor")
    inst.components.locomotor.walkspeed = TUNING.BISHOP_WALK_SPEED


    inst:SetStateGraph("SGbishop")
    inst:SetBrain(brain)


    inst:AddComponent("sleeper")
    inst.components.sleeper:SetWakeTest(ShouldWake)
    inst.components.sleeper:SetSleepTest(ShouldSleep)
    inst.components.sleeper:SetResistance(3)


    inst:AddComponent("combat")
    inst.components.combat.hiteffectsymbol = "waist"
    inst.components.combat:SetAttackPeriod(TUNING.BISHOP_ATTACK_PERIOD)
    inst.components.combat:SetRange(TUNING.BISHOP_ATTACK_DIST)
    inst.components.combat:SetRetargetFunction(3, Retarget)
    inst.components.combat:SetKeepTargetFunction(KeepTarget)


    inst:AddComponent("health")
    inst.components.health:SetMaxHealth(TUNING.BISHOP_HEALTH)
    inst.components.combat:SetDefaultDamage(TUNING.BISHOP_DAMAGE)
    inst.components.combat:SetAttackPeriod(TUNING.BISHOP_ATTACK_PERIOD)


    inst:AddComponent("inventory")


    inst:AddComponent("inspectable")
    inst:AddComponent("knownlocations")


    inst:DoTaskInTime(1*FRAMES, RememberKnownLocation)
    inst:DoTaskInTime(1, EquipWeapon)


    inst:AddComponent("follower")


    MakeMediumBurnableCharacter(inst, "waist")
    MakeMediumFreezableCharacter(inst, "waist")


    MakeHauntablePanic(inst)


    inst:ListenForEvent("attacked", OnAttacked)


    return inst
end


local function bishop_fn()
    local inst = common_fn("bishop_build")


    if not TheWorld.ismastersim then
        return inst
    end


    inst.components.lootdropper:SetChanceLootTable('bishop')
    inst.kind = ""
    inst.soundpath = "dontstarve/creatures/bishop/"
    inst.effortsound = "dontstarve/creatures/bishop/idle"


    return inst
end


local function bishop_nightmare_fn()
    local inst = common_fn("bishop_nightmare")


    if not TheWorld.ismastersim then
        return inst
    end


    inst.components.lootdropper:SetChanceLootTable('bishop_nightmare')
    inst.kind = "_nightmare"
    inst.soundpath = "dontstarve/creatures/bishop_nightmare/"
    inst.effortsound = "dontstarve/creatures/bishop_nightmare/rattle"


    return inst
end


return Prefab("chessboard/bishop", bishop_fn, assets, prefabs),
       Prefab("cave/monsters/bishop_nightmare", bishop_nightmare_fn, assets, prefabs)



 

Any help would be appreciated.

 

Edited by Aquaterion
Link to comment
Share on other sites

 

The bug is just a typo klei made

local bothFollowingSamePlayer = myLeader and (myLeader == theirLeader) and myleader:HasTag("player")

the last myleader has a lower case L.

 

 

Ah thanks, Silly Klei for that typo, and silly me for not checking well.

Link to comment
Share on other sites

  • Developer

Ah Awesome, Just maybe if u wanna fix it too, chessjunk.lua had some problems with "end"s if I remember, it had 2 extra ones.

 

Chessjunk is a caves thing and we haven't gotten to updating it quite yet. In time! (I will keep this in mind as something to watch out for when we do get there)

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...