Jump to content

Multiple Items using Same atlas


Recommended Posts

Hey everyone I was able to get some stuff up and running thanks to the help of @Ultroman  I was able to create my own prefabs and reciepes and have them working.  However I would like to be able to include multiple prefabs into one mod and use the same tex and atlas file for both.  It will work just fine if I duplicate and rename the tex and atlas file for the second prefab but if I try and get them to use the same one it gives me no inventory image.  From what I can tell the game will only use unique names or something of the sort for each prefab.  My question is can I use the same blowdart tex and atlas file for multiple different prefabs?  Here is my code.

 

-- mod main
PrefabFiles = {
    "blowdarts",
}

Assets = 
{
	Asset("ATLAS", "images/inventoryimages/blowdart.xml"),
}

G = GLOBAL
T = G.TUNING
RECIPETABS = G.RECIPETABS
Recipe = G.Recipe
Ingredient = G.Ingredient

local dart = G.AllRecipes["blowdart_pipe"]
print("****************************************************************")
print(T.PIPE_DART_DAMAGE)
print("****************************************************************")

G.STRINGS.NAMES.BLACK_DART = "Black Dart"
G.STRINGS.RECIPE_DESC.BLACK_DART = "Standard Issue Blowdart"
G.STRINGS.CHARACTERS.GENERIC.DESCRIBE.BLACK_DART = "Finally a dart that makes sense."

G.STRINGS.NAMES.RED_DART = "Red Dart"
G.STRINGS.RECIPE_DESC.RED_DART = "Standard Issue Blowdart"
G.STRINGS.CHARACTERS.GENERIC.DESCRIBE.RED_DART = "Finally a dart that makes sense."

local black_dart = AddRecipe("black_dart", { Ingredient("cutreeds", 1), Ingredient("stinger", 1), Ingredient("feather_crow",1)}, RECIPETABS.WAR, {SCIENCE = 1} )
local red_dart = AddRecipe("red_dart", { Ingredient("cutreeds", 1), Ingredient("stinger", 1), Ingredient("feather_robin",1)}, RECIPETABS.WAR, {SCIENCE = 1} )
black_dart.atlas = "images/inventoryimages/blowdart.xml"
red_dart.atlas = "images/inventoryimages/blowdart.xml"
black_dart.sortkey = 156.05
red_dart.sortkey = 156.06

and here is the prefab code.

 

local assets =
{
    Asset("ANIM", "anim/blow_dart.zip"),
    Asset("ANIM", "anim/swap_blowdart.zip"),
    Asset("ANIM", "anim/swap_blowdart_pipe.zip"),
}

local prefabs =
{
    "impact",
}

local function onequip(inst, owner)
    owner.AnimState:OverrideSymbol("swap_object", "swap_blowdart", "swap_blowdart")
    owner.AnimState:Show("ARM_carry")
    owner.AnimState:Hide("ARM_normal")
end

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

local function onhit(inst, attacker, target)
    local impactfx = SpawnPrefab("impact")
    if impactfx ~= nil then
        local follower = impactfx.entity:AddFollower()
        follower:FollowSymbol(target.GUID, target.components.combat.hiteffectsymbol, 0, 0, 0)
        if attacker ~= nil then
            impactfx:FacePoint(attacker.Transform:GetWorldPosition())
        end
    end
    inst:Remove()
end

local function onthrown(inst, data)
    inst.AnimState:SetOrientation(ANIM_ORIENTATION.OnGround)
end

