Can't quite get a lua module to work

I feel like I’ve got the syntax right, but the value returned is nil.

the module

local B = {}

function B.dmg(self, v, message_id, message, sender, damage)
	damage = 1
	if message_id == hash("dmg") then
			damage = 2
		local del = nil
		del = timer.delay(10, false, function(self)
				damage = 1
			end)
			del = nil
		end
		
	end


	

	function B.get(damage)
		local value = damage
		return value
	end
	return B

the script it’s targeting(ignore the bad spelling)


local B = require "main.enimeises.dmg"
self.dmg = B.get(damage)

Hello there!
Please check the docs. It has a good example implementing an animation system module.

(I think you need to remove that ‘.dmg’ from require. Edit: or .dmg is your lua file?)

There’s a few issues here and I don’t think it’s a problem with your module syntax.

The main problem is the damage variable. It doesn’t appear to be declared anywhere other than inside B.dmg(), where it is declared as a global variable. I would either declare it as B.damage (if you want it to be directly accessible from outside the module) or as a local variable inside B (in which case you could use a function like B.get() to return the value.

local B = {}

B.damage = 1
--or
local damage = 1

--etc

Your function B.get() doesn’t really make sense as currently written. It will basically just return whatever value you pass in. E.g. B.get(2) will return 2, no matter what else is going on inside your module. I would write it as:

function B.get()
    return damage
    --or return B.damage
end

Depending on how you scoped the damage variable.

I don’t exactly understand what you are trying to achieve in function B.dmg(), but it doesn’t make much sense to me and probably needs a redesign.

1 Like

.dmg is the lua module file. I put all of it into my project and the addressing is correct.

1 Like

Sorry for the late response, I’ve had a lot of stuff to deal with recently, but the purpose of the Module is to create and change a value for player damage that can be stored and accessed by any file that needs it, e.g an enemy. I’ve also tried the b.damage and return b.damage and it still returns nil. Not sure what else I can do, but I don’t really feel like restructuring it for the forth time.

I wouldn’t think about it as “restructuring for the fourth time”, but rather as a learning experience. It’s obvious it’s not quite clicking for you just yet so it’s an investment in future skills. Once you get it, it’ll be trivial to do in the future. I have dozens of things that used to be really difficult that I can now type out in my sleep. For loops, basic vector math, and indeed modules - all were things that used to be tricky that now form the basis of all my games.

Give up if you want, but it doesn’t seem to me like a massively complex module so it should be relatively easy to fix. First step is figuring out why your get function still isn’t working. After that we figure out the dmg function.

If you post the most recent state of the module and explain what you’ve done, I’ll take a look again.

3 Likes

can’t believe I’ve been so stupid. I mean, at least i think that this is the main error. I didn’t change the message passing from the slime script, from when I was trying to do it without modules for some reason. is message passing to a module even possible though?

if message.group == hash("player") then
		pprint("dectecting player interactions")
		msg.post("slime#slime", "dmg")
		pprint(msg)
		go.delete("item")

end 

also making this a local instead of self makes the module value the actual value instead of nil i think

local dmg = B.get(damage)

						pprint("dmg is ", dmg)
						```

No. It has to go to the on_message() function of a script which then can forward it to a function in the module.

	if message.group == hash("player") then
		pprint("dectecting player interactions")
		msg.post("enimeises#dmg.lua", "dmg")
		pprint(msg)
		go.delete("item")

end 

I’m not fully sure if I understand what you’re saying. is there a different syntax for message passing to a module or is it completely impossible and I’m just being stupid? code is from a script btw

Passing a message to a module doesn’t really exist as a concept. The module just stores information, such as variables or functions.

Take this example module:

local M = {}

function M.pos()

    print(go.get_position())

end

return M

If you call M.pos() from a script attached to a game object, what you will get is the position of that game object. The module itself does not have a position. So, in the same way, if we have a module like this:

local M = {}

function M.handle_message()

    print(msg.url())

    --do stuff to handle an incoming message

end

return M

And call the function in the on_message function of a script:

function on_message(self, message_id, message, sender)

    M.handle_message()

end

Then the output of the print() will be the url of the script that is receiving the message, not the module. Because the module doesn’t have a url.

You might be using a module because multiple scripts share similar behaviours. Or you are storing variables in the module, so handling the message using a module function might make more sense (you could modify a variable local to the module that way).

Does this make sense?

1 Like

Can you explain in words what you are trying to achieve with the two functions in your module?

its so I can store a global value for the player’s current damage, so that it can be subtracted dynamically from enemy health. the message passing is so that it can increase and then decrease after being triggered since it’s supposed to be a limited time buff. I was trying the message passing because I didn’t know any other way to get a trigger targeting the module.

Okay, here is what I would do. It’s untested so you might run into some issues. The way you structured your timer was suboptimal so I cleaned it up, and you still include a “damage” parameter in your get function which is not necessary.

local B = {}

B.damage = 1

B.buff_timer_handle = nil

function B.buff_damage()

    --reset active timers, if any

    if B.buff_timer_handle then

        timer.cancel(B.buff_timer_handle)

        B.buff_timer_handle = nil

    end

    --buff the damage

    B.damage = 2

    --create a timer to reset the damage to normal

    B.buff_timer_handle = timer.delay(10, false, function()

        B.damage = 1

        B.buff_timer_handle = nil

    end)

end

function B.get_damage()

    return B.damage

end

return B

Note that I’ve removed the message_id check because I think that is best done in the on_message function of your receiving script, like so:

function on_message(self, message_id, message, sender)

    if message_id == hash("dmg") then

        B.buff_damage()

    end

end

This has the added benefit of making your buff_damage function more flexible - you can call it in other contexts, not just in a message.

4 Likes

just so you know, its not completely working but I probably won’t be doing more stuff on it for a little while. (one day at most) it’s nearly fixed and I need a little mental break. the error though is that when one of the functions is called health and damage end up with a nil value.

Fair enough. I’m fairly confident what I wrote works and it certainly shouldn’t let the damage variable become nil, so the issue is probably in some other part of your scripts that you haven’t posted.

1 Like

WOW I did not mean to take that long of a break, downward spirals are really something huh. Wouldn’t be surprised actually if you’ve given up on this. Oh well, after messing around with my code I managed to get your system working, I can’t even remember what I was doing wrong. bruh. Anyway, the only thing I need to get the full system working is a way to get the message passing used to subtract the health to only trigger once.
There’s probably a way you’re supposed to do this without message passing, with a time to live thing, but I couldn’t seem to get it working.

if message.group == hash("bullet") then
					if not message_id == hash("bk") then
						
						msg.post("player#bullet", "death")
					end
						local damaged = true
						--tiemr = 1
						pprint("bullet collision")
						if damaged == true then
							
							pprint("health decreased")
							self.health = self.health - dmg1
							damaged = false
						end
						pprint("dmg is ", dmg1)
						pprint("health is ",self.health)
					end
				end

The bullet hash gets called repeatedly due to the bullet being in constant contact to the slime, even repeats when telling the bullet to delete after touching the slime.

First things first - are you sure the bullet is actually being deleted? I would think that with message timing you might get a second damage message before the bullet is deleted, but if you are getting more than two hits then something is wrong.

1 Like

this is what I have set up to handle bullet deletion.

slime script

if message.group == hash("bullet") then
					if not message_id == hash("bk") then
						
						msg.post("player#bullet", "death") <--
					end

bullet script

if message_id == hash("death") then
		msg.post("slime#slime", "bk")
	go.delete()    <--

	end

I guess the message passing to handle the bullet death itself could be faulty, but I feel like it might be delayed or something so it doesn’t realise it’s deleted before triggering the collision again.

This looks strange. Why are you checking message_id inside the outer if then? At that point you probably already know the message type since you use message.group.

I would also like to point out that the use of not like that won’t do what you expect. Note that not will negate the value to the right of it and it has precedence over the equality check. What you want is either of these:

if not (foo == "bar") then
    print("Foo is not equal to bar")
end

-- Check if something is not equal uses this: ~= (similar to != in other languages)
if foo ~= "bar" then
    print("Foo is not equal to bar")
end
1 Like

the second if statement is supposed to be a check to make sure that the slime object is alive, since the message will get continuously sent to an object that doesn’t exist otherwise.

function on_message(self, message_id, message, sender)

	if message_id == hash("contact_point_response") then
		go.delete()
	end
	
	if message_id == hash("death") then
		msg.post("slime#slime", "bk")   <--
	go.delete()

	end
	
end

it could cause a loop I guess, since it’s going back and forth