Jump to content

Custom character coding - what am I doing wrong?


Recommended Posts

Heya,

I'm making a custom character based on the grim adventures of billy and mandy. I made a similar one for dont starve many years ago and left it at a wip state. Now I want to make it properly to the end this time around.

Spoiler

image.thumb.png.ad4ef06c0ec640512a6c13bdb2baeaca.png


local assets=
{ 
    Asset("ANIM", "anim/reaper.zip"),
    Asset("ANIM", "anim/swap_reaper.zip"), 

    Asset("ATLAS", "images/inventoryimages/reaper.xml"),
    Asset("IMAGE", "images/inventoryimages/reaper.tex"),
}

local prefabs = 
{
	"shadowtentacle",
}

local summonchance = 0.2

local function onattack(inst, owner, target)
    if math.random() < summonchance then
        local pt = target:GetPosition()
        local st_pt =  FindWalkableOffset(pt or owner:GetPosition(), math.random()*2*PI, 2, 3)
        if st_pt then
            inst.SoundEmitter:PlaySound("dontstarve/common/shadowTentacleAttack_1")
            --inst.SoundEmitter:PlaySound("dontstarve/common/shadowTentacleAttack_2")            
            st_pt = st_pt + pt
            local st = SpawnPrefab("shadowtentacle")
            --print(st_pt.x, st_pt.y, st_pt.z)
            st.Transform:SetPosition(st_pt.x, st_pt.y, st_pt.z)
            st.components.combat:SetTarget(target)
			st.components.sanityaura.aura = 0
        end
    end
end

local function OnEquip(inst, owner) 
    owner.AnimState:OverrideSymbol("swap_object", "swap_reaper", "reaper")
    owner.AnimState:Show("ARM_carry") 
    owner.AnimState:Hide("ARM_normal") 
end
	

local function OnUnequip(inst, owner) 
    owner.AnimState:Hide("ARM_carry") 
    owner.AnimState:Show("ARM_normal") 
end


local function fn()

    local inst = CreateEntity()
	
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
	inst.entity:AddNetwork()
	inst.entity:AddSoundEmitter()
	MakeInventoryPhysics(inst)
	
	inst.AnimState:SetBank("reaper")
    inst.AnimState:SetBuild("reaper")
    inst.AnimState:PlayAnimation("idle")

    if not TheWorld.ismastersim then
        return inst
    end
	
	inst.entity:SetPristine()
	
	inst:AddTag("sharp")

    inst:AddComponent("weapon")
    inst.components.weapon:SetDamage(TUNING.BATBAT_DAMAGE)
    inst.components.weapon:SetOnAttack(onattack)
	
	inst:AddComponent("inspectable")

    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem.imagename = "reaper"
    inst.components.inventoryitem.atlasname = "images/inventoryimages/reaper.xml"
    
    inst:AddComponent("equippable")
    inst.components.equippable:SetOnEquip( OnEquip )
    inst.components.equippable:SetOnUnequip( OnUnequip )
	
	MakeHauntableLaunch(inst)

    return inst
end

return  Prefab("common/inventory/reaper", fn, assets, prefabs)

 

I've made much progress but run into some complications. Firstly, my character doesn't display his custom item correctly on the character select screen (but it works correctly in the inventory after selecting him and spawning into the world). I thought I did everything correctly with his custom item but apparently not quite.

How can I fix it to display correctly in the character select screen? <-fixed by adding this line to my mod.main: TUNING.STARTING_ITEM_IMAGE_OVERRIDE["reaper"] = {atlas = "images/inventoryimages/reaper.xml", image = "reaper.tex"}

Also, I have this pickable prefab (called grimhead) that I want removed from the world after my character picks it. grimhead.lua:

Spoiler

local assets=
{ 
    Asset("ANIM", "anim/grimhead.zip"),
}

local prefabs = 
{
	"thegrimreaper",
}

