Modding infodump

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!
minmay
Posts: 2789
Joined: Mon Sep 23, 2013 2:24 am

Re: Modding infodump

Post by minmay »

Sorry, I haven't been looking into it.
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
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Modding infodump

Post by akroma222 »

Not a problem!
A further question... Anyone with any hints appreciated :)

If I needed to find which of the 2 Champs was to be hit by a (spell-based) custom Projectile (which hit the Party on a given Side)....
...what would/should I be checking for ?? (Evasion plays no part in projectiles hitting Champs - as stated above)
... DEX ? traits? race? other conditions?? surely diff in Evasion would count?
minmay
Posts: 2789
Joined: Mon Sep 23, 2013 2:24 am

Re: Modding infodump

Post by minmay »

When the party is hit by a projectile, both champions on the side of the projectile have an equal chance to be hit. It's the same for getting attacked by monsters that aren't part of groups.
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
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: Modding infodump

Post by akroma222 »

Ahh well that's not too complex at all!
Thanks again 8-)
User avatar
Lark
Posts: 178
Joined: Wed Sep 19, 2012 4:23 pm
Location: Springfield, MO USA

Re: Modding infodump

Post by Lark »

minmay wrote: Detecting reloads
To detect when the dungeon is loaded, place a single instance of this object anywhere in your dungeon:

Code: Select all

defineObject{
	name = "load_detector",
	placement = "floor",
	components = {
		{
			class = "Null",
			onInit = function(self)
				-- Whenever this function is called, the dungeon has
				-- been loaded; either a new game was started, or a
				-- saved game was loaded.
			end,
		},
	},
	editorIcon = 148,
	minimalSaveState = true,
}
]
Minmay: Thank you for the information. I understand the above and I'm wanting to build on it. Generically, what other conditions can be defined and how are they triggered? (Other conditions I've found are: onInitialActivate - appears to be run just once and NOT when the game is reloaded, onInitialDeactivate - I assume it runs only the first time it's deactivated, OnActivate, onDeactivate, and onToggle where I assume the last three are hit by scripts only.)

Specifically, I'm trying to define a floor tile that spawns a floor_trigger that calls a script contained in the object itself when the party steps on the tile. Spawning the trigger is no big deal, but can you connect the trigger to a script internal to the object? I can make it work with scripts external to the object, but it would be cleaner for the dungeon creator this way, I think. I also tried adding a script component but failed to get it to work.

I'd like something like myObj.floortrigger:addConnector("onActivate", self.go.id, "onDeactivate") but none of the combinations I've tried work.

Here's a test object:

Code: Select all

defineObject{
	name = "test_platform",
	baseObject = "base_floor_decoration",
	components = {
		{
			class = "Model",
      			model = "mod_assets/models/test_platform_01.fbx",
      			offset = vec(0,-3,-1.5),
			staticShadow = true,
		},
		{
			class = "Platform",
		},
		{
			class = "Controller",
			onInitialActivate = function(self)
				self:activate()
				local t = spawn("floor_trigger", self.go.level, self.go.x , self.go.y, self.go.facing, self.go.elevation, self.go.id .. "_trigger")
				t.floortrigger:setTriggeredByParty(true)
				t.floortrigger:setTriggeredByMonster(false)
				t.floortrigger:setTriggeredByItem(false)
				t.floortrigger:setTriggeredByDigging(false)
				t.floortrigger:setDisableSelf(false)
				t.floortrigger:addConnector("onActivate", self.go.id, "onDeactivate")	--This line fails... is it even possible?
			end,
			onInit = function(self)
				self.go.platform:enable()
			end,
			onInitialDeactivate = function(self)
				self.go.platform:disable()
			end,
			onActivate = function(self)
				print(self.go.id .. " onActivate raised.")
			end,
			onDeactivate = function(self)
				self.go.platform:disable()
				print(self.go.id .. " onDeactivate raised.")
			end,
			onToggle = function(self)
				if self.go.platform:isEnabled() then
					self:deactivate()
				else
					self:activate()
				end
			end,
		},		

	},
	minimalSaveState = true,
}
Has anyone done this? Thank you all for your time! -Lark
User avatar
zimberzimber
Posts: 432
Joined: Fri Feb 08, 2013 8:06 pm

Re: Modding infodump

Post by zimberzimber »

You can call an internal function (from a script component) from any other function (onInit, onActivate, onAnimationEvent, etc...) by having it 'navigate' to the script component, and execute a script as you would normally trigger functions through scripts.

Here's a definition of an Omnitool I made, which is basically a timer merged with a script entity, which can also be disabled by external sources.

Code: Select all

defineObject{
	name = "omnitool",
	components = {
		{
			class = "Timer",
			timerInterval = 120,
			onActivate = function(self)
				self.go.script:omnitoolFunction(self)
			end,
		},
		{
			class = "Controller",
			onActivate = function(self)
				self.go.timer:enable()
			end,
			onDeactivate = function(self)
				self.go.timer:disable()
			end,
			onToggle = function(self)
				if self.go.timer:isEnabled() then
					self.go.timer:disable()
				else
					self.go.timer:enable()
				end
			end,
		},
		{
			class = "Script",
			source = [[
function omnitoolFunction(self)
	hudPrint("Omnitool labled '"..self.go.id.."' activated at ("..self.go.x..","..self.go.y..")")
end
]]
		},
	},
	placement = "floor",
	editorIcon = 268,
	tags = { "zim_assets" },
}
As you can see, every time the timer runs out, it'll call the omnitoolFunction(). The script can be then edited in-editor, just like a script entity.
If you don't have a large screen, you'll probably not see the input box on the object, so you'll have to shrink the in-game view box. The input box appears at the bottom, after the full component list.
My asset pack [v1.10]
Features a bit of everything! :D
minmay
Posts: 2789
Joined: Mon Sep 23, 2013 2:24 am

