Ask a simple question, get a simple answer

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!
Azel
Posts: 808
Joined: Thu Nov 06, 2014 10:40 pm

Re: Ask a simple question, get a simple answer

Post by Azel »

minmay wrote:most of those lines are whitespace, brackets, etc. which don't exactly take a lot of time to read

I already accounted for whitespace in the initial approximation and brackets account for less than half of the total lines. Brackets and commas define a component and differentiate between all the properties, methods, functions, and classes; so they probably shouldn't be dismissed so easily.

Taking out brackets leaves you with over 8,600 lines of code, plus the 2,000 from the scripting reference, plus all the information in the LUA references, plus the thousands of lines of code that make up the Nexus file ("assets/dungeons/grimrock2") which you also expect everyone to cross-reference.

I'm just trying to put things in proper perspective. You expect that everyone should study well over 10,000 pieces of information before doing something that lets players hit rats and crabs with a baton :shock:

I still maintain that the Grimrock Editor software holds the responsibility of making the Modding experience more manageable; because requiring a 10,000 line review as a prerequisite is highly unreasonable. You spend almost every day on this forum chastising Modders for having "terrible" ideas, when you should really be directing your issues to Almost Human in an effort to update the Editor in a way that makes a 10,000+ line review unnecessary.
minmay wrote:this won't work; it doesn't account for items that the player may have placed on that square prior to the pit being spawned.
Which is why I suggested talking through the actual steps. My Teleport solution works once everything else is set up to function accordingly. Placing obstacles in the path of the "eventual pit" would be an easy solution. The player can "see" the area but not get to it until an event takes place. Once the event takes place, the obstacles(s) are removed and the pit appears.

The ideas are not "terrible" - they are "fun." You just can't seem to get beyond the idea that if it isn't "how minmay would do it then it is something awful that should never be done". It's kinda creepy, really :?
minmay
Posts: 2768
Joined: Mon Sep 23, 2013 2:24 am

Re: Ask a simple question, get a simple answer

Post by minmay »

Azel wrote:Which is why I suggested talking through the actual steps. My Teleport solution works once everything else is set up to function accordingly. Placing obstacles in the path of the "eventual pit" would be an easy solution. The player can "see" the area but not get to it until an event takes place. Once the event takes place, the obstacles(s) are removed and the pit appears.
actually i said it doesn't work because it literally doesn't work in this situation. no matter what kind of contrived stuff you come up with, teleporting that gold key is going to destroy some position/rotation information and cause a jump, which is a blatant bug. you can work around the item issues with that 8 line hack that anyone could write, i don't know why you would want to try to work around it with some contrived use of teleporters instead, even if it weren't literally impossible to do so, and it is literally impossible, so...
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
The cube
Posts: 94
Joined: Tue Apr 23, 2013 6:09 pm
Location: Barren Desert

Re: Ask a simple question, get a simple answer

Post by The cube »

From the description you gave, it's hard to tell exactly what should be happening, and when. If you can provide the exact details to how the area looks before, what the player does to trigger an event, and how it looks after, then perhaps we can recreate a much more effective way to achieve the same end result. You can PM me the description, and I can make a 1 room dungeon that (hopefully) achieves the same outcome.
Okay.

Before this happens, the player is in a cave below the place where the pit will be spawned. He places a bomb that blows up a pillar.
This creates a chasm to the level right above the cave, dropping all items from that tile to the cave.

That's how it should work. Everything but the chasm aboveground works fine.

Here are images before and after the bomb blows up:

UNDERGROUND:
BEFORE:
SpoilerShow
Image
AFTER:
SpoilerShow
Image
ABOVE GROUND:
BEFORE:
SpoilerShow
Image
AFTER:
SpoilerShow
Image
The player is unable to interact with the tiles where the chasms can spawn in any way, but he can see them.
The tile must look like a normal tile before the explosion, and have a chasm in it after the explosion.

