Freezing a retextured monster.

Ask for help about creating mods and scripts for Grimrock 2 or share your tips, scripts, tools and assets with other modders here. Warning: forum contains spoilers!
Post Reply
User avatar
DaggorathMaster
Posts: 37
Joined: Thu Sep 08, 2022 7:29 pm

Freezing a retextured monster.

Post by DaggorathMaster »

When I freeze a retextured monster, and it unfreezes, the material resets to the original monster.

e.g., I made storm and poison uggardians, both based on the fire one but with different textures showcasing their elements.
Freeze it (with the ice storm spell, naturally!), and when it unfreezes, it has the textures/material of the flame uggardian!

In my defs, the alternate monsters have baseObject as one of the existing monsters, with material = "<other>".

I suppose redoing both the model and the monster def with no reference to the original would fix that, but is there another way, that allows re-use of existing assets and doesn't cause bloat if I want a bunch of other retextured assets? (Tweaked in other ways like bolt types and resistances).

Perhaps I could overwrite the textures in the material, if the monster doesn't have the frozen condition, but that's per frame for something that doesn't happen that much.

So my uggardians, acolytes, and non-green slime (so far) are borky. Is that why the "raptor" creature in the defs is unused?
minmay
Posts: 2768
Joined: Mon Sep 23, 2013 2:24 am

Re: Freezing a retextured monster.

Post by minmay »

Yep, FrozenMonsterComponent doesn't account for material overrides and it's quite an annoying bug.

The most practical workaround is just to check if the monster's frozen on every frame, and if it isn't, set its material overrides to what you want. You can do this in a LightComponent onUpdate hook on the monster, or a TimerComponent onActivate hook with a timer interval of 0, for example:

Code: Select all

{
	class = "Timer",
	name = "frozenFix",
	timerInterval = 0,
	currentLevelOnly = true,
	onActivate = function(self)
		if not self.go.frozen then
			self.go.model:setMaterial("your_custom_material")
		end
	end,
}
The performance of this is much better than using an additional model file.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
DaggorathMaster
Posts: 37
Joined: Thu Sep 08, 2022 7:29 pm

Re: Freezing a retextured monster.

Post by DaggorathMaster »

OK I'll do that, and maybe I'll see what I can do about turning off the timer when not needed. Like having that onActivate hook turn it off, and having onDamage with type cold either turn it on for longer than the freeze will be, or have another check to see if the cold damage actually froze it (presumably unknown the same frame, and monsters don't have onReceiveCondition).

Are there other conditions etc. that change the material?
User avatar
DaggorathMaster
Posts: 37
Joined: Thu Sep 08, 2022 7:29 pm

Re: Freezing a retextured monster.

Post by DaggorathMaster »

Okay this seems to work, with minimal setup and with the timer shutting off when not needed.
Currently material changes need to be overrides, not setMaterial().
Monster needs "retex" trait.
Everything else is handled.

Code: Select all

-- Monsters based on other monsters, but with different materials, have a bug.
-- Freezing the monster, then having it unfreeze, the material resets to the original monster.
-- Keep track of those, and change the materials back when unfrozen.

-- Set up timer and onDamage hook. Called from monster's onInit(), or from setup_by_ids below..
function setup_ent (ent)
	local overr = ent.model:getMaterialOverrides()
	if not overr or ent.freezeRetexFixTimer then
		return
	end

	ent:createComponent ("Timer", "freezeRetexFixTimer")
	ent.freezeRetexFixTimer:addConnector ("onActivate", self.go.id, "matUpdate")
	ent.freezeRetexFixTimer:setTimerInterval (0)
	ent.freezeRetexFixTimer:stop()
	
	ent.monster:addConnector ("onDamage", self.go.id, "onDamage")
end

-- Called at game start with ids of any monsters having trait "retex".
--- At game start, cannot call from monster onInit().
function setup_by_ids (ids)
	for _, id in ipairs (ids) do
		local ent = findEntity (id)
		if ent and ent.monster and ent.monster:isAlive() then
			setup_ent (ent)
		end
	end
end

-- Called per frame, when timer is active.
-- If frozen condition either didn't happen or has ended,
-- overwrites material(s) and stops timer.
function matUpdate(timer)
	local ent = timer.go
	if not ent.frozen then
		ent.model:setMaterialOverrides (ent.model:getMaterialOverrides())
		
		-- Timer not needed until hit with cold damage again.
		timer:stop()
	end
end

-- When monster is hit with cold, start the timer.
function onDamage(monst, dmg, dam_ty)
	if dam_ty == "cold" then
		monst.go.freezeRetexFixTimer:start()
	end
end
Post Reply