how to "action" when monster dies.

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
User avatar
8kin
Posts: 5
Joined: Wed Nov 07, 2012 1:04 pm

Re: how to "action" when monster dies.

Post by 8kin »

HaunterV wrote:
akroma222 wrote:@ 8kin - I used the same script, works well! ;)

@HaunterV - could you possible make the onDie hook for the boss monster activate a script that went along the lines of:
SpoilerShow

Code: Select all

function openAllDoors()
  for i in allEntities(party.level) do
      if i.id:sub(1,200) == "boss_door_" then
        i:open()
      end
   end
end
(I have not tested this) but...
I have used a similar script connected to a plate to open all portcullis in order to reset a portcullis puzzle...
see i have 5 of those, 1 for each configuration of the room. waht i want is to call a script that fires all of them.
:?
I am still learning the basics of scripting so I hope I can help you out soon!
--
When you're a hammer, everything looks like a nail.
User avatar
HaunterV
Posts: 676
Joined: Mon Apr 16, 2012 9:54 pm
Location: Barrie, Ontario, Canada

Re: how to "action" when monster dies.

Post by HaunterV »

8kin wrote:#stuff

(I have not tested this) but...
I have used a similar script connected to a plate to open all portcullis in order to reset a portcullis puzzle...

see i have 5 of those, 1 for each configuration of the room. waht i want is to call a script that fires all of them.

:?
I am still learning the basics of scripting so I hope I can help you out soon!


Solved it. check out the results in the ORRR. Its a bit more cut n paste and duct tapey than I'd have liked but it works.
Grimrock Community 'FrankenDungeon 2012. Submit your entry now!: http://tinyurl.com/cnupr7h
SUBMIT YOUR ASSETS! Community Asset Pack (C.A.P.): http://tinyurl.com/bqvykrp
Behold! The HeroQuest Revival!: http://tinyurl.com/cu52ksc
Howl3r
Posts: 12
Joined: Fri Aug 12, 2016 11:34 pm
Location: Finland

Re: how to "action" when monster dies.

Post by Howl3r »

Hello!

It's me the one person everyone hates because I don't understand anything xP

So I have a problem. My "action" for the monster is (when it dies) that is says something. I have knowledge of the hudPrint and stuff (sure a full code is always nicer as then I have no problems with making it and I can study it from there easier), but how do I make it connected, so that when in my case when a warden dies, it says something?
User avatar
Isaac
Posts: 3185
Joined: Fri Mar 02, 2012 10:02 pm

Re: how to "action" when monster dies.

Post by Isaac »

Howl3r wrote:So I have a problem. My "action" for the monster is (when it dies) that is says something. I have knowledge of the hudPrint and stuff (sure a full code is always nicer as then I have no problems with making it and I can study it from there easier), but how do I make it connected, so that when in my case when a warden dies, it says something?
Is this a one time event (in your map), or would you be using it with several monsters that have last words?
Howl3r
Posts: 12
Joined: Fri Aug 12, 2016 11:34 pm
Location: Finland

Re: how to "action" when monster dies.

Post by Howl3r »

Isaac wrote:
Howl3r wrote:So I have a problem. My "action" for the monster is (when it dies) that is says something. I have knowledge of the hudPrint and stuff (sure a full code is always nicer as then I have no problems with making it and I can study it from there easier), but how do I make it connected, so that when in my case when a warden dies, it says something?
Is this a one time event (in your map), or would you be using it with several monsters that have last words?
It would be said multiple times. What I am trying to do (changing it around in case my stupidness and low experience with lua makes it too difficult) is to have a Warden at the end, that when he dies he says to you for example that he cannot be defeated and then spawns 2 Wardens. So technically it would be always a different enemy, but they all would have last words when they die.
Basically I guess knowing how the "onDie" script works would make this a lot easier :)
User avatar
Isaac
Posts: 3185
Joined: Fri Mar 02, 2012 10:02 pm

Re: how to "action" when monster dies.

Post by Isaac »

Howl3r wrote:So technically it would be always a different enemy, but they all would have last words when they die.
Basically I guess knowing how the "onDie" script works would make this a lot easier :)
Do they have Individual last words, or would they all just say the same thing?

Ondie() works two ways:
*As a connection calling a script when the hook is evaluated
*As a defined function in the monster definition itself; with the added option to cancel the monster's death

Since what you want is not canceling the death, the connector will work.

Code: Select all

 -- replace <monsterId> and replace <dialog function> with the name of your called function in quotes.
		<monster_Id>.monster:addConnector('onDie', self.go.id, <dialog function>)
	
Howl3r
Posts: 12
Joined: Fri Aug 12, 2016 11:34 pm
Location: Finland

