calling global function from object

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
.rhavin
Posts: 23
Joined: Fri Oct 13, 2017 1:10 pm
Location: Berlin
Contact:

calling global function from object

Post by .rhavin » Sun Oct 22, 2017 11:35 pm

In the following example, the global function qpttest is called after the script loaded. However, from inside the item, I get the notification "qpttest not defined", so qpttest is nil inside onEquipItem. How can i define a function inside a script like this that I can call?

Code: Select all

print("skript loaded")
function qpttest()
	print "test called"
end
qpttest()

defineObject{
	name = "breadling",
	baseObject = "bread",
	components = {
		{
			class = "Item",
			uiName = "breadling",
			gfxIndex = 1,
			onEquipItem = function(self, champion, slot)
				hudPrint(champion:getName().."uses breadling.")
				if (qpttest ~= nil) then
					qpttest()
				else
					print("qpttest not defined")
				end
			end,
		},
	},
}

minmay
Posts: 2404
Joined: Mon Sep 23, 2013 2:24 am

Re: calling global function from object

Post by minmay » Sun Oct 22, 2017 11:51 pm

Hooks get a different environment than init scripts. It's similar to the environment that ScriptComponents get.

There are three options:
1. Make it an upvalue by defining it as a local function. However, if you do this, you have to make sure to only use it in functions that don't get serialized.
2. Move it to a ScriptComponent in the dungeon. This can be annoying to maintain.
3. Put it in a table that is available in both environments, such as Config:

Code: Select all

print("skript loaded")
Config.qpttest = function()
   print "test called"
end
Config.qpttest()

defineObject{
   name = "breadling",
   baseObject = "bread",
   components = {
      {
         class = "Item",
         uiName = "breadling",
         gfxIndex = 1,
         onEquipItem = function(self, champion, slot)
            hudPrint(champion:getName().."uses breadling.")
            if (Config.qpttest ~= nil) then
               Config.qpttest()
            else
               print("qpttest not defined")
            end
         end,
      },
   },
}
This last approach is the most hacky of the three, but it's also the closest one to your desired functionality (sharing an environment between init scripts and hooks). Note that any changes made to Config (and the other "global" tables) will not be serialized, and will persist until the game is closed. This is fine for a case like this one, but it means you shouldn't try to store mutable data in it for instance.

User avatar
Isaac
Posts: 2605
Joined: Fri Mar 02, 2012 10:02 pm

Re: calling global function from object

Post by Isaac » Mon Oct 23, 2017 12:52 am

Anytime I've used Config for that, I've put it into categorized keys.

* Config.Isaac.ut.nudgeObject()
* Config.Isaac.ut.delayedCall2()
* Config.Isaac.colorTable['puce']
* Config.Isaac.gui.currentChampion
etc...

minmay
Posts: 2404
Joined: Mon Sep 23, 2013 2:24 am

Re: calling global function from object

Post by minmay » Mon Oct 23, 2017 3:18 am

Yep, that's a good way to make it less bad from a code quality perspective.

User avatar
.rhavin
Posts: 23
Joined: Fri Oct 13, 2017 1:10 pm
Location: Berlin
Contact:

Re: calling global function from object

Post by .rhavin » Mon Oct 23, 2017 11:02 am

Ok, comming closer ;)

Now, how do i add a hook for onDrawAttackPanel? The following code gets executed, but the actual hook never gets called:

Code: Select all

print("skript loaded")
if (Config.QDMF == nil) then
	Config.QDMF = {}
end
Config.QDMF.qpttest = function(self, champion, context, x, y)
	context.drawText("panel", 10, 10)
end
Config.QDMF.addhook = function(p,s)
	print "hook added"
	p.party:addConnector('onDrawAttackPanel', s.go.id, "Config.QDMF.qpttest")
end

defineObject{
	name = "a-test",
	baseObject = "dagger",
	components = {
		{
			class = "Item",
			uiName = "A-Test",
			gfxIndex = 10,
			gfxIndexPowerAttack = 415,
			onEquipItem = function(self, champion, slot)
				hudPrint(champion:getName().." uses A-Test.")
				Config.QDMF.addhook(party,self)
			end,
		},
	},
	tags = { "weapon" },
}

User avatar
Isaac
Posts: 2605
Joined: Fri Mar 02, 2012 10:02 pm

Re: calling global function from object

Post by Isaac » Mon Oct 23, 2017 2:46 pm

Certain Party hooks must be defined in the object, or they don't get called—despite having connectors to them.

Code: Select all

--object.lua
defineObject{
	name = "party",
	baseObject = "party", --copy/inherit object
	components = {
		{	--component changes must redefine the entire component being changed, not just the changes to it
			class = "Party",

			-- minimal dummy function to enable hook; this is all you need
			onDrawAttackPanel = function() end,   

			-- optional/ instead: defined to pass along parameters 
			onDrawAttackPanel = function(...) myScript.script.myFunction(...) end,  
		},
	}
}

Post Reply