• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

RevScripts Show text on screen without using movements or actionIDs.

Jaki Maoh

Member
Joined
Sep 13, 2017
Messages
52
Reaction score
12
Hello Community.
The idea is to have a message pop up everytime the player changes locations, with the intent of making the locations and name of the places better known.
Searching the forum I found some ways to make messages appear on the screen, but almost always based on a timer (onThink events).
So I tried modifying this script by @Sarah Wesker :

Here is a example TFS 1.3

data/scripts/texteffects.lua
Lua:
local config = {
    interval = 5000,
    texts = {
        { pos = Position(3191, 1810, 7), text = "Temple!", effects = { CONST_ME_TELEPORT, CONST_ME_DRAWBLOOD } },
        { pos = Position(3188, 1811, 7), text = "Depots!", effects = { CONST_ME_ICEAREA, CONST_ME_ENERGYHIT } },
        { pos = Position(3191, 1814, 7), text = "Skills!", effects = { CONST_ME_ENERGYAREA, CONST_ME_FERUMBRAS } }
    }
}

local textOnMap = GlobalEvent("TextOnMap")

function textOnMap.onThink(interval)
    local player = Game.getPlayers()[1]
    if not player then
        return true
    end

    for k, info in pairs(config.texts) do
        player:say(info.text, TALKTYPE_MONSTER_SAY, false, nil, info.pos)
        info.pos:sendMagicEffect(info.effects[math.random(1, #info.effects)])
    end
    return true
end

textOnMap:interval(config.interval)
textOnMap:register()



And got poor results, because the system was still based on an interval, and not on the previous storage (meaning the player that stands still on the "passage" between two places will have the message appearing from time to time).




Lua:
local config = {
    interval = 1000,
    texts = {
      
        { pos = Position(1633, 1530, 6), text = "Test 1"},
        { pos = Position(1637, 1530, 6), text = "Test 2"},
        { pos = Position(1641, 1530, 6), text = "Test 3"}
    }
}

local textOnMape = GlobalEvent("TextOnMape")

function textOnMape.onThink(interval)
    local player = Game.getPlayers()[1]
    if not player then
        return true
    end
    
    if player:getStorageValue(30004) < os.time() then
        for k, info in pairs(config.texts) do
            player:say(info.text, TALKTYPE_MONSTER_SAY, false, nil, info.pos)
            -- info.pos:sendMagicEffect(info.effects[math.random(1, #info.effects)])
            player:setStorageValue(30004, os.time() + 6)
        end
    end
    return true
end

textOnMape:interval(config.interval)
textOnMape:register()



So I've decided to ask for help, because my script modifying techniques are not near enough to do the modifications that I need.

If anyone can help me build a similar script based on the idea of "keeping the storage of the last message shown" and only show the next one after the player approaches the location of the new message it would be great!

Keep in mind that this script by Sarah is ideal (imo) because it is not based on movements and do not require the player to step on a specific tile (or set of tiles) to trigger the messages (avoiding the need to fill the entire map with endless actionIDs, in specific, narrowed down paths).

Thanks for your time!

Jaki
 
Solution
Most optimized way would be to create new OTC module, make table with positions (from-to) and assign area name to each position, connect onPositionChange event for LocalPlayer, check if current area (assign area name when changing areas) is different than previous, if so, show text/image or whatever.
There is not need to involve server into this because world map in Tibia is not generated so these positions won't change.

#Edit
Done.

eLjpDUMOQL.gif
I like this idea, could be usefull for what I need too. If there's a chance to load an image title via OTClient when the zone is changed would be amazing, and set-up the zone change by areas like it's done on rc_sound module (example: {fromPos = {x=xxx, y=xxx, z=xxx}, toPos = {x=xxx, y=xxx, z=xxx}). Looking up for this thread :)
 
I like this idea, could be usefull for what I need too. If there's a chance to load an image title via OTClient when the zone is changed would be amazing, and set-up the zone change by areas like it's done on rc_sound module (example: {fromPos = {x=xxx, y=xxx, z=xxx}, toPos = {x=xxx, y=xxx, z=xxx}). Looking up for this thread :)
Yeah, it would be really cool and immersive!
Let's hope the idea comes to a happy ending ;)
 
Most optimized way would be to create new OTC module, make table with positions (from-to) and assign area name to each position, connect onPositionChange event for LocalPlayer, check if current area (assign area name when changing areas) is different than previous, if so, show text/image or whatever.
There is not need to involve server into this because world map in Tibia is not generated so these positions won't change.

#Edit
Done.

eLjpDUMOQL.gif
 

Attachments

Last edited:
Solution
Most optimized way would be to create new OTC module, make table with positions (from-to) and assign area name to each position, connect onPositionChange event for LocalPlayer, check if current area (assign area name when changing areas) is different than previous, if so, show text/image or whatever.
There is not need to involve server into this because world map in Tibia is not generated so these positions won't change.

#Edit
Done.

View attachment 61665
I really can't believe how perfect the final result was!
A thousand thanks, your contribution was way above expectations!!!
 
I really can't believe how perfect the final result was!
A thousand thanks, your contribution was way above expectations!!!
No problem, feel free to post new thread with this module so it gets more attention in case someone is looking for something like that.

Or whoever is faster, free likes guaranteed! 🤣
 
@oen432 Amazing outcome, I have an idea to improve this a little bit.

I use rc_sound module and it has priority asignment on zones. So, if a player is not inside a trigger area, and is in a "unnamed" part, it will be considered as a default area with a default name. I don't know if I explain myself good, so here's the example.

Code:
SOUNDS = {
         {fromPos = {x=1191, y=813, z=1}, toPos = {x=1402, y=981, z=7}, priority = 1, sound="roshamuul.ogg"},     ----- mihen city
        {fromPos = {x=717, y=629, z=1}, toPos = {x=1500, y=1430, z=7}, priority = 0, sound="sprouting.ogg"}, ----- exploring
        {fromPos = {x=717, y=629, z=8}, toPos = {x=1500, y=1430, z=15}, priority = 1, sound="jetch.ogg"},  ------ cave
        {fromPos = {x=975, y=961, z=1}, toPos = {x=991, y=982, z=6}, priority = 2, sound="depot.ogg"},   ----- depot kilika  
        {fromPos = {x=1007, y=967, z=1}, toPos = {x=1027, y=986, z=7}, priority = 2, sound="temple.ogg"}, ------- temple
        {fromPos = {x=153, y=463, z=1}, toPos = {x=242, y=620, z=15}, priority = 2, sound="training.ogg"},    ------- trainer
        {fromPos = {x=1232, y=912, z=1}, toPos = {x=1259, y=931, z=7}, priority = 2, sound="depot.ogg"}, ------- depot mihen
        {fromPos = {x=1257, y=898, z=1}, toPos = {x=1264, y=905, z=7}, priority = 2, sound="temple.ogg"},  ------- temple mihen
        {fromPos = {x=839, y=769, z=1}, toPos = {x=1042, y=916, z=7}, priority = 2, sound="roshamuul.ogg"},  ----- roshamuul
        {fromPos = {x=837, y=922, z=1}, toPos = {x=944, y=968, z=7}, priority = 2, sound="exploring_ocean.ogg"},     ----- dragon kilika
        {fromPos = {x=1223, y=984, z=1}, toPos = {x=1389, y=1063, z=7}, priority = 2, sound="exploring_ocean.ogg"},     ----- mino mihen
        {fromPos = {x=964, y=937, z=12}, toPos = {x=1054, y=1018, z=15}, priority = 2, sound="fireplace.ogg"},  ------ fury
        {fromPos = {x=915, y=719, z=12}, toPos = {x=1091, y=898, z=15}, priority = 2, sound="fireplace.ogg"},     ----- warlocks  
        {fromPos = {x=1008, y=1022, z=11}, toPos = {x=1098, y=1087, z=13}, priority = 2, sound="earthquake.ogg"},     ----- behemoth  
        {fromPos = {x=1101, y=999, z=10}, toPos = {x=1199, y=1087, z=15}, priority = 2, sound="earthquake.ogg"},     ----- bog
        {fromPos = {x=1083, y=1102, z=10}, toPos = {x=1166, y=1150, z=13}, priority = 2, sound="earthquake.ogg"},     ----- dwarf
        {fromPos = {x=1053, y=840, z=1}, toPos = {x=1171, y=914, z=7}, priority = 2, sound="macalania.ogg"},     ----- ice
} ----------

An easier explaination of this is that ----cave and ----exploring are coordinates that covers a BIG area. All the areas with priority 2 are "sub-areas" that are inside the ----cave and ---exploring trigger. Whenever a player is outside a priority 2 area, it will set up the default name that should be ---cave or ----exploring.

Regards!
 
Last edited:
@oen432 Amazing outcome, I have an idea to improve this a little bit.

I use rc_sound module and it has priority asignment on zones. So, if a player is not inside a trigger area, and is in a "unnamed" part, it will be considered as a default area with a default name. I don't know if I explain myself good, so here's the example.

Code:
SOUNDS = {
         {fromPos = {x=1191, y=813, z=1}, toPos = {x=1402, y=981, z=7}, priority = 1, sound="roshamuul.ogg"},     ----- mihen city
        {fromPos = {x=717, y=629, z=1}, toPos = {x=1500, y=1430, z=7}, priority = 0, sound="sprouting.ogg"}, ----- exploring
        {fromPos = {x=717, y=629, z=8}, toPos = {x=1500, y=1430, z=15}, priority = 1, sound="jetch.ogg"},  ------ cave
        {fromPos = {x=975, y=961, z=1}, toPos = {x=991, y=982, z=6}, priority = 2, sound="depot.ogg"},   ----- depot kilika
        {fromPos = {x=1007, y=967, z=1}, toPos = {x=1027, y=986, z=7}, priority = 2, sound="temple.ogg"}, ------- temple
        {fromPos = {x=153, y=463, z=1}, toPos = {x=242, y=620, z=15}, priority = 2, sound="training.ogg"},    ------- trainer
        {fromPos = {x=1232, y=912, z=1}, toPos = {x=1259, y=931, z=7}, priority = 2, sound="depot.ogg"}, ------- depot mihen
        {fromPos = {x=1257, y=898, z=1}, toPos = {x=1264, y=905, z=7}, priority = 2, sound="temple.ogg"},  ------- temple mihen
        {fromPos = {x=839, y=769, z=1}, toPos = {x=1042, y=916, z=7}, priority = 2, sound="roshamuul.ogg"},  ----- roshamuul
        {fromPos = {x=837, y=922, z=1}, toPos = {x=944, y=968, z=7}, priority = 2, sound="exploring_ocean.ogg"},     ----- dragon kilika
        {fromPos = {x=1223, y=984, z=1}, toPos = {x=1389, y=1063, z=7}, priority = 2, sound="exploring_ocean.ogg"},     ----- mino mihen
        {fromPos = {x=964, y=937, z=12}, toPos = {x=1054, y=1018, z=15}, priority = 2, sound="fireplace.ogg"},  ------ fury
        {fromPos = {x=915, y=719, z=12}, toPos = {x=1091, y=898, z=15}, priority = 2, sound="fireplace.ogg"},     ----- warlocks
        {fromPos = {x=1008, y=1022, z=11}, toPos = {x=1098, y=1087, z=13}, priority = 2, sound="earthquake.ogg"},     ----- behemoth
        {fromPos = {x=1101, y=999, z=10}, toPos = {x=1199, y=1087, z=15}, priority = 2, sound="earthquake.ogg"},     ----- bog
        {fromPos = {x=1083, y=1102, z=10}, toPos = {x=1166, y=1150, z=13}, priority = 2, sound="earthquake.ogg"},     ----- dwarf
        {fromPos = {x=1053, y=840, z=1}, toPos = {x=1171, y=914, z=7}, priority = 2, sound="macalania.ogg"},     ----- ice
} ----------

An easier explaination of this is that ----cave and ----exploring are coordinates that covers a BIG area. All the areas with priority 2 are "sub-areas" that are inside the ----cave and ---exploring trigger. Whenever a player is outside a priority 2 area, it will set up the default name that should be ---cave or ----exploring.

Regards!
If there are caves then best way would be to just position entrances and exits only, cause they are limited in case of caves or such so no need to cover entire map area.
If the entrance is a hole then use position of the tile under that hole (where you use rope), tile next to the hole (entrance) would be area outside cave.
 
Last edited:
If there are caves then best way would be to just position entrances and exits only, cause they are limited in case of caves or such so no need to cover entire map area.
If the entrance is a hole then use position of the tile under that hole (where you use rope), tile next to the hole (entrance) would be area outside cave.
Following your guidance, the last question that remains is: the optimized way to add lots of "entrances" to the same area could be done similar to this?🤔 (script below)
Lua:
local areas = {
  {
    from = {x = 1616, y = 1524, z = 6},
    to = {x = 1650, y = 1536, z = 6},
    name = "First Area"
  },
  {
    from = {x = 1651, y = 1522, z = 6},
    to = {x = 1670, y = 1539, z = 6},
    name = "Second Area"
  },
  {
    from = {x = 1204, y = 833, z = 5}, -- bridge to north 1
    to = {x = 1207, y = 835, z = 5}, -- bridge to north 2
    from = {x = 1175, y = 856, z = 5}, -- bear exit 1
    to = {x = 1177, y = 857, z = 5}, -- bear exit 2
    from = {x = 1246, y = 817, z = 5}, -- spider cave exit 1
    to = {x = 1248, y = 819, z = 5}, -- spider cave exit 2
    from = {x = 1154, y = 806, z = 5}, -- goblins1 exit 1
    to = {x = 1155, y = 808, z = 5}, -- goblins1 exit 2
    from = {x = 1154, y = 865, z = 5}, -- goblins2 exit 1
    to = {x = 1156, y = 867, z = 5}, -- goblins2 exit 2
    from = {x = 1138, y = 845, z = 5}, -- goblins3 exit 1
    to = {x = 1140, y = 847, z = 5}, -- goblins3 exit 2
    from = {x = 1170, y = 797, z = 5}, -- stone golem exit 1
    to = {x = 1173, y = 798, z = 5}, -- stone golem exit 2
    from = {x = 1177, y = 725, z = 5}, -- rotworm exit 1
    to = {x = 1178, y = 728, z = 5}, -- rotworm exit 2
    from = {x = 1221, y = 705, z = 5}, -- return from the dark 1
    to = {x = 1224, y = 706, z = 5}, -- return from the dark 2
    from = {x = 1251, y = 709, z = 5}, -- mountain spiders exit 1
    to = {x = 1254, y = 710, z = 5}, -- mountain spiders exit 2
    from = {x = 1268, y = 720, z = 5}, -- dead body exit 1
    to = {x = 1270, y = 721, z = 5}, -- dead body exit 2
    from = {x = 1208, y = 711, z = 5}, -- tigers exit 1
    to = {x = 1210, y = 712, z = 5}, -- tigers exit 2
    from = {x = 1221, y = 800, z = 5}, -- trolls exit 1
    to = {x = 1225, y = 803, z = 5}, -- trolls exit 2
    from = {x = 1278, y = 806, z = 5}, -- stone wolfs exit 1
    to = {x = 1289, y = 814, z = 5}, -- stone wolfs exit 2
    from = {x = 1274, y = 831, z = 5}, -- return from haunted house 1
    to = {x = 1275, y = 832, z = 5}, -- return from haunted house 2
    name = "the northern forests"
  },
  {
    from = {x = 1613, y = 1524, z = 6},
    to = {x = 1615, y = 1539, z = 6},
    name = "Fourth Arena name"
  }
}
local currentArea = ""

local window = nil
local nameLabel = nil
local fadeOutEvent = nil

function init()
  connect(
    g_game,
    {
      onGameStart = create,
      onGameEnd = destroy
    }
  )

  if g_game.isOnline() then
    create()
  end
end

function create()
  window = g_ui.loadUI("areas", modules.game_interface.getMapPanel())
  window:setOpacity(0)
  nameLabel = window:getChildById("name")

  connect(LocalPlayer, {onPositionChange = onPositionChange})
end

local function isInArea(position, fromPos, toPos)
  local x = position.x
  local y = position.y
  local z = position.z
  if z ~= fromPos.z and z ~= toPos.z then
    return false
  end

  if x >= fromPos.x and x <= toPos.x and y >= fromPos.y and y <= toPos.y then
    return true
  end

  return false
end

local function fadeOut()
  g_effects.fadeOut(window, 750)
  fadeOutEvent = nil
end

function onPositionChange(player, newPos, oldPos)
  for i = 1, #areas do
    local area = areas[i]
    if currentArea ~= area.name then
      if isInArea(newPos, area.from, area.to) then
        currentArea = area.name
        nameLabel:setText("Entering " .. area.name)
        window:setWidth(nameLabel:getText():len() * 8)
        g_effects.fadeIn(window, 750)
        if fadeOutEvent then
          removeEvent(fadeOutEvent)
        end
        fadeOutEvent = scheduleEvent(fadeOut, 3000)
        break
      end
    end
  end
end

function terminate()
  disconnect(
    g_game,
    {
      onGameStart = create,
      onGameEnd = destroy
    }
  )
  if window then
    destroy()
  end
end

function destroy()
  disconnect(LocalPlayer, {onPositionChange = onPositionChange})

  if window then
    window:destroy()
    window = nil
  end

  nameLabel = nil
  fadeOutEvent = nil
  currentArea = ""
end
Not tested yet.


Thanks again🙂
Jaki
 
Following your guidance, the last question that remains is: the optimized way to add lots of "entrances" to the same area could be done similar to this?🤔 (script below)
Lua:
local areas = {
  {
    from = {x = 1616, y = 1524, z = 6},
    to = {x = 1650, y = 1536, z = 6},
    name = "First Area"
  },
  {
    from = {x = 1651, y = 1522, z = 6},
    to = {x = 1670, y = 1539, z = 6},
    name = "Second Area"
  },
  {
    from = {x = 1204, y = 833, z = 5}, -- bridge to north 1
    to = {x = 1207, y = 835, z = 5}, -- bridge to north 2
    from = {x = 1175, y = 856, z = 5}, -- bear exit 1
    to = {x = 1177, y = 857, z = 5}, -- bear exit 2
    from = {x = 1246, y = 817, z = 5}, -- spider cave exit 1
    to = {x = 1248, y = 819, z = 5}, -- spider cave exit 2
    from = {x = 1154, y = 806, z = 5}, -- goblins1 exit 1
    to = {x = 1155, y = 808, z = 5}, -- goblins1 exit 2
    from = {x = 1154, y = 865, z = 5}, -- goblins2 exit 1
    to = {x = 1156, y = 867, z = 5}, -- goblins2 exit 2
    from = {x = 1138, y = 845, z = 5}, -- goblins3 exit 1
    to = {x = 1140, y = 847, z = 5}, -- goblins3 exit 2
    from = {x = 1170, y = 797, z = 5}, -- stone golem exit 1
    to = {x = 1173, y = 798, z = 5}, -- stone golem exit 2
    from = {x = 1177, y = 725, z = 5}, -- rotworm exit 1
    to = {x = 1178, y = 728, z = 5}, -- rotworm exit 2
    from = {x = 1221, y = 705, z = 5}, -- return from the dark 1
    to = {x = 1224, y = 706, z = 5}, -- return from the dark 2
    from = {x = 1251, y = 709, z = 5}, -- mountain spiders exit 1
    to = {x = 1254, y = 710, z = 5}, -- mountain spiders exit 2
    from = {x = 1268, y = 720, z = 5}, -- dead body exit 1
    to = {x = 1270, y = 721, z = 5}, -- dead body exit 2
    from = {x = 1208, y = 711, z = 5}, -- tigers exit 1
    to = {x = 1210, y = 712, z = 5}, -- tigers exit 2
    from = {x = 1221, y = 800, z = 5}, -- trolls exit 1
    to = {x = 1225, y = 803, z = 5}, -- trolls exit 2
    from = {x = 1278, y = 806, z = 5}, -- stone wolfs exit 1
    to = {x = 1289, y = 814, z = 5}, -- stone wolfs exit 2
    from = {x = 1274, y = 831, z = 5}, -- return from haunted house 1
    to = {x = 1275, y = 832, z = 5}, -- return from haunted house 2
    name = "the northern forests"
  },
  {
    from = {x = 1613, y = 1524, z = 6},
    to = {x = 1615, y = 1539, z = 6},
    name = "Fourth Arena name"
  }
}
local currentArea = ""

local window = nil
local nameLabel = nil
local fadeOutEvent = nil

function init()
  connect(
    g_game,
    {
      onGameStart = create,
      onGameEnd = destroy
    }
  )

  if g_game.isOnline() then
    create()
  end
end

function create()
  window = g_ui.loadUI("areas", modules.game_interface.getMapPanel())
  window:setOpacity(0)
  nameLabel = window:getChildById("name")

  connect(LocalPlayer, {onPositionChange = onPositionChange})
end

local function isInArea(position, fromPos, toPos)
  local x = position.x
  local y = position.y
  local z = position.z
  if z ~= fromPos.z and z ~= toPos.z then
    return false
  end

  if x >= fromPos.x and x <= toPos.x and y >= fromPos.y and y <= toPos.y then
    return true
  end

  return false
end

local function fadeOut()
  g_effects.fadeOut(window, 750)
  fadeOutEvent = nil
end

function onPositionChange(player, newPos, oldPos)
  for i = 1, #areas do
    local area = areas[i]
    if currentArea ~= area.name then
      if isInArea(newPos, area.from, area.to) then
        currentArea = area.name
        nameLabel:setText("Entering " .. area.name)
        window:setWidth(nameLabel:getText():len() * 8)
        g_effects.fadeIn(window, 750)
        if fadeOutEvent then
          removeEvent(fadeOutEvent)
        end
        fadeOutEvent = scheduleEvent(fadeOut, 3000)
        break
      end
    end
  end
end

function terminate()
  disconnect(
    g_game,
    {
      onGameStart = create,
      onGameEnd = destroy
    }
  )
  if window then
    destroy()
  end
end

function destroy()
  disconnect(LocalPlayer, {onPositionChange = onPositionChange})

  if window then
    window:destroy()
    window = nil
  end

  nameLabel = nil
  fadeOutEvent = nil
  currentArea = ""
end
Not tested yet.


Thanks again🙂
Jaki
No, that won't work, you have to separate them, just use same name so it won't notify when walking on a different position for that same area.
 
Back
Top