Creating a timer on event in Warcraft in Lua - events
I'm looking for help checking for when the event "SPELL_INTERRUPT" fires so I can display a timer in the game World of Warcraft.
This is the code so far
local SPELL_LOCKOUTS = {
-- [interruptSpellID] = lockoutDuration, -- Spell Name (Class)
[2139] = 6, -- Counterspell (Mage)
[1766] = 5, -- Kick (Rogue)
[96231] = 4, -- Rebuke (Paladin)
[147362] = 3, -- Counter Shot (Hunter)
[6552] = 4, -- Pummel (Warrior)
[115781] = 6, -- Optical Blast (Warlock)
[47528] = 4, -- Mind Freeze (Death Knight)
[19647] = 6, -- Spell Lock (Warlock)
[173320] = 5, -- Spear Hand Strike (Monk)
[2139] = 6, -- Counterspell (Mage)
[106839] = 4, -- Skull Bash (Druid)
[57994] = 3, -- Wind Shear (Shaman)
[187707] = 3, -- Muzzle (Hunter)
[183752] = 3, -- Consume Magic (Demon Hunter)
}
-- If this is "DBM", DBM's timers will be used. If this is "SW", Blizzard's stopwatch will be used.
local MODE = "DBM"
-- The text to display on DBM Timers.
-- %SPELL% will be replaced with the name of the interrupt spell you cast.
-- %ISPELL% will be replaced with the name of the spell you interrupted
-- %DUR% will be replaced with the duration of the lockout.
local BARTEXT = "%SPELL% interrupted %ISPELL%. Locked out for %DUR% seconds"
-------------------
-- END OF CONFIG --
-------------------
local ARENA1_GUID;
local ARENA2_GUID;
local ARENA3_GUID;
local TARGET_GUID;
local PLAYER_GUID;
local ShowTimer; -- Declare the ShowTimer variable as local
if MODE == "DBM" and DBM then -- If MODE is "DBM" and there's a global variable DBM
local DBM = DBM -- Create a local alias to DBM
local gsubTable = {} -- This table is used to handle text substitutions with gsub
ShowTimer = function(seconds, interruptSpell, interruptedSpell) -- Define the ShowTimer function
gsubTable.SPELL = interruptSpell -- Populate the fields of the table
gsubTable.ISPELL = interruptedSpell
gsubTable.DUR = seconds
local text = BARTEXT:gsub("%%(%a+)%%", gsubTable) -- Replace each occurrence of %SPELL%, %ISPELL% or %DUR% with the corresponding field of gsubTable and assing the result to the text variable
DBM:CreatePizzaTimer(seconds, text) -- Create the timer
end
else -- Either MODE isn't "DBM", or there's no global variable DBM
ShowTimer = function(seconds)
Stopwatch_StartCountdown(0, 0, seconds)
Stopwatch_Play()
end
end
local f = CreateFrame("Frame") -- Create a frame and register some events.
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
f:SetScript("OnEvent", function(self, event, ...) -- Every time an event we're watching fires, call the corresponding method of the frame (e.g. PLAYER_ENTERING_WORLD calls f:PLAYER_ENTERING_WORLD() )
self[event](self, ...)
end)
function f:PLAYER_ENTERING_WORLD() -- This fires towards the end of the intitial login process.
ARENA1_GUID = UnitGUID("arena1") -- Record the arena1 GUID
ARENA2_GUID = UnitGUID("arena2") -- Record the arena2 GUID
ARENA3_GUID = UnitGUID("arena3") -- Record the arena3 GUID
TARGET_GUID = UnitGUID("target") -- Record the Target's GUID
PLAYER_GUID = UnitGUID("player") -- Record the player's GUID
self:UnregisterEvent("PLAYER_ENTERING_WORLD") -- Unregister this event, we don't care about it any more.
end
-- This fires any time someone does something combat-related near the player
function f:COMBAT_LOG_EVENT_UNFILTERED(timestamp, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, ...)
local spellId, spellName, spellSchool, extraSpellID, extraSpellName, extraSchool = ... -- Get the extra arguments from the vararg
local lockout = SPELL_LOCKOUTS[spellId] -- Check if we have a lockout time for this interrupt spell
if lockout then -- If we do, show a timer.
ShowTimer(lockout, spellName, extraSpellName)
end
end
The timer displays but will display whether or not the interrupt actually interrupted a spell. I need it to show the timer ONLY after a spell has been interrupted by one of the spellID's specified in SPELL_LOCKOUTS.
I know that in the last few lines (line 81 through 86) I need to add an and statement but I don't quite know how to phrase it.
Any help would be much appreciated!
I was answered by someone on the game. It needed to be changed from
if lockout then Showtimer
to
if lockout and event=="SPELL_INTERRUPT" then Showtimer
Related
How to create a Roblox game where the player has to guess a randomly generated pin?
So, I've been working on this for the past week. I have tried everything (based on the knowledge I know) and yet nothing... my code didn't work the first time, the second time, the third time... the forth... etc... at the end, I let frustration take control of me and I ended up deleting the whole script. Luckily not the parts and models, otherwise I'm really screwed... I need to create a game in which I have to create a keypad of sorts, at first I thought GUI would work... no, it needs to be SurfaceGUI, which I don't know how to handle well... Anyway, I needed to create a keypad using SurfaceGUI, and display it on a separate screen, as a typical keypad would... The Player would first have to enter an "initial" number, meaning in order to enter the randomly generated number he first needed to input the static pin in order to "log in," after that, then he would try to guess the number... I've literally tried everything I could but nothing... It's mainly because of my lack of experience in LUA, I'm more advanced in Python and barely know a thing in Java... If someone could assist me on how to do this, I would appreciate it greatly
First, download this and put it in a ScreenGui in StarterGui. Then, use the following LocalScript placed inside the PIN frame: -- Script settings local len = 4 -- replace this as needed... local regen = false -- determines whether PIN will regenerate after a failed attempt local regmes = "Enter PIN..." -- start message of PIN pad local badmes = "Wrong PIN!" -- message displayed when PIN is wrong local success = "Correct PIN!" -- message displayed when PIN is right -- Script workings local pin = script.Parent local top = pin.Top local txt = top.Numbers local nums = top.NumKeys local pin local stpin local nms txt.Text = regmes local see = game:GetStorage("ReplicatedStorage").PINActivate local function activate() if pin.Visible then pin.Visible = false for _, btn in pairs(nums:GetChildren()) do btn.Active = false end return else pin.Visible = true for _, btn in pairs(nums:GetChildren()) do btn.Active = true end return end end local function rand() math.randomseed(os.time) -- better random numbers this way return tostring(math.floor(math.random(0,9.9))) end local function gen() nms = {rand()} for i=2, len, 1 do nms[#nms+1]=rand() end stpin = nms[1] for i=2, #nms, 1 do stpin = stpin..nms[i] end pin = tonumber(stpin) -- converts the number string into an actual number end gen() local function activate(str) if tonumber(str) ~= pin then txt.Text = badmes wait(2) txt.Text = regmes if regen then gen() wait(0.1) end return else txt.Text = success wait(2) activate() -- insert code here... end end for _, btn in pairs(nums:GetChildren()) do btn.Activated:Connect(function() if txt.Text == "Wrong PIN!" then return end txt.Text = txt.Text..btn.Text if string.len(txt.Text) >= len then activate(txt.Text) end wait(0.1) end) end see.OnClientEvent:Connect(activate) And in a Script put this: local Players = game:GetService("Players") local see = game:GetService("ReplicatedStorage").PINActivate local plr -- replace Event with something like Part.Touched Event:Connect(function(part) if part.Parent.Head then plr = Players:GetPlayerFromCharacter(part.Parent) see:FireClient(plr) end end) What this will do is bring up a ScreenGui for only that player so they can enter the PIN, and they can close it as well. You can modify as needed; have a great day! :D
There is an easier way, try this First, Create a GUI in StarterGui, then, Create a textbox and postion it, after that, create a local script inside and type this. local Password = math.random(1000, 9999) print(Password) game.ReplicatedStorage.Password.Value = Password script.Parent.FocusLost:Connect(function(enter) if enter then if script.Parent.Text == tostring(Password) then print("Correct!") script.Parent.BorderColor3 = Color3.new(0, 255, 0) Password = math.random(1000, 9999) game.ReplicatedStorage.Correct1:FireServer() print(Password) game.ReplicatedStorage.Password.Value = Password else print("wrong!") print(script.Parent.Text) script.Parent.BorderColor3 = Color3.new(255, 0, 0) end end end) That's all in the textbox. Or if you want a random username script, create a textlabel, then, create a local script in the textlabel and type in this. local UserText = script.Parent local Username = math.random(1,10) while true do if Username == 1 then UserText.Text = "John" elseif Username == 2 then UserText.Text = "Thomas" elseif Username == 3 then UserText.Text = "Raymond" elseif Username == 4 then UserText.Text = "Ray" elseif Username == 5 then UserText.Text = "Tom" elseif Username == 6 then UserText.Text = "Kai" elseif Username == 7 then UserText.Text = "Lloyd" elseif Username == 8 then UserText.Text = "Jay" elseif Username == 9 then UserText.Text = "User" else UserText.Text = "Guest" end wait() end All of those if statments are checking what username has been chosen. I have made a roblox game like this recently, so I just took all the script from the game. If you want to check out my game, Click Here
Can I use Tarantool instead of Redis?
I'd like to use Tarantool to store data. How can I store data with TTL and simple logic (without the spaces)? Like this: box:setx(key, value, ttl); box:get(key)
Yes, you can expire data in Tarantool and in a much more flexible way than in Redis. Though you can't do this without spaces, because space is a container for data in Tarantool (like database or table in other database systems). In order to expire data, you have to install expirationd tarantool rock using tarantoolctl rocks install expirationd command. Full documentation on expirationd daemon can be found here. Feel free to use a sample code below: #!/usr/bin/env tarantool package.path = './.rocks/share/tarantool/?.lua;' .. package.path local fiber = require('fiber') local expirationd = require('expirationd') -- setup the database box.cfg{} box.once('init', function() box.schema.create_space('test') box.space.test:create_index('primary', {parts = {1, 'unsigned'}}) end) -- print all fields of all tuples in a given space local print_all = function(space_id) for _, v in ipairs(box.space[space_id]:select()) do local s = '' for i = 1, #v do s = s .. tostring(v[i]) .. '\t' end print(s) end end -- return true if tuple is more than 10 seconds old local is_expired = function(args, tuple) return (fiber.time() - tuple[3]) > 10 end -- simply delete a tuple from a space local delete_tuple = function(space_id, args, tuple) box.space[space_id]:delete{tuple[1]} end local space = box.space.test print('Inserting tuples...') space:upsert({1, '0 seconds', fiber.time()}, {}) fiber.sleep(5) space:upsert({2, '5 seconds', fiber.time()}, {}) fiber.sleep(5) space:upsert({3, '10 seconds', fiber.time()}, {}) print('Tuples are ready:\n') print_all('test') print('\nStarting expiration daemon...\n') -- start expiration daemon -- in a production full_scan_time should be bigger than 1 sec expirationd.start('expire_old_tuples', space.id, is_expired, { process_expired_tuple = delete_tuple, args = nil, tuples_per_iteration = 50, full_scan_time = 1 }) fiber.sleep(5) print('\n\n5 seconds passed...') print_all('test') fiber.sleep(5) print('\n\n10 seconds passed...') print_all('test') fiber.sleep(5) print('\n\n15 seconds passed...') print_all('test') os.exit()
Effect not showing up on guis
I'm making an effect in my game where it scrolls through some choices and slows down to a stop on one choice. There's 4 screens and I want each one to play the effect simultaneously, all the guis show up at the same time but the effect never plays. I've marked the part of the code that does the effect in the block of code below: message.chooseduel = function(spins) local lobby=workspace.Lobby local screens=lobby.Screens local n1,n2 for _, screen in pairs(screens:GetChildren()) do local gui=screen.SurfaceGui local ds=gui.DuelScreen gui.Enabled=true for i, v in pairs(ds.Container:GetChildren()) do local ll local lastpicked local t = ds.Container:GetChildren() local menuItems = #t -- number of menu items local repeats = 1 -- Repeated for R = 65 + spins, 1, -1 do ll = t[repeats] if ll:IsA("GuiObject") then --**effect**-- local newgui = coroutine.wrap(function() print("HI!") ll.BackgroundColor3=Color3.fromRGB(130, 125, 56) wait( R^-.7*.7 ) -- ll.BackgroundColor3=ll.BorderColor3 repeats = repeats % menuItems + 1 end) newgui() --**effect**-- end end ll = t[repeats] ll.BackgroundColor3=Color3.fromRGB(230, 225, 156) n1=string.sub(ll.n1.Image,64) n2=string.sub(ll.n2.Image,64) print("Returning:",n1,n2) end end wait(2) return {n1,n2} end
Hope this helps: message.chooseduel = function(spins) spins = math.ceil(spins) -- just making sure. local lobby=workspace.Lobby local screens=lobby.Screens local n1,n2 for _, screen in pairs(screens:GetChildren()) do local gui=screen.SurfaceGui local ds=gui.DuelScreen gui.Enabled=true spawn(function() -- I think this is where the coroutine / async function should start local ll local lastpicked -- Variable not used local t = ds.Container:GetChildren() local numMenuItems = #t -- number of menu items local current = 1 -- Repeated print("HI!") for R = 65 + spins, 1, -1 do ll = t[current] if ll:IsA("GuiObject") then ll.BackgroundColor3=Color3.fromRGB(130, 125, 56) wait( R^-.7*.7 ) -- ll.BackgroundColor3=ll.BorderColor3 current = current % numMenuItems + 1 end end print("BYE!") ll = t[current] ll.BackgroundColor3=Color3.fromRGB(230, 225, 156) n1=string.sub(ll.n1.Image,64) -- um... Interesting. wait what? n2=string.sub(ll.n2.Image,64) print("Returning:",n1,n2) end) end wait(2) return {n1,n2} end I'm not sure I totally get what you are doing here or how you have things set up, but in general you should try to move coroutines / spawned functions to the outsides of loops.
Join tiles in Corona SDK into one word for a Breakout game grid?
I have a game project to re-implement Breakout. I want to display two words, each word on a line. They are joined by the bricks block. Inside, the top line is the first name, aligned left. The bottom line is the last name, aligned right. They are input from textboxes, and rendered as shown: Each second that passes, the screen will add a configurable number of bricks to the grid (for example, five bricks per second) until the two words appear complete. I displayed a letter of the alphabet which is created from the matrix(0,1). ...But I don’t know how to join them into one word. How can I join these letters? This is what I've gotten so far: Bricks.lua local Bricks = display.newGroup() -- static object local Events = require("Events") local Levels = require("Levels") local sound = require("Sound") local physics = require("physics") local Sprites = require("Sprites") local Func = require("Func") local brickSpriteData = { { name = "brick", frames = {Sprites.brick} }, { name = "brick2", frames = {Sprites.brick2} }, { name = "brick3", frames = {Sprites.brick3} }, } -- animation table local brickAnimations = {} Sprites:CreateAnimationTable { spriteData = brickSpriteData, animationTable = brickAnimations } -- get size from temp object for later use local tempBrick = display.newImage('red_apple_20.png',300,500) --local tempBrick = display.newImage('cheryGreen2.png',300,500) local brickSize = { width = tempBrick.width, height = tempBrick.height } --tempBrick:removeSelf( ) ---------------- -- Rubble -- needs to be moved to its own file ---------------- local rubbleSpriteData = { { name = "rubble1", frames = {Sprites.rubble1} }, { name = "rubble2", frames = {Sprites.rubble2} }, { name = "rubble3", frames = {Sprites.rubble3} }, { name = "rubble4", frames = {Sprites.rubble4} }, { name = "rubble5", frames = {Sprites.rubble5} }, } local rubbleAnimations = {} Sprites:CreateAnimationTable { spriteData = rubbleSpriteData, animationTable = rubbleAnimations } local totalBricksBroken = 0 -- used to track when level is complete local totalBricksAtStart = 0 -- contains all brick objects local bricks = {} local function CreateBrick(data) -- random brick sprite local obj = display.newImage('red_apple_20.png') local objGreen = display.newImage('cheryGreen2.png') obj.name = "brick" obj.x = data.x --or display.contentCenterX obj.y = data.y --or 1000 obj.brickType = data.brickType or 1 obj.index = data.index function obj:Break() totalBricksBroken = totalBricksBroken + 1 bricks[self.index] = nil obj:removeSelf( ) sound.play(sound.breakBrick) end function obj:Update() if(self == nil) then return end if(self.y > display.contentHeight - 20) then obj:Break() end end if(obj.brickType ==1) then physics.addBody( obj, "static", {friction=0.5, bounce=0.5 } ) elseif(obj.brickType == 2) then physics.addBody( objGreen,"static",{friction=0.2, bounce=0.5, density = 1 } ) end return obj end local currentLevel = testLevel -- create level from bricks defined in an object -- this allows for levels to be designed local function CreateBricksFromTable(level) totalBricksAtStart = 0 local activeBricksCount = 0 for yi=1, #level.bricks do for xi=1, #level.bricks[yi] do -- create brick? if(level.bricks[yi][xi] > 0) then local xPos local yPos if(level.align == "center") then --1100-((99*16)*0.5) xPos = display.contentCenterX- ((level.columns * brickSize.width) * 0.5/3) + ((xi-1) * level.xSpace)--display.contentCenterX --xPos = 300 +(xi * level.xSpace) yPos = 100 + (yi * level.ySpace)--100 else xPos = level.xStart + (xi * level.xSpace) yPos = level.yStart + (yi * level.ySpace) end local brickData = { x = xPos, y = yPos, brickType = level.bricks[yi][xi], index = activeBricksCount+1 } bricks[activeBricksCount+1] = CreateBrick(brickData) activeBricksCount = activeBricksCount + 1 end end end totalBricks = activeBricksCount totalBricksAtStart = activeBricksCount end -- create bricks for level --> set from above functions, change function to change brick build type local CreateAllBricks = CreateBricksFromTable -- called by a timer so I can pass arguments to CreateAllBricks local function CreateAllBricksTimerCall() CreateAllBricks(Levels.currentLevel) end -- remove all brick objects from memory local function ClearBricks() for i=1, #bricks do bricks[i] = nil end end -- stuff run on enterFrame event function Bricks:Update() -- update individual bricks if(totalBricksAtStart > 0) then for i=1, totalBricksAtStart do -- brick exists? if(bricks[i]) then bricks[i]:Update() end end end -- is level over? if(totalBricksBroken == totalBricks) then Events.allBricksBroken:Dispatch() end end ---------------- -- Events ---------------- function Bricks:allBricksBroken(event) -- cleanup bricks ClearBricks() local t = timer.performWithDelay( 1000, CreateAllBricksTimerCall) --CreateAllBricks() totalBricksBroken = 0 -- play happy sound for player to enjoy sound.play(sound.win) print("You Win!") end Events.allBricksBroken:AddObject(Bricks) CreateAllBricks(Levels.currentLevel) return Bricks Levels.lua local Events = require("Events") local Levels = {} local function MakeLevel(data) local level = {} level.xStart = data.xStart or 100 level.yStart = data.yStart or 100 level.xSpace = data.xSpace or 23 level.ySpace = data.ySpace or 23 level.align = data.align or "center" level.columns = data.columns or #data.bricks[1] level.bricks = data.bricks --> required return level end Levels.test4 = MakeLevel { bricks = { {0,2,0,0,2,0,0,2,0}, {0,0,2,0,2,0,2,0,0}, {0,0,0,0,2,0,0,0,0}, {1,1,2,1,1,1,2,1,1}, {0,0,0,0,1,0,0,0,0}, {0,0,0,0,1,0,0,0,0}, {0,0,0,0,1,0,0,0,0}, } } Levels.test5 = MakeLevel { bricks = { {0,0,0,1,0,0,0,0}, {0,0,1,0,1,0,0,0}, {0,0,1,0,1,0,0,0}, {0,1,0,0,0,1,0,0}, {0,1,1,1,1,1,0,0}, {1,0,0,0,0,0,1,0}, {1,0,0,0,0,0,1,0}, {1,0,0,0,0,0,1,0}, {1,0,0,0,0,0,1,0} } } -- Levels.test6 = MakeLevel2 -- { -- bricks = -- { ----A "a" = {{0,0,0,1,0,0,0,0}, -- {0,0,1,0,1,0,0,0}, -- {0,0,1,0,1,0,0,0}, -- {0,1,0,0,0,1,0,0}, -- {0,1,1,1,1,1,0,0}, -- {1,0,0,0,0,0,1,0}, -- {1,0,0,0,0,0,1,0}, -- {1,0,0,0,0,0,1,0}, -- {1,0,0,0,0,0,1,0}}, ----B -- "b" = {{1,1,1,1,0,0,0}, -- {1,0,0,0,1,0,0}, -- {1,0,0,0,1,0,0}, -- {1,0,0,0,1,0,0}, -- {1,1,1,1,0,0,0}, -- {1,0,0,0,1,0,0}, -- {1,0,0,0,0,1,0}, -- {1,0,0,0,0,1,0}, -- {1,1,1,1,1,0,0}}, --........... --....... --... -- --Z -- "z"= {{1,1,1,1,1,1,1,0}, -- {0,0,0,0,0,1,0,0}, -- {0,0,0,0,1,0,0,0}, -- {0,0,0,0,1,0,0,0}, -- {0,0,0,1,0,0,0,0}, -- {0,0,1,0,0,0,0,0}, -- {0,0,1,0,0,0,0,0}, -- {0,1,0,0,0,0,0,0}, -- {1,1,1,1,1,1,1,0}} -- } -- } -- stores all levels in ordered table so that one can be selected randomly by index Levels.levels = { --Levels.test4, Levels.test5 -- Levels.test6, } function Levels:GetRandomLevel() return self.levels[math.random(#Levels.levels)] end Levels.notPlayedYet = {} Levels.currentLevel = Levels:GetRandomLevel() -- Events function Levels:allBricksBroken(event) self.currentLevel = Levels:GetRandomLevel() end Events.allBricksBroken:AddObject(Levels) return Levels The work I've done thus far (same as above) as an external download: http://www.mediafire.com/download/1t89ftkbznkn184/Breakout2.rar
In the interest of actually answering the question: I'm not 100% sure what you mean by "How can I join these letters", but from poking through the code I have a guess, so please clarify on whether it is accurate, or if I am wrong about what you wanted. Scenario 1 You haven't successfully achieved the image illustrated in the screenshot - you've been able to draw one letter, but not multiple ones. In this case, you'll need to have a better understanding of what your code is doing. The CreateBricksFromTable function takes in a Level object, which is created by the MakeLevel function from a table with a bricks property, which is a table of tables that represent rows with columns in them, showing what type of brick should be at each position. In your commented-out level, you have created an table where the bricks field contains a field for each letter, but the MakeLevel function still expects a bricks field that directly contains the grid of blocks. You will have to - as it seems you attempted - create a MakeWordLevel function (or the like) that takes this letter list, and a word for each line, and constructs a larger grid by copying the appropriate letters into it. StackOverflow is not your programming tutor, and an SO question is not the right forum for having people write code for you or getting into step-by-step details of how to do this, but I'll leave you a basic outline. Your function would look something like this: local function MakeWordLevel(data, line1, line2) local level = {} ... return level end And then would have to: Populate all of the same properties that MakeLevel does Calculate how wide (level.columns) the level should be with all the letters Create a table in the same format as the bricks properties, but big enough to hold all of the letters Go through the input strings (line1 and line2), find the correct letter data from what is now the test6 array, and copy that data into the large table Assign that table as level.bricks This question already is a bit outside of what StackOverflow is intended for in that it asks about how to implement a feature rather than achieve a small, specific programming task, so any further followup should take place in a chatroom - perhaps the Hello World room would be helpful. Scenario 2: This was my original guess, but after considering and reading past edits, I doubt this is answering the right question You may want a solid "background" of, say, red blocks, surrounding your letters and making the field into a solid "wall", with the name in a different color. And you may want these bricks to slowly show up a few at a time. In that case, the main thing you need to do is keep track of what spaces are "taken" by the name bricks. There are many ways to do this, but I would start with a matrix to keep track of that - as big as the final playing field - full of 0's. Then, as you add the bricks for the name, set a 1 at the x,y location in that matrix according to that block's coordinate. When you want to fill in the background, each time you go to add a block at a coordinate, check that "taken" matrix before trying to add a block - if it's taken (1), then just skip it and move onto the next coordinate. This works if you're filling in the background blocks sequentially (say, left to right, top to bottom), or if you want to add them randomly. With random, you'd also want to keep updating the "taken" matrix so you don't try to add a block twice. The random fill-in, however, presents its own problem - it will keep taking longer to fill in as it goes, because it'll find more and more "taken" blocks and have to pick a new one. There are solutions to this, of course, but I won't go too far down that road when I don't know if that's even what you want.
I don't really understand (or read, for that matter) your code but from what I see joining them into complete words is easy. You have two possibilities. You can "render" them directly into your level/display data, simply copy them to the appropriate places, like this: -- The level data. local level = {} -- Create the level data. for row = 1, 25, 1 do local rowData = {} for column = 1, 80, 1 do rowData[column] = "." end level[row] = rowData end -- Now let us setup the letters. local letters = { A = { {".",".",".","#",".",".",".","."}, {".",".","#",".","#",".",".","."}, {".",".","#",".","#",".",".","."}, {".","#",".",".",".","#",".","."}, {".","#","#","#","#","#",".","."}, {"#",".",".",".",".",".","#","."}, {"#",".",".",".",".",".","#","."}, {"#",".",".",".",".",".","#","."}, {"#",".",".",".",".",".","#","."} }, B = { {"#","#","#","#",".",".","."}, {"#",".",".",".","#",".","."}, {"#",".",".",".","#",".","."}, {"#",".",".",".","#",".","."}, {"#","#","#","#",".",".","."}, {"#",".",".",".","#",".","."}, {"#",".",".",".",".","#","."}, {"#",".",".",".",".","#","."}, {"#","#","#","#","#",".","."} } } -- The string to print. local text = "ABBA" -- Let us insert the data into the level data. for index = 1, #text, 1 do local char = string.sub(text, index, index) local charData = letters[char] local offset = index * 7 for row = 1, 9, 1 do local rowData = charData[row] for column = 1, 7, 1 do level[row][offset + column] = rowData[column] end end end -- Print everything for row = 1, 25, 1 do local rowData = level[row] for column = 1, 80, 1 do io.write(rowData[column]) end print() end You save you letters in a lookup table and then copy them, piece by piece, to the level data. Here I replaced the numbers with dots and number signs to make it prettier on the command line. Alternately to that you can also "render" the words into a prepared buffer and then insert that into the level data by using the same logic.
Making variables persistent after a restart on NodeMCU
I'm making a smart home system using nodeMCU, and I need to store and retrieve data from the module. I used the following function. function save_settings(name,value) file.remove(name) file.open(name,"w+") file.writeline(value) file.close() end It works but it's slow and the NodeMCU crashes if I trigger the above function rapidly... Sometimes requiring a FS format to be able to use it again. So my question is: is there any other way to make variables persistent between restarts?
I'm using the latest firmware, 0.9.6-dev_20150704, the float version (https://github.com/nodemcu/nodemcu-firmware/releases) This code took 62-63 ms to complete at first, and seems to add a few fractions of a millisecond with each successive run of the code, after a few hundred executions, it was up to almost 100 ms. It never crashed on me. function save_setting(name, value) file.open(name, 'w') -- you don't need to do file.remove if you use the 'w' method of writing file.writeline(value) file.close() end function read_setting(name) if (file.open(name)~=nil) then result = string.sub(file.readline(), 1, -2) -- to remove newline character file.close() return true, result else return false, nil end end startTime = tmr.now() test1 = 1200 test2 = 15.7 test3 = 75 test4 = 15000001 save_setting('test1', test1) save_setting('test2', test2) save_setting('test3', test3) save_setting('test4', test4) 1exists, test1 = read_setting('test1') 2exists, test2 = read_setting('test2') 3exists, test3 = read_setting('test3') 4exists, test4 = read_setting('test4') completeTime = (tmr.now()-startTime)/(1000) print('time to complete (ms):') print(tostring(completeTime))
If you upgrade to the newer version (based on SDK 1.4.0) you can use the rtcmem memory slots: local offset = 10 local val = rtcmem.read32(offset, 1) rtcmem.write32(offset, val + 1) That memory is documented to persist through a deep sleep cycle; I've found it to persist across both hardware and software resets (but not cycling power.)