AGS-Lua Evangelism

Started by Calin Leafshade, Mon 24/12/2012 13:23:28

Previous topic - Next topic

Calin Leafshade

I actually think the strength of AGS is that it's capable of both.

AGS is remarkably good at just being an adventure game engine with a very low barrier to entry but it's also remarkably good at being extensible. Or rather it *could* be in my opinion.

AGS can do some very nice things such as those seen in games like Resonance but it's also effective at recreating, faithfully a more classic style of adventure like the BJ series.

Denzil Quixode

#61
Quote from: Milhouse on Sun 30/12/2012 13:16:25
The first group (artists) probably isn't interested in learning how to handle exceptions and all the stuff a full featured programming language comes with. My guess is they will be fine with the current language.
Well, Lua's exception handling is actually pretty weak. It doesn't have native try/catch blocks like most other exception-supporting languages. Instead you use a special function called pcall to call a function instead of running it normally - pcall(myFunction, parameter1, parameter2) instead of myFunction(parameter1, parameter2) - and what you get back if there is an error is just an error message string, not a full object with additional information. (Actually, if you throw your own errors using the error() function, you can use any value, it's the built-in errors are all only strings.)

Also, in some ways Lua is less of a "programmer's language" than AGS-Script. Lacking "mutation" statements like a++ and a += 2 has already been mentioned. Lua also does not have binary operator support, although this is possible through an extension module (that I should probably get built in to the plugin), but then it is functions rather than operators - e.g. bit.bor(a, b) instead of (a | b), bit.band(c, d) instead of (c & d) and so on. (Lua 5.2 does have its own version of this module built-in, but for various reasons I intend to stick to version 5.1 for the plugin for now.)

Also, like JavaScript, Lua only has one kind of number (double-precision floating point). The way these bit operations work is all arguments are converted to 32-bit ints, the operation is done, and the result is converted back to a double. (Again, the same is true in JavaScript.) So if you want to do something that really relies on using true 8-bit/16-bit integer values like char and short, you will find this a lot easier to do in AGS-Script than Lua.

Calin Leafshade

Lack of bitwise functions is actually a serious problem when dealing with ags colours and stuff. I was going to mention that in the lua plugin thread.

Monsieur OUXX

#63
The things that Lua has and AGS doesn't have (and haven't been mentionned yet) are :
- A consistent syntax
- No need to map the darn AGS objects/variables to your wrapper every time you create one (IMO that's the main reason why plugins have limited features: because the guys who make them doen't go through the effort of mapping the hundreds of available functions of the underlying library to AGS). For example, the Direct3D plugin is fine, but the guy didn't implement everything into AGS. And I'm sure there is already a complete Lua/Direct3D wrapper somewhere out there.
- Libraries for data storage (arrays, trees, hashmaps, etc.). This is a BIG BIG issue in AGS at the moment. Every time you want to program a puzzle of some sort: "oh no, I'll have to code a search function yet again". Existing modules in AGS help, but overall it's still a real pain in the neck.


 

Denzil Quixode

Calin - It's not going to fast, definitely not something you want to be using a lot every frame, but there is a pure-Lua module for bitops you could use for now: http://files.luaforge.net/releases/bit/bit/luabitv0.4

Calin Leafshade

Quote from: Denzil Quixode on Sun 30/12/2012 15:01:27
Calin - It's not going to fast, definitely not something you want to be using a lot every frame, but there is a pure-Lua module for bitops you could use for now: http://files.luaforge.net/releases/bit/bit/luabitv0.4

Then it might be a good idea to expose some functions to us in the API to get colours from AGS colours since thats the only reason we'd need bitwise functions anyway probably.

Denzil Quixode

I've been thinking about making the Lua plugin even more powerful by allowing for scripts that get run in the editor, rather than in-game. I was going to post about it here but I think the plugin thread might be a better place.

monkey0506

