Looping everything between two objects in a list - lua

I'm working on a block coding engine in Roblox, I have some blocks made like move, change size and rotate. But I can't figure out how to make a loop, I have to find every item between two items in a for i,v in pairs loop.
for i, block in pairs(script.Parent.Parent.Script:GetChildren()) do
wait(0.1)
if block.Value == "MoveX" then
game.Character.Position = UDim2.new(game.Character.Position.X.Scale, (game.Character.Position.X.Offset + block.EpicValue.Value), game.Character.Position.X.Scale, game.Character.Position.Y.Offset)
end
if block.Value == "MoveY" then
game.Character.Position = UDim2.new(game.Character.Position.X.Scale, game.Character.Position.X.Offset, game.Character.Position.X.Scale, (game.Character.Position.Y.Offset + block.EpicValue.Value))
end
if block.Value == "Rotate" then
game.Character.Rotation = game.Character.Rotation + block.EpicValue.Value
end
if block.Value == "SizeX" then
game.Character.Size = UDim2.new(game.Character.Size.X.Scale, math.abs(block.EpicValue.Value), game.Character.Size.X.Scale, game.Character.Size.Y.Offset)
end
if block.Value == "SizeY" then
game.Character.Size = UDim2.new(game.Character.Size.X.Scale, game.Character.Size.X.Offset, game.Character.Size.Y.Scale, math.abs(block.EpicValue.Value))
end
if block.Value == "LoopStart" then
-- start loop
end
end

Instead of a foreach loop, use a while loop. Then you can easily convert this while loop into a state machine:
local i = 1
local instructions = script.Parent.Parent.Script:GetChildren()
while i < #instructions do
-- fetch current instruction
local block = instructions[i]
if block.Value == "MoveX" then
--...
elseif block.Value == "LoopStart" then
if not insertYourLoopCondition then
i = instructionIndexOfLoopEnd
end
elseif block.Value == "LoopEnd" then
i = instructionIndexOfLoopStart - 1
end
-- next instruction
i = i + 1
end
In words: you need jumps. A loop consists of a condition and a "jump" at the end to return to the condition.
A condition is a "conditional jump".
When generating your blocks you need to gather the target indices of all jumps once.

Related

GMOD Lua Player death causing game to crash

