Lens of Truth?

Started by Starlock, November 17, 2015, 05:50:25 PM

Previous topic - Next topic
Hey, I would like to try to create an item similar to the Lens of Truth from OoT, and I would just like to make sure something like that is possible. My initial thought process is to make the item enable specific dynamic tiles while it is being used and then re-disable them when the item is no longer in use.

November 17, 2015, 06:11:23 PM #1 Last Edit: November 17, 2015, 06:13:21 PM by Christopho
I have never done it yet. You probably want to do show/hide dynamic tiles, but also chests, enemies, etc.
Enabling/disabling entities is probably a way. Another way is to change visibility with set_visible(). It depends on whether you want entities to still be present and act as obstacle when not seen.

To control what entities you want to enable/disable or show/hide, you can do something based on their name. The lens of truth script would do something like
Code (lua) Select

-- Hide all entities whose name starts with "lens_"
for entity in map:get_entities("lens_") do
  entity:set_visible(false)
end

I am only giving the idea. You would probably hide the entities when a map starts with the lens off, show them with similar code when the lens is used, and hide them when the lens stops.

But maybe this would conflict with other systems that already do something based on names. Like the separator manager or a script that opens a door when all enemies with some prefix are killed.

So a more robust solution can be to store, on each map who needs it, a list of entities affected by the lens of truth.
Usually, there are not hundreds of maps with entities reacting to the lens of truth so this is okay to maintain.
The lens of truth script would look like
Code (lua) Select

-- Hide all entities that the map wants to.
if map.lens_entities ~= nil then
  for entity in ipairs(map.lens_entities) do
    entity:set_visible(false)
  end
end

And map scripts that want to make entities react to the lens of truth would do
Code (lua) Select

local map = ...

map.lens_entities = { enemy_1, my_chest, an_invisible_tile }

-- ... rest of the map script


And for the displaying, you can show a semi-transparent pink image over the game, with a fully transparent circle at the center. Possibly as a HUD element.
The only problem is that the circle part at the center should remain centered on the hero, and the hero is not always centered on the screen due to map limits and separator. But this information can be retrieved by getting the position of the camera. Show the image centered at (hero_x - camera_x, hero_y - camera_y).

Hi! This seems a cool feature to script for a fangame, and it should not be too hard. You can also use the same kind of functions to hide false objects and walls. Enabling/disabling is worse because you could get stuck if you make the hero overlap some solid entity, so it would be better just changing the visibility with set_visible.

The only restriction you have is that you cannot show or hide only a part of each entity, so maybe it would be better to make the outer part of the circle completely opaque. This is better if you hide/show very large entities (like a bridge).
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Hello !
I've done something like this when I developped the lens for my project with RM2K. I didn't make it yet with solarus but I have a lot of things to do before !!

November 18, 2015, 03:01:35 PM #4 Last Edit: November 18, 2015, 03:18:27 PM by Username
You can first in you item script call a sprite representing the lens effect and create a sensor around the clear area that follows the hero and display the event / active it if it is in the sensor range.

This item is also in my todo, I might start it soon.

Since the Lens of Truth is separated in 2 process (on and off), it might be more complex, you might need more coding to do in on_using() and in on_map_changed (if you want to keep it active in another map while being teleported)

This is a mock up but this is what I'm going to do, but, I don't know how to control the magic

  if state ==1then
  magic_timer = sol.timer.start(500, function()
  magic - 1
  return true
  end)
  else magic_timer:stop()
  end


This is a brieve thing on the current script, it works in-game but the magic drop drastivally, magic - 1 isn't stopped when the item is stopped


Perhaps you could give some context? Like, where those variables are defined and when the if-condition is checked. But anyway, it would probably be less error-prone to check inside of the timer whether it should still be executed. Like this:
Code ( lua) Select
sol.timer.start(500,function()
  if state == 1 then --A state of one probably means that the lens are activated. Correct me if I'm wrong
    magic = magic - 1
    return true
  end
end)

November 18, 2015, 05:51:37 PM #6 Last Edit: November 19, 2015, 10:16:58 PM by Username
Quote from: the bread on November 18, 2015, 04:29:57 PM
Perhaps you could give some context? Like, where those variables are defined and when the if-condition is checked. But anyway, it would probably be less error-prone to check inside of the timer whether it should still be executed. Like this:
Code ( lua) Select
sol.timer.start(500,function()
  if state == 1 then --A state of one probably means that the lens are activated. Correct me if I'm wrong
    magic = magic - 1
    return true
  end
end)


State = what is the current item state (on or off)
magic : getting the current magic level and set an algorythm that will take 1 Magic P. each 500 milliseconds.
return true = the timer is looped

The condition is active when the state of the item, declared in a local (game:get_value()) reach 1., the others are also local variables.
This might be the culprit

Everything is explained in the API

There is another method to do the lens of truth much easier but it need pixel opacity calculations on a surface, which is still not possible to do with solarus