You're all right actually. I was just resisting change. AGScript should never be used by anyone. It's practically worthless. You can't do anything with it. It has no features. It doesn't even remotely resemble a scripting language. Chris Jones is borderline mentally challenged for putting as much effort into creating AGScript as he did. In fact, AGS should basically just be rewritten from scratch. None of the program is usable in any fashion whatsoever. You guys have truly opened my eyes. I think we should write AGS v4 in Lua with a new engine and editor, and only allow Lua scripts to be used. All praise Lua forever.

Crimson Wizard

#68
I really hoped I never would have to say something harsh like this, but
Quote from: monkey_05_06 on Sun 30/12/2012 20:16:36Chris Jones is borderline mentally challenged for putting as much effort into creating AGScript as he did.
You do realize that people make mistakes that become visible only after number of years?
You do realize that something that was enough 15 years ago, may become not enough after 15 years?
You do realize that although the person's experience and skill grow over time, and he sees his past mistakes, he sometimes cannot change anything, because he does not have enough free time to do that properly?
You do realize that sometimes even program author decides to rewrite his past creation from scratch - exactly because he became more experienced and sees his mistakes? Did not Chris Jones himself remade AGS Editor from scratch? Was it because previous AGS 2.* editor was completely worthless?
For how many times I read the code I wrote like 5 years ago and wanted to make a "facepalm"... Did not that ever happened to you?
Haven't Chris Jones himself told that, quote:
Quote from: Pumaman on Wed 27/04/2011 01:55:57
DO NOT use this source code as a learning resource or a guide on best practice.
The state of the source code is VERY BAD and should in fact be considered an example of BAD PRACTICE.
Unlike the AGS Editor code which is relatively modern and a generally good standard, the engine code dates back 12 years to 1999, and has a severe case of the another-bit-being-bolted-onto-the-side disease. It also retains compatibility with old versions which means that some of the old and particularly dire code paths cannot yet be removed.
So just to be clear, YES I KNOW that the code is in a bad state. You don't need to tell me that.

Why do you have such a zeal to protect Chris Jones from something that is not even an attack on him?

Denzil Quixode

Quote from: Calin Leafshade on Sun 30/12/2012 15:13:13
Then it might be a good idea to expose some functions to us in the API to get colours from AGS colours since thats the only reason we'd need bitwise functions anyway probably.

Oh, like the Colour Finder you mean? I do have a function for that:

Code: Lua

local floor = math.floor

local low32 = {
  [-1] = 0x000000; -- COLOR_TRANSPARENT
  [ 0] = 0x000000; [ 1] = 0x0000A5; [ 2] = 0x00A500; [ 3] = 0x00A5A5;
  [ 4] = 0xA50000; [ 5] = 0xA500A5; [ 6] = 0xA5A500; [ 7] = 0xA5A5A5;
  [ 8] = 0x525252; [ 9] = 0x5252FF; [10] = 0x52FF52; [11] = 0x52FFFF;
  [12] = 0xFF5252; [13] = 0xFF52FF; [14] = 0xFFFF52; [15] = 0xFFFFFF;
  [16] = 0x000000; [17] = 0x101010; [18] = 0x212121; [19] = 0x313131;
  [20] = 0x424242; [21] = 0x525252; [22] = 0x636363; [23] = 0x737373;
  [24] = 0x848484; [25] = 0x949494; [26] = 0xA5A5A5; [27] = 0xB5B5B5;
  [28] = 0xC6C6C6; [29] = 0xD6D6D6; [30] = 0xE7E7E7; [31] = 0xF7F7F7;
}

function getRGB(agsColor)
  if agsColor < 32 then
    local rgb = low32[agsColor] or 0x000000
    return floor(rgb / 0x10000) % 0x100,
           floor(rgb /   0x100) % 0x100,
                 rgb            % 0x100
  end
  return (floor(agsColor / 0x800) % 0x20) * 8,
         (floor(agsColor /  0x20) % 0x40) * 4,
         (      agsColor          % 0x20) * 8
end


...to be used like this:

Code: Lua
local r, g, b = getRGB(65535)

Khris

I guess we need more practical examples like this, because I'm starting to like the idea. I'm quite fond of AGSScript but of course miss the stuff it doesn't support (yet).