local function onpickedfn(inst, picker)
	if picker.prefab == "thegrimreaper" then
		if picker:HasTag("headless") then
			picker.togglehead(picker)
		else
			picker.components.talker:Say("Dat's not mine.")
		end
	else 
		picker.components.talker:Say("It doesn't accept me.")
	end
	
end

local function fn()

    local inst = CreateEntity()
	
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
	inst.entity:AddNetwork()
	--inst.entity:AddSoundEmitter()
	MakeInventoryPhysics(inst)
	
	inst.AnimState:SetBank("grimhead")
    inst.AnimState:SetBuild("grimhead")
    inst.AnimState:PlayAnimation("idle")

    if not TheWorld.ismastersim then
        return inst
    end
	
	inst.entity:SetPristine()
	
	inst:AddComponent("inspectable")
	inst:AddComponent("pickable")
	inst.components.pickable.onpickedfn = onpickedfn
	inst.components.pickable:SetUp(nil, 0.01)
	
	
    return inst
end

return  Prefab("grimhead", fn, assets, prefabs)

 

It works otherwise fine but I'm having trouble despawning it from within my character.lua. thegrimreaper.lua:

Spoiler

local MakePlayerCharacter = require "prefabs/player_common"

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

local prefabs = 
{
        "reaper",
		"grimhead",
}

-- Your character's stats
TUNING.THEGRIMREAPER_HEALTH = 125
TUNING.THEGRIMREAPER_HUNGER = 150
TUNING.THEGRIMREAPER_SANITY = 175
local headdropchance = .5 --default .07 = 7%
local bonedropchance = .06 --default .06 = 6%
local toothdropchance = .02 --default .02 = 2%
local headlesssanitydrain = -0.25 --default -0.25
local myhead = nil

-- Custom starting inventory
TUNING.GAMEMODE_STARTING_ITEMS.DEFAULT.THEGRIMREAPER = {
	"reaper",
	"pigskin",
}

local start_inv = {}
for k, v in pairs(TUNING.GAMEMODE_STARTING_ITEMS) do
    start_inv[string.lower(k)] = v.THEGRIMREAPER
end

local prefabs = FlattenTree(start_inv, true)

-- When the character is revived from human
local function onbecamehuman(inst)
	-- Set speed when not a ghost (optional)
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "thegrimreaper_speed_mod", 1)
	if inst:HasTag("headless") then
		inst.AnimState:SetBuild("thegrimreaper_headless")
		--inst.AnimState:PlayAnimation("idle") 
		-- Change the stats for the transformed character here.
		inst.components.sanity.dapperness = headlesssanitydrain
		-- No head = no mouth, so no eating either
		inst.components.eater.caneat = nil
		-- No head = no mouth, so no speaking either
		inst.components.talker:IgnoreAll(inst)
		if inst.myhead~= nil then
			inst.myhead:Remove()
		end
	end
end

local function onbecameghost(inst)
	-- Remove speed modifier when becoming a ghost
    inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "thegrimreaper_speed_mod")
	if inst:HasTag("headless") then
		inst.components.sanity.dapperness = 0
		inst.components.eater.caneat = { FOODGROUP.OMNI }
		inst.components.talker:StopIgnoringAll(inst)
		inst:RemoveTag("headless")
		
		--Remove dropped grimhead
		if inst.myhead~= nil then
			inst.myhead:Remove()
		end
	end
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