The player is in the level below so he can not see the chasm appear.
Azel
Posts: 808
Joined: Thu Nov 06, 2014 10:40 pm

Re: Ask a simple question, get a simple answer

Post by Azel »

Oh dude, that's pretty damn creative! I love the idea of a bomb below causing a chasm above. :mrgreen:

I would love to try to make something like this happen, so let me give it a shot; I will upload a demo dungeon that does this by tonight. Fun! :mrgreen:
minmay
Posts: 2768
Joined: Mon Sep 23, 2013 2:24 am

Re: Ask a simple question, get a simple answer

Post by minmay »

The cube wrote:
From the description you gave, it's hard to tell exactly what should be happening, and when. If you can provide the exact details to how the area looks before, what the player does to trigger an event, and how it looks after, then perhaps we can recreate a much more effective way to achieve the same end result. You can PM me the description, and I can make a 1 room dungeon that (hopefully) achieves the same outcome.
Okay.

Before this happens, the player is in a cave below the place where the pit will be spawned. He places a bomb that blows up a pillar.
This creates a chasm to the level right above the cave, dropping all items from that tile to the cave.

That's how it should work. Everything but the chasm aboveground works fine.

Here are images before and after the bomb blows up:

UNDERGROUND:
BEFORE:
SpoilerShow
Image
AFTER:
SpoilerShow
Image
ABOVE GROUND:
BEFORE:
SpoilerShow
Image
AFTER:
SpoilerShow
Image
The player is unable to interact with the tiles where the chasms can spawn in any way, but he can see them.
The tile must look like a normal tile before the explosion, and have a chasm in it after the explosion.

The player is in the level below so he can not see the chasm appear.
Ok, this is easy then. Place this object on that square:

Code: Select all

defineObject{
	name = "forest_chasm_bomb",
	components = {
		{
			class = "Pit",
		},
		{
			class = "Model",
			model = "assets/models/env/forest_ground_01.fbx",
			staticShadow = true,
		},
		{
			class = "Controller",
			onActivate = function(self)
				if self.go.platform:isEnabled() then
				-- spawn edges
				local adj = {}
				for i=0,3 do
					local dx,dy = getForward(i)
					local adjacent = false
					for e in self.go.map:entitiesAt(self.go.x + dx, self.go.y + dy) do
						if e.name == "forest_chasm" or (e.name == "forest_chasm_bomb" and not e.platform:isEnabled()) then
							adjacent = true
						elseif e.facing == (i+2)%4 and (e.name == "forest_chasm_edge" or e.name == "forest_chasm_corner")
							or (e.facing == (i+3)%4) and e.name == "forest_chasm_corner" then
							-- destroy adjoining edge
							e:destroy()
						end
					end
					adj[i] = adjacent
					if not adjacent then
						spawn("forest_chasm_edge", self.go.level, self.go.x, self.go.y, i, 0)
					end
				end
				
				-- spawn corners
				for i=0,3 do
					if not adj[i] and not adj[(i+3)%4] then
						spawn("forest_chasm_corner", self.go.level, self.go.x, self.go.y, i, 0)
					end
				end
				-- remove ground model
				self.go.model:disable()

				-- open pit
				self.go.platform:disable()
				end
			end,
		},
		{
			class = "Platform",
		},
	},
	replacesFloor = true,
	placement = "floor",
	killHeightmap = true,
	editorIcon = 40,
}
When the bomb goes off, activate the controller. No item problems and it will update any adjacent chasm borders if necessary. No reason to use teleporters or dynamically spawn a PitComponent.
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.
Azel
Posts: 808
Joined: Thu Nov 06, 2014 10:40 pm

Re: Ask a simple question, get a simple answer

Post by Azel »

The cube wrote:The player is unable to interact with the tiles where the chasms can spawn in any way, but he can see them.
The tile must look like a normal tile before the explosion, and have a chasm in it after the explosion.

The player is in the level below so he can not see the chasm appear.
Okay so I was able to get everything to work in a Dungeon by spawning a Pit and using some tricks. I know it's not an outdoor Chasm but I was limited on time today and I wanted to get you something at least semi-useful.

