Attempt to index local 'v' (a nil value) - lua

I'm trying to edit a lua script to add on my Garry's Mod Server, but I get this error and I dont know what to do.
Error:
[ERROR] --/sh_worlditemspawner.lua:56: attempt to index local 'v' (a nil value)
Code:
local PLUGIN = PLUGIN
PLUGIN.name = "World Item Spawner"
PLUGIN.author = "Black Tea"
PLUGIN.desc = "World Item Spawner."
PLUGIN.itempoints = PLUGIN.itempoints or {}
PLUGIN.spawngroups = {
["default"] = {
{"bleach"},
},
["example"] = {
{"ration"},
},
["junks"] = {
{"junk_ws"},
{"junk_wj"},
{"junk_be"},
{"junk_bt"},
{"junk_p"},
{"junk_ss"},
{"junk_bl"},
{"junk_k"},
{"junk_p"},
{"junk_hp"},
{"junk_ec"},
{"junk_ej"},
}
}
PLUGIN.spawnrate = 30
PLUGIN.maxitems = 10
PLUGIN.itemsperspawn = 2
PLUGIN.spawneditems = PLUGIN.spawneditems or {}
if SERVER then
local spawntime = 1
function PLUGIN:Think()
if spawntime > CurTime() then return end
spawntime = CurTime() + self.spawnrate
for k, v in ipairs(self.spawneditems) do
if (!v:IsValid()) then
table.remove(self.spawneditems, k)
end
end
if #self.spawneditems >= self.maxitems then return end
for i = 1, self.itemsperspawn do
if #self.spawneditems >= self.maxitems then return end
local v = table.Random(self.itempoints)
if #self.spawneditems > self.maxitems then
return
end
local data = {}
data.start = v[1]
data.endpos = data.start + Vector(0, 0, 1)
data.filter = client
data.mins = Vector(-16, -16, 0)
data.maxs = Vector(16, 16, 16)
local trace = util.TraceHull(data)
if trace.Entity:IsValid() then
continue
end
local idat = table.Random(self.spawngroups[v[2]]) or self.spawngroup["default"]
local item = nut.item.Spawn(v[1] + Vector( math.Rand(-8,8), math.Rand(-8,8), 10 ), AngleRand(), idat[1], idat[2] or {})
table.insert( self.spawneditems, item )
end
end
function PLUGIN:LoadData()
self.itempoints = nut.util.ReadTable("itempoints")
end
function PLUGIN:SaveData()
for k, v in ipairs(self.spawneditems) do
v:Remove()
end
nut.util.WriteTable("itempoints", self.itempoints)
end
else
netstream.Hook("nut_DisplaySpawnPoints", function(data)
for k, v in pairs(data) do
local emitter = ParticleEmitter( v[1] )
local smoke = emitter:Add( "sprites/glow04_noz", v[1] )
smoke:SetVelocity( Vector( 0, 0, 1 ) )
smoke:SetDieTime(10)
smoke:SetStartAlpha(255)
smoke:SetEndAlpha(255)
smoke:SetStartSize(64)
smoke:SetEndSize(64)
smoke:SetColor(255,186,50)
smoke:SetAirResistance(300)
emitter:Finish()
end
end)
end
nut.command.Register({
adminOnly = true,
onRun = function(client, arguments)
local trace = client:GetEyeTraceNoCursor()
local hitpos = trace.HitPos + trace.HitNormal*5
local spawngroup = arguments[1] or "default"
table.insert( PLUGIN.itempoints, { hitpos, spawngroup } )
nut.util.Notify( "You added ".. spawngroup .. " item spawner." )
end
}, "itemspawnadd")
nut.command.Register({
adminOnly = true,
onRun = function(client, arguments)
local trace = client:GetEyeTraceNoCursor()
local hitpos = trace.HitPos + trace.HitNormal*5
local range = arguments[1] or 128
local mt = 0
for k, v in pairs( PLUGIN.itempoints ) do
local distance = v[1]:Distance( hitpos )
if distance <= tonumber(range) then
PLUGIN.itempoints[k] = nil
mt = mt + 1
end
end
nut.util.Notify( mt .. " item spawners has been removed.")
end
}, "itemspawnremove")
nut.command.Register({
adminOnly = true,
onRun = function(client, arguments)
if SERVER then
netstream.Start(client, "nut_DisplaySpawnPoints", PLUGIN.itempoints)
nut.util.Notify( "Displayed All Points for 10 secs." )
end
end
}, "itemspawndisplay")

This is because
table.Random(self.itempoints)
returns nil. Did you mean math.random? If you post code for that table.Random func I can give more info.

Related

Can't set the damage value(s) to insta-kill NPCs/Players in a Garry's Mod "Spartan Kick" addon

