How to update a variable in corona SDK? - lua

I have a function, which changes the variable from what it was to something new. I am using load-save .json tables to get and load data. How do I update the startmoneyTxt to display the new variable?
My function:
local function unlockBall(event)
ballfirst = loadsave.loadTable("firstBall.json", system.DocumentsDirectory)
currentMoney1 = loadsave.loadTable("cashTable.json", system.DocumentsDirectory)
difference = currentMoney1 - ballfirstUnlock
if(ballfirst == 0 and difference >= 0)then
ballfirstID = 1
loadsave.saveTable(ballfirstID, "firstBall.json", system.DocumentsDirectory)
loadsave.saveTable(difference, "cashTable.json", system.DocumentsDirectory)
end
end
My code which should be updated:
currentMoney = loadsave.loadTable("cashTable.json", system.DocumentsDirectory)
startmoneyTxt= display.newText("$ "..currentMoney.." " , 0,0, "Helvetica", 20)
sceneGroup:insert(startmoneyTxt)

Whenever you want change text use
startmoneyTxt.text = "Your text here"
Note: As names saveTable and loadTable imply functions are indent to save/load tables. So you can use one file to save/load multiple values.
I use loadsave module to save/load setings in my game The Great Pong.

Related

Unable to assign property Text. string expected, got Instance