You can download both the playable dungeon and the editor project files here: http://mystrock.com/files/chasms.zip

Tomorrow I will add the outdoor region and do the same thing with a forest_chasm. I tested this out (save/reload, etc) and everything works fine. I was able to simulate the item problem you mentioned (it didn't fall when the pit spawned), but a simple invisible teleporter solved it. You will notice a floor trigger where the pit appears. The trigger is a placeholder, but if for some reason a Chasm doesn't work the same as the Pit, then I have a function near the floor trigger that can be called to simulate the party falling down the chasm.

This was pretty fun; I hope to have the outdoor version ready by tomorrow night :mrgreen:
User avatar
Isaac
Posts: 3172
Joined: Fri Mar 02, 2012 10:02 pm

Re: Ask a simple question, get a simple answer

Post by Isaac »

Is it possible to spawn a script_entity, define its source, and then call functions in it? I must be missing something, because every time I try to do this, the script exists, its script component exists, but there seem to be no functions in the script.
minmay
Posts: 2768
Joined: Mon Sep 23, 2013 2:24 am

Re: Ask a simple question, get a simple answer

Post by minmay »

Isaac wrote:Is it possible to spawn a script_entity, define its source, and then call functions in it? I must be missing something, because every time I try to do this, the script exists, its script component exists, but there seem to be no functions in the script.
Yes, but it's tricky: you have to call setSource or loadFile BEFORE the ScriptComponent initializes, or the code won't be run. The ScriptComponent's onInit hook is already too late, so it's easiest to do this with an onInit hook from another component that initializes first (components SEEM to just initialize in the same order as they are in the "components" table in the definition), Here is an example.

Code: Select all

defineObject{
	name = "goofy_script_loader",
	placement = "floor",
	components = {
		{
			class = "Null",
			onInit = function(self)
				-- works with loadFile too
				self.go.script:setSource([[print("yo")]])
			end,
		},
		{
			class = "Script",
		},
	},
}
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
Isaac
Posts: 3172
Joined: Fri Mar 02, 2012 10:02 pm

Re: Ask a simple question, get a simple answer

Post by Isaac »

minmay wrote:Yes, but it's tricky:...
That did it! 8-) 8-)
Thank you minmay.

Tricky is an understatement ~that was bizarre.
_______________________

Alright, I have one of my own these spawned chasm assets. It's not perfect (and unfinished). It does not support closed trap doors underneath it; but most items will fall when the chasm is opened, and breakable items will crack when they hit the floor below; including falling through additional pits.

*Call it beta, but it seems to work well enough for my purposes. There is a known bug in that it really doesn't like the beach titleset; but I haven't determined just why that is yet. When I do, I'll fix it.

I had first thought to chain the pits, so that opening one opened them all... but it seems faster to just ensure that all chasm pits are opened at the same time. An easy way for that is to call them all in a loop; or connect them all to an off screen button or lever, and trigger it from a script, or leave the switch accessible to the player (as in the demo).

Code: Select all

