Changing Variable by using variable+string? LUA - 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" }

Related

attempt to index a boolean value (local 'target')

I have looked at different ways to fix this but have no understanding at all. I've tried fixing the code in every was possible and still have no success.
RegisterServerEvent('housing:attemptsale')
AddEventHandler('housing:attemptsale',
function(args,price,hid,model)
local src = source
local user = exports["np-base"]:getModule("Player"):GetUser(src)
local char = user:getCurrentCharacter()
local target = exports["np-base"]:getModule("Player"):GetUser(args)
local targetchar = user:getCurrentCharacter()
if target:getCash() >= price then
target:removeMoney(price)
exports.ghmattimysql:execute("UPDATE houses SET `cid` = #cid, `price` = #price, `model` = #model WHERE `id` = #id", {
['#cid'] = targetchar.id,
['#price'] = price,
['#id'] = hid,
['#model'] = model
})
else
TriggerClientEvent('DoShortHudText', args, 'You dont got money', 2)
end
end)
As you did not provide any resources on those functiosn you're using there is not much we can do for you.
Actually this is pretty simple.
You're indexing a boolean value local target.
That means your doing something like target:something(), target.something, target[something].
Here you create target:
local target = exports["np-base"]:getModule("Player"):GetUser(args)
Then you do this target:getCash(). At this point target is a boolean, that means it is either true or false.
So you know exports["np-base"]:getModule("Player"):GetUser(args) returned true or false.
Now you have two options.
find out why the function returns a boolean and not what you expect and fix that
don't index target if target is not indexable.

Lua, local variables in a table

Sorry in advance if this is an incorrect question. I'm fairly new to Lua and I'm not sure how to go about this. I want to access a variable stored in a table from a function variable.
As far as I know there is no self-referencing tables before constructed.
An example would be this:
local bigTable = {
a = {
foo = 0,
bar = function(y)
print(foo) --Incorrect
end
}
}
What would be the best approach for this situation?
What you want to do is to create a table first, and append the keys to it:
local a = {}
a.foo = 0
a.bar = function()
print(a.foo)
end
local bigTable = {
a = a
}
bigTable.a.bar() -- prints 0
local bigTable = {
a = {
foo = 0,
bar = function(self, ...)
print(self.foo)
end,
}
}
-- Somewhere else in the code...
bigTable.a.bar(bigTable.a) --> 0
-- or the shorter but (almost) equivalent form:
bigTable.a:bar() --> prints 0
I anticipate your next question will be "What does the : do?", and for that there's lots of answers on SO already :)
Note that there's potential for a performance improvement here: if the above code gets called a lot, the bar method will be created again and again, so it could make sense to cache it; but that's pointless unless the surrounding code is already fast enough that this one allocation would have a noticeable impact on its runtime.

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.

Re-initialize table without losing references