-- Transformation for headless
local function togglehead(inst)

	-- Ignore while we are a ghost.
	if inst:HasTag("playerghost") then return end

	if not inst:HasTag("headless") then
		inst:AddTag("headless")
		-- Set the animation build for the transformed form here.
		inst.AnimState:SetBuild("thegrimreaper_headless")
		--inst.AnimState:PlayAnimation("idle") 
		-- Change the stats for the transformed character here.
		inst.components.sanity.dapperness = headlesssanitydrain
		inst.components.sanity:DoDelta(-5)
		-- No head = no mouth, so no eating either
		inst.components.eater.caneat = nil
		-- No head = no mouth, so no speaking either
		inst.components.talker:IgnoreAll(inst)
		-- No head, so no wearing anything on head
		local item = inst.components.inventory:Unequip(EQUIPSLOTS.HEAD)
		if item then
			inst.components.inventory:DropItem(item)
		end
		local x,y,z = inst.Transform:GetWorldPosition()
		inst.myhead = SpawnPrefab("grimhead").Transform:SetPosition(x,y+2.5,z)
		
	else
		-- Set the animation build for the original form here.
		inst.AnimState:SetBuild("thegrimreaper")
		--inst.AnimState:PlayAnimation("idle") 
		-- Change the stats for the original character here.
		inst.components.sanity.dapperness = 0
		inst.components.eater.caneat = { FOODGROUP.OMNI }
		inst.components.talker:StopIgnoringAll(inst)
		if inst and inst.components.talker then
			inst.components.talker:Say("Phew... I am whole again.")
		end
		inst:RemoveTag("headless")
		if inst.myhead ~= nil then
			inst.myhead:Remove()
		end
	end
	

end


-- For bone dropping chance on being attacked and also head dropping
local function OnAttacked(inst)
	local headitem = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
	if not headitem or not headitem.components.armor then
		local headdroprng = math.random()
		if headdroprng < headdropchance and not inst:HasTag("headless") then
			togglehead(inst)
		end
	end
	
	local rng = math.random()
	if  rng < bonedropchance then
		if rng < toothdropchance then
			inst.components.shedder.shedItemPrefab = "houndstooth"
			inst.components.shedder:DoSingleShed()
		else 
			inst.components.shedder.shedItemPrefab = "boneshard"
			inst.components.shedder:DoSingleShed()
		end
		inst.components.talker:Say("AGHH! Did I break a bone?")
    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( "thegrimreaper.tex" )
end

-- This initializes for the server only. Components are added here.
local master_postinit = function(inst)
	-- Set starting inventory
    inst.starting_inventory = start_inv[TheNet:GetServerGameMode()] or start_inv.default
	
	-- choose which sounds this character will play
	inst.soundsname = "warly"
	inst.entity:AddSoundEmitter()
	
	-- For bone dropping
	inst:AddComponent("shedder")
	inst.components.shedder.shedItemPrefab = "boneshard"
    inst.components.shedder.shedHeight = 2.5
	
	-- Stats	
	inst.components.health:SetMaxHealth(TUNING.THEGRIMREAPER_HEALTH)
	inst.components.hunger:SetMax(TUNING.THEGRIMREAPER_HUNGER)
	inst.components.sanity:SetMax(TUNING.THEGRIMREAPER_SANITY)
	
	inst.components.sanity.neg_aura_mult = 0.5
	
	inst.components.sanity.night_drain_mult = 0.5
	
	-- Damage multiplier (optional)
    inst.components.combat.damagemultiplier = 1.2
	
	-- Hunger rate (optional)
	inst.components.hunger.hungerrate = 0.4 * TUNING.WILSON_HUNGER_RATE
	local myhead = nil
	
	-- Blocks use of headgear when headless
	local _Equip = inst.components.inventory.Equip

	inst.components.inventory.Equip = function(self, item, old_to_active)
		if not item or not item.components.equippable or not item:IsValid() then
			return
		end
	
		if inst:HasTag("headless") and item.components.equippable.equipslot == EQUIPSLOTS.HEAD then
			self:DropItem(item)
			self:GiveItem(item)
			return
		end		
		return _Equip(self, item, old_to_active)	
	end
	
	inst:ListenForEvent("attacked", OnAttacked)
	
	inst.OnLoad = onload
    inst.OnNewSpawn = onload
	inst.togglehead = togglehead
	
end

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

 

As I believe the problem lies in how I handle the variable 'myhead' but I've tried fidgeting with it for a while now and seem to run in circles in how to handle trying to despawn it. <-fixed in my comment