defineObject{
	name = "forest_spawn_chasm",
	baseObject = "base_pit_trapdoor",
	replacesFloor = true,
	killHeightmap = true,
	placement = "floor",
	editorIcon = 40,
	automapIcon = 108,
	components = {
		{
		     class = "Model",
		     name = "trapDoorModel",
		     model = "assets/models/env/forest_ground_02.fbx",
		},	  
		{
			class = "Pit",
			onInit = function(self)
										
						local align = {self.go:getPosition()}
						align[3] = 1
						align[4], align[5]  = self.go.elevation, align[4]
						self.go:setPosition(unpack(align))
						-- spawn edges [asset pack]
							local adj = {}
							for i=0,3 do
								local dx,dy = getForward(i)
								local adjacent = false
								for e in self.go.map:entitiesAt(self.go.x + dx, self.go.y + dy) do
									if string.find(e.name, "_floor") and e.model then
											self.go.trapDoorModel:setMaterial(e.name)
									end	
									if e.name == self.go.name then
										adjacent = true
										--break
									end
								end
								adj[i] = adjacent
								if not adjacent then
									spawn("forest_chasm_edge", self.go.level, self.go.x, self.go.y, i, 0).model:disable()
								end
							end
							-- spawn corners  [asset pack]
							for i=0,3 do
								if not adj[i] and not adj[(i+3)%4] then
									spawn("forest_chasm_corner", self.go.level, self.go.x, self.go.y, i, 0).model:disable()
								end
							end
					end
		},
		
		{
		     class = "Controller",
		     onInitialOpen = function(self)
						self.go.controller:open()
			end,
		     onOpen = function(self)
				if not self.go.pit:isOpen() then
					self.go.pit:open()
					self.go.trapDoorModel:disable()
					spawn('forest_pit_fog',self.go.level ,self.go.x, self.go.y, self.go.facing, self.go.elevation)
					for e in self.go.map:entitiesAt(self.go.x, self.go.y) do
						if string.find(e.name, "chasm" ) and e.model and not e.model:isEnabled() then
							e.model:enable()
						end
						if string.find(e.name, "block" ) and e.name ~= "blocker" or e.name == "chest" then
							e:createComponent("Gravity")
							local loc = {e:getPosition()}
							loc[5] = e.level +1
							local recurse = false
							local double_tap = false
							repeat  
								for each in Dungeon.getMap(loc[5]):entitiesAt(loc[1], loc[2]) do
									for _,comp in each:componentIterator() do
										if comp.go.pit then
											if loc[5] < Dungeon.getMaxLevels() then
												loc[5] = loc[5] +1
												recurse = true
												break
											end	
										 else recurse = false	
										end								
									end
								end
							until(recurse == false)
							if e.name == "chest" then 
								spawn('base_obstacle',loc[5], loc[1], loc[2], loc[3], Dungeon.getMap(loc[5]):getElevation(loc[1], loc[2]))
							
							elseif e.name == "pushable_block"  then
														
							else
								local trigger = spawn("floor_trigger",loc[5], loc[1], loc[2], loc[3], Dungeon.getMap(loc[5]):getElevation(loc[1], loc[2]))
								trigger.floortrigger:addConnector("onActivate", "chasm_fall_damager" , 'breakStuff')
							end
						end
					end
				end
			end,
		onClose = function(self)
				if not self.go.pit:isClosed() then
					self.go.pit:close() 
					self.go.trapDoorModel:enable()
					for e in self.go.map:entitiesAt(self.go.x, self.go.y) do
						if string.find(e.name, "chasm" ) and e.model and e.model:isEnabled() then
							e.model:disable() 
						elseif e.name == 'forest_pit_fog' then
							e:destroy()
						end
					end
					
				end
			end,
		onToggle = function(self) 
					if self.go.pit:isOpen() then
						self.go.controller:close()
					 else self.go.controller:open()
					end
			end,
		onInit = function(self) 
						if not findEntity("chasm_fall_damager") then
							spawn("chasm_fall_damager", self.go.level, 0, 0, 0 , 0, "chasm_fall_damager")
							chasm_fall_damager.script:setSource("function breakStuff(target) damageTile(target.go.level, target.go.x,target.go.y,target.go.facing,target.go.elevation, 64, 'physical', 90) target.go.floortrigger:setDisableSelf(true) end")

						end	
					end,	
		}
	},
}


defineObject{
	name= "chasm_fall_damager",
	baseObject = "script_entity",
	components = {
		{
			class = "Script",
			name = "chasm_fall_damager",
		}
	},
}

User avatar
The cube
Posts: 94
Joined: Tue Apr 23, 2013 6:09 pm
Location: Barren Desert

Re: Ask a simple question, get a simple answer

Post by The cube »

How do i make a item that triggers a script on power attack?
Post Reply