Re: how to "action" when monster dies.

Post by Howl3r »

Isaac wrote:
Howl3r wrote:So technically it would be always a different enemy, but they all would have last words when they die.
Basically I guess knowing how the "onDie" script works would make this a lot easier :)
Do they have Individual last words, or would they all just say the same thing?

Ondie() works two ways:
*As a connection calling a script when the hook is evaluated
*As a defined function in the monster definition itself; with the added option to cancel the monster's death

Since what you want is not canceling the death, the connector will work.

Code: Select all

 -- replace <monsterId> and replace <dialog function> with the name of your called function in quotes.
		<monster_Id>.monster:addConnector('onDie', self.go.id, <dialog function>)
	
They will have individual words.

But yeah thanks! ^^
Will be asking for more help if needed :P
Howl3r
Posts: 12
Joined: Fri Aug 12, 2016 11:34 pm
Location: Finland

Re: how to "action" when monster dies.

Post by Howl3r »

Isaac wrote:
Howl3r wrote:So technically it would be always a different enemy, but they all would have last words when they die.
Basically I guess knowing how the "onDie" script works would make this a lot easier :)
Do they have Individual last words, or would they all just say the same thing?

Ondie() works two ways:
*As a connection calling a script when the hook is evaluated
*As a defined function in the monster definition itself; with the added option to cancel the monster's death

Since what you want is not canceling the death, the connector will work.

Code: Select all

 -- replace <monsterId> and replace <dialog function> with the name of your called function in quotes.
		<monster_Id>.monster:addConnector('onDie', self.go.id, <dialog function>)
	
