AGS-Lua Evangelism

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

Previous topic - Next topic

Calin Leafshade

Well, I won't lie and say that what I posted is simple to *set up* but it is simple *to use*.

but ok I will try and compose a quick example of exactly how the system would work:

A coroutine is basically a function that can be stopped (yield) and resumed. So to use it would look like this:

Code: lua

activeCoroutines = {} -- a new table for all our coroutines

function FireCoroutine(f)
    activeCoroutines[#activeCoroutines + 1] = f -- add our coroutine to a table
end

RegisterEvent("AfterFadeIn", function() -- this all happens in After_FadeIn
    FireCoroutine(backgroundThread) -- fire our coroutine off
end)

function backgroundThread() -- our coroutine
    while(true) do
        cNPC:AsyncWalk(300,300)
        cNPC:AsyncWalk(100,300)
    end
end

RegisterEvent("repeatedly_execute_always", function()
    for i,v in ipairs(activeCoroutines or nil) do
        coroutine.resume(v)
    end
end

function ags.Character:AsyncWalk(x,y)
    self:Walk(x,y,ags.eNoBlock)
    while(self.Walking) do
        coroutine.yield()
    end    
end


Yes, there is a lot of set up there but the set up only needs to be done *once* and not *by the user*, it can be done by a module maker.

Also, this is not the best way to do it and this code would cause problems like the coroutine being fired everytime the room is entered but you could engineering a very nice system whereby each character was essentially a closed system, each with its own behaviour all contained within a single function

Crimson Wizard

#41
Well, sorry, I finally got it myself. Although my head nearly exploded in the process. Exactly the Lua ability to invent new variables when I make a typo or forget to add "ags." prior to AGS function calls. :P
(Or maybe it hides all runtime errors?)

http://www.mediafire.com/?82ahevtx9po0994

I did this:
Code: lua


function ags.Character:NonBlockingWalk(x, y)
  self:Walk(x, y, ags.eNoBlock)
  self:SayBackground("Where I am going?")
  while (self.Moving) do
    coroutine.yield()
  end
end

function ags.Character:NonBlockingRamble()
  self:SayBackground("What am I doing here?");
  ticks = 0
  while (ticks < 120) do
    coroutine.yield()
    ticks = ticks + 1
  end
end

local function BemanWalkAroundAndRamble()
  while (true) do
    ags.cBman:NonBlockingWalk(ags.Random(300),ags.Random(200))
    ags.cBman:NonBlockingRamble()
  end
end

local co

function OnRoomEnter()
  co = coroutine.create(BemanWalkAroundAndRamble)
end

function OnRoomTick()
  coroutine.resume(co)
end


In AGS Script:
Code: ags

function room_FirstLoad()
{
  <...>

  Lua.Call("OnRoomEnter");
}

<...>

function room_RepExec()
{
  Lua.Call("OnRoomTick");
}

Calin Leafshade

Quote from: Crimson Wizard on Wed 26/12/2012 14:57:21
(Or maybe it hides all runtime errors?)

Oh yea, another thing Lua can do that AGS can't. (Exceptions)

miguel

Played your testgame CW, very nice indeed.
But you guys can code much better than me, I hate not understanding what I'm doing.
Anyway, I would use modules made with Lua, that's for sure.
Working on a RON game!!!!!

AJA

Good points from both sides.

Here are my thoughts, based on my experience working on Barely Floating, which has around 10 lines of AGSScript and slightly over 32000 lines of Lua code. Excuse me for my excessive babbling.

So, why did I try the Lua plugin? Basically, I was sick and tired of AGSScript. It had serviced me fine for the many years I'd made games with AGS, but having to jump through all sorts of hoops to create workarounds, even for some simpler things, had become a nightmare. Back when I was working on this, I tried to script a custom dialogue option system that would give me a bit more freedom to do things my way. In the end, I had a global script full of all kinds of crap because I couldn't do forward declarations for some things and spread them all neatly inside modules. I think that was the last straw. The next games I worked on were OROWs so I didn't have the time to experiment with the Lua plugin until I started work on Barely Floating.

In the meantime, I had also made a remake of one of my OROW games with an engine made by myself. That thing was scriptable with Lua so I already had some ideas how the framework should be organized on Lua's end (dialogue systems, interactions, etc.). So, my mission statement for Barely Floating was to write a framework (based on my earlier work) that required you to do only a minimal amount of scripting in AGS. Everything should be in Lua scripts. Everything should be modifiable without even opening AGS: adding hotspots (rectangles), working with hotspots, regions, characters, dialogue trees, etc. It took a while to make but in the end, I don't think I would've finished the game if I'd had to rebuild the game every time I made a change in AGSScript. In the end, the executable was over 1 GB in size, so rebuilding was not instant, even if I made no changes to the graphical assets.

Since most of the discussion has been about the low level features of AGSScript vs Lua, I'll concentrate on things you can build with the Lua building blocks.

Here's some things the Lua framework did that I couldn't live without:

1. Script console. One of the first things I made for the framework, and one of the things I used most: press a button, an input box appears, write some Lua code, hit enter and the code gets executed. Want to jump forward to a specific puzzle? Easy. (Check #6 aswell.) Quickly test calling a function. Move things around. Pretty much anything you could do with one line of code since AGS doesn't support multiline input boxes.

2. Reload interaction scripts. While the game is running. Seriously, what a time saver. Found a typo? A character walked to the wrong spot? Fix it in the script, press a button to reload it, and test again.

3. Coroutines. This has been mentioned many times in this thread and it really makes seemingly multi-threaded interactions really simple to make. Of course, you'll eventually run into problems with concurrency, like a background thread controlling a character and then the main thread needing to control that character at the same time.

4. Return self and being able to chain method calls. Here's an example of what my interaction scripts are full of. The methods seductive/concerned would change the character's facial expression accordingly.
Code: Lua

cDude:seductive()
     :say( "What's up, love?" )
     :say( "How about we go for a walk?" )
     :concerned()
     :say( "Do you think I'm asking too many questions?" )


5. Edit mode. Press tab and you can move characters, objects and hotspots, create new hotspots and finally export the room's Lua script so you can do simple AGS editorey things within the game.

6. Puzzle tracking. All the game's puzzles are defined as simple state machines that also modify the game environment when certain states are reached. I was pretty lazy about this, so basically, when you reach the end of a puzzle the puzzle's end state makes sure the game is in the correct state: hotspots are turned on/off, objects moved, etc. And then comes the best part, you can skip puzzles, and the game will be in the correct state, as if you'd played through the puzzle. Very handy when debugging. Of course, you need to be careful that the puzzle script actually changes the game state correctly.

7. Making a table (~array) log any changes made to its indexed values. Very handy for debugging.
Code: Lua

cDude.state.happy = true
-- Prints to the log something about key happy being set to true


As with most things, there are drawbacks:

1. You need to be really careful with interpreted languages like Lua. You don't get a neat list of errors when you compile your game, informing you of critical typos and such. Nope, you only get a crash or an error message or worse, nothing at all, when you reach the part of the game where that invalid piece of code gets executed. This is, in my book, the greatest drawback of interpreted languages, however the flipside of it is also their greatest asset: not needing to wait for it to compile, ability to reload scripts, etc.

2. Until there is a publicly available AGS-Lua framework, most of the advantages I listed earlier would have to be created from scratch which is going to take some time depending on what you need. I still haven't had the energy to clean up my framework for public release, unfortunately, even though I promised months ago. :(

Can't think of any more major drawbacks right now. Learning new syntax isn't really a drawback. You usually get the hang of it quite quickly when you start scripting. Syntax only becomes a drawback when it prevents you from doing things. There's one such thing in Lua that annoys me: not being able to do "value++", instead you have to do "value = value + 1".

Many of these things I've mentioned are most likely not of much interest to beginning scripters but to more experienced ones, I'm sure they'll find at least one or two things they wouldn't want to pass up on.

And since the coroutines are a hot topic right now, here's my Thread class from Barely Floating (comments are in Finnish but I hope you get the idea): http://www.serpentpictures.net/randomia/Thread.lua

Ryan Timothy B

Quote from: AJA on Wed 26/12/2012 15:20:56
There's one such thing in Lua that annoys me: not being able to do "value++", instead you have to do "value = value + 1".
There isn't even "value += 1" ? Odd.

Why isn't Lua included with AGS? I haven't used AGS in awhile, but if I were to use it, the only thing holding me back from using Lua is laziness. lol

AJA

Nope. Can't remember why, though. It had something to do with the design of the language.

monkey0506

Quote from: AJA on Wed 26/12/2012 15:20:561. Script console. One of the first things I made for the framework, and one of the things I used most: press a button, an input box appears, write some Lua code, hit enter and the code gets executed. Want to jump forward to a specific puzzle? Easy. (Check #6 aswell.) Quickly test calling a function. Move things around. Pretty much anything you could do with one line of code since AGS doesn't support multiline input boxes.

Adding a proper mechanic to equate function pointers would be trivial, as already proven by a plugin Calin wrote. Adding a new control type for multiline text boxes (text areas) would probably be more complicated, but is something that should be added to AGS anyway. A text-script parser could then be supplied or custom designed with these features.

Quote from: AJA on Wed 26/12/2012 15:20:562. Reload interaction scripts. While the game is running. Seriously, what a time saver. Found a typo? A character walked to the wrong spot? Fix it in the script, press a button to reload it, and test again.

Since AGScript is compiled and not interpreted, this is a by-design "con" of the language. However, C++ stands as a strong proof that compiled languages are still viable. Offering interpreted alternatives such as Lua should be a goal that is kept in mind by those updating the engine, but should not be included in the engine itself. Alternate languages should be provided via plugins, as extensions to AGS.

It might be useful to consider moving toward an interpreted design, perhaps even just for the debugger, but I don't view being a compiled language as a direct flaw in AGScript.

Quote from: AJA on Wed 26/12/2012 15:20:563. Coroutines. This has been mentioned many times in this thread and it really makes seemingly multi-threaded interactions really simple to make. Of course, you'll eventually run into problems with concurrency, like a background thread controlling a character and then the main thread needing to control that character at the same time.

I understand how coroutines are useful, but I haven't heard many specific examples of how they would be used in making an adventure game. Queued background speech is something that has been done multiple times (my module is updated to work with recent AGS versions, although I don't believe it uses any of the 3.2 audio functions). The CharacterControl module handles queuing various other types of interactions. The examples I've seen here of coroutines have applied to simplify the process, essentially just negating the need for the modules. But the modules have already been made publicly available, and the resultant code is of comparable simplicity.

I'm not trying to sound close minded here, allowing AGScript to create and run separate threads in the engine would be nice for advanced users. I simply don't feel that a compelling case has been made for this point, more just that this is one more thing added to the list.

Quote from: AJA on Wed 26/12/2012 15:20:564. Return self and being able to chain method calls. Here's an example of what my interaction scripts are full of. The methods seductive/concerned would change the character's facial expression accordingly.
Code: Lua

cDude:seductive()
     :say( "What's up, love?" )
     :say( "How about we go for a walk?" )
     :concerned()
     :say( "Do you think I'm asking too many questions?" )

Personally I feel that chaining unrelated function calls is simply bad practice. You're doing this solely for the purpose of avoiding having to reference the object again. It's ultimately a matter of preference I suppose (for languages that support it), but it could lead to confusion or error-prone code. For example, what if I have a function that just happens to return a Character*, but uses null for an error case? If you've used it in your chain without knowing about the error case then you could have some difficulty debugging the code.

Quote from: AJA on Wed 26/12/2012 15:20:565. Edit mode. Press tab and you can move characters, objects and hotspots, create new hotspots and finally export the room's Lua script so you can do simple AGS editorey things within the game.

I'm not certain what you're referencing here. It would be simple to set up a debugging interface for moving things around, turning them on and off, etc. There are modules that provide some of this generically. As far as creating new hotspots, the AGS engine itself doesn't allow new hotspots to be created at run-time so I'm guessing that you're managing this yourself in Lua code? I imagine that it would be of comparable complexity to implement something similar in AGScript (but then I'm not sure how you're doing it).

Quote from: AJA on Wed 26/12/2012 15:20:566. Puzzle tracking. All the game's puzzles are defined as simple state machines that also modify the game environment when certain states are reached. I was pretty lazy about this, so basically, when you reach the end of a puzzle the puzzle's end state makes sure the game is in the correct state: hotspots are turned on/off, objects moved, etc. And then comes the best part, you can skip puzzles, and the game will be in the correct state, as if you'd played through the puzzle. Very handy when debugging. Of course, you need to be careful that the puzzle script actually changes the game state correctly.

A finite state machine is something that is incredibly simple to set up in AGScript. You could use rep_ex to keep the game state consistent with the machine state for now. When function pointers are eventually implemented in AGScript you could add a callback function instead of having to manage it in rep_ex. All in all this would be comparable in implementation.

Quote from: AJA on Wed 26/12/2012 15:20:567. Making a table (~array) log any changes made to its indexed values. Very handy for debugging.
Code: Lua

cDude.state.happy = true
-- Prints to the log something about key happy being set to true

While AGS doesn't have something like this built-in, logging changes like this would be simple to set up with encapsulation. You could either just have the accessor methods exposed as part of the public interface or use attributes to mask that nastiness. In either case the actual data would be protected and in the accessor methods you would call the logging function.

I'm really not trying to oppose Lua as an alternative to AGScript, but I am trying to debunk this idea that AGScript needs to be replaced. Just because there are a few things that need to be added doesn't mean that AGScript is suddenly obsolete and should be deprecated entirely.

Quote from: Calin Leafshade on Wed 26/12/2012 15:07:14Oh yea, another thing Lua can do that AGS can't. (Exceptions)

The connotation represented by this statement is that AGS will never have exception handling. The fact of the matter is that AGS already detects both run-time and compile-time errors (the latter being something that Lua, as an interpreted language "can't do"). AGS doesn't currently have a way for the user to handle exceptions (such as a null pointer being (de)referenced), but that doesn't mean it couldn't (or shouldn't) be included at a later time. Isn't improving the current state of AGS the entire point of releasing new versions of the program?

Calin Leafshade

Quote from: monkey_05_06 on Thu 27/12/2012 21:15:34
Adding a proper mechanic to equate function pointers would be trivial, as already proven by a plugin Calin wrote.

To be clear, my plugin wasn't even close to allowing true function pointers. It simply queued a script function which is not the same thing at all. There was no control over the params and you couldnt manipulate the pointer in any sense. It was entirely faked.

Quote from: monkey_05_06 on Thu 27/12/2012 21:15:34
A text-script parser could then be supplied or custom designed with these features.

You need more than simplistic access to user functions to make a sciprt parser. Unless you plan on implementing all the other language constructs by hand which would be amusing.

Quote from: monkey_05_06 on Thu 27/12/2012 21:15:34
Quote from: AJA on Wed 26/12/2012 15:20:562. Reload interaction scripts. While the game is running. Seriously, what a time saver. Found a typo? A character walked to the wrong spot? Fix it in the script, press a button to reload it, and test again.

Since AGScript is compiled and not interpreted, this is a by-design "con" of the language. However, C++ stands as a strong proof that compiled languages are still viable. Offering interpreted alternatives such as Lua should be a goal that is kept in mind by those updating the engine, but should not be included in the engine itself. Alternate languages should be provided via plugins, as extensions to AGS.

No one is arguing that compiled languages are not "still viable" for a lot of things. But they are not (or less) suitable for game scripting. There is a reason that a huge majority of games use interpreted languages for their content and it's exactly the reason AJA mentioned. It is invaluable, especially when making someting like an adventure game which is mostly scripted content as opposed to engine stuff.

Quote from: monkey_05_06 on Thu 27/12/2012 21:15:34
Quote from: AJA on Wed 26/12/2012 15:20:564. Return self and being able to chain method calls. Here's an example of what my interaction scripts are full of. The methods seductive/concerned would change the character's facial expression accordingly.
Code: Lua

cDude:seductive()
     :say( "What's up, love?" )
     :say( "How about we go for a walk?" )
     :concerned()
     :say( "Do you think I'm asking too many questions?" )

Personally I feel that chaining unrelated function calls is simply bad practice. You're doing this solely for the purpose of avoiding having to reference the object again. It's ultimately a matter of preference I suppose (for languages that support it), but it could lead to confusion or error-prone code. For example, what if I have a function that just happens to return a Character*, but uses null for an error case? If you've used it in your chain without knowing about the error case then you could have some difficulty debugging the code.

Well the point is that in Lua this is *possible*, not mandatory. In AGS you can't reference function returns as objects in an immediate fashion. (prove me i'm wrong with incredibly complex #defines or accessor functions or something as is expected)

Quote from: monkey_05_06 on Thu 27/12/2012 21:15:34
I'm really not trying to oppose Lua as an alternative to AGScript, but I am trying to debunk this idea that AGScript needs to be replaced. Just because there are a few things that need to be added doesn't mean that AGScript is suddenly obsolete and should be deprecated entirely.

Although this was never my argument, I do think that AGS Script should be replaced. Not necessarily by Lua (although Lua is an excellent choice) but I think the strongest reason to keep AGSScript is that "everyone knows it". Which I don't think is a good reason. It could be replaced with Angel Script which is functionally equivilent to AGS Script in most ways but has many more features and has good support upstream.

Crimson Wizard

#49
I have to say, I am disappointed to see this thread is turning towards "improve AGSScript VS replace with Lua".
That's an interesting topic on its own, but it belongs to engine development.

If I remember correctly, the point of this thread was that in current state Lua may be better than AGSScript.

So far my impression was that it is easier to write advanced stuff. Maybe because you don't have to keep various AGSScript restrictions in mind (that thing sometimes have a psychological impact). But having much experience with coding, I am using it rather intuitively.
I am yet unsure how easier that would be for beginners to learn it. I think only people can tell.

Denzil Quixode

Quote from: monkey_05_06 on Thu 27/12/2012 21:15:34
compile-time errors (the latter being something that Lua, as an interpreted language "can't do").
This actually isn't quite right, Lua is not interpreted but compiled to a virtual machine bytecode, so any genuine syntax errors (as opposed to typos creating unintended new variables) can be caught and cause an error at compile-time.

SpeechCenter

Reading this thread, I think CW is correct that the question of what's better is unnecessary. It seems that Lua has advantages for some complex scenarios and AGS Script has advantages for those who would like to keep it simple.

I seem to recall this discussion already took place in another thread and one option was decoupling the language from the editor, making Lua an option, but retaining AGS Script capabilities. Was this approach discussed and abandoned or simply ignored?


Crimson Wizard

#52
Quote from: SpeechCenter on Sat 29/12/2012 17:27:39
Reading this thread, I think CW is correct that the question of what's better is unnecessary.
That's not really what I meant, but okay. :)

Quote from: SpeechCenter on Sat 29/12/2012 17:27:39
I seem to recall this discussion already took place in another thread and one option was decoupling the language from the editor, making Lua an option, but retaining AGS Script capabilities. Was this approach discussed and abandoned or simply ignored?
I am afraid that many discussions about improving AGS end in nothing because no one starts working on them. At least that's how it seems.
Since I am acquainted with the engine more than with editor, and also was working with script interpreter for a while now, I can mention that, in my opinion, it is pretty possible to make abstract "script runner" interface, and hide script interpreters behind one. By doing so we will allow to either put more than one implementation into engine, or implement interpreters (AGSScript too) as more specialized plugins.

Ryan Timothy B

Quote from: SpeechCenter on Sat 29/12/2012 17:27:39
It seems that Lua has advantages for some complex scenarios and AGS Script has advantages for those who would like to keep it simple.
In my opinion, this statement is completely wrong.

AGS Script is as "simple" as a TV with only a knob for controlling channels. Having to get up to turn the dial instead of what is normally efficient and easy by just using the TV remote. I found with AGS Script I had to wrap myself around a telephone pole 6 times before I could do something beyond its scope.

As Calin said, AngelScript or something similar to C (or Java - Monkey loves Java!), has nearly the exact same syntax as you're familiar with in AGS Script. It just has more capabilities. This is why I'm so confused why someone as intelligent as Monkey keeps saying all we need is AGS Script, because he enjoys 20 workarounds to do something ordinarily simple. :-\

Babar

Quote from: Crimson Wizard on Fri 28/12/2012 08:58:57
I am yet unsure how easier that would be for beginners to learn it. I think only people can tell.
Not at all being qualified to weigh in on any of the other stuff, but I don't think that THAT specific scenario is really the problem at all. If someone who knew nothing about either AGSscript OR Lua approached making a game in AGS, I'm not sure learning either language would be more difficult than learning the other.

Again, I don't know about the other problems, or the technical issues in either Lua or AGSscript so I am not qualified to speak on those, but it is true, even with me being knowledgeable about programming languages in general and how syntax would usually work in most languages, sheer laziness would definitely be a major factor in me continuing to use the usual AGSscript, as opposed to downloading the Lua plugin and using Lua to code in AGS (even though I should probably learn Lua at some point :D, seeing how widely used it is in the game industry especially).
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

Calin Leafshade

I think the *best* way forward would be a language agnostic system with several different bindings for different languages.

However, my original argument was simply that right now it's silly to use AGS Script when Lua is available.

Monsieur OUXX

To me, the biggest argument in favor of dropping the AGS language is that its grammar has loopholes; and the object-oriented inheritance system's implementation is half-baked. I'm ok with any syntax as long as that syntax has been proven consistent by armies of languages specialists -- instead of invented along the way (no offense to CJ -- as it's been said before, he used the appropriate technology level at all times, and provided amazing tools on his own).

I support the idea of moving to a "language-agnostic system with several different bindings for different languages" (these are Calin's words).

For the time-being and a smooth transition, would it be possible to provide both in the template? Why not offer the choice of mixing the languages, using tags in the code? (just a silly idea).

The very least would be that, at first, the Lua version looks exactly the same as the AGS one in its structure (execute_always, etc.) and function names. This would be an incentive to migrate to it.

 

SpeechCenter

Quote from: Calin Leafshade on Sat 29/12/2012 19:45:43
However, my original argument was simply that right now it's silly to use AGS Script when Lua is available.
I can see two arguments:

  • More AGS developers know it so there would be more options to recruit a person to a game.
  • As far as I know there are some editor functions that would not work with the current plugin, such as creating a translation file. This means that the specific plugin would have to produce all those functions on its own.

I'm not arguing against Lua, just that there may be cases where AGS Script makes sense in the current state.

theSynapse

Moving over to Lua would be a good move for the future development and propagation of the engine and the community. Lua is a de facto standard in the games industry and lots of people program in it outside of that. It's meant to be one of the easiest languages to learn. Already, now that I've learned that AGS uses Lua, I'll be more likely to think about doing some serious development in AGS rather than looking at something else like Unity (at least to start with).

It's worth thinking about what will benefit the community and development of AGS long-term. It's open source now - you want to think about pushing the Lua side so that more people will get involved.

Milhouse

For me (new to AGS) it is not clear in what direction AGS is heading to:
- 2D retro (fan) games with easy to use development tools
- "state of the art" adventure games playable on multiple platforms with the option of using 3D characters or even environments (probably steep learning curve)

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. The second group is probably afraid of having to switch to another tool and drop AGS in order to get their (commercial) adventure games running in less time/for less money, etc. Lua also seems to be a kind of standart in game programming. So probably developers having used other tools with Lua support would have an easier start / be easier to find.

So the actual question to be answered is in what direction is AGS supposed to go? 8-)

Marcus

SMF spam blocked by CleanTalk