I'd like to re-initialize a table without losing references to it.
What I want to achieve is defining tables in files, and when a file is changed (with a text editor) the file is reloaded, changing the table. Of course this doesn't change the table but creates a new instance, old references will still point to the old table.
Any suggestions?
EDIT: I want to elaborate on what I want to achieve. An example with game characters and weapons. I want to modify the weapons.lua and so affect the characters.
-- weapons.lua
sword = { damage = 3 }
-- characters.lua
character = { weapon = sword }
Adding a level of indirection (putting "sword" inside "weapons") like suggested by JWT doesn't help, unless I split character into { weaponTable = weapons, weaponKey = "sword" } but I don't see this as an option.
Anchor everything that needs to survive in the global environment. Nesting is fine, and this doesn't have to be your primary reference. (You can still local things, but make sure to initialize those local variables from the global environment and update the global if you change the local.)
To initialize the global values, say
foo = foo or value -- if foo is always true-ish
bar = (bar == nil) and value or bar -- if bar may be `false`
To initialize or update tables, you can
foo = foo or { }
foo.bar = foo.bar or 23
foo.baz = foo.baz or 42
-- and so on...
but that's kinda icky, so maybe say
function reinit( new, old ) -- (re)initialize one level, prefer old
if old == nil then return new end
if type( old ) ~= "table" then return old end
for k, v in pairs( new ) do
if old[k] == nil then old[k] = v end
end
return old
end
function reset( new, old ) -- (re)initialize one level, prefer new
if old == nil then return new end
if type( old ) ~= "table" then return new end
for k, v in pairs( new ) do old[k] = v end
return old
end
and then just
foo = reinit( { bar = 23, baz = 42 }, foo ) -- only setting if not defined
-- or
foo = reset( { bar = 23, baz = 42 }, foo ) -- always overriding given fields
or maybe make it even more fancy and say
function traverse( t, path )
local here, last, lastk, created = t
-- follow path of several keys starting from t, creating tables as needed
for k in path:gmatch "[^.]+" do
k = tonumber( k ) or k -- convert all-number keys to integer (for arrays)
local next = here[k]
if not next then
next, created = { }, true
here[k] = next
else
created = false
end
lastk, last, here = k, here, next
end
return here, last, lastk, created
end
function repopulate( path, value, update )
update = update or reinit -- pass 'reset' as 'update' for the other behavior
-- or something entirely different if that's what you need
local here, last, lastk, created = traverse( _G, path )
if type( value ) == "table" then
update( value, here )
else
if created then last[lastk] = nil end -- created one level too much
update( { [lastk] = value }, last )
end
end
and then (with arbitrary nesting)
-- No need to create 'state' first if it doesn't exist yet!
-- (If it exists, it will get updated, otherwise it's created)
repopulate( "state.player.weapon", { kind = "sword", damage = 11 } )
-- Do keep in mind that generally update order is relevant -- you may want to
-- give a newly created player a default inventory, but you may not want to
-- "refill" the player's inventory on every reload. So generally `repopulate`
-- with the parent and all child nodes for from-scratch creation, then
-- `repopulate` the child nodes that need to be checked & potentially updated
-- as well.
-- (So here you'd probably repopulate `state.player` first and then
-- `state.player.weapon` or other fields only if they should be updated anyway.)
-- e.g.:
repopulate( "state.player", {
x = 0, y = 0, hp = 100, mp = 100, level = 0, -- and so on
weapon = { kind = "sword", damage = 11 }, -- etc. etc.
} )
-- on reload always force a sword-kind weapon, leave rest (damage, ...) as-is
repopulate( "state.player.weapon", { kind = "sword" }, reset )
-- or alternatively: only if player has no weapon, give them a sword
repopulate( "state.player.weapon", { kind = "sword", damage = 3 } )
And you can go further, add metamethods to hide some of that shuffling, define different update policies, ... – you've seen some of the possibilities, now go and build your own version that fits your style and your code.
(While you're free to use the above code in any way, please note that it was written ad-hoc in the browser. I did some testing, fixed some glitches, and it seems to work now, but don't be surprised if there's still one or two bugs hiding in there. So play with this, change it, break it (and see how/why it breaks), adapt and extend it, ... – but unless you completely understand what it does and can fix any bugs, I strongly suggest you write your own version, or just stick to the basics. You probably don't need everything that this does, and you're likely to need other things that this doesn't do. As this is a central part of the reloading/live-coding infrastructure and everything has to be adapted to be reload-compatible, any mismatch between your tooling and what you actually need will result in a lot of pain everywhere in your code. So if you need something like this, put in a day or two to make it work the way you need it to, or you will regret it.)
(Free bonus warning: If you do OOP, you'll probably have to store and retrieve your classes instead of creating them every time, otherwise old objects from previous iterations will miss code updates and still run their old methods. I've forgotten about that more than just a couple of times and wasted several hours pondering "why isn't it fixed now?!?" after repeatedly re-loading code... So remember to anchor your metatables, anchor your classes!)
You could nest the tables in another table.
Before:
local a = { 1, 2, 3 }
local b = { 7, 8, 9 }
print(a[2] + b[2]) -- #=> 10
After:
local lookup = {
a = { 1, 2, 3 },
b = { 7, 8, 9 }
}
print(lookup.a[2] + lookup.b[2]) -- #=> 10
Then you can fully replace (or just update) a table in the lookup table and any dependent statements will use that updated value:
lookup.a = { 100, 50, 0 }
print(lookup.a[2] + lookup.b[2]) -- #=> 58
I don't know if it's exactly what you needed (As an ID is necessary) but I hope it will fit your needs.
meta = {
tables = {},
__call = function(arg, t)
for k, v in pairs(t) do
arg[k] = v
end
end,
__bnot = function(arg)
return arg.__key
end,
__newindex = function(arg, key, val)
meta.tables[arg.__key][key] = val
end,
__index = function(arg, key)
return meta.tables[arg.__key][key]
end
}
function RefTable(arg)
local newtable = {}
if arg ~= nil then
newtable.__key = arg
setmetatable(newtable, meta)
if meta.tables[arg] == nil then
meta.tables[arg] = {}
end
else
error("RefTable can't have nil key")
end
return newtable
end
-- Using the RefTable
sword = RefTable("Sword")
sword({damage = 3})
sword.cooldown = 10
character = {sword = sword}
print("base", sword.damage, sword.cooldown)
print("embed", character.sword.damage, character.sword.cooldown)
sword = RefTable("Sword")
sword({damage = 8, cooldown = 50})
print("embed2", character.sword.damage, character.sword.cooldown)
print(sword.__key, sword.cooldown)
ref = RefTable("Sword")
ref.cooldown = 1000
print(sword.cooldown)

Lua: Desired Results are Received Then Not Without Changing Code

Right now I'm trying to use Lua to receive variables from barcodes sent out from an outside source. When I run this, there is a variable rotation from the local function rot(input) that appears to be "buggy". If I run this code exactly as it is with the print statements below, the rotation will appear and disappear. Please help me understand why this may happen?
Please note: There are two aspects of this code that I'm currently working on. A) Code128 is not properly retrieving the variables. B)My code can definitely be shortened. But I'm new and learning as I go. The main purpose for this thread is to help me understand why code will sometimes display the desired result, then won't the next minute?
Thank you.
Edited: I've updated the code a bit to make it cleaner. Condensed all of my string.match statements into tables with other barcode related fields. Still learning and looking to make it even more cleaner. I love learning this, but am still having the same problem with my local function rot(input) and getting intermittent results. Any help is greatly appreciated!
local function rot(input)
rotTable = {["R"] = "cw", ["I"] = "180", ["B"] = "ccw"}
for k,v in pairs (rotTable) do
if input == k then
rotation = v
else
rotation = ""
end
end
return rotation
end
local function barCode(input)
local bcID = string.match(input,"%^(B%w)")
if bcID == "BY" then
bcID = string.match(input,"%^BY.*%^(B%w)")
end
local bcTable = {
["BC"] = {"code128", 10, string.match(input,"%^BY.*%^BC(%u),(%d*),(%u),%u,%u%^FD(.*)%^FS")},
["B2"] = {"bc2of5i", 20, string.match(input,"%^B2(%u),(%d*),(%u),%u,%u%^FD(.*)%^FS")},
["BE"] = {"ean13", 10, string.match(input,"%^BE(%u),(%d*),(%u),%u%^FD(.*)%^FS")},
["B8"] = {"ean8", 10, string.match(input,"%^B8(%u),(%d*),(%u),%u%^FD(.*)%^FS")},
["B3"] = {"code39", 10, string.match(input,"%^B3(%u),%u,(%d*),(%u),%u%^FD(.*)%^FS")},
["BU"] = {"upc_a", -1, string.match(input,"%^BU(%u),(%d*),(%u),%u%,%u^FD(.*)%^FS")}
}
for k,v in pairs (bcTable) do
if bcID == k then
bcFields = v
bcType, qzone, bcR, bcH, bcHr, bcData = unpack(bcFields)
end
end
hPos = 0
vPos = 0
bcOutput = '<'..bcType..' qzone=\"'..qzone..'\" hbb=\"0\" vbb=\"0\" bbwidth=\"1\" hpos=\"'..hPos..'\" vpos=\"'..vPos..'\" rotation = \"'..rot(bcR)..'\" bgcolor=\"0\" barcolor=\"255\" textcolor=\"255\" barwidth=\"1\" height=\"8\">'..bcData..'</'..bcType..'>'
return bcOutput
end
print(barCode("^BY3^BCN,102,N,N^FDCHF05000042^FS"))
print(barCode("^B2B,110,N,N,N^FD45681382^FS"))
print(barCode("^BUN,183,N,N,N^FD61414199999^FS"))
print(barCode("^B8I,146,N,N^FD212345645121^FS"))
print(barCode("^BEB,183,N,N^FD211234567891^FS"))
I'm not sure what is wrong with your code, if anything, but rot can be written more simply as
local rotTable = {["R"] = "cw", ["I"] = "180", ["B"] = "ccw"}
local function rot(input)
return rotTable[input] or ""
end
In general, you shouldn't need to search Lua tables. For instance, the loop for k,v in pairs (bcTable) do can be replace by indexing as in the code above.

Resources