
------------------------------------------------------------------
-- Variables
------------------------------------------------------------------

local require = GLOBAL.require
local Ingredient = GLOBAL.Ingredient

local PlayablePets = require("pp_util")
local SETTING = require("pp_settings")
local STRINGS = require("pp_strings")
local MOBTYPE = require("pp_mobtype")
local SKIN = require("pp_skin")


------------------------------------------------------------------
-- Configuration Data
------------------------------------------------------------------

PlayablePets.Init(env.modname)

GLOBAL.MOBPRESET = PlayablePets.GetModConfigData("MobPreset")
GLOBAL.MONSTERHUNGER = PlayablePets.GetModConfigData("MobHunger")
GLOBAL.MONSTERSANITY = PlayablePets.GetModConfigData("MobSanity")
GLOBAL.MOBCRAFT = PlayablePets.GetModConfigData("MobCraft")
GLOBAL.MOBHOUSE = PlayablePets.GetModConfigData("MobHouseMethod")
GLOBAL.MOBPVP = PlayablePets.GetModConfigData("MobPvP")
GLOBAL.MOBGHOST = PlayablePets.GetModConfigData("MobGhosts")
GLOBAL.MOBVISION = PlayablePets.GetModConfigData("MobSpecialVision")
GLOBAL.MOBPVPMODE = PlayablePets.GetModConfigData("MobPvPMode")
GLOBAL.MOBFIRE = PlayablePets.GetModConfigData("MobFire")
GLOBAL.GVG_MODE = PlayablePets.GetModConfigData("GvGMode")

-- For preventing Growth on mobs that grow into disabled mobs
GLOBAL.MOB_DRAGONFLY = PlayablePets.GetModConfigData("Dragonfly")
GLOBAL.MOB_TALLBIRD = PlayablePets.GetModConfigData("Tallbird")

------------------------------------------------------------------
-- Prefabs
------------------------------------------------------------------

PrefabFiles = {
	-------Houses--------
	"mermhouse_player",
	"pighouse_player",
	"igloo_player",
	"spidernest_p",
	"houndmound_p",
	"catcoonden_p",
	"maggothome",
	"lavapond_p",
	"spiderhome",
	"houndhome",
	"cathome",
	-------Tools---------
	"monster_wpn",
	"pigtorch_p",
}

-- Centralizes a number of related functions about playable mobs to one convenient table
-- Name is the prefab name of the mob
-- Fancyname is the name of the mob, as seen in-game
-- Gender is fairly self-explanatory
-- Skins is a list of any custom mob skins that may be available, using the Modded Skins API by Fidoop
-- Skins are not required for mobs to function, but they will display a custom portrait when the mob is examined by a player
GLOBAL.PP_MobCharacters = {
	houndplayer        = { fancyname = "Hound",           gender = "MALE",   mobtype = {}, skins = {1, 2} },
	houndiceplayer     = { fancyname = "Ice Hound",       gender = "MALE",   mobtype = {}, skins = {1} },
	houndredplayer     = { fancyname = "Hell Hound",      gender = "MALE",   mobtype = {}, skins = {1} },
	hounddarkplayer    = { fancyname = "Nightmare Hound", gender = "MALE",   mobtype = {}, skins = {} }, --Used for testing new features.
	blackspiderplayer  = { fancyname = "Spider",          gender = "MALE",   mobtype = {}, skins = {1} },
	warriorp           = { fancyname = "Spider Warrior",  gender = "MALE",   mobtype = {}, skins = {1} },
	whitespiderplayer  = { fancyname = "Depth Dweller",   gender = "MALE",   mobtype = {}, skins = {1} },
	queenspiderplayer  = { fancyname = "Spider Queen",    gender = "FEMALE", mobtype = {MOBTYPE.GIANT}, skins = {1} },
	wqueenspiderplayer = { fancyname = "Dweller Queen",   gender = "FEMALE", mobtype = {MOBTYPE.GIANT}, skins = {1} },
	treeplayer         = { fancyname = "Tree Guard",      gender = "ROBOT",  mobtype = {MOBTYPE.GIANT}, skins = {2} },
	vargplayer         = { fancyname = "Varg",            gender = "MALE",   mobtype = {MOBTYPE.GIANT}, skins = {1} },
	babygooseplayer    = { fancyname = "Mosling",         gender = "FEMALE", mobtype = {}, 	skins = {1} },
	moosegooseplayer   = { fancyname = "Moose/Goose",     gender = "FEMALE", mobtype = {MOBTYPE.GIANT}, skins = {1} },
	maggotplayer       = { fancyname = "Lavae",           gender = "MALE",   mobtype = {}, 	skins = {1} },
	dragonplayer       = { fancyname = "Dragonfly",       gender = "MALE",   mobtype = {MOBTYPE.GIANT}, skins = {1} },
	bearplayer         = { fancyname = "Bearger",         gender = "MALE",   mobtype = {MOBTYPE.GIANT}, skins = {1,6} },
	deerplayer         = { fancyname = "Deerclops",       gender = "MALE",   mobtype = {MOBTYPE.GIANT}, skins = {1} },
	ghostplayer        = { fancyname = "Ghost",           gender = "MALE",   mobtype = {}, skins = {1} },
	pigmanplayer       = { fancyname = "Pig",             gender = "MALE",   mobtype = {MOBTYPE.CRAFTY}, skins = {1} },
	mermplayer         = { fancyname = "Merm",            gender = "MALE",   mobtype = {MOBTYPE.CRAFTY}, skins = {1} },
	walrusplayer       = { fancyname = "McTusk",          gender = "MALE",   mobtype = {MOBTYPE.CRAFTY}, skins = {1} },
	tentaclep          = { fancyname = "Tentacle",        gender = "MALE",   mobtype = {}, skins = {1} },
	krampusp           = { fancyname = "Krampus",         gender = "MALE",   mobtype = {}, skins = {1,2} },
	catplayer          = { fancyname = "Catcoon",         gender = "FEMALE", mobtype = {}, skins = {1,2} },
	beefplayer         = { fancyname = "Beefalo",         gender = "FEMALE", mobtype = {}, skins = {1} },
	smallbirdp         = { fancyname = "Smallbird",       gender = "FEMALE", mobtype = {}, skins = {1} },
	tallbirdplayer     = { fancyname = "Tallbird",        gender = "FEMALE", mobtype = {}, skins = {1} },
	goatp              = { fancyname = "Volt Goat",       gender = "MALE",   mobtype = {}, skins = {1} },
	clockwork1player   = { fancyname = "Knight",          gender = "ROBOT",  mobtype = {}, skins = {1} },
	clockwork2player   = { fancyname = "Bishop",          gender = "ROBOT",  mobtype = {}, skins = {1} },
	clockwork3player   = { fancyname = "Rook",            gender = "ROBOT",  mobtype = {}, skins = {1} },
}