This is a uh usual change of what I post here on StackOverflow! Today I'm trying to edit someone's Garry's Mod Workshop Addon.
I wanted to make it a one-hit kill and it's a Spartan Kick.
Here is the code:
if( SERVER ) then
AddCSLuaFile( "shared.lua" );
end
if( CLIENT ) then
SWEP.Category = "Epic Kicks";
SWEP.PrintName = "Spartan Kick";
SWEP.WepSelectIcon = surface.GetTextureID("VGUI/entities/spartan_kick")
SWEP.Slot = 1;
SWEP.SlotPos = 4;
SWEP.DrawAmmo = false;
SWEP.DrawCrosshair = false;
end
SWEP.Author = "Shot846 (Original) + 2Epic4You (Modified)"
SWEP.Instructions = "A better Sparta Kick. Use sv_cheats 1 for slow-motion!"
SWEP.Contact = "..."
SWEP.Purpose = "THIS IS EDITED SPARTAAAAAAA!"
SWEP.ViewModelFOV = 75
SWEP.ViewModelFlip = false
SWEP.Spawnable = true
SWEP.AdminSpawnable = true
SWEP.NextStrike = 0;
SWEP.ViewModel = "models/weapons/v_kick.mdl"
SWEP.WorldModel = ""
-------------Primary Fire Attributes----------------------------------------
SWEP.Primary.Delay = 0.4 --In seconds
SWEP.Primary.Recoil = 0 --Gun Kick
SWEP.Primary.Damage = math.huge --Damage per Bullet
SWEP.Primary.NumShots = 1 --Number of shots per one fire
SWEP.Primary.Cone = 0 --Bullet Spread
SWEP.Primary.ClipSize = -1 --Use "-1 if there are no clips"
SWEP.Primary.DefaultClip = -1 --Number of shots in next clip
SWEP.Primary.Automatic = true --Pistol fire (false) or SMG fire (true)
SWEP.Primary.Ammo = "none" --Ammo Type
-------------Secondary Fire Attributes----------------------------------------
SWEP.Secondary.Delay = 0 --In seconds
SWEP.Secondary.Recoil = 0 --Gun Kick
SWEP.Secondary.Damage = math.huge --Damage per Bullet
SWEP.Secondary.NumShots = 1 --Number of shots per one fire
SWEP.Secondary.Cone = 0 --Bullet Spread
SWEP.Secondary.ClipSize = -1 --Use "-1 if there are no clips"
SWEP.Secondary.DefaultClip = -1 --Number of shots in next clip
SWEP.Secondary.Automatic = true --Pistol fire (false) or SMG fire (true)
SWEP.Secondary.Ammo = "none" --Ammo Type
-------------Precache Sounds----------------------------------------
util.PrecacheSound("player/skick/madness.mp3")
util.PrecacheSound("player/skick/foot_kickwall.wav")
util.PrecacheSound("player/skick/foot_kickbody.wav")
util.PrecacheSound("player/skick/sparta.mp3")
util.PrecacheSound("player/skick/kick1.wav")
util.PrecacheSound("player/skick/kick2.wav")
util.PrecacheSound("player/skick/kick3.wav")
util.PrecacheSound("player/skick/kick4.wav")
util.PrecacheSound("player/skick/kick5.wav")
util.PrecacheSound("player/skick/kick6.wav")
function SWEP:Initialize()
if( SERVER ) then
self:SetWeaponHoldType("normal");
end
self.Hit = {
Sound( "player/skick/foot_kickwall.wav" )};
self.FleshHit = {
Sound( "player/skick/kick1.wav" ),
Sound( "player/skick/kick2.wav" ),
Sound( "player/skick/kick3.wav" ),
Sound( "player/skick/kick4.wav" ),
Sound( "player/skick/kick5.wav" ),
Sound( "player/skick/kick6.wav" ) } ;
end
function SWEP:Precache()
end
function SWEP:Deploy()
self.Weapon:SendWeaponAnim( ACT_VM_IDLE );
return true;
end
function SWEP:PrimaryAttack()
if( CurTime() < self.NextStrike ) then return; end
self.Weapon:EmitSound("player/skick/sparta.mp3")
self.NextStrike = ( CurTime() + 3.5 );
timer.Simple( 1.80, function() self.AttackAnim(self) end)
timer.Simple( 2.40, function() self.Weapon:SendWeaponAnim( ACT_VM_IDLE ) end)
timer.Simple( 2.0, function() self.ShootBullets (self) end)
self.Owner:SetAnimation( PLAYER_ATTACK1 );
end
function SWEP:ShootBullets()
self.Weapon:EmitSound("player/skick/foot_swing.wav");
local trace = self.Owner:GetEyeTrace();
if trace.HitPos:Distance(self.Owner:GetShootPos()) <= 130 then
if( trace.Entity:IsPlayer() or trace.Entity:IsNPC() or trace.Entity:GetClass()=="prop_ragdoll" ) then
timer.Simple(0, function() game.ConsoleCommand("host_timescale 0.1\n") end)
timer.Simple(0.1, function() game.ConsoleCommand("host_timescale 1\n") end)
self.Owner:EmitSound( self.FleshHit[math.random(1,#self.FleshHit)] );
else
self.Owner:EmitSound( self.Hit[math.random(1,#self.Hit)] );
end
bullet = {}
bullet.Num = 5
bullet.Src = self.Owner:GetShootPos()
bullet.Dir = self.Owner:GetAimVector()
bullet.Spread = Vector(0.04, 0.04, 0.04)
bullet.Tracer = 0
bullet.Force = math.huge
bullet.Damage = math.huge
self.Owner:FireBullets(bullet)
end
if trace.Entity:GetClass() == "prop_door_rotating" then
trace.Entity:EmitSound(Sound("physics/wood/wood_box_impact_hard3.wav"))
trace.Entity:Fire("open", "", .001)
trace.Entity:Fire("unlock", "", .001)
local pos = trace.Entity:GetPos()
local ang = trace.Entity:GetAngles()
local model = trace.Entity:GetModel()
local skin = trace.Entity:GetSkin()
trace.Entity:SetNotSolid(true)
trace.Entity:SetNoDraw(true)
local function ResetDoor(door, fakedoor)
door:SetNotSolid(false)
door:SetNoDraw(false)
fakedoor:Remove()
end
local norm = (pos - self.Owner:GetPos()):Normalize()
local push = 1000000 * norm
local ent = ents.Create("prop_physics")
ent:SetPos(pos)
ent:SetAngles(ang)
ent:SetModel(model)
if(skin) then
ent:SetSkin(skin)
end
ent:Spawn()
timer.Simple(.01, ent.SetVelocity, ent, push)
timer.Simple(.01, ent:GetPhysicsObject().ApplyForceCenter, ent:GetPhysicsObject(), push)
timer.Simple(140, ResetDoor, trace.Entity, ent)
end
end
function SWEP:SecondaryAttack()
if( CurTime() < self.NextStrike ) then return; end
self.NextStrike = ( CurTime() + 0.75 );
timer.Simple( 0.00, function() self.AttackAnim(self) end)
timer.Simple( 0.75, function() self.Weapon:SendWeaponAnim( ACT_VM_IDLE ) end)
timer.Simple( 0.20, function() self.ShootBullets (self) end)
self.Owner:SetAnimation( PLAYER_ATTACK1 );
end
function SWEP:Reload()
if( CurTime() < self.NextStrike ) then return; end
self.Weapon:EmitSound("player/skick/madness.mp3")
self.NextStrike = ( CurTime() + 2.00 );
end
function SWEP:AttackAnim()
self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
end
Yes it works however it isn't instantly killing the NPC I spawn.
What value do I need to change to make it insta-kill?
What I've tried:
Changing all damage values found to math.huge
What I've found:
I have found that it does still damage the NPC and the original value was 1000000 however it didn't insta-kill the NPC.
I've actually figured it out! After some extensive researching on the Wiki, I found out you can have bullet.Callback and so this is what I did:
bullet = {}
bullet.Num = 10
bullet.Src = self.Owner:GetShootPos()
bullet.Dir = self.Owner:GetAimVector()
bullet.Spread = Vector(0.04, 0.04, 0.04)
bullet.Tracer = 0
bullet.Force = 20000
bullet.Damage = 999999
bullet.Callback = function(attacker, tree, damageinfo)
if(trace.Entity:IsNPC()) then
trace.Entity:SetHealth(0)
elseif(trace.Entity:IsPlayer()) then
trace.Entity:Kill()
end
end
self.Owner:FireBullets(bullet)

Issue with a Lua Script

i really hope im right here, as on a discord server no one wants to help me for some reason.
We run a Project for a game called Garry's Mod and currently try to get a "Toxic Gas" Script Working.
But we face the following issue
[ERROR] gamemodes/zombierp/plugins/toxicgas/sh_plugin.lua:44: attempt to index local 'item' (a boolean value)
1. IsEquippingGasmask - gamemodes/zombierp/plugins/toxicgas/sh_plugin.lua:44
2. v - gamemodes/zombierp/plugins/toxicgas/sh_plugin.lua:121
3. unknown - gamemodes/helix/gamemode/core/libs/sh_plugin.lua:477
And me being fairly new to Lua, im just completly confused and dont know how to fix it.
Here is the Full Script
local config = {
smokeColor = Color(63, 127, 0),
smokeAlpha = 110,
maskItem = "gasmask",
smokeSpawnerDistance = 100 -- distance between the smoke emitters on the box line
}
local PLUGIN = PLUGIN
PLUGIN.name = "Toxic Gas"
PLUGIN.author = ""
PLUGIN.description = ""
PLUGIN.positions = PLUGIN.positions or {}
PLUGIN.smokeStacks = PLUGIN.smokeStacks or {}
function PLUGIN:LoadData()
PLUGIN.positions = self:GetData()
self:UpdateWorldData()
end
function PLUGIN:SaveData()
self:SetData(PLUGIN.positions)
self:UpdateWorldData()
end
function PLUGIN:UpdateWorldData()
SetNetVar("toxicGasPositions", PLUGIN.positions)
-- global netvar doesn't seem to sync without this
for _, ply in pairs(player.GetAll()) do
ply:SyncVars()
end
end
function PLUGIN:IsEquippingGasmask(ply)
local character = ply:GetCharacter()
if not character then return false end
local inventoryID = character:GetInventory():GetID()
local inventory = ix.item.inventories[inventoryID]
for x, items in pairs(inventory.slots) do
for y, item in pairs(items) do
if item.uniqueID == config.maskItem
and item:GetData("equip") == true then
return true
end
end
end
return false
end
local function GetBoxLine(min, max)
local deltaX = math.abs(min.x - max.x)
local deltaY = math.abs(min.y - max.y)
local lineStart, lineEnd
if deltaX < deltaY then
lineStart = Vector(min.x + (max.x - min.x) / 2, min.y, min.z)
lineEnd = Vector(min.x + (max.x - min.x) / 2, min.y + (max.y - min.y), min.z)
else
lineStart = Vector(min.x, min.y + (max.y - min.y) / 2, min.z)
lineEnd = Vector(min.x + (max.x - min.x), min.y + (max.y - min.y) / 2, min.z)
end
return lineStart, lineEnd
end
if SERVER then
function PLUGIN:Think()
for idx, gasBox in pairs(PLUGIN.positions) do
if PLUGIN.smokeStacks[idx] == nil then
local min, max = gasBox.min, gasBox.max
local startSmoke, endSmoke = GetBoxLine(min, max)
PLUGIN.smokeStacks[idx] = {
count = math.floor(startSmoke:Distance(endSmoke) / config.smokeSpawnerDistance),
stacks = {}
}
for i = 1, PLUGIN.smokeStacks[idx].count do
local smoke = ents.Create("env_smokestack")
smoke:SetPos(startSmoke + (endSmoke - startSmoke):GetNormalized() * (i) * config.smokeSpawnerDistance)
smoke:SetKeyValue("InitialState", "1")
smoke:SetKeyValue("WindAngle", "0 0 0")
smoke:SetKeyValue("WindSpeed", "0")
smoke:SetKeyValue("rendercolor", tostring(config.smokeColor))
smoke:SetKeyValue("renderamt", tostring(config.smokeAlpha))
smoke:SetKeyValue("SmokeMaterial", "particle/particle_smokegrenade.vmt")
smoke:SetKeyValue("BaseSpread", tostring(config.smokeSpawnerDistance))
smoke:SetKeyValue("SpreadSpeed", "10")
smoke:SetKeyValue("Speed", "32")
smoke:SetKeyValue("StartSize", "32")
smoke:SetKeyValue("EndSize", "32")
smoke:SetKeyValue("roll", "8")
smoke:SetKeyValue("Rate", "64")
smoke:SetKeyValue("JetLength", tostring(max.z - min.z))
smoke:SetKeyValue("twist", "6")
smoke:Spawn()
smoke:Activate()
smoke.Think = function()
if PLUGIN.positions[idx] == nil then
smoke:Remove()
end
end
PLUGIN.smokeStacks[idx].stacks[i] = smoke
end
end
end
for _, ply in pairs(player.GetAll()) do
local pos = ply:EyePos()
if not ply:Alive() then continue end
local canBreathe = false
if not canBreathe then
canBreathe = self:IsEquippingGasmask(ply)
end
if not canBreathe then
for _, gasBox in pairs(PLUGIN.positions) do
if pos:WithinAABox(gasBox.min, gasBox.max) then
ply.nextGasDamage = ply.nextGasDamage or CurTime()
if CurTime() >= ply.nextGasDamage then
ply.nextGasDamage = CurTime() + .75
ply:TakeDamage(6)
ix.util.Notify("You are choking. You need a gas mask.", ply)
end
break
end
end
end
end
end
end
if CLIENT then
-- toggles showing toxic gas boxes when in noclip/observer
CreateConVar("ix_toxicgas_observer", "0", FCVAR_ARCHIVE)
local function IsInRange(min, max, scale)
local localPos = LocalPlayer():GetPos()
local distance = min:Distance(max)
if localPos:Distance(min + ((max - min) / 2)) <= distance * scale then
return true
end
return false
end
function PLUGIN:PostDrawTranslucentRenderables()
local toxicGasPositions = GetNetVar("toxicGasPositions")
if toxicGasPositions == nil then return end
for _, gasBox in pairs(toxicGasPositions) do
local min, max = gasBox.min, gasBox.max
if not IsInRange(min, max, 3) then continue end
local observerCvar = GetConVar("ix_toxicgas_observer")
if LocalPlayer():IsAdmin()
and LocalPlayer():GetMoveType() == MOVETYPE_NOCLIP
and observerCvar and observerCvar:GetBool() then
render.DrawWireframeBox(min, Angle(), Vector(0, 0, 0), max - min, Color(142, 222, 131, 255), false)
local startSmoke, endSmoke = GetBoxLine(min, max)
render.DrawLine(startSmoke, endSmoke, Color(0, 255, 0), false)
end
end
end
function PLUGIN:HUDPaint()
-- this is an FPS killer tbh
--[[
local toxicGasPositions = game.GetWorld():GetNetVar("toxicGasPositions")
if toxicGasPositions == nil then return end
local inToxicGas = false
local center
local cornerDist
for _, gasBox in pairs(toxicGasPositions) do
local min, max = gasBox.min, gasBox.max
center = min + ((max - min) / 2)
cornerDist = min:Distance(max)
if LocalPlayer():EyePos():WithinAABox(min, max) then
inToxicGas = true
continue
end
end
if inToxicGas then
local isEquippingGasmask = self:IsEquippingGasmask(LocalPlayer())
local distance = LocalPlayer():EyePos():Distance(center)
ix.util.DrawBlurAt(0, 0, ScrW(), ScrH(), 1, 0.2, isEquippingGasmask and 50 or 255)
end
]]
end
end
ix.command.Add("AddToxicGas", {
description = "Adds a toxic gas box from where you're standing and where you're looking at.",
adminOnly = true,
OnRun = function(self, client)
local pos = client:GetPos()
local tr = client:GetEyeTrace()
if not tr then return end
local hitPos = tr.HitPos
table.insert(PLUGIN.positions, {
min = pos, max = hitPos
})
PLUGIN:SaveData()
return "Added toxic gas."
end
})
ix.command.Add("RemoveToxicGas", {
description = "Removes the closest toxic gas point relative to you.",
adminOnly = true,
OnRun = function(self, client)
local closestDistance = -1
local closestIndex = -1
for idx, gasBox in pairs(PLUGIN.positions) do
local min, max = gasBox.min, gasBox.max
local center = min + ((max - min) / 2)
local distance = client:GetPos():Distance(center)
if closestDistance == -1 or distance < closestDistance then
closestDistance = distance
closestIndex = idx
end
end
if closestIndex ~= -1 then
table.remove(PLUGIN.positions, closestIndex)
if PLUGIN.smokeStacks[closestIndex] then
for k, v in pairs(PLUGIN.smokeStacks[closestIndex].stacks) do
v:Remove()
end
table.remove(PLUGIN.smokeStacks, closestIndex)
end
PLUGIN:SaveData()
return "Removed 1 toxic gas box."
else
return "Could not find any toxic gas to remove!"
end
end
})
I Really hope someone can help me with that as im trying since 2 days now
Try replacing for y, item in pairs(items) do with for item, _ in pairs(items) do.
Reason: there is a chance that items is a set, i.e., a Lua table, in which keys are set members and values are true.
change line 44
if item.uniqueID == config.maskItem
either by refusing boolean values
if type(item) ~= 'boolean' and item.uniqueID == config.maskItem
or only allowing tables, because they could possibly contain .uniqueID
if type(item) == 'table' and item.uniqueID == config.maskItem

How to get over the 32 bits for storing numbers like - 2,147,483,647 to 2,147,483,647

I try to fix some old Basewars script for Gmod amd there is something i tried to fix but i dont know what i am missing there. Basicly its about a Bank script. This Bank could original store a amount of 2 Billion $. I would like to expand that storage amount to 1 Quadtrillion.
So Basicly the Basewars Gamemode allows players to have an high amount of money up to 10^18 $
= 1 Quintillion. I looked up into https://wiki.garrysmod.com/page/Category:number
so basicly lua uses double-precision floating-point format. So lua uses 32 bits for storing numbers and that means the number can be from a range of
-2,147,483,647 to 2,147,483,647.
The Basewars Gamemode uses a Function to make out of 10^18
= 1 Quintillion
function BaseWars.NumberFormat(num)
local t = BaseWars.LANG.Numbers
for i = 1, #t do
local Div = t[i][1]
local Str = t[i][2]
if num >= Div or num <= -Div then
return string.Comma(math.Round(num / Div, 1)) .. " " .. Str
end
end
return string.Comma(math.Round(num, 1))
end
The Gamemode is using that faction to convert the amount of money.
and here is the BaseWars.LANG.Numbers:
BaseWars.LANG = {}
BaseWars.LANG.__LANGUAGELOOK = {}
BaseWars.LANG.__LANGUAGELOOK.ENGLISH = {
Numbers = {
[5] = {10^6, "Million"},
[4] = {10^9, "Billion"},
[3] = {10^12, "Trillion"},
[2] = {10^15, "Quadtillion"},
[1] = {10^18, "Quintillion"},
},
CURFORMER = CURRENCY .. "%s",
CURRENCY = CURRENCY,
}
So i know that this function does work but i dont get it, how the variable num can be that high!
Why do i know what it does work ?
Here is what i tried and it manipulated the Capacity up to 1 Quadtrillion but at the point i manipluated a other Problem came up and i do not know what i do wrong!
Here how it was Original:
ENT.Capacity = 2000000000 --Max money in the bank. Can be bugs if it is more than 2000000000 (2 bil)
ENT.Money = 0
ENT.MaxPaper = 0
local Clamp = math.Clamp
function ENT:GSAT(slot, name, min, max)
self:NetworkVar("Int", slot, name)
local getVar = function(minMax)
if self[minMax] and isfunction(self[minMax]) then return self[minMax](self) end
if self[minMax] and isnumber(self[minMax]) then return self[minMax] end
return minMax or 0
end
self["Add" .. name] = function(_, var)
local Val = self["Get" .. name](self) + var
if min and max then
Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))
end
self["Set" .. name](self, Val)
end
self["Take" .. name] = function(_, var)
local Val = self["Get" .. name](self) - var
if min and max then
Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))
end
self["Set" .. name](self, Val)
end
end
function ENT:StableNetwork()
self:GSAT(2, "Capacity")
self:GSAT(3, "Money", 0, "GetCapacity")
self:GSAT(4, "Paper", 0, "MaxPaper")
self:GSAT(5, "Level", 0, "MaxLevel")
end
function ENT:ThinkFunc() --This Funtion is to auto collect all the Money of Printers
for k, v in pairs( ents.FindByClass( "bw_printer_*" ) ) do
if v:CPPIGetOwner() == self:CPPIGetOwner() then
if self:GetMoney() < self.Capacity then
local allmoney = v:GetMoney()
v:TakeMoney(allmoney)
self:AddMoney(allmoney)
end
end
end
for k, v in pairs( ents.FindByClass( "bw_base_moneyprinter" ) ) do
if v:CPPIGetOwner() == self:CPPIGetOwner() then
if self:GetMoney() < self.Capacity then
local allmoney = v:GetMoney()
v:TakeMoney(allmoney)
self:AddMoney(allmoney)
end
end
end
end
if CLIENT then
local Cp = self:GetCapacity()
local money = tonumber(self:GetMoney()) or 0
local cap = tonumber(Cp) or 0
local moneyPercentage = math.Round( money / cap * 100 ,1)
draw.DrawText( moneyPercentage .."%" , fontName .. ".Huge", w - 4-430, 71+610, self.FontColor, TEXT_ALIGN_CENTER)
local currentMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(money)
local maxMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap)
local font = fontName .. ".Big"
if #currentMoney > 16 then
font = fontName .. ".MedBig"
end
if #currentMoney > 20 then
font = fontName .. ".Med"
end
local fh = draw.GetFontHeight(font)
local StrW,StrH = surface.GetTextSize("")
local moneyW,moneyH = surface.GetTextSize(currentMoney)
draw.DrawText(currentMoney.. " / " .. BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap) , font,
w/2 - StrW/2-225 , (font == fontName .. ".Big" and 106 or 105 + fh / 4)+675, self.FontColor, TEXT_ALIGN_CENTER)
end
Here the changes i did:
removed line:
local cap = tonumber(Cp) or 0
added
local cap = 10^15
if self:GetMoney() < cap then
ENT.Capacity = 2000000000 --Max money in the bank. Can be bugs if it is more than 2000000000 (2 bil)
local cap = 10^15
ENT.Money = 0
ENT.MaxPaper = 0
local Clamp = math.Clamp
function ENT:GSAT(slot, name, min, max)
self:NetworkVar("Int", slot, name)
local getVar = function(minMax)
if self[minMax] and isfunction(self[minMax]) then return self[minMax](self) end
if self[minMax] and isnumber(self[minMax]) then return self[minMax] end
return minMax or 0
end
self["Add" .. name] = function(_, var)
local Val = self["Get" .. name](self) + var
if min and max then
Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))
end
self["Set" .. name](self, Val)
end
self["Take" .. name] = function(_, var)
local Val = self["Get" .. name](self) - var
if min and max then
Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))
end
self["Set" .. name](self, Val)
end
end
function ENT:StableNetwork()
self:GSAT(2, "Capacity")
self:GSAT(3, "Money", 0, "GetCapacity")
self:GSAT(4, "Paper", 0, "MaxPaper")
self:GSAT(5, "Level", 0, "MaxLevel")
end
function ENT:ThinkFunc() --This Funtion is to auto collect all the Money of Printers
for k, v in pairs( ents.FindByClass( "bw_printer_*" ) ) do
if v:CPPIGetOwner() == self:CPPIGetOwner() then
if self:GetMoney() < cap then
local allmoney = v:GetMoney()
v:TakeMoney(allmoney)
self:AddMoney(allmoney)
end
end
end
for k, v in pairs( ents.FindByClass( "bw_base_moneyprinter" ) ) do
if v:CPPIGetOwner() == self:CPPIGetOwner() then
if self:GetMoney() < cap then
local allmoney = v:GetMoney()
v:TakeMoney(allmoney)
self:AddMoney(allmoney)
end
end
end
end
if CLIENT then
local Cp = self:GetCapacity()
local money = tonumber(self:GetMoney()) or 0
local moneyPercentage = math.Round( money / cap * 100 ,1)
draw.DrawText( moneyPercentage .."%" , fontName .. ".Huge", w - 4-430, 71+610, self.FontColor, TEXT_ALIGN_CENTER)
local currentMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(money)
local maxMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap)
local font = fontName .. ".Big"
if #currentMoney > 16 then
font = fontName .. ".MedBig"
end
if #currentMoney > 20 then
font = fontName .. ".Med"
end
local fh = draw.GetFontHeight(font)
local StrW,StrH = surface.GetTextSize("")
local moneyW,moneyH = surface.GetTextSize(currentMoney)
draw.DrawText(currentMoney.. " / " .. BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap) , font,
w/2 - StrW/2-225 , (font == fontName .. ".Big" and 106 or 105 + fh / 4)+675, self.FontColor, TEXT_ALIGN_CENTER)
end
So now if you i look into the game it looks like this:
and now i have the problem that when it collects money it does it up to 2 billion and if i try to change
local money = tonumber(self:GetMoney()) or 0
to
local money =self:GetMoney()
i get straight -2.1 Bil
or i tried to change the min max values:
function ENT:GSAT(slot, name, min, max)
self:NetworkVar("Int", slot, name)
local getVar = function(minMax)
if self[minMax] and isfunction(self[minMax]) then return self[minMax](self) end
if self[minMax] and isnumber(self[minMax]) then return self[minMax] end
return minMax or 0
end
self["Add" .. name] = function(_, var)
local Val = self["Get" .. name](self) + var
if min and max then
Val = Clamp(tonumber(Val) or 0, getVar(min), 10^15)
end
self["Set" .. name](self, Val)
end
self["Take" .. name] = function(_, var)
local Val = self["Get" .. name](self) - var
if min and max then
Val = Clamp(tonumber(Val) or 0, getVar(min), 10^15)
end
self["Set" .. name](self, Val)
end
end
Basicly these lines:
Val = Clamp(tonumber(Val) or 0, getVar(min), 10^15)
if i run the game the Bank will just collect the money up to 2 Bill and then it goes to -2.1Bil. And at that point i dont know why and when a value does go buggy like it self sets to -2.1 Bil. does math.Round create this bug or do funktion return only return full integer ?
thx for any help
Because the network variable that the bank uses is an integer, it will only be able to store $(2^31-1) through $-(2^31-1). Try changing it to a networked float:
-- ...
function ENT:GSAT(slot, name, min, max)
-- self:NetworkVar("Int", slot, name), changes into:
self:NetworkVar("Float", slot, name)
-- ...
But, beware as the more money players accumulate the less precision will be put into those numbers.