Say I want to use lua tables to store all my tile info for an RPG.
What do I do to draw on a room background? Do I still use AGS's raw drawing?
(Apologies in advance if this is plainly obvious in the plugin's documentation, I haven't looked at it yet.)

Denzil Quixode

Quote from: Khris on Sun 30/12/2012 21:32:14
Say I want to use lua tables to store all my tile info for an RPG.
What do I do to draw on a room background? Do I still use AGS's raw drawing?

Yes, you'd still use the same functions essentially, just with (slightly) different syntax. Here is a Lua equivalent for the manual's example for Room.GetDrawingSurfaceForBackground():

Code: Lua
local surface = ags.Room.GetDrawingSurfaceForBackground()
surface.DrawingColor = 14
surface:DrawLine(0, 0, 50, 50)
surface:Release()


It should seem pretty familiar... the tricky one is that method calls on the surface object must use a colon ':' rather than a dot '.' before the method name, while property accesses still use the dot, and so do static function calls on the Room type.

monkey0506

Quote from: Crimson Wizard on Sun 30/12/2012 20:52:19Why do you have such a zeal to protect Chris Jones from something that is not even an attack on him?

Lol, no. I'm agreeing with you. We're better off without Chris Jones. Finally we can take the extremely easy step of replacing AGScript with the glory and power that is Lua. Only by doing this can AGS move forward. I agree. Good job. Sorry it took me so long to see the light guys. :)

Calin Leafshade

#73
@Khris re: RPG

Take a look at my very unfinished RPG engine made entirely in Lua (with a little AGS Script support).

https://dl.dropbox.com/u/27247158/NightThorn.zip (source)

It still contains a lot of AGS script but i've converted a lot of it to Lua and just havent removed the original ags script version.

Features include loading maps (it all takes place in a single room) and a rudimentary inventory (press esc)

(Also, monkey stop being a cock)

(Second also, I love syntax like this:

Code: lua

local r, g, b = getRGB(65535)


Multiple returns from a function is cool as shit)

Crimson Wizard

Quote from: Calin Leafshade on Sun 30/12/2012 22:13:03
(Second also, I love syntax like this:

Code: lua

local r, g, b = getRGB(65535)

And I don't :/. That looks like defining two variables with undefined value and initialize one variable with function's return value.

Crimson Wizard

Quote from: monkey_05_06 on Sun 30/12/2012 21:59:50
Quote from: Crimson Wizard on Sun 30/12/2012 20:52:19Why do you have such a zeal to protect Chris Jones from something that is not even an attack on him?

Lol, no. I'm agreeing with you. We're better off without Chris Jones. Finally we can take the extremely easy step of replacing AGScript with the glory and power that is Lua. Only by doing this can AGS move forward. I agree. Good job. Sorry it took me so long to see the light guys. :)


...
Now I feel extremely stupid and embarassed for replying first time.

Denzil Quixode

