Quotes
Make sure your operating system isn't putting ``smart quotes´´ in to your text editor. A tell take sign of this is lots of question marks in your mod description shown on the mods screen in game. It will screw up everything, only normal quotes can be used.
Debugging
Getting Game.DebugOut() to work... For some unknown reason the in-game debug window will only appear if there's an error in your script. Here's how I format my script to ensure that this happens in a safe and reliable manner...
Code: Select all
-- define any locals, etc., here
function log(s) Game.DebugOut(tostring(s)) end;
function Create()
-- object init code goes here
log("obj create")
end
function Update()
-- object update code goes here
log("obj update")
end
-- any other code goes here
print(); -- this will throw error and open debug window
Put print() right down at the end of the script, because it will throw an error and Lua will not run anything past that point in the script.
The next interesting thing about the debug window is that it's scoped to the first script that makes it appear. This means, as far as I can tell, you can only debug one script at a time - whichever script most recently threw an error.
Apparently the debug output should also appear in debug.txt in the main PA folder, but on a Mac at least this does not work. I've searched the disk for other debug.txt and found none, and can't find any other logs that seem related to PA. Things may be different on other operating systems, but on a Mac I seem limited to the in-game debug window for now.
Update() updates a lot
The Update() function is called dozens, if not hundreds, of times a second. The only code you should put in Update() is something to check the amount of time since the last Update() otherwise you're just wasting CPU cycles. Your object doesn't need updating dozens/hundreds of times a second, in fact it probably only needs updating every 5 seconds (5 prison minutes) or so in most cases.
Code: Select all
local time = Game.Time
local delay = 15 -- seconds
local was, ready = time()
function Create()
-- init your object
end
function Update()
local now = time()
if now > ready then
DoStuff( now - was )
was = now
ready = now + delay
end
end
function DoStuff( elapsedTime )
-- your update code here
end
We're basically using Update() as a de-spamming function. Note that Game.Time() will always have changed between Create() and the first Update() so the first Update() will still trigger DoStuff().
But wait... Do we even need the elapsedTime any more? It's just going to be 'delay' (except on the first Update() call), so we can shrink the code further to:
Code: Select all
local time = Game.Time
local delay = 15 -- seconds
local ready = time()
function Create()
-- init your object
end
function Update()
local now = time()
if now > ready then
DoStuff()
ready = now + delay
end
end
function DoStuff()
-- your update code here
end
Checking if a table is full or empty
For my smoke detector object I use Object.GetNearbyObjects() to detect nearby fires. I don't need any details about the fires, I just need to know if there are any.
Looking through other mods I saw this sort of thing being used very regularly:
Code: Select all
local nearbyPrisoners = Object.GetNearbyObjects("Workman", 5.0)
local pris = "None"
for name, distance in pairs( nearbyPrisoners ) do
pris = name
end
if pris ~= "None" then
Object.SetProperty("Triggered",2)
else
Object.SetProperty("Triggered",0)
end
I've also seen people incrementing counters in the for loop, just to then check if the counter is >0 at the end of the loop. That's just nuts, it's doing far too much processing.
After some digging I found a better (faster, shorter) way to check if some objects have been returned - Lua's next() function:
Code: Select all
local find = Object.GetNearbyObjects
local withinRange = 10
local found = next
function DoStuff()
local fires = find("Fire", withinRange)
if found( fires ) then
-- sound the alarm!
else
-- turn off alarm
end
end
The next() function (which I access via my local 'find' variable) pulls the first item from the table (in an undefined order); in this scenario I don't care what order things are in, I just want to know if something was found.
Note also that I'm regularly making local references to function chunks, it reduces the amount of time taken for Lua to get a pointer to the chunk (it's not searching through as many metatables, etc).
In my case I didn't need to keep a list of the fires, so I further further simplified the code as follows:
Code: Select all
local found = next
local any = Object.GetNearbyObjects
local nearby = 10
function DoStuff()
if found( any("Fire", nearby) ) then
-- sound the alarm!
else
-- turn off alarm
end
end