"no such file or directory" in preloader

I'm making a preloader for a large application. Today the error occurred "no such file or directory". This error occurs only on Android device. On the computer(in the simulator) works fine. All file names and directories to lowercase.
Code:
---------------------------------------------
---------------- Прелоадер ------------------
-- Сервис по загрузке текстур, звука --------
---------------------------------------------
TEXTURES = {} -- место в оперативной памяти для текстур
SOUNDS = {} -- место в оперативной памяти для звука
local Preloader = {}
local path = {
animations = "assets/images/animations/",
army_run = "assets/images/animations/army_run/",
area = "assets/images/area/",
access = "assets/images/area/access/",
artefacts = "assets/images/artefacts/",
castles = "assets/images/building/castles/",
mining = "assets/images/building/mining/",
flags = "assets/images/flags/",
interface = "assets/images/interface/",
marker = "assets/images/interface/marker/",
items = "assets/images/items/",
raw = "assets/images/raw/",
}
-- Место для путей к текстурам
Preloader.texture = {}
-- Место для путей к звуку
Preloader.sound = {}
-- Загрузка текстур в оперативную память
Preloader.loadingTextures = function(arr)
TEXTURES[arr.id] = {}
for i = 1, #arr do
local name = string.gsub(arr[i], '.*(.*)/', '')
TEXTURES[arr.id][name] = graphics.newTexture( { type="image", filename = arr[i] } )
TEXTURES[arr.id][name]:preload()
end
end
-- Загрузка звука в оперативную память
Preloader.loadingSounds = function()
for i = 1, #Preloader.sound do
sounds[Preloader.sound[i]] = audio.loadSound( "snd/"..Preloader.sound[i] )
end
end
-- Таймер
Preloader.getTimer = function()
return system.getTimer()
end
-- Окно загрузки
Preloader.screenLoader = nil
Preloader.loaderShow = function()
if(Preloader.screenLoader)then
return false
end
Preloader.screenLoader = display.newGroup()
Preloader.screenLoader.x = _W/2
Preloader.screenLoader.y = _H/2
local screen = display.newRect( 0, 0, _W, _H )
screen:setFillColor( 0, 0, 0 )
Preloader.screenLoader:insert(screen)
local imgLoad = "assets/images/animations/army_run/150.png"
local sheetLoad = graphics.newImageSheet( imgLoad, { width = 224, height = 224, numFrames = 8 } )
local animLoad = display.newSprite( Preloader.screenLoader, sheetLoad, { start = 1, count = 8, time = 800, loopCount=0 } )
animLoad.xScale, animLoad.yScale = _H*.001, _H*.001
animLoad.x, animLoad.y = 0, _H*-.07
animLoad:play()
-- Загрузка в процентах
tfLoader = display.newText( TEXTS.Preloader.loading..": 0%", 0, _H*.08, font, _H*.035 )
tfLoader:setTextColor( 1,1,1)
Preloader.screenLoader:insert(tfLoader)
Preloader.screenLoader.tf = tfLoader
-- Загрузка в этапах
stepLoader = display.newText( TEXTS.Preloader.start_load, 0, _H*.125, font, _H*.022 )
stepLoader:setTextColor( 160/255, 160/255, 160/255 )
Preloader.screenLoader:insert(stepLoader)
Preloader.screenLoader.step = stepLoader
end
-- Создание массивов с путями
Preloader.createPath = function()
for k, v in pairs(path) do
local i = 0
Preloader.texture[k] = { id = k }
for l in lfs.dir(v) do
if ( l ~= "." and l ~= ".." and l ~= "..." ) then
i = i + 1
Preloader.texture[k][i] = v..l
end
end
end
end
-- Запуск прелоадера и контроль процесса загрузки
Preloader.start = function()
-- Создаём шаги для загрузки
local loading_steps = {}
-- Шаг 1 - Загрузка путей
table.insert(loading_steps, function()
Preloader.createPath()
Preloader.screenLoader.step.text = TEXTS.Preloader.path_load..'...'
end)
-- Шаг 2 - Загрузка текстур интерфейса
table.insert(loading_steps, function()
Preloader.loadingTextures(Preloader.texture.interface)
Preloader.loadingTextures(Preloader.texture.marker)
Preloader.screenLoader.step.text = TEXTS.Preloader.interface_load..'...'
end)
-- Шаг 3 - Загрузка анимаций
table.insert(loading_steps, function()
Preloader.loadingTextures(Preloader.texture.animations)
Preloader.loadingTextures(Preloader.texture.army_run)
Preloader.screenLoader.step.text = TEXTS.Preloader.animations_load..'...'
end)
-- Шаг 4 - Создание карты
table.insert(loading_steps, function()
Preloader.loadingTextures(Preloader.texture.area)
Preloader.loadingTextures(Preloader.texture.access)
Preloader.loadingTextures(Preloader.texture.castles)
Preloader.loadingTextures(Preloader.texture.mining)
Preloader.screenLoader.step.text = TEXTS.Preloader.map_load..'...'
end)
-- Шаг 5 - Загрузка ресурсов
table.insert(loading_steps, function()
Preloader.loadingTextures(Preloader.texture.raw)
Preloader.loadingTextures(Preloader.texture.items)
Preloader.loadingTextures(Preloader.texture.artefacts)
Preloader.screenLoader.step.text = TEXTS.Preloader.res_load..'...'
end)
-- Шаг 6 - Загрузка параметров игрока
table.insert(loading_steps, function()
Preloader.loadingTextures(Preloader.texture.flags)
Preloader.screenLoader.step.text = TEXTS.Preloader.res_load..'...'
end)
local loading_steps_max = #loading_steps+1
local st = Preloader.getTimer()
Preloader.loaderShow()
local function mainHandler(e)
if(#loading_steps>0)then
loading_steps[1]()
table.remove(loading_steps, 1)
if(Preloader.screenLoader)then
local loading_p = math.floor((loading_steps_max - #loading_steps)*100/loading_steps_max)
Preloader.screenLoader.tf.text = TEXTS.Preloader.loading..': '..loading_p..'%'
end
return true
end
Preloader.loaderClose()
print('Time load: '..(Preloader.getTimer()-st)..'ms')
Runtime:removeEventListener("enterFrame", mainHandler)
end
Runtime:addEventListener("enterFrame", mainHandler)
end
-- Окончание загрузки
Preloader.loaderClose = function()
if(Preloader.screenLoader)then
if(Preloader.screenLoader.removeSelf)then
Preloader.screenLoader:removeSelf()
end
end
Preloader.screenLoader = nil
-- Переход на стартовую сцену
composer.gotoScene( start_scene, "fade", 0 )
end
-- Сборщик мусора
Preloader.garbage_collector = function()
for key in pairs(TEXTURES) do
for i=1, #TEXTURES[key] do
TEXTURES[key][i]:releaseSelf()
end
end
TEXTURES = {}
end
return Preloader
That's how I show images on stage:
M.dial = display.newImageRect( M.gr, TEXTURES.interface["btn_compas_comp.png"].filename, TEXTURES.interface["btn_compas_comp.png"].baseDir, 272, 272 )
M.dial.x, M.dial.y = X, Y
Thanks in advance friends.
1) All file names and directories to lowercase - I suggest to double-check this because Android filesystem is case sensitive.
2) Also check your build.settings to ensure that excludeFiles section doesn't include any of directories from your code
Edit: Another idea based on corona lfs doc - try following before loading:
local resourcesPath = system.pathForFile( "", system.ResourceDirectory )
-- Change current working directory
local success = lfs.chdir( resourcesPath ) --returns true on success
I guess that lfs doesn't point on resource directory by default. All your assets should be in this directory, but don't try to modify them - For security reasons, this directory is read-only and enforced by the operating system, not by Corona.
Edit 2: Solution that don't rely on current directory
Preloader.createPath = function()
for k, v in pairs(path) do
local i = 0
local pathForDirectory = system.pathForFile(v, system.ResourceDirectory)
Preloader.texture[k] = { id = k }
for l in lfs.dir(pathForDirectory) do
if ( l ~= "." and l ~= ".." and l ~= "..." ) then
i = i + 1
Preloader.texture[k][i] = v..l
end
end
end
end

Error: attempt to index global 'playerBul' (a nil value)

The error is saying:
game.lua:171: attempt to index global 'playerBul' (a nil value)
Sorry if I put too much unnecessary code, I just do not know what is causing this error.
here are all the files for this game:
menu.lua:
local menu = {}
local bannermenu;
local selection;
menu.name = 'Menu'
local function play()
mode = require('game')
mode.load()
end
local options = {
{['text'] = 'Play', ['action'] = play},
{['text'] = 'Exit', ['action'] = love.event.quit}
}
function menu.load()
bannermenu = love.graphics.newImage(BANNER)
selection = 1
pointer = love.graphics.newImage(POINTER)
mode = menu
end
function menu.update()
return mode
end
function menu.draw()
love.graphics.draw(bannermenu, 200,10)
for i = 1,#options do
if i == selection then
love.graphics.draw(pointer, 300, 200 + i *20)
end
love.graphics.printf(options[i].text,0,200 + i * 20, love.graphics.getWidth(), 'center')
end
end
function menu.keypressed(key)
if key == "up" then
selection = (selection - 2)%(#options) + 1
elseif key == "down" then
selection = (selection) % (#options) + 1
elseif key == "return" then
options[selection].action()
elseif key == "escape" then
love.event.quit()
end
end
return menu
main.lua
TITLE = 'Die Aliens Die!'
PLAYER_BULLET = 'Images/playerbullet.png'
ENEMY_BULLET = 'Images/enemybullet.png'
HEALTH_IMG = 'Images/life.png'
ENEMY_UFO = {
ENEMY_1 = 'Images/enemy1.png',
ENEMY_2 = 'Images/enemy2.png',
ENEMY_3 = 'Images/enemy3.png'
}
PLAYER_IMG = 'Images/spaceship.png'
YOU_WIN = 'Images/win.png'
BANNER = 'Images/banner.png'
POINTER = 'Images/pointer.png'
function love.load()
love.window.setTitle(TITLE)
mode = require "menu"
mode.load()
end
function love.draw()
mode.draw()
end
function love.keypressed(key, isrepeat)
mode.keypressed(key)
end
function love.update(dt)
mode.update(dt)
end
game.lua
local game = {}
local playerShip = {}
local alienUFO = {}
local bullets = {}
local alienBullets = {}
local playerBullets = {}
local aliens = {{},{},{},{},{},{},{},{},{},{}}
local health = 3
local score = 0
local level = 1
local alienMovement = true
local healthImage;
local alienQty = 0
local pause
--local function gameOver()
--local function gamwWin()
local function clearTable(t)
for i = #t,1,-1 do
table.remove(t,i)
end
end
local function clearAliens()
for i=#aliens,1,-1 do
for j = #aliens[i],1,-1 do
table.remove(aliens[i],j)
end
end
end
local function insertAliens()
alienQty = 0
for i=1,4 do
for j =1,10 do
local alien = {}
alien.x = (j-1) *alienUFO.width + 10
alien.y = (j-1) *alienUFO.width + 35
if level ==2 then
alien.life = 2
if level == 3 then
alien.life = 3
end
table.insert(aliens[j], alien)
alienQty = alienQty + 1
end
end
end
end
local function initGame()
clearTable(playerBullets)
clearTable(alienBullets)
clearAliens()
insertAliens()
playerShip.x = love.graphics.getWidth() / 2 - playerShip.width /2
end
local function playerShoot()
local bullet = {}
playerShip.x = playerShip.x + 32
playerShip.y = playerShip.y + 10
table.insert(playerBullets, bullet)
end
local function AlienShoot(x,y)
local bullet = {}
bullet.x = alienUFO.width/2
bullet.y = y -5
table.insert(alienBullets, bullet)
end
local function playerShots(dt)
if next(playerBullets) ~= nil then
for i = #playerBullets,1,-1 do
playerBullets[i].y = playerBullets[i].y - dt* playerBullets.bulletSpeed
if playerBullets[i].y < 0 then
table.remove(playerBullets,i)
else
for j = #aliens, 1,-1 do
for k = #aliens[j],1,-1 do
if next(playerBullets) ~= nil and playerBullets[i] ~= nil and
aliens[j][k].x <= playerBullets[i].x and aliens[j] [k].x + 50 >= playerBullets[i].x
and aliens[j][k].y <= playerBullets[i].y and aliens[j] [k].y + 47 >= playerBullets[i].y then
table.remove(playerBullets, i)
if level == 2 and aliens[j][k].life > 0 then
aliens[j][k].life = aliens[j][k].life - 1
if level == 3 and aliens[j][k].life > 0 then
aliens[j][k].life = aliens[j][k].life - 1
else
table.remove(aliens[j], k)
alienQty = alienQty - 1
score = score + 100
end
break
end
end
end
end
end
end
end
local function PlayerShot()
health = health - 1
if health == 0 then
love.event.quit() -- COME BACK HERE FOR LOSE
end
end
local function AlienShots(dt)
if next(alienBullets) ~= nil then
for i = #alienBullets,1,-1 do
alienBullets[i].y = alienBullets[i].y + dt * alienUFO.bulletSpeed
if alienBullets[i].y > love.graphics.getHeight() then
table.remove(alienBullets, i)
elseif playerShip.x <= alienBullets[i].x and playerShip.x + playerShip.width >= alienBullets[i].x
and playerShip.y <= alienBullets[i].y and playerShip.y + playerShip.height >- alienBullets[i].y then
table.remove(alienBullets, i)
PlayerShot()
end
end
end
end
local function nextLVL()
level = level + 1
if level == 2 then
alienUFO.image = love.graphics.newImage(alienUFO.ENEMY1)
alienUFO.speed = 100
alienUFO.shotProb = 20
alienUFO.bullet = alienBul.image
initGame()
elseif level == 3 then
alienUFO.image = love.graphics.newImage(alienUFO.ENEMY2)
initGame()
elseif level > 3 then
love.event.quit() -- COME BACK HERE FOR WIN
end
end
function game.load()
pause = false
level = 1
health = 3
score = 0
playerShip.speed = 300
playerShip.bulletSpeed = 300
playerShip.width = 75
playerShip.height = 71
alienUFO.speed = 70
alienUFO.width = 50
alienUFO.height = 47
alienUFO.ENEMY1 = ENEMY_UFO.ENEMY_1
alienUFO.ENEMY2 = ENEMY_UFO.ENEMY_2
alienUFO.ENEMY3 = ENEMY_UFO.ENEMY_3
alienUFO.bulletSpeed = 300
alienUFO.image = love.graphics.newImage(alienUFO.ENEMY3)
playerShip.IMAGE = PLAYER_IMG
playerShip.image = love.graphics.newImage(playerShip.IMAGE)
healthImage = love.graphics.newImage(HEALTH_IMG)
playerShip.x = love.graphics.getWidth() / 2 - playerShip.width/2
playerShip.y = love.graphics.getHeight() - 100
playerBul.image = love.graphics.newImage(PLAYER_BULLET)
alienBul.image = love.graphics.newImage(ENEMY_BULLET)
initGame()
end
function game.draw()
if pause then
love.graphics.print('GAME PAUSED',love.graphics.getWidth()/2 - 20,20)
end
if next(playerBullets) ~= nil then
for i = 1, #playerBullets do
love.graphics.draw(playerBul.image, playerBullets[i].x, playerBullets[i].y)
end
end
if next(alienBullets) ~= nil then
for i = 1, #alienBullets do
love.graphics.draw(alienBul.image, alienBullets[i].x, alienBullets[i].y)
end
end
if next(aliens) ~= nil then
for i = 1, #aliens do
for j = 1, #aliens[i] do
love.graphics.draw(alienUFO.image, aliens[i][j].x, aliens[i][j].y)
end
end
end
love.graphics.print('Score: '..score, love.graphics.getWidth() - 100,20)
love.graphics.draw(playership.image, playership.x, playerShip.y)
for i = 1, lives do
love.graphics.draw(healthImage, 10+ 1 * 15,20)
end
end
function game.update(dt)
if not pause then
if alienQty == 0 then
nextLVL()
end
if love.keyboard.isDown("right") then
playerShip.x = playerShip.x + dt * playerShip.speed
elseif love.keyboard.isDown("left") then
playerShip.x = playerShip.x - dt * playerShip.speed
end
if love.keyboard.isDown(" ") then
playerShoot()
end
playerShots(dt)
AlienShots(dt)
if love.math.random(1,100) < alienUFO.shotProb then
local r = love.math.random(1,#aliens)
if next(aliens[r]) ~= nil then
alienShoot(aliens[r][#aliens[r]].x, aliens[r][#aliens[r]].y)
end
end
if alienMovement then
for i = 1, #aliens do
for j = 1, #aliens[i] do
aliens[i][j].x = aliens[i][j].x + dt * alienUFO.speed
if aliens[i][j].x + alienUFO.width + 2 >= love.graphics.getWidth() then
alienMovement = false
end
end
end
else
for i =1, #aliens do
for j = 1, #aliens[i] do
aliens[i][j].x = aliens[i][j].x - dt * alienUFO.speed
if aliens[i][j].x - 2 <= 0 then
alienMovement = true
end
end
end
end
if playerShip.x < 0 then
playerShip.x = 0
elseif playerShip.x > love.graphics.getWidth() - 75 then
playerShip.x = love.graphics.getWidth() -75
end
end
end
end
function game.keypressed(key)
if key =='p' then
pause = not pause
end
end
return game
you haven't defined a load function on the game table you return in game.lua. it looks like you already wrote the load logic but wrote it as a local function named loadGame. to fix your issue update game.lua to export the load function and just have it call the load function you've already created, like this:
function game.load()
loadGame()
end
somewhere before you return the game table in game.lua, say after your definition of game.keypressed
or you could alternatively just change local function loadGame() to function game.load() to remove the local function and redefine it as exported functionality

Resources