The basic logic behind my character is that if he gets hit while he doesnt have a helmet on, he has a chance to drop his head (spawn grimhead, transform into headless char texture). Then he can pick his dropped head back up and regain his lost form (despawn head when picked by my character with a tag "headless" and transform back to base char texture). I'm probably breaking some sort of form in my code since it doesnt save the headless transformation (on relog my character has his head back) and I'm unable to despawn the dropped head properly...) . What can or should I do to make him I want him to work?

Modmain if it is needed:

Spoiler

PrefabFiles = {
	"thegrimreaper",
	"thegrimreaper_none",
	"reaper",
	"grimhead",
}

Assets = {
    Asset( "IMAGE", "images/saveslot_portraits/thegrimreaper.tex" ),
    Asset( "ATLAS", "images/saveslot_portraits/thegrimreaper.xml" ),

    Asset( "IMAGE", "images/selectscreen_portraits/thegrimreaper.tex" ),
    Asset( "ATLAS", "images/selectscreen_portraits/thegrimreaper.xml" ),
	
    Asset( "IMAGE", "images/selectscreen_portraits/thegrimreaper_silho.tex" ),
    Asset( "ATLAS", "images/selectscreen_portraits/thegrimreaper_silho.xml" ),

    Asset( "IMAGE", "bigportraits/thegrimreaper.tex" ),
    Asset( "ATLAS", "bigportraits/thegrimreaper.xml" ),
	
	Asset( "IMAGE", "images/map_icons/thegrimreaper.tex" ),
	Asset( "ATLAS", "images/map_icons/thegrimreaper.xml" ),
	
	Asset( "IMAGE", "images/avatars/avatar_thegrimreaper.tex" ),
    Asset( "ATLAS", "images/avatars/avatar_thegrimreaper.xml" ),
	
	Asset( "IMAGE", "images/avatars/avatar_ghost_thegrimreaper.tex" ),
    Asset( "ATLAS", "images/avatars/avatar_ghost_thegrimreaper.xml" ),
	
	Asset( "IMAGE", "images/avatars/self_inspect_thegrimreaper.tex" ),
    Asset( "ATLAS", "images/avatars/self_inspect_thegrimreaper.xml" ),
	
	Asset( "IMAGE", "images/names_thegrimreaper.tex" ),
    Asset( "ATLAS", "images/names_thegrimreaper.xml" ),
	
	Asset( "IMAGE", "images/names_gold_thegrimreaper.tex" ),
    Asset( "ATLAS", "images/names_gold_thegrimreaper.xml" ),
	
	Asset("ANIM", "anim/thegrimreaper_headless.zip"),
	Asset("ANIM", "anim/reaper.zip"),
	Asset("ANIM", "anim/swap_reaper.zip"),
	Asset("IMAGE", "images/inventoryimages/reaper.tex"),
	Asset("ATLAS", "images/inventoryimages/reaper.xml"),
	
	Asset("ANIM", "anim/grimhead.zip"),

}


AddMinimapAtlas("images/map_icons/thegrimreaper.xml")

local require = GLOBAL.require
local STRINGS = GLOBAL.STRINGS

-- The character select screen lines
STRINGS.CHARACTER_TITLES.thegrimreaper = "The Grim Reaper"
STRINGS.CHARACTER_NAMES.thegrimreaper = "Grim"
STRINGS.CHARACTER_DESCRIPTIONS.thegrimreaper = "*Not that afraid of the dark or monsters.\n*Small chance to drop bits of bone on getting hit.\n*Starts with his scythe.\n*Protect his head..."
STRINGS.CHARACTER_QUOTES.thegrimreaper = "\"I am de Grim Reaper, master of de forces of life and death! Or at least I was, until I met Billy and Mandy.\""
STRINGS.CHARACTER_SURVIVABILITY.thegrimreaper = "Grim"

-- Custom speech strings
STRINGS.CHARACTERS.THEGRIMREAPER = require "speech_thegrimreaper"