local function common(anim, tags, removephysicscolliders)
    local inst = CreateEntity()

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

    MakeInventoryPhysics(inst)

    inst.AnimState:SetBank("blow_dart")
    inst.AnimState:SetBuild("blow_dart")
    inst.AnimState:PlayAnimation(anim)

    inst:AddTag("blowdart")
    inst:AddTag("sharp")

    --projectile (from projectile component) added to pristine state for optimization
    inst:AddTag("projectile")

    if tags ~= nil then
        for i, v in ipairs(tags) do
            inst:AddTag(v)
        end
    end

    if removephysicscolliders then
        RemovePhysicsColliders(inst)
    end

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    inst:AddComponent("weapon")
    inst.components.weapon:SetDamage(0)
    inst.components.weapon:SetRange(8, 10)

    inst:AddComponent("projectile")
    inst.components.projectile:SetSpeed(60)
    inst.components.projectile:SetOnHitFn(onhit)
    inst:ListenForEvent("onthrown", onthrown)
    -------

    inst:AddComponent("inspectable")

    inst:AddComponent("inventoryitem")
    inst:AddComponent("stackable")

    inst:AddComponent("equippable")
    inst.components.equippable:SetOnEquip(onequip)
    inst.components.equippable:SetOnUnequip(onunequip)
    inst.components.equippable.equipstack = true

    MakeHauntableLaunch(inst)

    return inst
end


-------------------------------------------------------------------------------
-- black Dart (Damage)
-------------------------------------------------------------------------------
local function pipeequip(inst, owner)
    owner.AnimState:OverrideSymbol("swap_object", "swap_blowdart_pipe", "swap_blowdart_pipe")
    owner.AnimState:Show("ARM_carry")
    owner.AnimState:Hide("ARM_normal")
end

local function pipethrown(inst)
    inst.AnimState:PlayAnimation("dart_pipe")
    inst:AddTag("NOCLICK")
    inst.persists = false
end

local function BlackDart()
    local inst = common("idle_pipe")

    if not TheWorld.ismastersim then
        return inst
    end

    inst.components.equippable:SetOnEquip(pipeequip)
    inst.components.weapon:SetDamage(TUNING.PIPE_DART_DAMAGE)
    inst.components.projectile:SetOnThrownFn(pipethrown)
	inst.components.inventoryitem.atlasname = "images/inventoryimages/blowdart.xml"

    return inst
end

-------------------------------------------------------------------------------
-- Red Dart (Damage)
-------------------------------------------------------------------------------
local function pipeequip(inst, owner)
    owner.AnimState:OverrideSymbol("swap_object", "swap_blowdart_pipe", "swap_blowdart_pipe")
    owner.AnimState:Show("ARM_carry")
    owner.AnimState:Hide("ARM_normal")
end

local function pipethrown(inst)
    inst.AnimState:PlayAnimation("dart_pipe")
    inst:AddTag("NOCLICK")
    inst.persists = false
end

local function RedDart()
    local inst = common("idle_pipe")

    if not TheWorld.ismastersim then
        return inst
    end

    inst.components.equippable:SetOnEquip(pipeequip)
    inst.components.weapon:SetDamage(TUNING.PIPE_DART_DAMAGE)	
    inst.components.projectile:SetOnThrownFn(pipethrown)
	inst.components.inventoryitem.atlasname = "images/inventoryimages/blowdart.xml"

    return inst
end


-------------------------------------------------------------------------------
return Prefab("black_dart", BlackDart, assets, prefabs),
	   Prefab("red_dart", RedDart, assets, prefabs)

 

Link to comment
Share on other sites

The answer is in these lines from the Recipe "constructor" function (which, if you recall, AddRecipe calls internally):

self.product       = product or name
self.tab           = tab
self.imagefn       = type(image) == "function" and image or nil
self.image         = self.imagefn == nil and image or (self.product .. ".tex")
self.atlas         = (atlas and resolvefilepath(atlas))-- or resolvefilepath(GetInventoryItemAtlas(self.image))

If you give it a function in the "image" parameter, it will set that to the imagefn variable, use that to get the image when queried for one, while image will be set to nil. If you give it a filename in the "image" parameter, imagefn will be set to nil, and the image variable will be set to the value of the "image" parameter. If you give it nothing (like you are doing), it will default to self.product..".tex". Since you are not providing it with a value for the "product" parameter, the product variable is set to the prefab name you've given it, and so, image is set to be "red_dart.tex", which is not what you want, since you only have "black_dart.tex". Furthermore, it sets the atlas variable using the value given in the "atlas" parameter, but in your case you give it nothing, so it defaults to nil since they've commented out the part that resolves the file path using the image variable. This is a recent change, but don't worry, they just moved that part into the function used to get the atlas:

function Recipe:GetAtlas()
	self.atlas = self.atlas or resolvefilepath(GetInventoryItemAtlas(self.image))
	return self.atlas
end

So, in your case, if you did not change the atlas after the fact, it would try to use the file name saved in the image variable, which would be "red_dart.tex", which does not exist. But since you set the atlas variable after the fact to point to your blow_dart.xml, your atlas will be resolved correctly, but your image variable will still be "red_dart.tex".

In short, you have to set the image variable to "black_dart.tex", as well. You could also save yourself some lines, and just use the whole AddRecipe function, and just give it the values for atlas and image (I still left out "testfn" and "product" at the end):

local black_dart = AddRecipe("black_dart", { Ingredient("cutreeds", 1), Ingredient("stinger", 1), Ingredient("feather_crow",1)}, RECIPETABS.WAR, {SCIENCE = 1}, nil, nil, nil, nil, nil, "images/inventoryimages/blowdart.xml", "black_dart.tex")
local red_dart = AddRecipe("red_dart", { Ingredient("cutreeds", 1), Ingredient("stinger", 1), Ingredient("feather_robin",1)}, RECIPETABS.WAR, {SCIENCE = 1}, nil, nil, nil, nil, nil, "images/inventoryimages/blowdart.xml", "black_dart.tex")

 

Edited by Ultroman
Link to comment
Share on other sites

@Ultroman  Thank you as this is all starting to make so much more sense.  The way I went about resolving this issue was to simply duplicate the image and pack the tex with more then one image using the same prefab name as the entity I was creating. Also making sure the xml file was pointing to the correct reference of the texture file.  This worked perfectly.  Would I be saving my self any processing time by simply pointing to the same texture vs packing another image into it?

Link to comment
Share on other sites

No. In one way it would be neater to reuse the tex if they are the same, because less files is a good thing, but in another way it would be less neat, because it might be confusing that you're using the same image. Maybe if you get back to your code in a year, you won't remember what you did with the textures, and you'll only have one and be like "wtf? The other item has not tex file". But in the end, it's your mod. You can do whatever you want. It's just 64kb of extra memory used for the tex (or however much it is). And the code is practically the same, and those calls are one-shot and have no bearing on processing power.

Why do they have the same image, anyway? Isn't one supposed to be red? :confused:

Link to comment
Share on other sites

Yeah I suppose they are suppose to be different images but I haven't got around to changing it yet.  I have made a few other things like dart tips and have actually messed around with some images.  However, I am about the worst graphically inclined person in the world lol.  The one thing that I still need to figure out is how I go about using the spriter and official mod tools thing so I can get my mod up on the workshop and I need to make ground animations for some of my new custom items.  Can you think of a good tutorial on that stuff?

Link to comment
Share on other sites

There are a bunch of old tutorials if you follow the links in my newcomer post. I can't be sure which ones are outdated. I can't find anything newer than 2015, and most of the newest replies are "It's not working!" This one, written by bizziboi, seems to describe how to get the game to automatically convert your PNG files to tex and xml files, and the same for animations. I've never worked with images for my mods, other than the preview/modicon images, and for those I've always used the TEXtool, even though I could probably just put in my PNGs. I dunno, old habits die hard.

Using the Mod Tools to upload your mod is insanely simple. In the top text box just browse to your mod folder. In the preview image, you have to select a PNG not a tex (which I think it defaults to, when you select your mod folder above). Write a name and description (it should have taken defaults from your modinfo.lua). Click the appropriate tags at the bottom, and click publish. It's that easy. Just make sure you check that the mod works for you on a server with and without caves, because then you'll have checker both client and server behavior, respectively (adding caves makes you join as a client, while without caves your join as the server).

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