Page 1 of 1

[SCRIPT] Hooks for Ogre/Warden charging

Posted: Sun Mar 02, 2014 9:51 am
by Diarmuid
Hey guys!

Ever wished to script fun stuff with ogres' charging attacks, but had to resort to improbable hacks to make it happen? Ever just wished for an "onCharge" hook?

Enter the Ogre Tracker! (tu-dum).

A simple to use tracking system for ogres which allows you to add onCharge(self, startingX, startingY) and onChargeEnd(self) hooks to your monster.

1. put that script in a script entity named ogreTracker:
SpoilerShow

Code: Select all

--[[ 
OGRE TRACKING SYSTEM

Version: 0.9
Scripting by Diarmuid
]]

debugMessages = false;

ogres = {}

function startTracking(id)
	if (ogres[id]) then return; end
	local ogreEntity = findEntity(id);
	if not(ogreEntity) then return; end
	
	ogres[id] = {};
	local ogre = ogres[id];
	ogre.id = id;
	ogre.moveDir = -1;
	ogre.chargeDir = -1;
	ogre.x = ogreEntity.x;
	ogre.y = ogreEntity.y;
	ogre.stopCtr = 0;
	
	if fw then
		fw.setHook(id..".ogreTracker.onMove",
			function(monster, direction)
				if ogreTracker and ogreTracker.ogres[monster.id] then
					ogreTracker.ogres[monster.id].moveDir = direction;
				end
				return true;
			end
		)
	end
	
	ogre.update = function(self)
		local ogreEntity = findEntity(self.id);
		if not(ogreEntity) then 
			self:stopTracking();
			return; 
		end
		local level, x, y = ogreEntity.level, ogreEntity.x, ogreEntity.y;
		if x ~= self.x or y ~= self.y then
			if self.moveDir ~= -1 then
				self.moveDir = -1;
				self.x = x;
				self.y = y;
			else
				if y < self.y then self.chargeDir = 0; end
				if x > self.x then self.chargeDir = 1; end
				if y > self.y then self.chargeDir = 2; end
				if x < self.x then self.chargeDir = 3; end
				if not(self.charging) then
					if debugMessages then
						print("OGRE TRACKER: "..self.id.." started charging at ", level, self.x, self.y, "facing", self.chargeDir);
					end
					if self.onCharge then
						self.onCharge(ogreEntity, self.x, self.y);
					end
				end
				self.x = x;
				self.y = y;
				self.charging = true;
			end
		elseif self.chargeDir ~= -1 then
			if self.stopCtr < 4 then
				self.stopCtr = self.stopCtr + 1;
			else
				if debugMessages then
					print("OGRE TRACKER: "..self.id.." ended its charge at ", level, x, y, "facing", self.chargeDir);
				end
				self.moveDir = -1;
				self.x = x;
				self.y = y;
				if self.onChargeEnd then
					self.onChargeEnd(ogreEntity);
				end
				self.chargeDir = -1;			
				self.stopCtr = 0;
				self.charging = false;
			end
		end
	end;
	
	ogre.stopTracking = function(self)
		if debugMessages then
			print("OGRE TRACKER: stopped tracking "..self.id);
		end
		if fw then fw.removeHook(self.id..".ogreTracker.onMove"); end
		ogreTracker.ogres[self.id] = nil;
	end;

	if debugMessages then
		print("OGRE TRACKER: started tracking "..id);
	end
	
	return ogre;
end

function stopTracking(id)
	if ogres[id] then ogres[id]:stopTracking(); end
end

function addHook(id, hookName, funct)
	local ogre = ogres[id];
	if not(ogre) then 
		print("OGRE TRACKER: warning, trying to add hook to "..id..", not registered for tracking");
		return; 
	end
	if hookName == "onCharge" then
		ogre.onCharge = funct;
	elseif hookName == "onChargeEnd" then
		ogre.onChargeEnd = funct;
	end
end

function update()
	for _, ogre in pairs(ogres) do
		ogre:update();
	end
end
2. Plug in a timer to tick ogreTracker.update() every 0.2 seconds. Ideally you should use one of the many methods which ensure that this is constant no matter the party level.


3. If your mod uses the LoG framework, nothing else is required for setup. If you don't you need to manually add this to the onMove hook of the monsters you wish to track:
SpoilerShow

Code: Select all

onMove = function(monster, direction)
				if ogreTracker and ogreTracker.ogres[monster.id] then
					ogreTracker.ogres[monster.id].moveDir = direction;
				end
				return true;
			end

USAGE:

First you need to register the monster in the tracker by calling

Code: Select all

ogreTracker.startTracking(id)
Then, add either hook you wish:

Code: Select all

ogreTracker.addHook(id, "onCharge", function(self, startingX, startingY)
    --Put your code here
end)

ogreTracker.addHook(id, "onChargeEnd", function(self)
    --Put your code here
end)
If you wish to stop tracking that ogre, just call:

Code: Select all

ogreTracker.stopTracking(id)
The system is fairly optimized, but if you wish to manage a lot of ogres, it would be a good practice to start/stop tracking only when the party enters/exits the zone/level/room, to avoid any performance slowdowns.

Also, don't worry, the system will stop tracking automatically and cleanUp data if the monster dies or is destroyed.

a debugMessages variable at the top allows you to get some info on what hooks are called.

IMPORTANT NOTE: The system detects the charge AFTER the monster already started it and is one square away. That's why onCharge returns a startingX and a startingY parameter so that you can know the initial position.This means you cannot use this system to "prevent" the monster from charging on certain conditions, but you can always stop it after a 1 tile charge by spawning a blocker on the next square, if you wish.