Well speaking about being in need of help, I hope I got this right.
So monster_Id in my case is replaced by warden_1 (or whatever is my enemy id that I want to say it when it dies). And then <dialog function> is the name of the function I wish to execute when it dies (in my case I just simply named it "die"). Now I probably will be able to figure out the other stuff, but mine says when I write it (in many different ways like <function die> <"function die"> <"die"> <die> and pretty much in any way and order there is. But the problem is that it says "unexpected symbol near '<' X". Now can you tell me (or do you know) that what is the problem. This is the code edits I've made so far. (sorry if this is a stupid question) :P

Code: Select all

<warden_1>.monster:addConnector('onDie', self.go.id, <"function die">)
Also I have tried it with, and without an end after the code so I can figure these kind of stuff out with trial and error ^^
But yeah thanks for your help though! You've been the most helpful ^^
User avatar
Isaac
Posts: 3185
Joined: Fri Mar 02, 2012 10:02 pm

Re: how to "action" when monster dies.

Post by Isaac »

Isaac wrote:

Code: Select all

 -- replace <monsterId> and replace <dialog function> with the name of your called function in quotes.
		<monster_Id>.monster:addConnector('onDie', self.go.id, <dialog function>)
	
Howl3r wrote:

Code: Select all

<warden_1>.monster:addConnector('onDie', self.go.id, <"function die">)
Based on your example, this is how it should be:

Code: Select all

warden_1.monster:addConnector('onDie', self.go.id, "function die")
**BUT... this is only correct for LoG2; (my mistake in not spotting the thread section/title... I'm assuming you are using LoG1)
... and it doesn't work like that in LoG1. :(
[AFAIK] LoG1 monsters cannot have connectors, it has to be done with hooks in the definition.

So...

What you'll need to do is open the monsters.lua file in your project's scripts folder.
SpoilerShow
On Windows [Vista/7/+], this is typically found in your documents folder here:
*Try pasting the following into the file name field in your text editor (like Windows Notepad) address bar:

Code: Select all

"%systemdrive%\%userprofile%\documents\Almost Human\Legend of Grimrock\Dungeons"

, and then choose the folder with the same name as your project, then the mod_assets folder, then scripts; and open the Monsters.lua file.

Alternatively: In a text editor, choose to open a file, and navigate to your documents folder, then further into the 'Almost Human' folder; then into the 'Legend of Grimrock' folder, then dungeons; then the name of your map ~folder, then mod_assets, then ~finally the script's folder, where you select monsters.lua
Once you have the file open, paste this script into it, and save it.
SpoilerShow

Code: Select all

cloneObject{
	name = "talkative_warden",
	baseObject = "warden",
	onDie = function(self)  if lastWord then lastWord:speak()
						    end

						    local spawnPoints = {"sWarden_1", "sWarden_2"}

						    for c = 1, #spawnPoints do					    
					   			local delay = spawn("timer", self.level, self.x, self.y, 0)
					   			delay:setTimerInterval(math.random(2)+1)
					   			delay:addConnector("activate", spawnPoints[c], "nSpawn")
					   			delay:addConnector("activate", delay.id, "deactivate")
					   			delay:activate()
				   			end	
			end			   
}
Then place two script_entities where you want the two other wardens to appear. name them sWarden_1 and sWarden_2; face them appropriately.
In each script paste the following:
SpoilerShow

Code: Select all

--Place a copy of this script_entity where each Warden should spawn; and with correct facing.
default = "talkative_warden"

function nSpawn(caller, monsterName)
	local monsterName = monsterName or default
	if lastWord.next < #lastWord.statements then
			spawn(monsterName, self.level, self.x, self.y, self.facing)
			spawn("fx", self.level, self.x, self.y, self.facing):setParticleSystem("crystal")
			playSoundAt("teleport", self.level, self.x, self.y)	
	end
	
end
Place the new asset 'talkative_warden' as your initial warden/boss enemy, and when it dies the other two will spawn. Each has a parting remark that you can customize in the next script.
SpoilerShow

Code: Select all

next = 1
statements = {
			"You've got a lot to learn before you beat me, try again kiddo!",
			"The Force is strong with this one.",	
			"Never tell me the odds!",
			}
				
function speak(self)
	if next <= #statements then					
		hudPrint(statements[next])
		next = next + 1
	end					
end
Paste the above into a script_entity named lastWord
_________________________
The above script set is simplified version that only spawns two, and only supports three hudPrinted statements; but the one below, supports as many as one wants, and is designed to spawn a single warden randomly from among a set of spawn locations.
SpoilerShow

Code: Select all

cloneObject{
	name = "talkitive_warden",
	baseObject = "warden",
	onDie = function(self) if lastWord then lastWord:speak()
						   end
						   local spawnPoints = {""}
						   local count = 0
						   for each in allEntities(self.level) do
						   		if each.nSpawn then
						   			count = count +1
						   			spawnPoints[count] = each.id
						   		end	
						   end
					    
				   			local delay = spawn("timer", self.level, self.x, self.y, 0)
				   			delay:setTimerInterval(math.random(2)+1)
				   			delay:addConnector("activate", spawnPoints[math.random(#spawnPoints)], "nSpawn")
				   			delay:addConnector("activate", delay.id, "deactivate")
				   			delay:activate()
			end			   
}

Code: Select all

--Place a copy of this script_entity everywhere a Warden should spawn; and with correct facing.
default = "talkitive_warden"

function nSpawn(caller, monsterName)
	local monsterName = monsterName or default
	if lastWord.next <= #lastWord.statements then
		local cancel = false
		for each in entitiesAt(self.level, self.x, self.y) do
			if each.class == "monster" then 
				cancel = true
			end
		end
		if not cancel then
			spawn(monsterName, self.level, self.x, self.y, self.facing)
			spawn("fx", self.level, self.x, self.y, self.facing):setParticleSystem("crystal")
			playSoundAt("teleport", self.level, self.x, self.y)
		end
		
	end
	
end

Code: Select all

next = 1
statements = {
			"You've got a lot to learn before you beat me, try again kiddo!",
			"The Force is strong with this one.",	
			"Never tell me the odds!",
			"We were not the droids you were looking for!",
			"We seem to be made to suffer. Its our lot in life.",
			}
				
function speak(self)
	if next <= #statements then					
		hudPrint(statements[next])
		next = next + 1
	end					
end

Howl3r
Posts: 12
Joined: Fri Aug 12, 2016 11:34 pm
Location: Finland

Re: how to "action" when monster dies.

Post by Howl3r »

Isaac wrote:
Isaac wrote:

Code: Select all

 -- replace <monsterId> and replace <dialog function> with the name of your called function in quotes.
		<monster_Id>.monster:addConnector('onDie', self.go.id, <dialog function>)
	
Howl3r wrote:

Code: Select all

<warden_1>.monster:addConnector('onDie', self.go.id, <"function die">)
Based on your example, this is how it should be:

Code: Select all

warden_1.monster:addConnector('onDie', self.go.id, "function die")
**BUT... this is only correct for LoG2; (my mistake in not spotting the thread section/title... I'm assuming you are using LoG1)
... and it doesn't work like that in LoG1. :(
[AFAIK] LoG1 monsters cannot have connectors, it has to be done with hooks in the definition.

So...

What you'll need to do is open the monsters.lua file in your project's scripts folder.
SpoilerShow
On Windows [Vista/7/+], this is typically found in your documents folder here:
*Try pasting the following into the file name field in your text editor (like Windows Notepad) address bar:

Code: Select all

"%systemdrive%\%userprofile%\documents\Almost Human\Legend of Grimrock\Dungeons"

, and then choose the folder with the same name as your project, then the mod_assets folder, then scripts; and open the Monsters.lua file.

Alternatively: In a text editor, choose to open a file, and navigate to your documents folder, then further into the 'Almost Human' folder; then into the 'Legend of Grimrock' folder, then dungeons; then the name of your map ~folder, then mod_assets, then ~finally the script's folder, where you select monsters.lua
Once you have the file open, paste this script into it, and save it.
SpoilerShow

Code: Select all

cloneObject{
	name = "talkative_warden",
	baseObject = "warden",
	onDie = function(self)  if lastWord then lastWord:speak()
						    end

						    local spawnPoints = {"sWarden_1", "sWarden_2"}

						    for c = 1, #spawnPoints do					    
					   			local delay = spawn("timer", self.level, self.x, self.y, 0)
					   			delay:setTimerInterval(math.random(2)+1)
					   			delay:addConnector("activate", spawnPoints[c], "nSpawn")
					   			delay:addConnector("activate", delay.id, "deactivate")
					   			delay:activate()
				   			end	
			end			   
}
Then place two script_entities where you want the two other wardens to appear. name them sWarden_1 and sWarden_2; face them appropriately.
In each script paste the following:
SpoilerShow

Code: Select all

--Place a copy of this script_entity where each Warden should spawn; and with correct facing.
default = "talkative_warden"

function nSpawn(caller, monsterName)
	local monsterName = monsterName or default
	if lastWord.next < #lastWord.statements then
			spawn(monsterName, self.level, self.x, self.y, self.facing)
			spawn("fx", self.level, self.x, self.y, self.facing):setParticleSystem("crystal")
			playSoundAt("teleport", self.level, self.x, self.y)	
	end
	
end
Place the new asset 'talkative_warden' as your initial warden/boss enemy, and when it dies the other two will spawn. Each has a parting remark that you can customize in the next script.
SpoilerShow

Code: Select all

next = 1
statements = {
			"You've got a lot to learn before you beat me, try again kiddo!",
			"The Force is strong with this one.",	
			"Never tell me the odds!",
			}
				
function speak(self)
	if next <= #statements then					
		hudPrint(statements[next])
		next = next + 1
	end					
end
Paste the above into a script_entity named lastWord
_________________________
The above script set is simplified version that only spawns two, and only supports three hudPrinted statements; but the one below, supports as many as one wants, and is designed to spawn a single warden randomly from among a set of spawn locations.
SpoilerShow

Code: Select all

cloneObject{
	name = "talkitive_warden",
	baseObject = "warden",
	onDie = function(self) if lastWord then lastWord:speak()
						   end
						   local spawnPoints = {""}
						   local count = 0
						   for each in allEntities(self.level) do
						   		if each.nSpawn then
						   			count = count +1
						   			spawnPoints[count] = each.id
						   		end	
						   end
					    
				   			local delay = spawn("timer", self.level, self.x, self.y, 0)
				   			delay:setTimerInterval(math.random(2)+1)
				   			delay:addConnector("activate", spawnPoints[math.random(#spawnPoints)], "nSpawn")
				   			delay:addConnector("activate", delay.id, "deactivate")
				   			delay:activate()
			end			   
}

Code: Select all

--Place a copy of this script_entity everywhere a Warden should spawn; and with correct facing.
default = "talkitive_warden"

function nSpawn(caller, monsterName)
	local monsterName = monsterName or default
	if lastWord.next <= #lastWord.statements then
		local cancel = false
		for each in entitiesAt(self.level, self.x, self.y) do
			if each.class == "monster" then 
				cancel = true
			end
		end
		if not cancel then
			spawn(monsterName, self.level, self.x, self.y, self.facing)
			spawn("fx", self.level, self.x, self.y, self.facing):setParticleSystem("crystal")
			playSoundAt("teleport", self.level, self.x, self.y)
		end
		
	end
	
end

Code: Select all

next = 1
statements = {
			"You've got a lot to learn before you beat me, try again kiddo!",
			"The Force is strong with this one.",	
			"Never tell me the odds!",
			"We were not the droids you were looking for!",
			"We seem to be made to suffer. Its our lot in life.",
			}
				
function speak(self)
	if next <= #statements then					
		hudPrint(statements[next])
		next = next + 1
	end					
end

EDIT: Well turns out I am an idiot. For some reason I spawned a monster as the first one instead of a script_entity.
I got it to work, so now I just need to figure out if it is possible to do the thing I said earlier in the other post (which is fiddling with the timers so that you would need to kill the warden within a given time).

But yeah thank you so much! This helped me to do at least the most important part in the ending parts of my map ^^
Post Reply