STRINGS.NAMES.REAPER = "Grim's Scythe"
STRINGS.RECIPE_DESC.REAPER = "The reaper's scythe."
STRINGS.CHARACTERS.GENERIC.DESCRIBE.REAPER = "A farmer's scythe, perhaps?"
STRINGS.CHARACTERS.WX78.DESCRIBE.REAPER = "A TOOL TO CUT HAY."
STRINGS.CHARACTERS.THEGRIMREAPER.DESCRIBE.REAPER = "Me beloved scythe. Better not lose it!"

STRINGS.NAMES.GRIMHEAD = "Grim's Disembodied Head"
STRINGS.CHARACTERS.GENERIC.DESCRIBE.GRIMHEAD = "Has someone lost their head?"
STRINGS.CHARACTERS.WX78.DESCRIBE.GRIMHEAD = "A CRANIUM WITHOUT A HOST."
STRINGS.CHARACTERS.THEGRIMREAPER.DESCRIBE.GRIMHEAD = "What de...? Whose head is dat?"

-- The character's name as appears in-game 
STRINGS.NAMES.THEGRIMREAPER = "Grim"
STRINGS.SKIN_NAMES.thegrimreaper_none = "Grim"

STRINGS.CHARACTERS.GENERIC.DESCRIBE.THEGRIMREAPER = 
{
	GENERIC = "Hey, %s. Still stuck between a history textbook and a tunafish sandwich?",
	ATTACKER = "He doesn't look very friendly...",
	MURDERER = "%s is taking his job literally!",
	REVIVER = "%s isn't that bad after all.",
	GHOST = "What a paradox...",
}

-- The skins shown in the cycle view window on the character select screen.
-- A good place to see what you can put in here is in skinutils.lua, in the function GetSkinModes
local skin_modes = {
    { 
        type = "ghost_skin",
        anim_bank = "ghost",
        idle_anim = "idle", 
        scale = 0.75, 
        offset = { 0, -25 } 
    },
}

-- Add mod character to mod character list. Also specify a gender. Possible genders are MALE, FEMALE, ROBOT, NEUTRAL, and PLURAL.
AddModCharacter("thegrimreaper", "MALE", skin_modes)

 

I made all these by adjusting examples and my previously existing code/assets... Would REALLY appreciate general pointers or help with my specific issues.

Edited by Tempos
an issue was fixed
Link to comment
Share on other sites

Hi there! I had the same "custom items don't display on the selection screen" problem as you.

To fix it, I added:

Quote

TUNING.STARTING_ITEM_IMAGE_OVERRIDE["yourprefab"] =
{
    atlas = "images/inventoryimages/yourprefab.xml",
    image = "yourprefab.tex",
}

to my character's modmain.lua, just above the other select screen parts. Just swap out "yourprefab" with whatever your items are called.

Sorry I can't help with anything else - it's far beyond my skill level. Best of luck with your mod!

Edited by Chesed
Link to comment
Share on other sites

21 hours ago, Chesed said:

Hi there! I had the same "custom items don't display on the selection screen" problem as you.

To fix it, I added:

to my character's modmain.lua, just above the other select screen parts. Just swap out "yourprefab" with whatever your items are called.

Sorry I can't help with anything else - it's far beyond my skill level. Best of luck with your mod!

Hey, every bit helps! :)

That solves one problem. Thank you very much!

Regards to my parameter handling, I tried changing things around a little but still running into the same problem... When my char picks the 'grimhead' prefab off the floor, the prefab doesn't get removed... IE, the droppedhead parameter is nil when I check it... mychararacter.lua:

Spoiler

local MakePlayerCharacter = require "prefabs/player_common"

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

local prefabs = 
{
        "reaper",
		"grimhead",
}

-- Your character's stats
TUNING.THEGRIMREAPER_HEALTH = 125
TUNING.THEGRIMREAPER_HUNGER = 150
TUNING.THEGRIMREAPER_SANITY = 175
local headdropchance = .5 --default .07 = 7%
local bonedropchance = .06 --default .06 = 6%
local toothdropchance = .02 --default .02 = 2%
local headlesssanitydrain = -0.25 --default -0.25

