Lua for rooms.xyz

https://github.com/nntrn/save/issues/49

Created on Last updated on


Hide walls and floor

getThing("NORTH_WALL"):setPosition(0, 100000, 0)
getThing("EAST_WALL"):setPosition(0, 100000, 0)
getThing("FLOOR"):setPosition(0, 100000, 0)

Movement

-- time when moving and waiting 
moveTime = 1

function moveSouth()
  -- Move 20 units south
  startMoveBy(0, 0, -20, moveTime)
  wait(moveTime, moveWest)
end

function moveWest()
  -- Turn body
  setRotation(0,-90,0)
  -- Move 20 units west
  startMoveBy(-20, 0, 0, moveTime)
  wait(moveTime, sayDone)
end

function sayLocation()
  say(string.format("%.1f %.1f %.1f", getPosition()))
end

function sayDone()
  sayLocation()
end

function onStart()
  sayLocation()
  wait(moveTime,moveSouth)
end

Get comments

function inspectComments(tbl)
  for j,r in ipairs(tbl) do
    for i,v in pairs(r) do
      print(string.format("[%d]%s: %s",j,i,v))
    end
    print(string.rep("-",10))
  end
end

function cb(cmt, cont) 
  --inspectComments(cmt)
  setMedia(cmt[1].photo)
  setText("@"..cmt[1].author)
  if cont ~= nil then
    cb(cmt,cont)
  end
end

Debug

Print current location without using ..

print(string.format("%.1f/%.1f/%.1f", getPosition()))

local x,y,z = getPosition()
print(string.format("%.1f/%.1f/%.1f",x,y,z))

Utils

-- https://stackoverflow.com/a/1407187
function listvalues(s)
    local t = { }
    for k,v in ipairs(s) do
        t[#t+1] = tostring(v)
    end
    return table.concat(t,"\n")
end

Print environment variable names

for key, value in pairs(_G) do 
  print(key, type(value))
end

function inspectTable(tbl)
  for i,v in pairs(tbl) do
    print(string.format("%s: %s",i,v))
  end
end

Time

-- Converting `Seconds` to `Hours`;
function getHour(t)
  return (math.floor( t * (1/60) * (1/60) % 12 )) +1
end

-- returns array with hour, min, and seconds
function getTime(t)
  t = t or unixTime()
  --math.floor(unix_time / 3600 % 24)
  return    math.floor(t / 3600 % 12) +1
     , math.floor(t / 60 % 60)
     , math.floor(t % 60)
end

Set clock hands

function setHour(h)
  if h > 12 then h = h - 12 end
  local degree = round((h/12) * 360) * -1
  hourHand:setLocalRotation(0,0,degree)
end

function setMinutes(m)
  local degree = round((m/60) * 360) * -1
  minHand:setLocalRotation(0,0,degree)
end

Analog clock by alex

hourHand = getThing("A-Hour Hand")
minuteHand = getThing("A-Minute Hand")
secondHand = getThing("A-Second Hand")

function onStart()
  playSound("clockTick.mp3", true, 0.1)
  outputCurrentTime()
  moveHands()
end

function outputCurrentTime()
  hour, minute, second = formatTime(dateTime():sub(12, 19))

  local hourAngle = (hour % 12) * 30 + minute / 2
  local minuteAngle = minute * 6
  local secondAngle = second * 6

  hourHand:setRotation(0, 0, -hourAngle)
  minuteHand:setRotation(0, 0, -minuteAngle)
  secondHand:setRotation(0, 0, -secondAngle)
end

function formatTime(dateTimeString)
  local hour, minute, second = dateTimeString:match("(%d+):(%d+):(%d+)")
  hour, minute, second = tonumber(hour), tonumber(minute), tonumber(second)

  if hour > 12 then hour = hour - 12 end -- non-military time

  return hour, minute, second
end

function moveHands()
  hourHand:startSpin(-30/60/60,nil,"Z")
  minuteHand:startSpin(-360/60/60,nil,"Z")
  secondHand:startSpin(-360/60,nil,"Z")
end
dt = "01:09:23"
hour, minute, second = dt:match("(%d+):(%d+):(%d+)")

Comments

function inspectComments(tbl)
  for j,r in ipairs(tbl) do
    for i,v in pairs(r) do
      print(string.format("[%d]%s: %s",j,i,v))
    end
    print(string.rep("-",10))
  end
end

function cb(cmt, cont) 
  --inspectComments(cmt)
  --setMedia(cmt[1].photo)
  --setText("@"..cmt[1].author)
  if cont ~= nil then
    cb(cont)
  end
end

function onStart()
  fetchComments(cb)
end

Queues

Although we can implement queues trivially using insert and remove (from the table library), this implementation can be too slow for large structures. A more efficient implementation uses two indices, one for the first and another for the last element:

function ListNew ()
  return {first = 0, last = -1}
end

To avoid polluting the global space, we will define all list operations inside a table, properly called List. Therefore, we rewrite our last example like this:

List = {}

function List.new ()
  return {first = 0, last = -1}
end

-- Now, we can insert or remove an element at both ends in constant time:

function List.pushleft (list, value)
  local first = list.first - 1
  list.first = first
  list[first] = value
end
    
function List.pushright (list, value)
  local last = list.last + 1
  list.last = last
  list[last] = value
end
    
function List.popleft (list)
  local first = list.first
  if first > list.last then error("list is empty") end
  local value = list[first]
  list[first] = nil        -- to allow garbage collection
  list.first = first + 1
  return value
end

function List.popright (list)
  local last = list.last
  if list.first > last then error("list is empty") end
  local value = list[last]
  list[last] = nil         -- to allow garbage collection
  list.last = last - 1
  return value
end

https://www.lua.org/pil/11.4.html

Color

-- source: urdad69

function rgbToHex(r, g, b)
  hex = string.format("#%02X%02X%02X", r, g, b)
end

function setColor()
  r = randomBetween(0, 255)
  g = randomBetween(0, 255)
  b = randomBetween(0, 255)
  rgbToHex(r, g, b)
  setTint(hex)
  setText(hex)
end

function hsvToRgb(h, s, v)
    local c = v * s
    local x = c * (1 - math.abs((h / 60) % 2 - 1))
    local m = v - c
    local r, g, b

    if h < 60 then
        r, g, b = c, x, 0
    elseif h < 120 then
        r, g, b = x, c, 0
    elseif h < 180 then
        r, g, b = 0, c, x
    elseif h < 240 then
        r, g, b = 0, x, c
    elseif h < 300 then
        r, g, b = x, 0, c
    else
        r, g, b = c, 0, x
    end

    r = (r + m) * 255
    g = (g + m) * 255
    b = (b + m) * 255

    return string.format("#%02X%02X%02X", math.floor(r), math.floor(g), math.floor(b))
end
-- source: suslike
HEX = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}