I was making random text script (dont mind the sounds thing) and I got this error: Unable to assign property Text. string expected, got Instance.
while thing == true do
wait(math.random(3, 12))
local txts = game.ServerStorage.CallTexts:GetChildren()
local Choices = script:GetChildren()
local RandomIndex = math.random(1, #Choices)
local RandomSound = Choices[RandomIndex]
local RandomTextIndex = math.random(1, #txts)
local RandomText = Choices[RandomTextIndex]
RandomSound:Play()
game.Workspace["Talking Ben's Room"].furniture.desk.phone["De Text"].BilBord.toxt.Text = RandomText
wait(RandomSound.TimeLength)
end
Text should be a string. RandomText is an Instance. Like the error told you. What type are the Choices, e.g. the children of CallTexts? Do they have a getter/toString?
If they are StringValues you will need RandomText.Value
If they are TextLabels (your case), you will need RandomText.ContentText

Changing Variable by using variable+string? LUA

I have a script where I have many variables for different guns. There are
UMP45Ammo = false
UMP45Fov = false
AKMAmmo = false
AKMFov = false
etc I got like 12 guns and more variables
Then I have a global variable called cgun
My problem is when a button is clicked I wanna change the value of selected guns specific property(like ammo to true)
So I tried something like
cgun+Ammo = true and I tried even making new local variable
mgun1 = cgun+Ammo
mgun1 = true
etc. How can I do this or is it impossible?
It may be better to use objects to describe the guns. Then it's easy to change a gun property of the current gun.
-- gun list
UMP45 = {Ammo = false, Fov = false}
AKMA = {Ammo = false, Fov = false}
cgun = UMP45 -- set current gun
print(cgun.Ammo)
cgun.Ammo = true -- set Ammo of current gun
print(cgun.Ammo)
Yes, it is possible to access global memory using the _G variable. It works, but it's ugly in this case:
_G[cgun.."Ammo"] = 0
Note that if cgun is a reference you have to change it to a string, either using debug.getlocal or using a simple search:
for k, v in pairs(_G) do if v == cgun then _G[k.."Ammo"] = 0 break end
Again this is not a very good solution. Generally speaking, you don't want to pollute the global space _G with a lot of variables.
Just store a reference to your current gun as Mike suggested.
currentGun = { ammo = 10, name = "AK47" }

LUA: Looking for a specific table by its variable

I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!

Trying to implement object-oriented programming in Lua, but it's not quite working

Ok, so I'm trying to follow the instructions found here: https://www.lua.org/pil/16.1.html to do something resembling OO programming in Lua (and the LOVE game framework), but it's not working. Here's the core of my code. I have a generic Object class:
local Object = {}
function Object:load(arg)
end
function Object:update(dt)
end
function Object:draw()
end
function Object:new(arg)
o = {}
setmetatable(o, self)
self.__index = self
o:load(arg)
return o
end
return Object
and a Ship class that inherits from it:
Object = require('objects.object')
local Ship = Object:new()
Ship.sprite = love.graphics.newImage('assets/sprites/ship.png')
Ship.sprite:setFilter('nearest', 'nearest', 0)
Ship.px = Ship.sprite:getWidth()/2
Ship.py = Ship.sprite:getHeight()/2
function Ship:load(arg)
self.x = arg.x or 0
self.y = arg.y or 0
self.sx = arg.sx or arg.s or 1
self.sy = arg.sy or arg.s or 1
self.rot = arg.rot or 0
self.tint = arg.tint or {255, 255, 255}
end
function Ship:draw()
love.graphics.setColor(self.tint)
love.graphics.draw(self.sprite, self.x, self.y, self.rot,
self.sx, self.sy, self.px, self.py)
love.graphics.setColor({255, 255, 255})
end
return Ship
Now the problem is, I create two of these Ships as members of another object with this code:
self.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
self.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
But when I draw them, I only see one - the second. As it turns out, it's like the code above doesn't assign the new instances of Ship to ship1 and ship2, but directly to self, for reasons that I can't understand. Did I do something wrong or is this a weird bug of the interpreter?
It is not bug of the interpreter, it is designed behavior of the language. o={} creates global variable, which is not expected by the programmer here. "Why it is so?" is a frequent question to the language creator. There are many efforts to take control over that behavior simpler .
o = {} without local creates global variable global variable is accessible and shared between all the functions in the program, unless you use fancy environment scoping techniques. Using global variable inside a function opens up doors for various side effects, you should be careful with side effects.
I've removed some of the syntactic sugar and added code above can be equivalently written as follows:
Object.new = function(table_before_colon,arg)
highlander = {} --global variable, there can be only one
setmetatable(highlander,table_before_colon);
table_before_colon.__index = table_before_colon;
highlander:load(arg) -- table_before_colon.__index.load(highlander,arg)
return highlander
end
local Ship = Object:new()
--global highlander == Ship
--Ship.new points to Object.new
function Ship:load(arg)--equivalent to: Ship.load=function(self,arg)
--code that sets fields of the `self` object and is called from within new
self.x = arg.x or 0 -- equivalently highlander.x=arg.x or 0
end
Now, the presence of the global variable would not matter, if nothing happened to it in the period from the start of the new till the new returns. But, apparently, your other code is similar to this:
local OtherObject = Object:new()
--otherObject == highlander
OtherObject.load = function(new_other_obj,arg)
--highlander == new_other_obj
new_other_obj.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
--highlander == new_other_obj.ship1
new_other_obj.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
--highlander == new_other_obj.ship2
end
So, OtherObject.load calls other functions, and those functions also access and modify the same global variable.
local some_object = OtherObject:new()
returns the global variable as it is at the end of the call, which is last set to the ship2 inside the call to Ship:new inside the call to OtherObject.load inside call to OtherObject:new.
Solved! Apparently, what was needed was this little snippet:
function Object:new(arg)
local o = {}
setmetatable(o, self)
self.__index = self
o:load(arg)
return o
end
Making o local in all my new methods solved everything. I don't know how it worked exactly but I assume having it in the global variable space broke something when the meta tables are set.

How to access user typed text inside a text box to make it as a variable? (Roblox)

So, I want to make a converter GUI, converting Bitcoin to Dollar. I use a textbox to get the user input and a text button to submit. But, when I type number for example 8 to the textbox while test the game and print what is inside the textbox, it printed nothing. Even though I have type 8 to the text box. Thanks for all the answers! Here is the code I use.
-- text variable below
local input = script.Parent
local val = input.Text
-- button variable below
local submit = input:FindFirstChild("btcSubmit")
-- player variable below
local gams = game.Players.LocalPlayer
local ld = gams:WaitForChild("leaderstats")
local bitcoin = ld:WaitForChild("Bitcoin").Value
local dollar = ld:WaitForChild("Dollar").Value
-- function
function btcEx()
val = tonumber(val)
if val > bitcoin then
val = tostring(val)
val = "Sorry, your Bitcoin isn't enough"
wait(4)
val = "Input the number of bitcoin you want to exchange here!"
else
dollar = val * 8000
val = tostring()
end
end
submit.MouseButton1Click:Connect(btcEx)
When you set a variable to a value rather than a reference, it remains that value until you change it.
object.Value = 5
local myValue = object.Value
object.Value = 10
print(myValue) -- Prints 5.
This happens because they are not linked and thus changes do not carry over, like these variables below:
local a = 5
local b = a
a = 10
print(b) -- Prints 5, because b was never changed (but a was).
What you want to do is define your button and your value-objects as references, and simply access .Text or .Value when you need to read the value.
local myButton = button
button.Text = "Howdy!"
print(myButton.Text) -- Prints "Howdy!"
myButton.Text = "Hey there" -- this is the same as button.Text
print(myButton.Text) -- Prints "Hey there"

Resources