weight alcove

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!
bongobeat
Posts: 1076
Joined: Thu May 16, 2013 5:58 pm
Location: France

weight alcove

Post by bongobeat »

Hello there,

I post this here, because TheLastOrder asked if it can be used in log2:
(original thread in log1 forum: viewtopic.php?f=14&t=6667)
I made a small modification, based on a script that minmay gives me.
There is still an issue, sorry but this comes at a point where I am lost :D

if you put a stack of (stackable) items it won't work.
e.g: if you put a stack of 12 shuriken (0,1kg each, for the alcw3 or alcw4)
It works only if you put the shurikens one by one.

I suppose it is because it has to count the items if there is stackable items.
I just think of that because Minmay gives me a script for a forge system, which check and count the stackable items.
SpoilerShow

Code: Select all

    weight = 0
    weight2 = 0
    weight3 = 0
    weight4 = 0
    finish = 0

    function weightcheck(surface, item)

    if finish == 0 then

    weight = 0
    weight2 = 0
    weight3 = 0
    weight4 = 0


       for _,i in alcw1.surface:contents() do
       weight = weight + i:getWeight()
       end
       for _,j in alcw2.surface:contents() do
       weight2 = weight2 + j:getWeight()
       end
       for _,k in alcw3.surface:contents() do
       weight3 = weight3 + k:getWeight()
       end
       for _,l in alcw4.surface:contents() do
       weight4 = weight4 + l:getWeight()
       end
       
       check()

    end
    end

    function check()

    if finish == 0 then

    if weight == 0.1 and
       weight2 == 0.2 and
       weight3 == 1.2 and
       weight4 == 1.2 then
       
iron_weight.door:open()
       playSound("secret")
       finish = 1
       else
iron_weight.door:close()
    end

    end
    end
My asset pack: viewtopic.php?f=22&t=9320

Log1 mod : Toorum Manor: viewtopic.php?f=14&t=5505
User avatar
JohnWordsworth
Posts: 1397
Joined: Fri Sep 14, 2012 4:19 pm
Location: Devon, United Kingdom
Contact:

Re: weight alcove

Post by JohnWordsworth »

Here is a relatively extensive solution - but you can take as much or as little as you like!

- The function getSurfaceWeight simply takes a surface component as a parameter and returns the weight of all items (including stacked items) on that surface.
- The function getManySurfaceWeights takes a list of strings and returns a 'dictionary' table where you can get the weight of each surface by key.
- The onSurfaceActivate function is an example of how to use each of these methods.

Code: Select all

----
-- Given a surface component, get the weight of all items on that surface.
-- Example: 
--     local weight = getSurfaceWeight(entity.surface);
--     hudPrint("Surface Weight: " .. weight);

function getSurfaceWeight(surface)
	if ( surface == nil ) then
		Console.warn("Attempted to measure weight on nil surface.");
		return 0;
	end
	
	local totalWeight = 0;
	
	for _,item in surface:contents() do
		totalWeight = totalWeight + item:getWeight() * item:getStackSize();
	end
	
	return totalWeight;
end


---- 
-- Given a list of names of entities with surfaces, return a table with all of surface weights.
-- Note. This does checks and warns you if you type in the wrong name of a surface.
-- Example: 
--     local weights = getManySurfaceWeights({"alcove1", "alcove2"});
--     hudPrint("alcove1 Weighs: " .. weights["alcove1"]);

function getManySurfaceWeights(surfaceNames)
	local result = { };

	if ( surfaceNames == nil ) then
		Console.warn("Attempted to get weights on zero surfaces.");
		return result;
	end
	
	for _,surfaceName in ipairs(surfaceNames) do
		local entity = findEntity(surfaceName);
		
		if ( entity == nil or entity.surface == nil ) then
			Console.warn("Surface with name '" .. surfaceName .. "' doesn't exist.");
		else 
			result[surfaceName] = getSurfaceWeight(entity.surface);
		end
	end
	
	return result;
end


----
-- Function to hook into a surface's onInsertItem and onRemoveItem connectors.

function onAlcoveActivated(sender)
	-- For Testing, you could do this...
	local weight = getSurfaceWeight(sender);
	hudPrint("Stuff Weighs: " .. weight);
	
	-- For your sort of puzzle specifically, you do this...
	local weights = getManySurfaceWeights({"dng1_alcove1", "dng1_alcove2"});
	
	if ( weights["dng1_alcove1"] == 0.7 and weights["dng1_alcove2"] == 3.2 ) then
		hudPrint("HUZZAH");
	else
		hudPrint("BOO");
	end
end
My Grimrock Projects Page with links to the Grimrock Model Toolkit, GrimFBX, Atlas Toolkit, QuickBar, NoteBook and the Oriental Weapons Pack.
User avatar
Thorham
Posts: 80
Joined: Sat May 04, 2013 5:12 pm