function onStart()
  setTint("" .. randomPick(HEX) .. randomPick(HEX) .. randomPick(HEX) .. randomPick(HEX) .. randomPick(HEX) .. randomPick(HEX))
end
-- source: btco
local COLOR_PER_TIER = {
  -- Tier 1
  {1.00, 1.00, 1.00},
  -- Tier 2
  {0.97, 1.00, 0.50},
  -- Tier 3
  {1.00, 0.65, 0.13},
  -- Tier 4
  {1.00, 0.40, 0.16}
}

function updateTint()
  if pinned then
    setTint(0, 1, 0)
  else
    -- Get the color from the COLOR_PER_TIER table, and
    -- pass it as R, G, B parameters to setTint.
    setTint(table.unpack(COLOR_PER_TIER[tier]))  
  end
end

Sources:

The next example collects all pairs key=value from the given string into a table:

-- https://cyevgeniy.github.io/luadocs/06_standard_lib/ch04.html#string-manipulation

t = {}
s = "from=world, to=Lua"

for k, v in string.gmatch(s, "(%w+)=(%w+)") do
  t[k] = v
end
f()                -- adjusted to 0 results

g(f(), x)          -- f() is adjusted to 1 result

g(x, f())          -- g gets x plus all results from f()

a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)

a,b = ...          -- a gets the first vararg argument, b gets the second (both a and b can get nil if there is no corresponding vararg argument)
     
a,b,c = x, f()     -- f() is adjusted to 2 results

a,b,c = f()        -- f() is adjusted to 3 results

return f()         -- returns all results from f()

return ...         -- returns all received vararg arguments

return x,y,f()     -- returns x, y, and all results from f()

{f()}              -- creates a list with all results from f()
     
{...}              -- creates a list with all vararg arguments
     
{f(), nil}         -- f() is adjusted to 1 result
total=0
function sum(n)
  total=total+(tonumber(n) or 0) 
end

string.gsub("1 2 5.3 7", "(%g+)", sum)
print(total)    -- returns 15.3

How to round to decimal

y=14.518239974976
print(math.floor(y*100)/100)   -- => 14.52
print(math.floor(y*1000)/1000) -- => 14.519

Local Values

local score = 0
function onScore(args)
  score = score + (args.pts or 1)
  setText(score)
end
 -- to all text things with onScore()
broadcast("Score",{pts=5})

-- to single thing
send(getThing("thing name"),"Score",{pts=5})

Set Tint

function onStart()
  tint=getThing("FLOOR"):getTint()
  all=getParent():getChildren()
  getThing("NORTH_WALL"):setTint(tint)
  getThing("EAST_WALL"):setTint(tint)

  for k,v in ipairs(all) do
    if v:getTint() == "#ffffff" then
      v:setTint(tint)
    end
   -- print(v:getName())
  end
end

Prompt

-- source: rooms.xyz/jing/barchart
function onClick()
  prompt("Enter label", EditLabel)
end

function EditLabel(input)
  setText(input)
end

Resources