-- Necessary to ensure a specific order when adding mobs to the character select screen. This table is iterated and used to index the one above
PP_Character_Order = {"houndplayer", "houndiceplayer", "houndredplayer", "hounddarkplayer", "vargplayer", "blackspiderplayer", "warriorp", "whitespiderplayer", "queenspiderplayer", "wqueenspiderplayer", "treeplayer", "babygooseplayer", "moosegooseplayer", "maggotplayer", "dragonplayer", "bearplayer", "deerplayer", "ghostplayer", "pigmanplayer", "mermplayer", "walrusplayer", "tentaclep", "krampusp", "catplayer", "beefplayer", "smallbirdp", "tallbirdplayer", "goatp", "clockwork1player", "clockwork2player", "clockwork3player"}

------------------------------------------------------------------
-- Assets
------------------------------------------------------------------

Assets = {
	Asset("ANIM", "anim/ghost_monster_build.zip"), -- Might make it not needed on every prefab.
	--------------------------HOMES--------------------------------
	Asset( "IMAGE", "images/inventoryimages/houseplayer.tex" ),
	Asset( "ATLAS", "images/inventoryimages/houseplayer.xml" ),
	Asset( "IMAGE", "images/inventoryimages/rundownplayer.tex" ),
	Asset( "ATLAS", "images/inventoryimages/rundownplayer.xml" ),
	Asset( "IMAGE", "images/inventoryimages/iglooplayer.tex" ),
	Asset( "ATLAS", "images/inventoryimages/iglooplayer.xml" ),
	Asset( "IMAGE", "images/inventoryimages/spiderhome.tex" ),
	Asset( "ATLAS", "images/inventoryimages/spiderhome.xml" ),
	Asset( "IMAGE", "images/inventoryimages/houndhome.tex" ),
	Asset( "ATLAS", "images/inventoryimages/houndhome.xml" ),
	Asset( "IMAGE", "images/inventoryimages/maggothome.tex" ),
	Asset( "ATLAS", "images/inventoryimages/maggothome.xml" ),
	Asset( "IMAGE", "images/inventoryimages/cathome.tex" ),
	Asset( "ATLAS", "images/inventoryimages/cathome.xml" ),
	--------------------------TOOLS---------------------------------
	Asset( "IMAGE", "images/inventoryimages/monster_wpn.tex" ),
	Asset( "ATLAS", "images/inventoryimages/monster_wpn.xml" ),
}

------------------------------------------------------------------
-- Custom Recipes
------------------------------------------------------------------

-- Pig house
local pigrecipe = AddRecipe("pighouse_player", {Ingredient("boards", 4),Ingredient("cutstone", 2)}, GLOBAL.RECIPETABS.TOWN, GLOBAL.TECH.SCIENCE_ONE, "pighouse_placer", nil, nil, 1, "pigmanplayer", "images/inventoryimages/houseplayer.xml", "houseplayer.tex")

-- Merm house
local mermrecipe = AddRecipe("mermhouse_player", {Ingredient("boards", 4),Ingredient("cutstone", 2)}, GLOBAL.RECIPETABS.TOWN, GLOBAL.TECH.SCIENCE_ONE, "pighouse_placer", nil, nil, 1,"mermplayer", "images/inventoryimages/rundownplayer.xml", "rundownplayer.tex" )

-- Igloo
local walrusrecipe = AddRecipe("igloo_player", {Ingredient("boards", 2),Ingredient("cutstone", 6), Ingredient("ice", 20)}, GLOBAL.RECIPETABS.TOWN, GLOBAL.TECH.SCIENCE_ONE, "pighouse_placer", nil, nil, 1,"walrusplayer", "images/inventoryimages/iglooplayer.xml", "iglooplayer.tex" )

-- Pig torch
local pigtorchrecipe = AddRecipe("pigtorch_p", {Ingredient("boards", 4),Ingredient("cutgrass", 6), Ingredient("pigskin", 3)}, GLOBAL.RECIPETABS.LIGHT, GLOBAL.TECH.SCIENCE_TWO, "pigtorch_p_placer", nil, nil, 1, "pigmanplayer", "images/inventoryimages/houseplayer.xml", "houseplayer.tex")

pigrecipe.sortkey = -7.0
mermrecipe.sortkey = -8.0
walrusrecipe.sortkey = -9.0
pigtorchrecipe.sortkey = -10.0

local MobHouseMethod = PlayablePets.GetModConfigData("MobHouseMethod")

-- Add home crafting recipes if enabled
if MobHouseMethod == SETTING.HOUSE_ON_CRAFT or MobHouseMethod == SETTING.HOUSE_BOTH then
	-- Spider nest
	local spiderhomerecipe = AddRecipe("spidernest_p", {Ingredient("silk", 10), Ingredient("spidergland", 3), Ingredient("papyrus", 2)}, GLOBAL.RECIPETABS.TOWN, GLOBAL.TECH.SCIENCE_ONE, "spidereggsack_placer", nil, nil, 1 ,nil, "images/inventoryimages/spiderhome.xml", "spiderhome.tex" )

	-- Hound mound
	local houndhomerecipe = AddRecipe("houndmound_p", {Ingredient("houndstooth", 5), Ingredient("boneshard", 5), Ingredient("monstermeat", 3)}, GLOBAL.RECIPETABS.TOWN, GLOBAL.TECH.SCIENCE_ONE, "houndmound_p_placer", nil, nil, 1 ,nil, "images/inventoryimages/houndhome.xml", "houndhome.tex" )

	-- Catcoon den
	local cathomerecipe = AddRecipe("catcoonden_p", {Ingredient("log", 8), Ingredient("silk", 5), Ingredient("rope", 3)}, GLOBAL.RECIPETABS.TOWN, GLOBAL.TECH.SCIENCE_ONE, "catcoonden_p_placer", nil, nil, 1 ,nil, "images/inventoryimages/cathome.xml", "cathome.tex" )

	-- Lava pond
	local maggothomerecipe = AddRecipe("lavapond_p", {Ingredient("shovel", 1), Ingredient("charcoal", 10), Ingredient("rocks", 10)}, GLOBAL.RECIPETABS.TOWN, GLOBAL.TECH.SCIENCE_TWO, "lavapond_p_placer", nil, nil, 1 ,nil, "images/inventoryimages/maggothome.xml", "maggothome.tex" )
end

------------------------------------------------------------------
-- Component Overrides
------------------------------------------------------------------

