Jump to content

Recommended Posts

Hey! I've been making mods for a while now and they're mostly simple. But I have a problem that I don't know how to deal with. I want to make an artist whose drawings come to life. For this I want to use the Umbra codex system, but I have no idea how to do it. I will be glad if you help me, sorry in advance for my English. 

rumia.png

Link to comment
https://forums.kleientertainment.com/forums/topic/145732-help-pls/
Share on other sites

At its core it seems to be comprised of these three components attached to the "spellbook" item; Spellbook, AOETargetting, and AOESpell

Both the Spellbook and AOETargetting component should be added before SetPristine

It comes down to mostly copy/pasting from waxwelljournal.lua, it doesn't take too much to get a very simple "spell" working

This is just me tinkering and having it spawn a rabbit with no fuel needed

local prefabs = 
{
	"rabbit"
}

-- The function the codex uses to tell if a location is valid for the aoe spell
local function ReticuleTargetAllowWaterFn()
	local player = ThePlayer
	local ground = TheWorld.Map
	local pos = Vector3()
	--Cast range is 8, leave room for error
	--4 is the aoe range
	for r = 7, 0, -.25 do
		pos.x, pos.y, pos.z = player.entity:LocalToWorldSpace(r, 0, 0)
		if ground:IsPassableAtPoint(pos.x, 0, pos.z, true) and not ground:IsGroundTargetBlocked(pos) then
			return pos
		end
	end
	return pos
end

-- Just a basic "spell" that simply spawns a rabbit at targetted position
local function SummonRabbitFn(inst, doer, pos)
	-- This is where you would check for fuel
	local spell = SpawnPrefab("rabbit") -- Most of maxwell's spells spawn a prefab that's built from a prefab file with multiple prefabs like preparedfoods 	so they're harder to find if you go looking for them as an example
	-- spell.caster = doer -- gives the prefab a variable with the player attached, not needed here
	-- spell.item = inst -- gives the prefab a variable with this item attached, not needed here
	-- For setting the spell's position
	local platform = TheWorld.Map:GetPlatformAtPoint(pos.x, pos.z)
	if platform ~= nil then
		spell.entity:SetParent(platform.entity)
		spell.Transform:SetPosition(platform.entity:WorldToLocalSpace(pos:Get()))
	else
		spell.Transform:SetPosition(pos:Get())
	end
	-- This is where you would make the spell use fuel and any other effects on the item and player
	-- Can also have a check that returns false if the spell can not be done
	return true
end

-- AOE Targetting function for giving the player control over it
local function StartAOETargeting(inst)
	local playercontroller = ThePlayer.components.playercontroller
	if playercontroller ~= nil then
		playercontroller:StartAOETargetingUsing(inst)
	end
end

local ICON_SCALE = .6
local ICON_RADIUS = 50
local SPELLBOOK_RADIUS = 100
local SPELLBOOK_FOCUS_RADIUS = SPELLBOOK_RADIUS + 2
local SPELLS = {
	{ -- Sets the data for each individual spell in the table
		label = "Summon Rabbit", -- Name of the spell, the codex assigns it in STRINGS but doing it here works fine
		onselect = function(inst)
			inst.components.spellbook:SetSpellName("Summon Rabbit") -- Same as label
			inst.components.aoetargeting:SetDeployRadius(0)
			inst.components.aoetargeting:SetShouldRepeatCastFn(nil)
			inst.components.aoetargeting.reticule.reticuleprefab = "reticuleaoe_1d2_12"
			inst.components.aoetargeting.reticule.pingprefab = "reticuleaoeping_1d2_12"
			if TheWorld.ismastersim then
				inst.components.aoetargeting:SetTargetFX("reticuleaoesummontarget_1d2")
				inst.components.aoespell:SetSpellFn(SummonRabbitFn) -- The actual spell function
				inst.components.spellbook:SetSpellFn(nil) -- The spell function if it wasn't using AOE Targetting
			end
		end,
		execute = StartAOETargeting, -- Starts the new AOE Targetting system with the function above
		atlas = "images/spell_icons.xml", -- Just taken from the pillars spell, I tried my own image but it didn't work
		normal = "shadow_pillars.tex",
		widget_scale = ICON_SCALE, -- Size of the widget, set earlier
		hit_radius = ICON_RADIUS, -- I couldn't 100% tell what this did, but I'm guessing its how wide the "hitbox" for pressing it is
	},
}