-- Custom starting inventory
TUNING.GAMEMODE_STARTING_ITEMS.DEFAULT.THEGRIMREAPER = {
	"reaper",
	"pigskin",
}

local start_inv = {}
for k, v in pairs(TUNING.GAMEMODE_STARTING_ITEMS) do
    start_inv[string.lower(k)] = v.THEGRIMREAPER
end

local prefabs = FlattenTree(start_inv, true)

-- When the character is revived from human
local function onbecamehuman(inst)
	-- Set speed when not a ghost (optional)
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "thegrimreaper_speed_mod", 1)
	if inst:HasTag("headless") then
		inst.AnimState:SetBuild("thegrimreaper_headless")
		--inst.AnimState:PlayAnimation("idle") 
		-- Change the stats for the transformed character here.
		inst.components.sanity.dapperness = headlesssanitydrain
		-- No head = no mouth, so no eating either
		inst.components.eater.caneat = nil
		-- No head = no mouth, so no speaking either
		inst.components.talker:IgnoreAll(inst)
		local myhead = getmydroppedhead(inst)
		if myhead ~= nil then
			myhead:Remove()
			setmydroppedhead(inst, nil)
		end
	end
end

local function onbecameghost(inst)
	-- Remove speed modifier when becoming a ghost
    inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "thegrimreaper_speed_mod")
	if inst:HasTag("headless") then
		inst.components.sanity.dapperness = 0
		inst.components.eater.caneat = { FOODGROUP.OMNI }
		inst.components.talker:StopIgnoringAll(inst)
		inst:RemoveTag("headless")
		
		--Remove dropped grimhead
		local myhead = getmydroppedhead(inst)
		if myhead ~= nil then
			myhead:Remove()
			setmydroppedhead(inst, nil)
		end
	end
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

local function setmydroppedhead(inst, droppedhead)
	inst.mydroppedhead = droppedhead
end

local function getmydroppedhead(inst)
	return inst.mydroppedhead
end

-- Transformation for headless
local function togglehead(inst)

	-- Ignore while we are a ghost.
	if inst:HasTag("playerghost") then return end

	if not inst:HasTag("headless") then
		inst:AddTag("headless")
		-- Set the animation build for the transformed form here.
		inst.AnimState:SetBuild("thegrimreaper_headless")
		--inst.AnimState:PlayAnimation("idle") 
		-- Change the stats for the transformed character here.
		inst.components.sanity.dapperness = headlesssanitydrain
		inst.components.sanity:DoDelta(-5)
		-- No head = no mouth, so no eating either
		inst.components.eater.caneat = nil
		-- No head = no mouth, so no speaking either
		inst.components.talker:IgnoreAll(inst)
		-- No head, so no wearing anything on head
		local item = inst.components.inventory:Unequip(EQUIPSLOTS.HEAD)
		if item then
			inst.components.inventory:DropItem(item)
		end
		local x,y,z = inst.Transform:GetWorldPosition()
		setmydroppedhead(inst, SpawnPrefab("grimhead").Transform:SetPosition(x,y+2.5,z))
		
	else
		-- Set the animation build for the original form here.
		inst.AnimState:SetBuild("thegrimreaper")
		--inst.AnimState:PlayAnimation("idle") 
		-- Change the stats for the original character here.
		inst.components.sanity.dapperness = 0
		inst.components.eater.caneat = { FOODGROUP.OMNI }
		inst.components.talker:StopIgnoringAll(inst)
		if inst and inst.components.talker then
			inst.components.talker:Say("Phew... I am whole again.")
		end
		inst:RemoveTag("headless")
		local myhead = getmydroppedhead(inst)
		if myhead ~= nil then
			myhead:Remove()
			setmydroppedhead(inst, nil)
		end
	end
	

end