Re: weight alcove

Post by Thorham »

JohnWordsworth beat me to it, but here's some code anyway. Handles stack sizes properly. Be sure to make two connectors per alcove. One for onInsertItem and one for onRemoveItem.

Code: Select all

isFinished = false

function weightcheck()
    if isFinished == true then
        return
    end

    if getWeight(alcw1) == 0.1 and
       getWeight(alcw2) == 0.2 and
       getWeight(alcw3) == 1.2 and
       getWeight(alcw4) == 1.2 then

        iron_weight.door:open()
        playSound("secret")
        isFinished = true
    else
        iron_weight.door:close()
    end
end

function getWeight(alcove)
    local a
    local b = 0

    for _, a in alcove.surface:contents() do
        b = b + (a:getWeight() * a:getStackSize())
    end

    return b
end
User avatar
TheLastOrder
Posts: 104
Joined: Wed Oct 17, 2012 1:56 am

Re: weight alcove

Post by TheLastOrder »

I LOVE YOU GUYS.

Yeah, I had to use caps. :lol:

I´m about 95% ready to launch a campaign... after 2 months of full dedication!!!

Of course the puzzle has different numbers and a close (but different) mechanic, but here´s the code I needed to understand how it works. :D

Thank you and thank you again!
bongobeat
Posts: 1076
Joined: Thu May 16, 2013 5:58 pm
Location: France

Re: weight alcove

Post by bongobeat »

thanks all :D
My asset pack: viewtopic.php?f=22&t=9320

Log1 mod : Toorum Manor: viewtopic.php?f=14&t=5505
bongobeat
Posts: 1076
Joined: Thu May 16, 2013 5:58 pm
Location: France

Re: weight alcove

Post by bongobeat »

I have tested both script, it works not everywhere.

to Thorham :
it works
if I place a shuriken on alcw1 (0.1kg)
2 shuriken on alcw2 (0.2kg)
a branch in alcw3 and alcw4 (1,2 + 1,2 kg)

now if I put 12 shuriken in alcw3 instead of a branch, that don't work anymore, except if I put them one by one.

to JohnWordsworth:
it's the same thing. It depend on which alcove, if you put shurikens instead branchs it don't works.

here is the script, maybe am I configuring it wrong? the alcoves (mine_alcove_1, ..._2, etc..) are relied to the script, with insertItems and removeItems, on the OnAlcoveAct function
SpoilerShow

Code: Select all

    ----
    -- Given a surface component, get the weight of all items on that surface.
    -- Example:
    --     local weight = getSurfaceWeight(entity.surface);
    --     hudPrint("Surface Weight: " .. weight);

    function getSurfaceWeight(surface)
       if ( surface == nil ) then
          Console.warn("Attempted to measure weight on nil surface.");
          return 0;
       end
       
       local totalWeight = 0;
       
       for _,item in surface:contents() do
          totalWeight = totalWeight + item:getWeight() * item:getStackSize();
       end
       
       return totalWeight;
    end


    ----
    -- Given a list of names of entities with surfaces, return a table with all of surface weights.
    -- Note. This does checks and warns you if you type in the wrong name of a surface.
    -- Example:
    --     local weights = getManySurfaceWeights({"alcove1", "alcove2"});
    --     hudPrint("alcove1 Weighs: " .. weights["alcove1"]);

    function getManySurfaceWeights(surfaceNames)
       local result = { };

       if ( surfaceNames == nil ) then
          Console.warn("Attempted to get weights on zero surfaces.");
          return result;
       end
       
       for _,surfaceName in ipairs(surfaceNames) do
          local entity = findEntity(surfaceName);
          
          if ( entity == nil or entity.surface == nil ) then
             Console.warn("Surface with name '" .. surfaceName .. "' doesn't exist.");
          else
             result[surfaceName] = getSurfaceWeight(entity.surface);
          end
       end
       
       return result;
    end


    ----
    -- Function to hook into a surface's onInsertItem and onRemoveItem connectors.

    function onAlcoveActivated(sender)
       -- For Testing, you could do this...
       local weight = getSurfaceWeight(sender);
       hudPrint("Stuff Weighs: " .. weight);
       
       -- For your sort of puzzle specifically, you do this...
       local weights = getManySurfaceWeights({"mine_alcove_1" , "mine_alcove_2", "mine_alcove_3", "mine_alcove_4"});
       
       if ( weights["mine_alcove_1"] == 0.1 and weights["mine_alcove_2"] == 0.2 and weights["mine_alcove_3"] == 1.2 and weights["mine_alcove_4"] == 1.2) then
          hudPrint("HUZZAH");
       else
          hudPrint("BOO");
       end
    end
in this configuration, if you put, shurikens on the 1st and 2nd alcove, then branchs on the other alcove, it works very well.
if you replace branchs by shuriken, it don't work anymore