#76
Quote from: Crimson Wizard on Sun 30/12/2012 22:20:12
Quote from: Calin Leafshade on Sun 30/12/2012 22:13:03(Second also, I love syntax like this:
Code: lua
local r, g, b = getRGB(65535)
And I don't :/. That looks like defining two variables with undefined value and initialize one variable with function's return value.

If it disturbs you too much, you can always stick 'em in a table :)

Code: Lua
local rgb = {getRGB(65535)}
local r = rgb[1]
local g = rgb[2]
local b = rgb[3]


I know they're unusual, I think Google's "Go" is the only other language I remember seeing with multiple return values. There's some interesting things you can do with them. You can use multiple return values as multiple arguments to another function, for example:

Code: Lua
ags.SetFadeColor(getRGB(40892))    -- a nice eggshell blue...


The standard Lua function assert() takes two arguments. If the first argument is false or nil, it throws an error, using the second argument as the error message. Otherwise, it returns the first argument unchanged. For example, if you want to get the current active inventory item and throw an error if there isn't one, you could do this:

Code: Lua
local activeinv = assert(ags.player.ActiveInventory, "there is NO active inventory item!!")
-- ...do something with activeinv...


In combination with multiple return values from functions, this can be a useful coding-pattern. For example, if you try opening a file to read but the file doesn't exist, io.open() will return nil instead of a file object:

Code: Lua
local f = io.open('i_dont_exist.txt', 'rb')
if f == nil then
  print('unable to open the file!')
else
  -- ...do something with f...
end


...except it doesn't just return nil - it also returns a "file not found"-like error message string, as the second return value. You don't notice here because it just gets discarded. So, if you want to throw an error if the file cannot be opened, rather than handling it yourself:

Code: Lua
local f = assert( io.open('i_dont_exist.txt', 'rb') )   -- /!\ ERROR: i_dont_exist.txt: No such file or directory
-- ... do something with f


In this way, when you write a function you are not forced to choose between throwing an error if it is unable to get a valid result (which can be annoying if it's not a fatal problem), or just returning nil (which is "friendlier", but sometimes it is a fatal problem to your code, and it's helpful to have a handy error message around - especially if there's several different things that could have gone wrong).

SpeechCenter

Quote from: Denzil Quixode on Sun 30/12/2012 23:05:55
I know they're unusual, I think Google's "Go" is the only other language I remember seeing with multiple return values.
There are others, say Matlab (which I don't like the language)
Code: Matlab
[r g b] = getRGB(40892);


However, as you mentioned, the multiple return values problem is that it's easy to discard them, Matlab suffers from the same problem
Code: Matlab
c = getRGB(40892);

would work and c will have only the first return value.

Other languages cope with it by returning a tuple, like Scala
Code: Scala

def addAndSub(a:Int, b:Int) = { (a+b, a-b) }
val (sum, diff) = addAndSub(2, 3)
val bothValues = addAndSub(2, 3)

Here you can either assign them individually or assign a tuple to bothValues so nothing gets discarded silently.

Quote from: Denzil Quixode on Sun 30/12/2012 23:05:55
Code: Lua
local f = assert( io.open('i_dont_exist.txt', 'rb') )   -- /!\ ERROR: i_dont_exist.txt: No such file or directory
-- ... do something with f

This is considered very bad coding in any language that has a notion of debug and release compile as usually the whole assert statement is not compiled into anything in release (it's true that it doesn't usually return value, but this difference is easy to forget). It's a source of very nasty bugs in those environments. Solutions like Scala's Option can help cope with null return values or simply, use exceptions.

Given that Lua is a very flexible language, it  would require using some kind of style guide, otherwise the resulting code can become a horror to maintain.

Calin Leafshade

Quote from: SpeechCenter on Mon 31/12/2012 07:07:14
Quote from: Denzil Quixode on Sun 30/12/2012 23:05:55
Code: Lua
local f = assert( io.open('i_dont_exist.txt', 'rb') )   -- /!\ ERROR: i_dont_exist.txt: No such file or directory
-- ... do something with f

This is considered very bad coding in any language that has a notion of debug and release compile as usually the whole assert statement is not compiled into anything in release (it's true that it doesn't usually return value, but this difference is easy to forget). It's a source of very nasty bugs in those environments. Solutions like Scala's Option can help cope with null return values or simply, use exceptions.

I don't see it as a problem because assert will throw an exception on failure. It's similar to a try/catch block except the catch is always the calling function.

Khris

Quote from: Calin Leafshade on Sun 30/12/2012 22:13:03Take a look at my very unfinished RPG engine made entirely in Lua (with a little AGS Script support).
I did and I like!

So the two LuaControl scripts are used to keep the usual AGS events and would pretty much be essential for anybody willing to switch, right?
When I tried to compile the game, the "official" plugin couldn't deal with the Lua.Scripts/ScriptCount functions; I guess you added those to the plugin yourself?
(I called the scripts manually and it compiled fine.)

I'm still wondering though whether it's actually reasonable to use AGS and 99% Lua. It seems like you'd either use another engine entirely or stick to AGS/AGSScript and only use Lua when necessary, depending on whether you're creating mostly a classical adventure game or not. Does AGS's engine part warrant building a Lua game...?

And let's not forget that the current editor for the lua scripts is nothing more than a colorful Notepad. There's no jumping to functions, no auto-completion, no code folding.

SMF spam blocked by CleanTalk