-- Prevent mob spiders from attacking player spiders
local comb_rep = require("components/combat_replica")
local old_IsAlly = comb_rep.IsAlly
function comb_rep:IsAlly(guy,...)
	if self.inst:HasTag("spiderwhisperer") and not self.inst.prefab == "webber" and guy:HasTag("spider") and not guy:HasTag("player") then
		return true
	end
	return old_IsAlly(self,guy,...)
end

------------------------------------------------------------------
-- PostInits
------------------------------------------------------------------

-- Allows tallbird players to hatch their eggs.
AddComponentPostInit("hatchable", function (hatchable, inst)
 hatchable.oldupdatefn = hatchable.OnUpdate
	local FindEntity = GLOBAL.FindEntity
	local function IsMother(guy)
		return guy:HasTag("tallbird") and guy:HasTag("mommy")
	end
	
	function hatchable:OnUpdate(dt)
		if self.delay then
			return
		end
		
		local has_heater = FindEntity(self.inst, 1.5, IsMother) ~= nil or FindEntity(self.inst, TUNING.HATCH_CAMPFIRE_RADIUS, IsExothermic, { "campfire", "fire"}) ~= nil
		local wants_heater = self:GetHeaterPref()
		--local has_heater = FindEntity(self.inst, TUNING.HATCH_CAMPFIRE_RADIUS, IsMother) ~= nil

		self.toohot = false
		self.toocold = false

		if wants_heater ~= nil then
			if has_heater and not wants_heater then
				self.toohot = true
			elseif not has_heater and wants_heater then
				self.toocold = true
			end
		end

		if self.state == "unhatched" then
			if has_heater then
				self.progress = self.progress + dt
				if self.progress >= self.cracktime then
					self.progress = 0
					self:OnState("crack")
				end
			else
				self.progress = 0
			end
			return
		end

		local oldstate = self.state

		if self.toohot or self.toocold then
			self:OnState("uncomfy")
		else
			self:OnState("comfy")
		end

		if self.state == "comfy" then
			self.discomfort = math.max(self.discomfort - dt, 0)
			if self.discomfort <= 0 then
				self.progress = self.progress + dt
			end

			if self.progress >= self.hatchtime then
				self:StopUpdating()
				self:OnState("hatch")
			end
		else
			self.discomfort = self.discomfort + dt
			if self.discomfort >= self.hatchfailtime then
				self:StopUpdating()
				self:OnState("dead")
			end
		end
	end
 
end)

--Skin Puppet Stuff
local DEFAULT_SCALE = 0.20