-- In the prefab's fn, above SetPristine
inst:AddComponent("spellbook")
	-- Tag required for the user
	inst.components.spellbook:SetRequiredTag("charactertag")
	inst.components.spellbook:SetRadius(SPELLBOOK_RADIUS)
	inst.components.spellbook:SetFocusRadius(SPELLBOOK_FOCUS_RADIUS)
	inst.components.spellbook:SetItems(SPELLS)
	-- Used for changing the image of the codex to open or closed if needed
	--inst.components.spellbook:SetOnOpenFn(OnOpenSpellBook)
	--inst.components.spellbook:SetOnCloseFn(OnCloseSpellBook)
	inst.components.spellbook.opensound = "dontstarve/common/together/book_maxwell/use"
	inst.components.spellbook.closesound = "dontstarve/common/together/book_maxwell/close"
	
	inst:AddComponent("aoetargeting")
	inst.components.aoetargeting:SetAllowWater(true) -- Water is valid spot for the spell
	inst.components.aoetargeting.reticule.targetfn = ReticuleTargetAllowWaterFn -- Sets the targetting function
	inst.components.aoetargeting.reticule.validcolour = { 1, .75, 0, 1 } -- Color for when location is valid
	inst.components.aoetargeting.reticule.invalidcolour = { .5, 0, 0, 1 } -- Color for when its not
	inst.components.aoetargeting.reticule.ease = true -- Not entirely sure what this does
	inst.components.aoetargeting.reticule.mouseenabled = true -- Can use mouse to target
	inst.components.aoetargeting.reticule.twinstickmode = 1 -- For controller
	inst.components.aoetargeting.reticule.twinstickrange = 8 -- For Controller

-- Below SetPristine with the other AddComponents
	inst:AddComponent("aoespell")

Most of the stuff I commented was probably self-explanatory, but just in case since its been removed from its original context

Hopefully this helps get you started with using the spellbook and aoetargetting component, you can look through the correlated files yourself to get a better idea of what else can be done with it but this all the code that appears to be needed to make it function. Its also possible to do a spell without the aoetargetting component, waxwelljournal.lua has an example of that with the commented out tophat spell

On 1/26/2023 at 5:35 PM, Merkyrrie said:

At its core it seems to be comprised of these three components attached to the "spellbook" item; Spellbook, AOETargetting, and AOESpell

Both the Spellbook and AOETargetting component should be added before SetPristine

It comes down to mostly copy/pasting from waxwelljournal.lua, it doesn't take too much to get a very simple "spell" working

This is just me tinkering and having it spawn a rabbit with no fuel needed

local prefabs = 
{
	"rabbit"
}

-- The function the codex uses to tell if a location is valid for the aoe spell
local function ReticuleTargetAllowWaterFn()
	local player = ThePlayer
	local ground = TheWorld.Map
	local pos = Vector3()
	--Cast range is 8, leave room for error
	--4 is the aoe range
	for r = 7, 0, -.25 do
		pos.x, pos.y, pos.z = player.entity:LocalToWorldSpace(r, 0, 0)
		if ground:IsPassableAtPoint(pos.x, 0, pos.z, true) and not ground:IsGroundTargetBlocked(pos) then
			return pos
		end
	end
	return pos
end

-- Just a basic "spell" that simply spawns a rabbit at targetted position
local function SummonRabbitFn(inst, doer, pos)
	-- This is where you would check for fuel
	local spell = SpawnPrefab("rabbit") -- Most of maxwell's spells spawn a prefab that's built from a prefab file with multiple prefabs like preparedfoods 	so they're harder to find if you go looking for them as an example
	-- spell.caster = doer -- gives the prefab a variable with the player attached, not needed here
	-- spell.item = inst -- gives the prefab a variable with this item attached, not needed here
	-- For setting the spell's position
	local platform = TheWorld.Map:GetPlatformAtPoint(pos.x, pos.z)
	if platform ~= nil then
		spell.entity:SetParent(platform.entity)
		spell.Transform:SetPosition(platform.entity:WorldToLocalSpace(pos:Get()))
	else
		spell.Transform:SetPosition(pos:Get())
	end
	-- This is where you would make the spell use fuel and any other effects on the item and player
	-- Can also have a check that returns false if the spell can not be done
	return true