this is the 4th dimension :D
I have configured the weight in each alcove with different values for alcove 3 and 4, then I filled them only with shurikens.
I don't know why, but I figured that maybe, when the weight get a value > to 1, it goes into another dimension for the stackable items and maybe this goes behind the planck measures :D
or maybe is it 1.1 there?

mine_alcove_1 = 0.1
mine_alcove_2 = 0.2
mine_alcove_3 = 0.8 1.0
mine_alcove_4 = 0.8 2.0 1.1
works, no doubt on that!
then I ve change the value of the alcove4 to 1.2, it won't work anymore. I got boo, boo, and boo! :D
My asset pack: viewtopic.php?f=22&t=9320

Log1 mod : Toorum Manor: viewtopic.php?f=14&t=5505
User avatar
Prozail
Posts: 158
Joined: Mon Oct 27, 2014 3:36 pm

Re: weight alcove

Post by Prozail »

It's a floating point error.. I have no good way of solving it but the following works.

Code: Select all


    ----
    -- Given a surface component, get the weight of all items on that surface.
    -- Example:
    --     local weight = getSurfaceWeight(entity.surface);
    --     hudPrint("Surface Weight: " .. weight);

    function getSurfaceWeight(surface)
       if ( surface == nil ) then
          Console.warn("Attempted to measure weight on nil surface.");
          return 0;
       end
       
       local totalWeight = 0;
       
       for _,item in surface:contents() do
          totalWeight = totalWeight + item:getWeight() * item:getStackSize();
       end
       
       return totalWeight;
    end


    ----
    -- Given a list of names of entities with surfaces, return a table with all of surface weights.
    -- Note. This does checks and warns you if you type in the wrong name of a surface.
    -- Example:
    --     local weights = getManySurfaceWeights({"alcove1", "alcove2"});
    --     hudPrint("alcove1 Weighs: " .. weights["alcove1"]);

    function getManySurfaceWeights(surfaceNames)
       local result = { };

       if ( surfaceNames == nil ) then
          Console.warn("Attempted to get weights on zero surfaces.");
          return result;
       end
       
       for _,surfaceName in ipairs(surfaceNames) do
          local entity = findEntity(surfaceName);
          
          if ( entity == nil or entity.surface == nil ) then
             Console.warn("Surface with name '" .. surfaceName .. "' doesn't exist.");
          else
             result[surfaceName] = math.floor(getSurfaceWeight(entity.surface)*10);
          end
       end
       
       return result;
    end


    ----
    -- Function to hook into a surface's onInsertItem and onRemoveItem connectors.

    function onAlcoveActivated(sender)
       -- For Testing, you could do this...
       local weight = getSurfaceWeight(sender);
       hudPrint("Stuff Weighs: " .. weight);
       
       -- For your sort of puzzle specifically, you do this...
       local weights = getManySurfaceWeights({"mine_alcove_1" , "mine_alcove_2", "mine_alcove_3", "mine_alcove_4"});
	
	print(weights["mine_alcove_1"],weights["mine_alcove_2"],weights["mine_alcove_3"],weights["mine_alcove_4"])
       
       if ( weights["mine_alcove_1"] == 1 and weights["mine_alcove_2"] == 2 and weights["mine_alcove_3"] == 12 and weights["mine_alcove_4"] == 12) then
          hudPrint("HUZZAH");
       else
          hudPrint("BOO");
       end
    end
User avatar
Thorham
Posts: 80
Joined: Sat May 04, 2013 5:12 pm

Re: weight alcove

Post by Thorham »

Yeah, it's a floating point comparison problem.

A better way to solve it is to check a range, for example, for 1.2 you check if the weight is between 1.195 and 1.205. The problem is the size of the range. How small can it be?

Edit: Code removed because crappy solution.
Last edited by Thorham on Fri Jan 09, 2015 10:45 am, edited 2 times in total.
User avatar
JohnWordsworth
Posts: 1397
Joined: Fri Sep 14, 2012 4:19 pm
Location: Devon, United Kingdom
Contact:

Re: weight alcove

Post by JohnWordsworth »

Well, I guess floating point errors are only going to affect very minor digits - so you can compare against a value so small that it would never be enough to sneak another object in there (in terms of Grimrock object weights).

Code: Select all

if math.abs(alcoveWeight - targetWeight) < 0.000001 then
  -- All good!
end
I will fix my code above later on this evening / over the weekend :).
My Grimrock Projects Page with links to the Grimrock Model Toolkit, GrimFBX, Atlas Toolkit, QuickBar, NoteBook and the Oriental Weapons Pack.
User avatar
Thorham
Posts: 80
Joined: Sat May 04, 2013 5:12 pm

Re: weight alcove

Post by Thorham »

The weight unit really should have been grams instead of kilos, and only allow integer values for weights. The problem simply wouldn't exist then.
Post Reply