-- For bone dropping chance on being attacked and also head dropping
local function OnAttacked(inst)
	local headitem = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
	if not headitem or not headitem.components.armor then
		local headdroprng = math.random()
		if headdroprng < headdropchance and not inst:HasTag("headless") then
			togglehead(inst)
		end
	end
	
	local rng = math.random()
	if  rng < bonedropchance then
		if rng < toothdropchance then
			inst.components.shedder.shedItemPrefab = "houndstooth"
			inst.components.shedder:DoSingleShed()
		else 
			inst.components.shedder.shedItemPrefab = "boneshard"
			inst.components.shedder:DoSingleShed()
		end
		inst.components.talker:Say("AGHH! Did I break a bone?")
    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( "thegrimreaper.tex" )
end

-- This initializes for the server only. Components are added here.
local master_postinit = function(inst)
	-- Set starting inventory
    inst.starting_inventory = start_inv[TheNet:GetServerGameMode()] or start_inv.default
	
	-- choose which sounds this character will play
	inst.soundsname = "warly"
	inst.entity:AddSoundEmitter()
	
	-- For bone dropping
	inst:AddComponent("shedder")
	inst.components.shedder.shedItemPrefab = "boneshard"
    inst.components.shedder.shedHeight = 2.5
	
	-- Stats	
	inst.components.health:SetMaxHealth(TUNING.THEGRIMREAPER_HEALTH)
	inst.components.hunger:SetMax(TUNING.THEGRIMREAPER_HUNGER)
	inst.components.sanity:SetMax(TUNING.THEGRIMREAPER_SANITY)
	
	inst.components.sanity.neg_aura_mult = 0.5
	
	inst.components.sanity.night_drain_mult = 0.5
	
	-- Damage multiplier (optional)
    inst.components.combat.damagemultiplier = 1.2
	
	-- Hunger rate (optional)
	inst.components.hunger.hungerrate = 0.4 * TUNING.WILSON_HUNGER_RATE
	
	-- Mydroppedhead parameter
	inst.mydroppedhead = nil
	
	-- Blocks use of headgear when headless
	local _Equip = inst.components.inventory.Equip

	inst.components.inventory.Equip = function(self, item, old_to_active)
		if not item or not item.components.equippable or not item:IsValid() then
			return
		end
	
		if inst:HasTag("headless") and item.components.equippable.equipslot == EQUIPSLOTS.HEAD then
			self:DropItem(item)
			self:GiveItem(item)
			return
		end		
		return _Equip(self, item, old_to_active)	
	end
	
	inst:ListenForEvent("attacked", OnAttacked)
	
	--inst.mydroppedhead = mydroppedhead
	inst.setmydroppedhead = setmydroppedhead
	inst.getmydroppedhead = getmydroppedhead
	inst.OnLoad = onload
    inst.OnNewSpawn = onload
	inst.togglehead = togglehead
	
end

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

 

I think I'm getting closer to the root of the problem by trying out applying a getter and a setter but something is apparently still off with my logic as getmydroppedhead returns nil...

Edited by Tempos
Link to comment
Share on other sites

Derp, I fixed the parameter issue with mydroppedhead being nil...

Before:

		local x,y,z = inst.Transform:GetWorldPosition()
		setmydroppedhead(inst, SpawnPrefab("grimhead").Transform:SetPosition(x,y+2.5,z))

After:

        local x,y,z = inst.Transform:GetWorldPosition()
        local headentity = SpawnPrefab("grimhead")
        headentity.Transform:SetPosition(x,y+2.5,z)
        setmydroppedhead(inst, headentity)

The problem was "SpawnPrefab("grimhead").Transform:SetPosition(x,y+2.5,z) not returning a spawned entity. Sure, SpawnPrefab(whatever) returns the spawned prefab or whatever but I had attached Transform:SetPosition to it which returns nil (or doesn't return much of anything).

I feel a little dumb for not noticing it earlier but these things happen sometimes :D

 

Now the only problem remains that my character reverts back to having a head after disconnecting and relogging.

Edited by Tempos
better phrasing
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...