end

-- AOE Targetting function for giving the player control over it
local function StartAOETargeting(inst)
	local playercontroller = ThePlayer.components.playercontroller
	if playercontroller ~= nil then
		playercontroller:StartAOETargetingUsing(inst)
	end
end

local ICON_SCALE = .6
local ICON_RADIUS = 50
local SPELLBOOK_RADIUS = 100
local SPELLBOOK_FOCUS_RADIUS = SPELLBOOK_RADIUS + 2
local SPELLS = {
	{ -- Sets the data for each individual spell in the table
		label = "Summon Rabbit", -- Name of the spell, the codex assigns it in STRINGS but doing it here works fine
		onselect = function(inst)
			inst.components.spellbook:SetSpellName("Summon Rabbit") -- Same as label
			inst.components.aoetargeting:SetDeployRadius(0)
			inst.components.aoetargeting:SetShouldRepeatCastFn(nil)
			inst.components.aoetargeting.reticule.reticuleprefab = "reticuleaoe_1d2_12"
			inst.components.aoetargeting.reticule.pingprefab = "reticuleaoeping_1d2_12"
			if TheWorld.ismastersim then
				inst.components.aoetargeting:SetTargetFX("reticuleaoesummontarget_1d2")
				inst.components.aoespell:SetSpellFn(SummonRabbitFn) -- The actual spell function
				inst.components.spellbook:SetSpellFn(nil) -- The spell function if it wasn't using AOE Targetting
			end
		end,
		execute = StartAOETargeting, -- Starts the new AOE Targetting system with the function above
		atlas = "images/spell_icons.xml", -- Just taken from the pillars spell, I tried my own image but it didn't work
		normal = "shadow_pillars.tex",
		widget_scale = ICON_SCALE, -- Size of the widget, set earlier
		hit_radius = ICON_RADIUS, -- I couldn't 100% tell what this did, but I'm guessing its how wide the "hitbox" for pressing it is
	},
}

-- In the prefab's fn, above SetPristine
inst:AddComponent("spellbook")
	-- Tag required for the user
	inst.components.spellbook:SetRequiredTag("charactertag")
	inst.components.spellbook:SetRadius(SPELLBOOK_RADIUS)
	inst.components.spellbook:SetFocusRadius(SPELLBOOK_FOCUS_RADIUS)
	inst.components.spellbook:SetItems(SPELLS)
	-- Used for changing the image of the codex to open or closed if needed
	--inst.components.spellbook:SetOnOpenFn(OnOpenSpellBook)
	--inst.components.spellbook:SetOnCloseFn(OnCloseSpellBook)
	inst.components.spellbook.opensound = "dontstarve/common/together/book_maxwell/use"
	inst.components.spellbook.closesound = "dontstarve/common/together/book_maxwell/close"
	
	inst:AddComponent("aoetargeting")
	inst.components.aoetargeting:SetAllowWater(true) -- Water is valid spot for the spell
	inst.components.aoetargeting.reticule.targetfn = ReticuleTargetAllowWaterFn -- Sets the targetting function
	inst.components.aoetargeting.reticule.validcolour = { 1, .75, 0, 1 } -- Color for when location is valid
	inst.components.aoetargeting.reticule.invalidcolour = { .5, 0, 0, 1 } -- Color for when its not
	inst.components.aoetargeting.reticule.ease = true -- Not entirely sure what this does
	inst.components.aoetargeting.reticule.mouseenabled = true -- Can use mouse to target
	inst.components.aoetargeting.reticule.twinstickmode = 1 -- For controller
	inst.components.aoetargeting.reticule.twinstickrange = 8 -- For Controller

-- Below SetPristine with the other AddComponents
	inst:AddComponent("aoespell")

Most of the stuff I commented was probably self-explanatory, but just in case since its been removed from its original context

Hopefully this helps get you started with using the spellbook and aoetargetting component, you can look through the correlated files yourself to get a better idea of what else can be done with it but this all the code that appears to be needed to make it function. Its also possible to do a spell without the aoetargetting component, waxwelljournal.lua has an example of that with the commented out tophat spell

God bless you! I was trying to do exactly that!

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
×
  • Create New...