Re: Modding infodump

Post by minmay »

Lark wrote:Minmay: Thank you for the information. I understand the above and I'm wanting to build on it. Generically, what other conditions can be defined and how are they triggered? (Other conditions I've found are: onInitialActivate - appears to be run just once and NOT when the game is reloaded, onInitialDeactivate - I assume it runs only the first time it's deactivated, OnActivate, onDeactivate, and onToggle where I assume the last three are hit by scripts only.)
I think you're confused about the purpose of ControllerComponent. The ControllerComponent hooks have no inherent meaning. ControllerComponent exists so that you have a convenient, consistent way to handle connector messages, and has absolutely nothing to do with the passage you quoted. onActivate is only called when you call ControllerComponent:activate(), either from a script or by triggering a connector with the message "activate". onDeactivate is only called when you call ControllerComponent:deactivate(). onToggle is only called when you call ControllerComponent:toggle(), and so on.
onInitialActivate is called once, when the ControllerComponent initializes, if the initial state (as selected in the object inspector) is "activate". onInitialDeactivate is called once, when the ControllerComponent initializes, if the initial state (as selected in the object inspector) is "deactivate".

Aside from ControllerComponent:setInitialState(), none of the ControllerComponent methods do anything except call the hooks. If you call ControllerComponent:open(), and don't have an onOpen hook defined for that ControllerComponent, nothing whatsoever will happen.

The reason your object doesn't work is that you're passing the message "onDeactivate" when you wanted to pass the message "deactivate". I question the use of two objects here in the first place, however. Wouldn't this be easier?

Code: Select all

defineObject{
   name = "test_platform",
   baseObject = "base_floor_decoration",
   components = {
      {
         class = "Model",
               model = "mod_assets/models/test_platform_01.fbx",
               offset = vec(0,-3,-1.5),
         staticShadow = true,
      },
      {
         class = "Platform",
      },
      {
         class = "FloorTrigger",
         triggeredByMonster = false,
         triggeredByItem = false,
         triggeredByDigging = false,
         onActivate = function(self)
           self.go.controller:activate()
         end,
      },
      {
         class = "Controller",
         onInitialActivate = function(self)
            self:activate()
         end,
         onInitialDeactivate = function(self)
            self.go.platform:disable()
         end,
         onActivate = function(self)
            print(self.go.id .. " onActivate raised.")
         end,
         onDeactivate = function(self)
            self.go.platform:disable()
            print(self.go.id .. " onDeactivate raised.")
         end,
         onToggle = function(self)
            if self.go.platform:isEnabled() then
               self:deactivate()
            else
               self:activate()
            end
         end,
      },      
   },
}
(I assume that you putting minimalSaveState on this was an accident, since I can't imagine why you'd want to reactivate the platform and spawn an additional floor trigger every time the game is loaded...)
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
Lark
Posts: 178
Joined: Wed Sep 19, 2012 4:23 pm
Location: Springfield, MO USA

Re: Modding infodump

Post by Lark »

Zimberzimber: Thank you! I'm just now seeing how you can combine different properties in the same object - like your script internal to your omnitool object. That really helps.

Minmay: Yes of course I see what you did in your example now and yes, it's much easier and proficuous. So duuuh :?, I never thought to combine classes that way, but now that I see it, it's beyond obvious. I get it now. Thank you!

Sincerely, -Lark
User avatar
Lark
Posts: 178
Joined: Wed Sep 19, 2012 4:23 pm
Location: Springfield, MO USA

Re: Modding infodump

Post by Lark »

zimberzimber wrote:You can call an internal function (from a script component) from any other function (onInit, onActivate, onAnimationEvent, etc...) by having it 'navigate' to the script component, and execute a script as you would normally trigger functions through scripts.
Zimber: I'm making progress and I have the internal script working because of your example, but I've found that when I change the script, I must delete and add the objects again - the old objects don't get the script change even on reloading the project. Can these scripts be external?

Code: Select all

      {
	     class = "Script",
	     setSource = "External",
	     loadFile = "mod_assets/scripts/test07.lua",
      },
The Scripting Reference shows that Script Components have the setSource and loadFile properties (although only loadFile appears to be required for external scripts), but everything I've tried in an object definition fails with something similar to "warning! invalid component property script.setSource". Have I missed something obvious again or is this not possible? I can't find any examples anywhere of someone defining an object with a script component that points to an external script.

Thanks, -Lark
User avatar
zimberzimber
Posts: 432
Joined: Fri Feb 08, 2013 8:06 pm

Re: Modding infodump

Post by zimberzimber »

1) The is no 'setSource' value in script, setSource and getSource are the functions that set/get the written script
2) 'source' is the written script, what the script typing box has in it when the object is created. Similar to what you'd type in a script_entity, except it begins with it. so setSource(string) is the equivalent of writing in a script entity inside an object.
3) You don't need 'source' and 'loadFile', because (from what I know), the latter will override the other.

EDIT: By the way, you don't have to link the object to an external through its definition, you can just give it a script component with written script (or without), and then link it through the editor. But always make sure the function called in the controller component exists in the internal/external script :!:
My asset pack [v1.10]
Features a bit of everything! :D
Post Reply