Jump to content

Add more items on graves loot


Recommended Posts

The relevant code is in mound.lua and trinkets.lua. Unfortunately, some of the relevant stuff is defined locally, such as parts of the loot list, but there are some function(s) you can hook into by overriding to change it without resorting to replacing one of the files with a custom version. For example, the function PickRandomTrinket() is completely global, so it can be overridden easily, and 50% of the time this function directly determines the loot item of a grave mound. Note that particular function is also used in determining a random trinket dropped by damaging Ancient Pseudoscience Stations.

 

Klei doesn't seem to be interested in making this better, so I'm working on a modding library that (among other things) should make this easier, by providing a kind of convenient API to do stuff like modifying various loot lists that aren't easily extensible, including grave mounds' and tumbleweeds', so once that's done, you should have an easy time with it, if you choose to use it.

 @DarkXero , maybe you know or can figure out a clever way to access the loot lists of mounds or tumbleweeds (and catcoons . . . etc?) from a mod, using the debug library or some such, so you don't need to manually copy and paste it to your mod and keep that duplication up to date (like f.ex. every tumbleweed loot mod seems to do)? Haven't started on this part yet, right now my current plan is actually to parse through the respective file and capture it that way... Should work, at least.

Link to comment
Share on other sites

There is no simple answer. Depending on the context, you can do one thing or the other.

 

In case of mounds, you can pull off something like:

-- 5% chance of having meat, 95% of everything else
AddPrefabPostInit("mound", function(inst)
	if inst.components.lootdropper then
		local _SpawnLootPrefab = inst.components.lootdropper.SpawnLootPrefab
		inst.components.lootdropper.SpawnLootPrefab = function(self, item)
			if math.random() < 0.05 then
				item = "meat"
			end
			return _SpawnLootPrefab(self, item)
		end
	end
end)

 

Using the debug library, to access the LOOTS table, could look like this:

local function GetUpvalue(func, name)
	local debug = GLOBAL.debug
	local i = 1
	while true do
		local n, v = debug.getupvalue(func, i)
		if not n then
			return nil, nil
		end
		if n == name then
			return v, i
		end
		i = i + 1
	end
end

local function SetUpvalue(func, ind, value)
	local debug = GLOBAL.debug
	debug.setupvalue(func, ind, value)
end

-- LOOTS table is upvalue of onfinishcallback function

local moundedit = true
AddPrefabPostInit("mound", function(inst)
	if moundedit then
		local fn = inst.components.workable.onfinish
		local LOOTS, LOOTS_index = GetUpvalue(fn, "LOOTS")
		-- since we got a table, we got a reference so we dont need SetUpvalue
		LOOTS["meat"] = 100
		-- now we add something with a weight for the cases we dont get trinkets
		moundedit = false
	end
end)

 

tumbleweed has the possible_loot hidden inside the MakeLoot function, and it isn't an upvalue of anything accesible.

So what can you do here?

You can touch the loot table generated for the tumbleweed, maybe using the same procees as MakeLoot, that uses weights to determine what goes in.

AddPrefabPostInit("tumbleweed", function(inst)
	-- MakeLoot edits inst.loot with the loot to drop
	-- this table will be the one dropped on pickup
	local loot = {"meat", "meat", "cutgrass", "twigs"}
	inst.loot = loot
end)

You can even roll for a chance to replace an element from the loot table:

AddPrefabPostInit("tumbleweed", function(inst)
	if math.random() < 0.05 then
		local lucky_key = math.random(#inst.loot)
		inst.loot[lucky_key] = "meat"
	end
end)

You can also go insane and write something crazy with debug like:

-- since the debug call is from GetLocal, GetLocal adds the extra level, from GetLocal to from wherever its called
-- same for SetLocal

local function GetLocal(stacklevel, name)
	stacklevel = stacklevel + 1
	local debug = GLOBAL.debug
	local i = 1
	while true do
		local n, v = debug.getlocal(stacklevel, i)
		if not n then
			return nil, nil
		end
		if n == name then
			return v, i
		end
		i = i + 1
	end
end

local function SetLocal(stacklevel, ind, value)
	stacklevel = stacklevel + 1
	local debug = GLOBAL.debug
	debug.setlocal(stacklevel, ind, value)
end

local function HackTumbleweeds(self)
	local _IsLocked = self.IsLocked
	self.IsLocked = function(...)
		-- current level is 1
		-- from IsLocked to MakeLoot is 1 level jump
		local tumbleweed, tumbleweed_index = GetLocal(2, "inst")
		if tumbleweed and not tumbleweed.loothacked then 
			local possible_loot, possible_loot_index = GetLocal(2, "possible_loot")
			if possible_loot then
				tumbleweed.loothacked = true
				table.insert(possible_loot, {chance = 500, item = "meat"})
			end
		end
		return _IsLocked(...)
	end
end

AddComponentPostInit("chessunlocks", HackTumbleweeds)

 

But really. WhyEvenBother out of 10.

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