MobAnimTable =
{
	--PP
	babygooseplayer = {bank = "mossling", build = "mossling_build", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "mossling"},
	bearplayer = {bank = "bearger", build = "bearger_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.1, shinybuild = "bearger"},
	beefplayer = {bank = "beefalo", build = "beefalo_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "beefalo"},
	blackspiderplayer = {bank = "spider", build = "spider_build", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "spider"},
	catplayer = {bank = "catcoon", build = "catcoon_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "catcoon"},
	clockwork1player = {bank = "knight", build = "knight_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "knight"},
	clockwork2player = {bank = "bishop", build = "bishop_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "bishop"},
	clockwork3player = {bank = "rook", build = "rook_build", anim = "idle", scale = DEFAULT_SCALE - 0.05, shinybuild = "rook"},
	deerplayer = {bank = "deerclops", build = "deerclops_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "deerclops"},
	dragonplayer = {bank = "dragonfly", build = "dragonfly_build", anim = "idle", scale = DEFAULT_SCALE - 0.075, shinybuild = "dragonfly"},
	ghostplayer = {bank = "ghost", build = "ghost_build", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "ghost"},
	goatp = {bank = "lightning_goat", build = "lightning_goat_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "lightning_goat"},
	hounddarkplayer = {bank = "hound", build = "hounddarkplayer", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "hound_dark"},
	houndiceplayer = {bank = "hound", build = "hound_ice", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "hound_ice"},
	houndredplayer = {bank = "hound", build = "hound_red", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "hound_red"},
	houndplayer = {bank = "hound", build = "hound", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "hound"},
	krampusp = {bank = "krampus", build = "krampus_build", anim = "idle", scale = DEFAULT_SCALE - 0.05, shinybuild = "krampus"},
	maggotplayer = {bank = "lavae", build = "lavae", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "lavae"},
	mermplayer = {bank = "pigman", build = "merm_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "merm"},
	pigmanplayer = {bank = "pigman", build = "pig_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "pig"},
	queenspiderplayer = {bank = "spider_queen", build = "spider_queen_build", anim = "idle", scale = DEFAULT_SCALE - 0.05, shinybuild = "spider_queen"},
	wqueenspiderplayer = {bank = "spider_queen", build = "wspider_queen_build", anim = "idle", scale = DEFAULT_SCALE - 0.05, shinybuild = "wspider_queen"},
	whitespiderplayer = {bank = "spider", build = "spider_white", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "spider_white"},
	smallbirdp = {bank = "smallbird", build = "smallbird_basic", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "smallbird"},
	tallbirdplayer = {bank = "tallbird", build = "ds_tallbird_basic", anim = "idle", scale = DEFAULT_SCALE - 0.05, shinybuild = "tallbird"},
	tentaclep = {bank = "tentacle", build = "tentacle", anim = "atk_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "tentacle"},
	treeplayer = {bank = "leif", build = "leif_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "leif"},
	vargplayer = {bank = "warg", build = "warg_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "warg"},
	warriorp = {bank = "spider", build = "spider_warrior_build", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "spider_warrior"},
	walrusplayer = {bank = "walrus", build = "walrus_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "walrus"},
	moosegooseplayer = {bank = "goosemoose", build = "goosemoose_build", anim = "idle", scale = DEFAULT_SCALE - 0.075, shinybuild = "goosemoose"},
		
	--Cave
    batp = {bank = "bat", build = "bat_basic", anim = "fly_loop", scale = 0.15, shinybuild = "bat" },
	wormp = {bank = "worm", build = "worm", anim = "taunt", scale = 0.15, shinybuild = "worm" },
	cspiderp = {bank = "spider_spitter", build = "ds_spider2_caves", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "spitter"},
	cspider2p = {bank = "spider_hider", build = "DS_spider_caves", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "hider"},
	monkeyp = {bank = "kiki", build = "kiki_basic", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "kiki"},
	hutchp = {bank = "hutch", build = "hutch_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "hutch"},
	slurperp = {bank = "slurper", build = "slurper_basic", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "slurper"},
	slurtlep = {bank = "slurtle", build = "slurtle", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "slurtle"},
	bunnyp = {bank = "manrabbit", build = "manrabbit_build", anim = "idle_loop", scale = 0.20, shinybuild = "manrabbit"},
	guardianp = {bank = "rook", build = "rook_rhino", anim = "idle", scale = 0.10, shinybuild = "guardian"},
	rocklobsterp = {bank = "rocky", build = "rocky", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "rocky"},
	shadowplayer = {bank = "shadowcreature1", build = "shadow_insanity1_basic", anim = "idle_loop", scale = 0.15, shinybuild = "crawlinghorror"},
	shadow2player = {bank = "shadowcreature2", build = "shadow_insanity2_basic", anim = "idle_loop", scale = 0.15, shinybuild = "terrorbeak"},
	--NR
	stagehandp = {bank = "stagehand", build = "stagehand", anim = "idle_loop_01", scale = DEFAULT_SCALE, shinybuild = "stagehand" },
	sheepp = {bank = "spat", build = "spat_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "spat" },
	toadstoolp = {bank = "toadstool", build = "toadstool_build", anim = "idle", scale = 0.08, shinybuild = "toadstool" },
	toadstool_darkp = {bank = "toadstool", build = "toadstool_dark_build", anim = "idle", scale = 0.08, shinybuild = "toadstool_dark" },
	klausp = {bank = "klaus", build = "klaus_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "klaus" },
	bird2p = {bank = "canary", build = "canary_build", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "canary" },
	antlionp = {bank = "antlion", build = "antlion_build", anim = "idle", scale = 0.1, shinybuild = "antlion" },
	babyhoundp = {bank = "pupington", build = "pupington_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "pupington" },
	babycatp = {bank = "kittington", build = "kittington_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "kittington" },
	babysheepp = {bank = "sheepington", build = "sheepington_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "sheepington" },
	babydragonp = {bank = "dragonling", build = "dragonling_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "dragonling" },
	babyglommerp = {bank = "glomling", build = "glomling_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "glomling" },
	gibletp = {bank = "perdling", build = "perdling_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "perdling" },
	stalkerp = {bank = "stalker", build = "stalker_cave_build", anim = "idle", scale = 0.1, shinybuild = "stalker_cave" },
	stalker_atriump = {bank = "stalker", build = "stalker_atrium_build", anim = "idle", scale = 0.1, shinybuild = "stalker_atrium" },
	stalker_forestp = {bank = "stalker_forest", build = "stalker_forest_build", anim = "idle", scale = 0.1, shinybuild = "stalker_forest" },
	shadow_knightp = {bank = "shadow_knight", build = "shadow_knight", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "shadow_knight" },
	shadow_bishopp = {bank = "shadow_bishop", build = "shadow_bishop", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "shadow_bishop" },
	shadow_rookp = {bank = "shadow_rook", build = "shadow_rook", anim = "idle_loop", scale = DEFAULT_SCALE -0.075, shinybuild = "shadow_rook" },
	deerp = {bank = "deer", build = "deer_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "deer" },
	deer_redp = {bank = "deer", build = "deer_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "deer" },
	deer_bluep = {bank = "deer", build = "deer_build", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "deer" },
	beequeenp = {bank = "bee_queen", build = "bee_queen_build", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "bee_queen" },
	beeguardp = {bank = "bee_guard", build = "bee_guard_build", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "bee_guard" },
	stalker_minionp = {bank = "stalker_minion_2", build = "stalker_minion_2", anim = "idle", scale = DEFAULT_SCALE, shinybuild = "stalker_minion_2" },
	
	--Event
	boaronp = {bank = "boaron", build = "lavaarena_boaron_basic", anim = "idle_loop", scale = DEFAULT_SCALE - 0.02, shinybuild = "boaron" },
	boarriorp = {bank = "boarrior", build = "lavaarena_boarrior_basic", anim = "idle_loop", scale = DEFAULT_SCALE - 0.07, shinybuild = "boarrior" },
	snapperp = {bank = "snapper", build = "lavaarena_snapper_basic", anim = "idle_loop", scale = DEFAULT_SCALE, shinybuild = "snapper" },
	peghookp = {bank = "peghook", build = "lavaarena_peghook_basic", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "peghook" },
	tortankp = {bank = "turtillus", build = "lavaarena_turtillus_basic", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "tortank" },
	trailsp = {bank = "trails", build = "lavaarena_trails_basic", anim = "idle_loop", scale = DEFAULT_SCALE - 0.05, shinybuild = "trails" },
	
} 

-------------------------------------------------------
--Wardrobe stuff--

--Note to a certain crow: the puppet prints to the clientlog, not the server log.
--Also I noticed some gross messages from there, probably due to this sloppy code.
--Skinpuppet code seems to load everytime you switch character while in the portrait select screen.

for k,v in ipairs(GLOBAL.KnownModIndex:GetModsToLoad()) do
    if GLOBAL.KnownModIndex:GetModInfo(v).name == "[API] Modded Skins" then
        GLOBAL.IsModdedSkinsEnabled = true
    else
        GLOBAL.IsModdedSkinsEnabled = false
    end
end

local UIAnim = require "widgets/uianim"
local SkinsPuppet = require "widgets/skinspuppet"
local Skinner = require "components/skinner"
local PlayerAvatarPopup = require "widgets/playeravatarpopup"
--grabbed from widget/skinspuppet
local emotes_to_choose = { "emoteXL_waving1", "emoteXL_waving2", "emoteXL_waving3" } 

--Copied directly from components/skinner. No edits yet, crashes when ran, ofc.
function SetSkinMode( anim_state, prefab, base_skin, clothing_names, skintype, default_build )
	local CLOTHING_SYMBOLS = GLOBAL.CLOTHING_SYMBOLS
    local HIDE_SYMBOLS = GLOBAL.HIDE_SYMBOLS
    local BASE_TORSO_TUCK = GLOBAL.BASE_TORSO_TUCK
    local BASE_LEGS_SIZE = GLOBAL.BASE_LEGS_SIZE
	local HAS_LEG_BOOT = GLOBAL.HAS_LEG_BOOT
    local BASE_FEET_SIZE = GLOBAL.BASE_FEET_SIZE
    local BASE_ALTERNATE_FOR_BODY = GLOBAL.BASE_ALTERNATE_FOR_BODY
    local BASE_ALTERNATE_FOR_SKIRT = GLOBAL.BASE_ALTERNATE_FOR_SKIRT
    local CLOTHING = GLOBAL.CLOTHING
    local ModManager = GLOBAL.ModManager
    local clothing_order = { "legs", "body", "feet", "hand" }
	
	skintype = skintype or "normal_skin"
	default_build = default_build or ""
	base_skin = base_skin or ""
	
	--print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	--print(prefab, base_skin)
	
	if skintype ~= "NO_BASE" then
		anim_state:SetSkin(base_skin, default_build)
	end
	for _,sym in pairs(CLOTHING_SYMBOLS) do
		anim_state:ClearOverrideSymbol(sym)
	end
	
	anim_state:ClearSymbolExchanges()
	for _,sym in pairs(HIDE_SYMBOLS) do
		anim_state:ShowSymbol(sym)
	end
					
	--if not ghost, then we need to apply the clothing
	if skintype ~= "ghost_skin" and skintype ~= "werebeaver_skin" and skintype ~= "ghost_werebeaver_skin" then
		local needs_legacy_fixup = not anim_state:BuildHasSymbol( "torso_pelvis" ) --support clothing on legacy mod characters
		local torso_build = nil
		local pelvis_build = nil
		local skirt_build = nil
		local leg_build = base_skin --for boot switching, default to the base skin
		local foot_build = base_skin --for boot switching, default to the base skin
		
		local tuck_torso = BASE_TORSO_TUCK[base_skin] or "skirt" --tucked into the skirt is the default
		--print( "tuck_torso is ", tuck_torso, base_skin )
		
		local legs_cuff_size = BASE_LEGS_SIZE[base_skin] or 1
		local feet_cuff_size = BASE_FEET_SIZE[base_skin] or 1
		--print( "legs_cuff_size and feet_cuff_size is ", legs_cuff_size, feet_cuff_size, base_skin )
		
		local allow_arms = true
		local allow_torso = true
		if prefab == "wolfgang" then
			if skintype == "wimpy_skin" then
				--allow clothing
			elseif skintype == "normal_skin" then
				allow_arms = false
			elseif skintype == "mighty_skin" then
				allow_arms = false
			
				--check to see if we're wearing a one piece clothing, if so, allow the torso
				local name = clothing_names["body"]
				if CLOTHING[name] ~= nil then
					local has_torso = false
					local has_pelvis = false
					for _,sym in pairs(CLOTHING[name].symbol_overrides) do
						if sym == "torso" then
							has_torso = true
						end
						if sym == "torso_pelvis" then
							has_pelvis = true
						end
					end
					if has_torso and has_pelvis then
						--one piece clothing, so allow the torso
						allow_torso = true
					else
						allow_torso = false
					end
				end
			end
		end
		
		--collect the list of symbols that the clothing pieces have requested to fall back to the base skin.
		local symbols_to_use_base = {}
		for _,name in pairs(clothing_names) do
			if CLOTHING[name] ~= nil and CLOTHING[name].base_fallbacks then
				for _,base_sym in pairs(CLOTHING[name].base_fallbacks) do
					table.insert(symbols_to_use_base, base_sym)
				end
			end
		end
		
		for _,type in pairs( clothing_order ) do
			local name = clothing_names[type]
			if CLOTHING[name] ~= nil then
				local src_symbols = nil
				if skintype == "wimpy_skin" and CLOTHING[name].symbol_overrides_skinny then
					src_symbols = CLOTHING[name].symbol_overrides_skinny
					allow_arms = true
				elseif skintype == "normal_skin" and (CLOTHING[name].symbol_overrides_skinny or CLOTHING[name].symbol_overrides_mighty) then
					allow_arms = true
				elseif skintype == "mighty_skin" and CLOTHING[name].symbol_overrides_mighty then
					src_symbols = CLOTHING[name].symbol_overrides_mighty
					allow_arms = true
					allow_torso = true
				end

				for _,sym in pairs(CLOTHING[name].symbol_overrides) do
					if not ModManager:IsModCharacterClothingSymbolExcluded( prefab, sym ) then
						if (not allow_torso and sym == "torso") or (not allow_arms and (sym == "arm_upper" or sym == "arm_upper_skin" or sym == "arm_lower")) then
							--skip this symbol for wolfgang
						
						elseif table.contains(symbols_to_use_base, sym) then
							--skip this symbol because one of the clothing requested it fall to the default (hand_willow_gladiator)
							--print("skip symbol and leave it at base:",sym)
						else
							--Slight cheat here, we know that name is the item name and the build for clothing, quicker than calling GetBuildForItem(name)
							if sym == "torso" then torso_build = name end
							if sym == "torso_pelvis" then pelvis_build = name end
							if sym == "skirt" then skirt_build = name end
							if sym == "leg" then leg_build = name end
							if sym == "foot" then foot_build = name end
							
							local src_sym = sym
							if src_symbols then
								src_sym = src_symbols[sym] or sym
							end
							anim_state:ShowSymbol(sym)
							anim_state:OverrideSkinSymbol(sym, name, src_sym )
							--print("setting skin", sym, name )
							
							if sym == "leg" then
								if CLOTHING[name].legs_cuff_size ~= nil then
									legs_cuff_size = CLOTHING[name].legs_cuff_size
									--print("setting legs_cuff_size to", legs_cuff_size, name )
								else
									legs_cuff_size = 1
								end
							end
							if sym == "foot" then
								if CLOTHING[name].feet_cuff_size ~= nil then
									feet_cuff_size = CLOTHING[name].feet_cuff_size
									--print("setting feet_cuff_size to", feet_cuff_size, name )
								else
									feet_cuff_size = 1
									--print("setting feet_cuff_size to 1", name )
								end
							end
						end
					end
				end
				
				--override the base skin's torso_tuck value
				if CLOTHING[name].torso_tuck ~= nil and allow_torso then
					tuck_torso = CLOTHING[name].torso_tuck
					--print("setting tuck_torso to", tuck_torso, name )
				end				
				if CLOTHING[name].symbol_hides then
					for _,sym in pairs(CLOTHING[name].symbol_hides) do
						anim_state:HideSymbol(sym)
					end
				end
			end
		end
		
		--Future work to be done here: Is this a workable solution long term for skirt issues?
		--Maybe we need a better system for tagging dresses that can't have torso symbols tucked into them.
		--Hide any of the base symbols if requested (probably only ever the default skirts). This allows us to turn the skirt on manually with a clothing choice)
		--for _,name in pairs( clothing_names ) do
		--	if CLOTHING[name] ~= nil and CLOTHING[name].symbol_hides_only_base then
		--		for _,sym in pairs(CLOTHING[name].symbol_hides_only_base) do
		--			if not symbol_overridden[sym] then
		--				anim_state:HideSymbol(sym)
		--			end
		--		end
		--	end
		--end
		
		local torso_symbol = "torso"
		local pelvis_symbol = "torso_pelvis"
		local wide = false
		--Certain builds need to use the wide versions to fit clothing, nil build indicates it will use the base
		if (BASE_ALTERNATE_FOR_BODY[base_skin] and torso_build == nil and pelvis_build ~= nil)
			or (BASE_ALTERNATE_FOR_SKIRT[base_skin] and torso_build == nil and skirt_build ~= nil) then
			torso_symbol = "torso_wide"
			--print("torso replaced with torso_wide")
			wide = true
			anim_state:OverrideSkinSymbol("torso", base_skin, torso_symbol )
		end
		
		if (BASE_ALTERNATE_FOR_BODY[base_skin] and torso_build ~= nil and pelvis_build == nil) 
			or (BASE_ALTERNATE_FOR_SKIRT[base_skin] and skirt_build ~= nil and pelvis_build == nil) then
			pelvis_symbol = "torso_pelvis_wide"
			--print("torso_pelvis replaced with torso_pelvis_wide")
			wide = true
			anim_state:OverrideSkinSymbol("torso_pelvis", base_skin, pelvis_symbol )
		end
		
		if BASE_ALTERNATE_FOR_BODY[base_skin] and torso_build ~= nil and skirt_build == nil then
			--print("skirt replaced with skirt_wide")
			wide = true
			anim_state:OverrideSkinSymbol("skirt", base_skin, "skirt_wide")
		end
		
		local use_leg_boot = (CLOTHING[leg_build] and CLOTHING[leg_build].has_leg_boot) or HAS_LEG_BOOT[leg_build]
		if leg_build == foot_build and use_leg_boot then
			anim_state:OverrideSkinSymbol("leg", leg_build, "leg_boot" )
		end
		
		
		--characters with skirts, and untucked torso clothing need to exchange the render order of the torso and skirt so that the torso is above the skirt
		if tuck_torso == "untucked" or (tuck_torso == "untucked_wide" and wide) then
			--print("torso over the skirt")
			anim_state:SetSymbolExchange( "skirt", "torso" )
		end
		if legs_cuff_size > feet_cuff_size then
			--if inst.user ~= "KU_MikeBell" then --mike always tucks his pants into all shoes, including high heels...
				--print("put the leg in front of the foot")
				anim_state:SetMultiSymbolExchange( "leg", "foot" ) --put the legs in front of the feet
			--end
		end
		
		if tuck_torso == "full" then
			torso_build = torso_build or base_skin
			pelvis_build = pelvis_build or base_skin
			--print("put the pelvis on top of the base torso")
			anim_state:OverrideSkinSymbol("torso", pelvis_build, pelvis_symbol ) --put the pelvis on top of the base torso by putting it in the torso slot
			--print("put the torso in pelvis slot")
			anim_state:OverrideSkinSymbol("torso_pelvis", torso_build, torso_symbol ) --put the torso in pelvis slot to go behind			
		elseif needs_legacy_fixup then
			if torso_build ~= nil and pelvis_build ~= nil then
				--fully clothed, no fixup required
			elseif torso_build == nil and pelvis_build ~= nil then
				--print("~~~~~ put base torso behind, [" .. base_skin .. "]")
				anim_state:OverrideSkinSymbol("torso_pelvis", base_skin, torso_symbol ) --put the base torso in pelvis slot to go behind
				anim_state:OverrideSkinSymbol("torso", pelvis_build, pelvis_symbol ) --put the clothing pelvis on top of the base torso by putting it in the torso slot
			elseif torso_build ~= nil and pelvis_build == nil then
				--print("~~~~~ fill in the missing pelvis, [" .. base_skin .. "]")
				anim_state:OverrideSkinSymbol("torso_pelvis", base_skin, "torso" ) --fill in the missing pelvis, with the base torso
			else
				--no clothing at all, nothing to fixup
			end
		end
	end
end

local OldUIAnim = UIAnim.SetSkins or function() return false end

function UIAnim:GetTransform()
    return self.inst.Transform
end

function UIAnim:GetSelf()
    return self.inst.entity
end

function UIAnim:GetSelf_1()
    return self.inst
end

function UIAnim:GetSelf_2()
    return self
end

local OldSkinsPuppet = SkinsPuppet.SetSkins or function() return false end
local OldPlayerAvatarPopup = PlayerAvatarPopup.UpdateData or function() return false end

function SkinsPuppet:EmoteUpdate(dt) --supposed to bypass the idle emotes, not working apparently.
	local emotes_to_choose = { "emoteXL_waving1", "emoteXL_waving2", "emoteXL_waving3" }
	local emote_min_time = 6
	local emote_max_time = 12

	local change_delay_time = .5
	if self.time_to_idle_emote > 0 and self.ismobanim == nil then
		self.time_to_idle_emote = self.time_to_idle_emote - dt
	else
		if self.animstate:AnimDone() and self.ismobanim == nil then
			self.time_to_idle_emote = math.random(emote_min_time, emote_max_time)
			self:DoIdleEmote()
		end
	end
		
	if self.time_to_change_emote > 0 then
		self.time_to_change_emote = self.time_to_change_emote - dt
		if self.time_to_change_emote <= 0 and self.ismobanim == nil then
			if self.animstate:IsCurrentAnimation("idle") then
				self.time_to_idle_emote = math.random(emote_min_time, emote_max_time) --reset the idle emote as well when starting the change emote
				self:DoChangeEmote()
			elseif self.ismobanim ~= nil then
			--
			else
				self.time_to_change_emote = 0.25 --ensure that we wait a little bit before trying to start the change emote, so that it doesn't play back to back with
			end
		end 
	end
		
	if self.animstate:AnimDone() then
		if self.ismobanim == nil then
        self.animstate:SetBank("corner_dude")
		self.animstate:PlayAnimation("idle", true)
		end
    end
end

function SkinsPuppet:SetCharacter(character) --attempting to combat the error logs.
    if MobAnimTable[prefabname] ~= nil then
        self.animstate:SetBuild(character)
    end
end

function SkinsPuppet:SetSkins(prefabname, base_skin, clothing_names, skip_change_emote)
	
	self.mob = self.anim:GetSelf()
	self.ui = self.anim:GetSelf_2()
	self.uianim = self.anim:GetSelf_1()
	--self.mob:AddTransform()
	--self.transform = self.anim:GetTransform()
	--local self = GLOBAL.self
	local base_skin = base_skin or prefabname
	base_skin = string.gsub(base_skin, "_none", "")	
	
	--self:AddComponent("skinner")
	SetSkinMode( self.animstate, prefabname, base_skin, clothing_names )
	local emotes_to_choose = { "emoteXL_waving1", "emoteXL_waving2", "emoteXL_waving3" }
	local emote_min_time = 6
	local emote_max_time = 12

	local change_delay_time = .5
	
	if not skip_change_emote then 
		--the logic here checking queued_change_slot and time_to_change_emote is to ensure we get the last thing to change (when dealing with multiple changes on one frame caused by the UI refreshing)
		if self.animstate:IsCurrentAnimation("idle") and (self.queued_change_slot == "" or self.time_to_change_emote < change_delay_time ) then
			if self.last_skins.prefabname ~= prefabname or self.last_skins.base_skin ~= base_skin then
				self.queued_change_slot = "base"
			end
			if self.last_skins.body ~= clothing_names.body then
				self.queued_change_slot = "body"
			end
			if self.last_skins.hand ~= clothing_names.hand then
				self.queued_change_slot = "hand"
			end
			if self.last_skins.legs ~= clothing_names.legs then
				self.queued_change_slot = "legs"
			end
			if self.last_skins.feet ~= clothing_names.feet then
				self.queued_change_slot = "feet"
			end
		end
		self.time_to_change_emote = change_delay_time
	else
		self.queued_change_slot = ""
	end
	
	if prefabname == "scarecrow" then
        self.animstate:SetBank("scarecrow")
		if self.scarecrow_pose == nil then
			self.scarecrow_pose = string.format( "pose%s", tostring(math.random( 1, 7 )))
		end
		self.animstate:PlayAnimation( self.scarecrow_pose, true )
	end

	local mobAnimData = MobAnimTable[prefabname]
	local isstalker = not string.find(prefabname, "minion") and string.match(prefabname, "stalker") or false
	local isdeer = string.match(prefabname, "deerp") or false --This is to avoid detecting deerclops
	local isdeergem = string.match(prefabname, "deer_") or false--Ditto
	local isshiny2 = string.match(base_skin, "[1-9]") or nil	
	
	
    if mobAnimData ~= nil then
        self.animstate:SetBank(mobAnimData.bank)
		if prefabname == base_skin and isstalker == false then
			self.animstate:SetBuild(mobAnimData.build)
		elseif isstalker ~= false then
			self.animstate:SetBuild("stalker_shadow_build")
			if prefabname == base_skin then
				self.animstate:AddOverrideBuild(mobAnimData.build)
			else
				self.animstate:AddOverrideBuild(mobAnimData.shinybuild.."_shiny_build_0"..base_skin)
			end
		else
			self.animstate:SetBuild(base_skin)
		end
		if not self.animstate:IsCurrentAnimation(mobAnimData.anim) then
        self.animstate:PlayAnimation(mobAnimData.anim, true)    
		end
		--self.mob.Transform:SetFourFaced()
		--self.mob.Transform:SetRotation(180 * DEGREES)
        self.anim:SetScale(mobAnimData.scale)
        skip_change_emote = true
        self.ismobanim = true
		
		if prefabname == "deerp" or isdeergem ~= false then
			local deerbuildx = prefabname == base_skin and mobAnimData.build or "deer_shiny_build_0"..isshiny2
			if prefabname == "deer_redp" then
				self.animstate:OverrideSymbol("swap_antler_red", deerbuildx, "swap_antler_red")
			elseif prefabname == "deer_bluep" then
				self.animstate:OverrideSymbol("swap_antler_red", deerbuildx, "swap_antler_blue")
			else
				self.animstate:OverrideSymbol("swap_antler_red", deerbuildx, "swap_antler3")
				self.animstate:Hide("CHAIN")
				self.animstate:OverrideSymbol("swap_neck_collar", deerbuildx, "swap_neck")
			end		
		end
		
		if prefabname == "tallbirdplayer" then
			self.animstate:Hide("beakfull")			
		end
		
       -- self.mob:AddTransform()
        --self.anim:AddTransform()
        --self.uianim:ForceFacePoint(500, 500, 500) 
        --self.transform:SetFourFaced()
		--self.transform:SetRotation(90 * GLOBAL.DEGREES)
    else
        self.ismobanim = nil
        self.anim:SetScale(.25)
		--self.animstate:SetBank("corner_dude")
		--self.animstate:PlayAnimation("idle", true)
    end
	
	self.last_skins.prefabname = prefabname
	self.last_skins.base_skin = base_skin
	self.last_skins.body = clothing_names.body
	self.last_skins.hand = clothing_names.hand
	self.last_skins.legs = clothing_names.legs
	self.last_skins.feet = clothing_names.feet
	
	
end
--Avatar Popup--
local PlayerAvatarPortrait = require "widgets/redux/playeravatarportrait"
local SkinsUltil = require "skinsutils"
local Image = require "widgets/image"

function PlayerAvatarPortrait:CorrectScale(scale) --New UI messes with current scale
	if scale ~= nil then
    self.puppet:SetScale(scale * 6)
	else
	print("Skinpuppet Error: Scale came up nil, tell Leo!")
	self.puppet:SetScale(0.05)
	end
end

function PlayerAvatarPortrait:CorrectStalker(build) --Applies Stalker's shadow build for puppets.
	self.puppet.animstate:SetBuild("stalker_shadow_build")	
	self.puppet.animstate:AddOverrideBuild(build)
end

function PlayerAvatarPopup:UpdateData(data)
	local unpack = GLOBAL.unpack
	local softresolvefilepath = GLOBAL.softresolvefilepath
	local mobAnimData = MobAnimTable[self.currentcharacter]
	

    if self.title ~= nil then
        if data.colour ~= nil then
            self.title:SetColour(unpack(data.colour))
        else
            self.title:SetColour(0, 0, 0, 1)
        end
    end

    if self.age ~= nil and data.playerage ~= nil then
        self.age:SetString(STRINGS.UI.PLAYER_AVATAR.AGE_SURVIVED.." "..data.playerage.." "..(data.playerage == 1 and STRINGS.UI.PLAYER_AVATAR.AGE_DAY or STRINGS.UI.PLAYER_AVATAR.AGE_DAYS))
        if self.netprofilebutton ~= nil then
            --left align to steam button if there is one
            --otherwise it is centered by default
            local w = self.age:GetRegionSize()
            self.age:SetPosition(w * .5 - 130, 60, 0)
        end
    end

    if self.puppet ~= nil then
		local isshiny = data.base_skin ~= nil and string.match(data.base_skin, '%d') or nil		
		local mobname = self.currentcharacter
		local isstalker2 = not string.find(self.currentcharacter, "minion") and string.match(self.currentcharacter, "stalker") or false
		local getmobname = string.gsub(self.currentcharacter, "_%d", "") or nil
		local mobAnimData = MobAnimTable[mobname]
        local build = self.currentcharacter == "unknownmod" and "mod_player_build" or self.currentcharacter
        local clothing =
        {
            body = data.body_skin,
            hand = data.hand_skin,
            legs = data.legs_skin,
            feet = data.feet_skin,
        }
		
		
		
        self.puppet:SetSkins(build, data.base_skin, clothing)
		self.puppet:UpdatePlayerListing(nil, nil, build, GLOBAL.GetSkinsDataFromClientTableData(data))
		
        if self.userid == nil then
            -- Only actual users get vanity items.
            self.puppet:HideVanityItems()
        end
		if mobAnimData ~= nil then
			if isstalker2 ~= false then
				--self.puppet:CorrectStalker(build)
			end
			
			if data.base_skin ~= nil and isshiny ~= nil then
				if isstalker2 ~= false then
					--build = "stalker_shadow_build"
				else
					build = mobAnimData.shinybuild.."_shiny_build_0"..isshiny
				end		
			else
			build = mobAnimData.build
			self.puppet:SetSkins(self.currentcharacter, data.base_skin, clothing)
			self.puppet:UpdatePlayerListing(nil, nil, build, GLOBAL.GetSkinsDataFromClientTableData(data))
			self.puppet:CorrectScale(mobAnimData.scale)
			end
			--[[
			if getmobname == "deerp" or getmobname == "deer_redp" or getmobname == "deer_bluep" then
				local deerbuildz = isshiny ~= nil and "deer_shiny_build_0"..isshiny or "deer_build"
				if getmobname == "deer_redp" then
					self.puppet:OverrideSymbol("swap_antler_red", deerbuildz, "swap_antler_red")
				elseif getmobname == "deer_bluep" then
					self.puppet:OverrideSymbol("swap_antler_red", deerbuildz, "swap_antler_blue")
				else
					self.puppet:OverrideSymbol("swap_antler_red", deerbuildz, "swap_antler3")
					self.puppet:Hide("CHAIN")
					self.puppet:OverrideSymbol("swap_neck_collar", deerbuildz, "swap_neck")
				end					
			end]]
			--self.puppet.animstate:SetScale(mobAnimData.scale)
		end
    end
	
	
    if self.portrait ~= nil then
        if data.base_skin ~= nil then
            if softresolvefilepath("bigportraits/"..data.base_skin..".xml") then
                self.portrait:SetTexture("bigportraits/"..data.base_skin..".xml", data.base_skin.."_oval.tex", self.currentcharacter.."_none.tex")
                self.portrait:SetPosition(94, 170)
            else
                -- Shouldn't actually be possible:
                self.portrait:SetTexture("bigportraits/"..self.currentcharacter..".xml", self.currentcharacter..".tex")
                self.portrait:SetPosition(94, 180)
            end
        elseif softresolvefilepath("bigportraits/"..self.currentcharacter.."_none.xml") then 
            self.portrait:SetTexture("bigportraits/"..self.currentcharacter.."_none.xml", self.currentcharacter.."_none_oval.tex")
            self.portrait:SetPosition(94, 170)
        else
            self.portrait:SetTexture("bigportraits/"..self.currentcharacter..".xml", self.currentcharacter..".tex")
            self.portrait:SetPosition(94, 180)
        end
    end

    if self.body_image ~= nil then
        self:UpdateSkinWidgetForSlot(self.body_image, "body", data.body_skin or "none")
    end
    if self.hand_image ~= nil then
        self:UpdateSkinWidgetForSlot(self.hand_image, "hand", data.hand_skin or "none")
    end
    if self.legs_image ~= nil then
        self:UpdateSkinWidgetForSlot(self.legs_image, "legs", data.legs_skin or "none")
    end
    if self.feet_image ~= nil then
        self:UpdateSkinWidgetForSlot(self.feet_image, "feet", data.feet_skin or "none")
    end
    if self.base_image ~= nil then
        self:UpdateSkinWidgetForSlot(self.base_image, "base", data.base_skin or self.currentcharacter.."_none")
    end

    if self.head_equip_image ~= nil then
        self:UpdateEquipWidgetForSlot(self.head_equip_image, GLOBAL.EQUIPSLOTS.HEAD, data.equip)
    end
    if self.hand_equip_image ~= nil then
        self:UpdateEquipWidgetForSlot(self.hand_equip_image, GLOBAL.EQUIPSLOTS.HANDS, data.equip)
    end
    if self.body_equip_image ~= nil then
        self:UpdateEquipWidgetForSlot(self.body_equip_image, GLOBAL.EQUIPSLOTS.BODY, data.equip)
    end
end

------------------------------------------------------------------
-- Asset Population
------------------------------------------------------------------

local assetPaths = { "bigportraits/", "images/map_icons/", "images/avatars/avatar_", "images/avatars/avatar_ghost_" }
local assetTypes = { {"IMAGE", "tex"}, {"ATLAS", "xml"} }

-- Iterate through the player mob table and do the following:
-- 1. Populate the PrefabFiles table with the mob prefab names and their skin prefabs (if applicable)
-- 2. Add an atlas and image for the mob's following assets:
-- 2.1 Character select screen portraits
-- 2.2 Character map icons
-- 2.3 ??? FIXME
-- 2.4 ??? FIXME
--for prefab, mob in pairs(GLOBAL.PP_MobCharacters) do
for _, prefab in ipairs(PP_Character_Order) do
	local mob = GLOBAL.PP_MobCharacters[prefab]
	table.insert(PrefabFiles, prefab)
	
	-- Add custom skin prefabs, if available
	-- Example: "dragonplayer_formal"
	for _, skin in ipairs(mob.skins) do
			table.insert(PrefabFiles, prefab.."_"..skin)
	end
	
	for _, path in ipairs(assetPaths) do
		for _, assetType in ipairs(assetTypes) do
			--print("Adding asset: "..assetType[1], path..prefab.."."..assetType[2])
			table.insert( Assets, Asset( assetType[1], path..prefab.."."..assetType[2] ) )
		end
	end
end

------------------------------------------------------------------
-- Mob Character Instantiation
------------------------------------------------------------------

-- Adds a mod character based on an individual mob
-- prefab is the prefab name (e.g. clockwork1player)
-- mob.fancyname is the mob's ingame name (e.g. Knight)
-- mob.gender is fairly self-explanatory
--for prefab, mob in pairs(GLOBAL.PP_MobCharacters) do
for _, prefab in ipairs(PP_Character_Order) do
	local mob = GLOBAL.PP_MobCharacters[prefab]
	
	if PlayablePets.MobEnabled(prefab) then
		AddMinimapAtlas("images/map_icons/"..prefab..".xml")
		AddModCharacter(prefab, mob.gender)
		
		if GLOBAL.SKIN_RARITY_COLORS.ModMade ~= nil then
			GLOBAL.MakeModCharacterSkinnable(prefab)
		end
	end
end