I'm working on a FFA gamemode in Garry's mod where players have to survive each other and a nextbot NPC hunting them. My override of the GM:PlayerDeath adequately indicates when the current round should be over, however after SpawnGhoulInitial() is called, any deaths cause the game to crash. Im doing all this round stuff in my roundsystem_2.lua file:
-- GLOBAL VALUES
roundActive = false
roundCountdownStartTime = 0
roundStartTime = 0
phase = 1
countDownLength = 5
initialGhoulDelay = 10
spawnWepDelay = 15
ghoulMadnessDelay = 20
roundLength = 30
DEFINE_BASECLASS( "gamemode_base" )
-- vector list dictionary of nexbot spawn locations per map, starting with initial spawn location
nextbot_spawns = {gm_backrooms_classic = {Vector(-7413, 318, 93), Vector(-4270, 4079, 93), Vector(-3279, -4620, 93), Vector(-11092, -4632, 93), Vector(-11086, 4316, 93)}}
function GM:UpdateTimer(time)
net.Start("round_timer")
net.WriteInt(time, 10)
net.Broadcast()
end
-- function used to spawn the first ghoul of the round
function SpawnGhoulInitial()
local name = RandomizeNextbot()
local Ent = ents.Create(name)
if( !IsValid(Ent)) then
print("entity is not valid.")
return
end
Ent:SetPos(nextbot_spawns.gm_backrooms_classic[1])
Ent:Spawn()
print("Spawned ghoul ".. name)
PrintMessage(4, "The Ghoul has spawned. SURVIVE!")
end
-- function called to spawn the next four ghouls to sweep the map and kill off straggling players
function SpawnGhoulMadness()
local name = RandomizeNextbot()
local Ent = ents.Create(name)
if( !IsValid(Ent)) then
print("entity is not valid.")
return
end
for i=2, 5 do
Ent:SetPos(nextbot_spawns.gm_backrooms_classic[i])
Ent:Spawn()
print("Spawned ghoul madness ghoul number ".. tostring(i))
end
PrintMessage(4, "The Ghoul has summoned some friends. RUN!")
end
-- function called to spawn in weapons for the players
function SpawnWeps()
for k, v in pairs(player.GetAll()) do
if (v:Alive()) then
v:Give("weapon_crowbar", false)
v:Give("weapon_pistol", false)
end
end
PrintMessage(4, "You've found supplies. Kill other survivors!")
end
function CountAlivePlayers()
local players = player.GetAll()
local alive = 0
for i = 1, #players do
local player = players[i]
if (player:Alive()) then
alive = alive + 1
end
end
return alive
end
-- function called to give us a random nextbot to spawn in
function RandomizeNextbot()
local names = {"table of nextbot names here, not posting them for stackoverflow because its embarrassing"}
local random_nextbot = math.random(#names)
return names[random_nextbot]
end
-- function called under the conditions that the round has ended, will start the next round.
function GM:EndRound(winner)
-- clear the map, clear sounds, print winner on screen, allow the respawning
if (winner == nil) then
PrintMessage(4, "Nobody Wins!")
else
PrintMessage(4, winner:Nick().." Wins!")
end
game.CleanUpMap(false, {})
RunConsoleCommand("stopsound")
timer.Remove("RoundTimer")
timer.Create("roundEndTimer", 5, 1, function()
for k, v in pairs(player.GetAll()) do
if (v:Alive()) then
v:StripWeapons()
v:KillSilent()
end
end
net.Start("round_active")
net.WriteBool(false)
net.Broadcast()
roundActive = false
end)
end
function GM:StartCountDownTimer(repetitions)
self:UpdateTimer(repetitions)
timer.Create("CountdownTimer", 1, repetitions, function()
repetitions = repetitions - 1
self:UpdateTimer(repetitions)
end)
end
function GM:StartRoundTimer(repetitions)
self:UpdateTimer(repetitions)
timer.Create("RoundTimer", 1, repetitions, function()
repetitions = repetitions - 1
self:UpdateTimer(repetitions)
if (repetitions <= 0) then
self:EndRound(nil)
end
end)
end
--overriding playerdeath function for best death results
function GM:PlayerDeath(victim, inflictor, attacker)
BaseClass.PlayerDeath(self, victim, inflictor, attacker)
local players = player.GetAll()
local lastAlive = NULL
for i = 1, #players do
local p = players[i]
if (p:Alive()) then
lastAlive = p
end
end
if (CountAlivePlayers() <= 1 && roundActive) then
self:EndRound(lastAlive)
end
end
-- hook for starting the round on player spawn if there are enough players.
-- countdown for round start will restart if a new player spawns in during the countdown.
function GM:DoRoundSpawn()
--every time player joins reset the countdown
if (CountAlivePlayers() > 1) then
roundCountdownStartTime = CurTime()
self:StartCountDownTimer(countDownLength)
end
end
-- The main timing of the round. Checks against curtime to find when
-- specific events in the round need to happen.
function GM:Think()
-- if there is more than one player, and the time elapsed is a full 30 sec, start round
if (CountAlivePlayers() > 1 && roundActive == false) then
if ((roundCountdownStartTime + countDownLength) < CurTime()) then
roundStartTime = CurTime()
roundActive = true
phase = 1
net.Start("round_active")
net.WriteBool(true)
net.Broadcast()
timer.Remove("CountdownTimer")
self:StartRoundTimer(roundLength)
PrintMessage(4, "The Round has begun. Last player to survive wins!")
end
end
-- if the round is active, do this stuff
if (roundActive == true) then
-- if its been 10 sec since round start, spawn the ghoul
if ((roundStartTime + initialGhoulDelay) < CurTime() && phase == 1) then
SpawnGhoulInitial()
phase = 2
end
-- if its been 30 sec since round start, spawn in weapons for players
if((roundStartTime + spawnWepDelay) < CurTime() && phase == 2) then
SpawnWeps()
phase = 3
end
-- if its been 120 sec (2 minutes) since round start, begin the ghoul madness
if((roundStartTime + ghoulMadnessDelay) < CurTime() && phase == 3) then
SpawnGhoulMadness()
phase = 4
end
end
end
However, I do call my GM:DoRoundSpawn function in my init.lua file:
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
include("roundsystem_2.lua")
util.AddNetworkString("round_timer")
util.AddNetworkString("round_active")
roundActive = false
playerSpawns = {--table of spawnpoints, too much to paste for stackoverflow}
function GM:PlayerSpawn(ply)
ply:SetGravity(.85)
ply:SetMaxHealth(100)
ply:SetupHands()
ply:SetWalkSpeed(250)
ply:SetRunSpeed(450)
ply:SetModel("models/player/Kleiner.mdl")
local random_spawn = math.random(#playerSpawns)
ply:SetPos(playerSpawns[random_spawn])
--this section basically will make it so if someone spawns
--in while the round is active, they will stay dead until
--the round is no longer active
print("Player: " .. ply:GetName() .. " has spawned!")
if (roundActive == true) then
ply:KillSilent()
return
end
self:DoRoundSpawn()
end
function GM:PlayerDeathThink(ply)
if (roundActive == false) then
ply:Spawn()
return true
else
return false
end
end
I've combed through both of these files a couple times over and I cant for the life of me figure out why deaths don't break the game until after the nextbot spawn happens. Is there something here I'm missing?

Lua Scripts disabling each other in Roblox Studio

I'm trying to make a game in Roblox (a tycoon) and, considering it's my first time making a game, I'm using some pre-made scripts and models along with youtube tutorials. My problem right now is that I have two scripts, both under the same name, DevProductHandler, (I've tried changing their names but the problem still persists) and it seems like only one will run at a time whenever I test the game. Disabling one script allows the other to run perfectly fine, and enabling both causes only one script to work, randomly picking which one will run each time.
One of the scripts is meant to control purchasing products that are prompted from a GUI, and the other controls purchases prompted from tycoon buttons that you walk on top of. I've tried merging the scripts by copy-pasting one underneath the other, but it still only makes the GUI DevProductHandler script work. I don't know if there are some overlapping variables or something that would cause one script to not allow the other to run, but I think that's most likely the issue, although I'm not sure how to go about fixing that I'm new at Lua and game creation so I was wondering if anyone could help me find out the issue. These are the scripts.
local Tycoon = script.Parent.Tycoons:GetChildren()[1]
script.Parent = game.ServerScriptService
local DevProducts = {}
local MarketplaceService = game:GetService('MarketplaceService')
for i,v in pairs(Tycoon:WaitForChild('Buttons'):GetChildren()) do
if v:FindFirstChild('DevProduct') then
if v.DevProduct.Value > 0 then
DevProducts[v.DevProduct.Value] = v -- the button
end
end
end
MarketplaceService.ProcessReceipt = function(receiptInfo)
for i,plr in pairs(game.Players:GetPlayers()) do
if plr.userId == receiptInfo.PlayerId then
if DevProducts[receiptInfo.ProductId] then
local obj = DevProducts[receiptInfo.ProductId]
local PlrT = game.ServerStorage.PlayerMoney:WaitForChild(plr.Name).OwnsTycoon
if PlrT.Value ~= nil then
--if PlrT.Value.PurchasedObjects:FindFirstChild(obj.Object.Value) == false then
local PlayerStats = game.ServerStorage.PlayerMoney:FindFirstChild(plr.Name)
Create({[1] = 0,[2] = obj,[3] = PlayerStats}, PlrT.Value.BuyObject)
--end
end
end
end
end
end
function Create(tab, prnt)
local x = Instance.new('Model')
Instance.new('NumberValue',x).Value = tab[1]
x.Value.Name = "Cost"
Instance.new('ObjectValue',x).Value = tab[2]
x.Value.Name = "Button"
local Obj = Instance.new('ObjectValue',x)
Obj.Name = "Stats"
Obj.Value = tab[3]
x.Parent = prnt
end
Above is the script for prompts from walking over buttons.
old_fog = game.Lighting.FogStart
local MarketplaceService = game:GetService("MarketplaceService")
function getPlayerFromId(id)
for i,v in pairs(game.Players:GetChildren()) do
if v.userId == id then
return v
end
end
return nil
end
MarketplaceService.ProcessReceipt = function(receiptInfo)
local productId = receiptInfo.ProductId
local playerId = receiptInfo.PlayerId
local player = getPlayerFromId(playerId)
local productName
if productId == 1172271849 then
local cashmoney = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
if cashmoney then
cashmoney.Value = cashmoney.Value + 10000
end
elseif productId == 1172270951 then
local cashmoney = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
if cashmoney then
cashmoney.Value = cashmoney.Value + 100000
end
elseif productId == 1172270763 then
local cashmoney = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
if cashmoney then
cashmoney.Value = cashmoney.Value + 1000000
end
elseif productId == 1172272327 then
local cashmoney = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
if cashmoney then
cashmoney.Value = cashmoney.Value + cashmoney.Value
end
elseif productId == 1172273117 then
local char = player.Character
if char then
local human = char:FindFirstChild("Humanoid")
if human then
human.WalkSpeed = human.WalkSpeed + human.WalkSpeed
end
end
elseif productId == 1172273437 then
game.ServerStorage.HyperlaserGun:Clone().Parent=player.Backpack
elseif productId == 1172272691 then
game.ServerStorage.FlyingCarpet:Clone().Parent=player.Backpack
end
return Enum.ProductPurchaseDecision.PurchaseGranted
end
Above is the script for purchases from a GUI prompt.
From the Roblox manual:
As with all callbacks, this function should be set once and only once
by a single Script. If you're selling multiple products in your game,
this callback must handle receipts for all of them.
You're implementing game:GetService('MarketplaceService').ProcessReceipt in both scripts. One overwrite the other.

How to Put Data Into a Table From an Existing File

I have a program for a turtle in ComputerCraft that is meant to be a storage unit. I input an item, and it should read a file to find where to put the item. If there is a new item, it adds the information to a file.
When I do
blockTypes = {}
local file = fs.open(blockTable","r")
line = file.readAll()
table.insert(blockTypes,line)
file.close()
The information gets put in as a string. This means that I can't do
print(blockTypes[1][1])
And recieve the value that would normally be in that position.
Here's my code:
blockAmount = 3
highestVal = {2,0,5}
blockTypes = {}
function addBlock()
local file = fs.open("blockTable", "a")
file.write(name)
file.write(" = {")
file.write(highestVal[1])
file.write(",")
file.write(highestVal[2])
file.write(",")
file.write(highestVal[3])
file.writeLine("};")
file.close()
end
function getBlock()
local file = fs.open("blockTable","r")
line = file.readAll()
table.insert(blockTypes,line)
file.close()
end
--This was used to test before implementing the new file system that I am trying to get to work
blockTypesOld = {
log = {2.0,0,1};
dirt = {2,0,2};
cobblestone = {2,0,3};
iron_ingot = {2,0,4};
planks = {2,0,5};
}
pos = {0,0,0}
looking = 0
function fuel()
if turtle.getFuelLevel() < 20 then
turtle.select(16)
turtle.refuel(1)
end
end
function left()
turtle.turnLeft()
looking = looking - 1
if looking < 0 then
looking = 3
end
end
function right()
turtle.turnRight()
looking = looking + 1
if looking > 3 then
looking = 0
end
end
function forward()
fuel()
if turtle.forward() then
if looking == 0 then
pos[1] = pos[1] - 1
elseif looking == 1 then
pos[3] = pos[3] - 1
elseif looking == 2 then
pos[1] = pos[1] + 1
elseif looking == 3 then
pos[3] = pos[3] + 1
else
end
end
end
function up()
fuel()
turtle.up()
pos[2] = pos[2] + 1
end
function down()
fuel()
turtle.down()
pos[2] = pos[2] - 1
end
function goHome()
while pos[3] > 0 do
while looking > 1 do
left()
end
forward()
end
while pos[2] > 0 do
down()
end
while pos[1] > 0 do
while looking > 0 do
left()
end
forward()
end
end
function goTo(a,b,c)
goHome()
while looking < 2 or looking > 2 do
right()
end
for i = pos[1],a do
forward()
end
while looking > 3 or looking < 3 do
right()
end
for i = pos[3],c do
forward()
end
for i = pos[2],b do
up()
end
while looking < 2 or looking > 2 do
left()
end
end
while true do
turtle.select(15)
while not turtle.suck() do
sleep(1)
end
itemDetails = turtle.getItemDetail()
--Finding what mod item is from and removing corresponding labels--
--EX: "minecraft:log" becomes "log"
if itemDetails.name:match("^ae2stuff:(.+)$") then
name = itemDetails.name:match("^ae2stuff:(.+)$")
elseif itemDetails.name:match("^minecraft:(.+)$") then
name = itemDetails.name:match("^minecraft:(.+)$")
elseif itemDetails.name:match("^appliedenergistics2:(.+)$") then
name = itemDetails.name:match("^appliedenergistics2:(.+)$")
elseif itemDetails.name:match("^buildcraftbuilders:(.+)$") then
name = itemDetails.name:match("^buildcraftbuilders:(.+)$")
elseif itemDetails.name:match("^forge:(.+)$") then
name = itemDetails.name:match("^forge:(.+)$")
elseif itemDetails.name:match("^buildcraftenergy:(.+)$") then
name = itemDetails.name:match("^buildcraftenergy:(.+)$")
elseif itemDetails.name:match("^buildcraftfactory:(.+)$") then
name = itemDetails.name:match("^buildcraftfactory:(.+)$")
elseif itemDetails.name:match("^buildcraftsilicon:(.+)$") then
name = itemDetails.name:match("^buildcraftsilicon:(.+)$")
elseif itemDetails.name:match("^buildcrafttransport:(.+)$") then
name = itemDetails.name:match("^buildcrafttransport:(.+)$")
elseif itemDetails.name:match("^buildcraftcore:(.+)$") then
name = itemDetails.name:match("^buildcraftcore:(.+)$")
elseif itemDetails.name:match("^buildcraftlib:(.+)$") then
name = itemDetails.name:match("^buildcraftlib:(.+)$")
elseif itemDetails.name:match("^computercraft:(.+)$") then
name = itemDetails.name:match("^computercraft:(.+)$")
elseif itemDetails.name:match("^enderstorage:(.+)$") then
name = itemDetails.name:match("^enderstorage:(.+)$")
elseif itemDetails.name:match("^extracells:(.+)$") then
name = itemDetails.name:match("^extracells:(.+)$")
elseif itemDetails.name:match("^thermaldynamics:(.+)$") then
name = itemDetails.name:match("^thermaldynamics:(.+)$")
elseif itemDetails.name:match("^thermalexpansion:(.+)$") then
name = itemDetails.name:match("^thermalexpansion:(.+)$")
elseif itemDetails.name:match("^thermalfoundation:(.+)$") then
name = itemDetails.name:match("^thermalfoundation:(.+)$")
elseif itemDetails.name:match("^tconstruct:(.+)$") then
name = itemDetails.name:match("^tconstruct:(.+)$")
elseif itemDetails.name:match("^webdisplays:(.+)$") then
name = itemDetails.name:match("^webdisplays:(.+)$")
elseif itemDetails.name:match("^ironchest:(.+)$") then
name = itemDetails.name:match("^ironchest:(.+)$")
else
print("ERROR MOD NOT FOUND")
end
getBlock()
local elem = blockTypes[name]
--Gets fuel from fuel chest
right()
turtle.select(16)
turtle.suck(5)
turtle.select(15)
if elem then
--If the item does exist, the turtle goes to it's chest and places it in the chest
goTo(elem[1]-1, elem[2]-1, elem[3]-1)
turtle.select(15)
turtle.drop()
goHome()
right()
turtle.select(16)
turtle.drop()
turtle.select(15)
left()
else
--Creates information for new item--
addBlock()
blockAmount = blockAmount + 1
highestVal[3] = highestVal[3] + 1
if highestVal[3] > 5 then
highestVal[3] = 1
highestVal[2] = highestVal[2] + 1
end
if highestVal[2] > 4 then
highestVal[2] = 0
highestVal[1] = highestVal[1] + 2
end
blockTypes[blockAmount] = name
blockTypes[name] = {highestVal[1],highestVal[2],highestVal[3]}
local elem = blockTypes[name]
left()
turtle.select(15)
turtle.drop()
right()
turtle.select(16)
turtle.suck(2)
fuel()
turtle.drop()
goTo(1,-1,4)
--Crafts an Iron Chest for the New Item
for i = 1,3 do
turtle.select(i)
turtle.suck(1)
end
turtle.select(5)
turtle.suck(1)
turtle.select(7)
turtle.suck(1)
for i = 9,11 do
turtle.select(i)
turtle.suck(1)
end
turtle.select(6)
turtle.craft()
goTo(1,-1,3)
for i = 1,3 do
turtle.select(i)
turtle.suck(1)
end
turtle.select(5)
turtle.suck(1)
turtle.select(7)
turtle.suck(1)
for i = 9,11 do
turtle.select(i)
turtle.suck(1)
end
turtle.select(1)
turtle.craft()
goHome()
right()
turtle.select(16)
turtle.suck(5)
goTo(elem[1]-1, elem[2]-1, elem[3]-1)
turtle.select(1)
turtle.place()
goHome()
end
end
The file containing the coordinates for the items is called blockTable and consist of this:
--blockName = {xCoord,yCoord,zCoord};--
oak_stairs = {2.0,0.0,5.0};
iron_ingot = {2.0,0.0,4.0};
turtle = {2.0,0.0,5.0};
When I put a new item in, it registers the item, makes a chest, and puts it in. When I put the same item in, it goes straight to the chest without crafting a new one. However, when I reboot the turtle and put the same item in, it creates another new chest and tries to place it for the new item. I want it to be able to keep its information even after a reboot. I've been struggling with this program for a while now, any help will be appreciated. Thank you!
Reading / Writing the entire file every time you add a new block seems a bit messy, specially if you consider that you might restart the turtle in the process of writing the new file and end up with half your data being lost.
You do have a file system, so why not use that instead? Create a directory and write a new file for every block name, then save the coordinates in it. This also allows you to store more than one chest for each block-type, in case you get filthy rich happens sooner than you'd expect when using turtles to excavate huge chunks of the map.
I just realized that I didn't actually answer the question, so here goes that:
When you have a file file, you can easily read a single line with file.readLine(). This returns either the line it read as a string, or nil if you're at the end of a file. Assuming you just write three coordinates separated by spaces after the block name, you can then parse them into a table like this:
local file = fs.open('chests')
local chests = {}
while true do
local line = file.readLine()
if line then
local name, x, y, z = line:match("(%a+) ([%d.+-]+) ([%d.+-]+) ([%d.+-]+)")
chests[name] = {
tonumber(x),
tonumber(y),
tonumber(z)
}
else
break
end
end
Wrap this all up in a function for extra neatness.
Side note:
Computercraft is somewhat inconvenient for dealing with files. In regular Lua I would have done this:
local function map(f, elem, ...)
if elem then return f(elem), map(f, ...) end
end
local function readchests(file)
local res = {}
for line in io.open(file):lines() do
local name, x, y, z = line:match("(%a+)"..(" [%d.-+]+"):rep(3))
res[name]={map(tonumber, x, y, z)}
end
return res
end
If you want to keep the format of storing data as valid Lua code, you could read the entire file with file.readAll(), add "return {" at the start and "}" at the end and then just load and execute that string. In general I don't recommend that though. Id't be better if the entire file was just valid Lua code that you can read and run.
While it is not advisable to read the file every time you add to a new block as stated by DarkWiiPlayer.
To answer your question, you can read the table in and the execute the code from the string using loadstring.
To do this using the existing strings in the file you provided there is some extra work that is needed.
This extra work can be removed by adjusting your the string in the file.
blockTypes = {}
line = "oak_stairs = {2.0,0.0,5.0};"
table_name = line:match("[%a_]+%s")
do_line = assert(loadstring('local ' .. line .. ' return ' .. table_name))
table = do_line();
table.insert(blockTypes,table)
Here we get the name of the table being loaded using match.
Create a string for loadstring that builds and returns the table.
Execute the loaded string, and insert it to the blockTypes.
Alternatively you can adjust the file you are saving to that it acts as a module.
local blocktypes = {
oak_stairs = {2.0,0.0,5.0},
iron_ingot = {2.0,0.0,4.0},
turtle = {2.0,0.0,5.0},
}
return blockTypes
Then you would this to load the data:
blockTypes = require("blockTable")

How to Call a Table from a Variable in Lua?

I'm creating a program for a turtle in ComputerCraft. The program is going to make the turtle control a warehouse of storage for my items in the game. It will check what item I put in, then it will figure out the chest's location, go there, and dump it in. I am storing the locations of each chest in a table. For example:
cobblestone = {2,0,1}
That tells the turtle that the cobblestone chest is stored at position x=2 y=0 and z=1. To get the turtle to tell what it needs to store, it does:
itemDetails = turtle.getItemDetail()
name = string.gsub(itemDetails.name, "minecraft:", "")
This gets the turtle to get the details of the item. It then sets a variable to be the name of the item minus the minecraft: at the beginning of it (I can't have a variable called "minecraft:cobblestone"). I don't know how to use this variable to call the table and find its position for the turtle to go to it. If anybody can help, I would appreciate any of the help. Thanks in advance!
Also, just a heads up, the code is still set up for debugging and testing purposes. The setup is a turtle, with an input chest in front of it, a fuel chest to the right, and the warehouse behind it.
I've tried doing:
cobblestone = {2,0,1}
--Putting a piece of cobblestone in--
itemDetails = turtle.getItemDetail()
--Returning name of "minecraft:cobblestone"--
name = string.gsub(itemDetails.name, "minecraft:", "")
print name[1]
So far this hasn't worked.
pos = {0,0,0}
looking = 0
cobblestone = {2,0,1}
function fuel()
if turtle.getFuelLevel() < 20 then
turtle.select(16)
turtle.refuel(1)
end
end
function left()
turtle.turnLeft()
looking = looking - 1
if looking < 0 then
looking = 3
end
print(looking)
end
function right()
turtle.turnRight()
looking = looking + 1
if looking > 3 then
looking = 0
end
print(looking)
end
function forward()
fuel()
if turtle.forward() then
if looking == 0 then
pos[1] = pos[1] - 1
elseif looking == 1 then
pos[3] = pos[3] - 1
elseif looking == 2 then
pos[1] = pos[1] + 1
elseif looking == 3 then
pos[3] = pos[3] + 1
else
print("wot")
end
end
end
function up()
fuel()
turtle.up()
pos[2] = pos[2] + 1
end
function down()
fuel()
turtle.down()
pos[2] = pos[2] - 1
end
function goHome()
while pos[3] > 0 do
while looking > 1 do
left()
end
forward()
end
while pos[2] > 0 do
down()
end
while pos[1] > 0 do
while looking > 0 do
left()
end
forward()
end
end
while true do
turtle.select(1)
while not turtle.suck() do
sleep(1)
end
itemDetails = turtle.getItemDetail()
name = string.gsub(itemDetails.name, "minecraft:", "")
print(name)
while looking < 2 or looking > 2 do
left()
end
for i = pos[1],name[1]-1 do
forward()
end
while looking > 3 or looking < 3 do
right()
end
for i = pos[3],name[3]-1 do
forward()
end
for i = pos[2],name[2]-1 do
up()
end
while looking < 2 or looking > 2 do
left()
end
turtle.select(1)
turtle.drop()
goHome()
end
I want to be able to do:
cobblestone = {2,0,1}
--Putting a piece of cobblestone in--
itemDetails = turtle.getItemDetail()
--Returning name of "minecraft:cobblestone"--
name = string.gsub(itemDetails.name, "minecraft:", "")
print name[1]
and have the turtle print the same thing as
cobblestone[1]
which would be 2. However, it returns with nil.
Currently, your cobblestone is global, what is bad for this example. At first, store all elements like this:
local myelems = {
cobblestone = {2,0,1};
grass = {3,1,2};
}
and so on. Use local variables when you can, it's good practice in programming at all.
So let's look at your code:
-- Returning name of "minecraft:cobblestone"
local name = string.gsub(itemDetails.name, "minecraft:", "")
print(name[1])
What it does? (I've changed it a bit)
At first,string.gsub look like an overkill here, use string.match instead:
local name = itemDetails.name:match("^minecraft:(.+)$")
Here itemDetails.name:match is same as calling string.match with itemDetails.name as first argument. It can be used for all string functions.
So here name is string variable. Indexing strings in different languages may have different results. In lua in actually provide access to all string functions to make calls to them easier (as above). There is no such function as string[1], so you get nil. However, now we have table myelems in which keys are strings and values are your tables.
Full code:
-- Table for all elements
local myelems = {
cobblestone = {2,0,1};
grass = {3,1,2};
}
-- Putting a piece of cobblestone in
local itemDetails = turtle.getItemDetail()
--Returning name of "minecraft:cobblestone"
local name = itemDetails.name:match("^minecraft:(.+)$")
-- Get our table
local elem = myelems[name]
if elem then
print(elem[1], elem[2], elem[3])
end

Lua - flushing input buffer during interactive terminal session

So I've got this lua test script for handling interactive user input in the terminal. It's working as expected, except I can't figure out a way to clear the input buffer between calls to io.read(1).
Before you say it, no, curses is not an option, nor is any third-party library. This script will (when it's done) be used on an embedded device with set firmware, so pure lua is the only option.
The code:
UP = 65
DOWN = 66
RIGHT = 67
LEFT = 68
local function sleep(seconds)
os.execute("sleep " .. tonumber(seconds));
end
local function write(String)
io.write(String);
io.flush();
end
local key = {
[27] = function()
group = (io.read(1)):byte();
if group == 91 then
direction = (io.read(1)):byte();
if direction == UP then return write("Up") end
if direction == DOWN then return write("Down") end
if direction == RIGHT then return write("Right") end
if direction == LEFT then return write("Left") end
return write("("..direction..")");
end
return write("("..direction..")");
end,
[113] = function() running = false end
}
running = true;
os.execute("stty raw -echo");
while running do
local k = io.read(1);
if k == 'w' then break end
k = k:byte();
if key[k] then key[k]();
else write('('..k..')') end
sleep(.25);
-- while io.read(1) ~= nil do end -- This blocks indefinitely
end
os.execute("stty sane")

Resources