Adventure Game Studio

Community => Adventure Related Talk & Chat => Topic started by: Calin Leafshade on Thu 01/05/2014 16:40:38

Title: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Thu 01/05/2014 16:40:38
Thing 1:

Dialogue *trees*.

AGS doesn't really have a true dialogue tree system in the traditional sense. Dialogues were a series of unconnected lists. So I made this:

(http://i.imgur.com/RvrRwJy.png)

True dialogue trees with link nodes and conditions. The code is loaded dynamically as lua scripts so any lua is valid within a dialogue script. Which brings me to...

Thing 2:

Dialogue scripting within main scripts.

There's no obvious reason why we should have to write cCharacter.Say("This is what I say"); all the time. It's a common enough thing to do and people dont write scripts like that. So what if we could do this:

Code (lua) Select

if myValue > 1 then
    Billy: Gee, I sure hope myValue was bigger than 1
else
    Billy: Lol, myValue.. You cad.
end


Since we can preprocess lua code before running it this is pretty trivial to automatically convert to the correct code. Goodie time-saver!

Thing 3.

Rewriting the pathfinder.

AGS script is probably too slow to rewrite the pathfinder and the lack of a hashtable means looking up nodes would be perilously slow. In Lua we don't have this problem.

(http://i.imgur.com/bSxKewC.png)

My new pathfinder is more accurate and has tunnel-based smoothing. Also, when walking, characters continue walking at the end of a node which avoids the nasty stopping that AGS characters have a tendency to do at sharp corners.

An added benefit of this is that the walking code is kept within the user domain which means you can dynamically edit the walking frames without that nasty 1 frame delay.

I think thats everything I've been playing with... THE POWER OF LUA! UNITE!
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Andail on Thu 01/05/2014 18:22:47
Pretty impressive!
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Thu 01/05/2014 20:53:37
4.

Use a sprite as a kind of "tint mask" to dictate the tinting/lighting of characters stood at that position which allows for gradual blending between tints.

Try starting with a blurred version of the background:

(http://i.imgur.com/qrvZaOH.png)

Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Eggie on Thu 01/05/2014 21:55:28
I'm torn about that dialogue editor, it looks very powerful and modern and just like a big fancy pro modding kit but there was just something I always liked about it being one big lump of text you could dive into and edit...
I mean, unless I needed to move options around. Those times I REALLY, REALLY want a big fancy pro dialogue editor.

Like I said, I'm torn. TORN.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Peder 🚀 on Thu 01/05/2014 23:00:59
You're posting about these awesome things you've done, but will you ever share the tools you've made and example code/source codes? :)
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Armageddon on Thu 01/05/2014 23:07:36
But what about Adore? :-D

It would be amazing if you'd release the pathfinding code, I hate the AGS pathfinding.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Secret Fawful on Fri 02/05/2014 00:15:06
Quote from: Calin Leafshade on Thu 01/05/2014 16:40:38
Thing 3.

Rewriting the pathfinder.

AGS script is probably too slow to rewrite the pathfinder and the lack of a hashtable means looking up nodes would be perilously slow. In Lua we don't have this problem.

(http://i.imgur.com/bSxKewC.png)

My new pathfinder is more accurate and has tunnel-based smoothing. Also, when walking, characters continue walking at the end of a node which avoids the nasty stopping that AGS characters have a tendency to do at sharp corners.

An added benefit of this is that the walking code is kept within the user domain which means you can dynamically edit the walking frames without that nasty 1 frame delay.

(http://media.tumblr.com/981cc7bca106b8c5dcf5eec44da942bb/tumblr_inline_moklkzufoN1qz4rgp.gif)

Dear god, I hate the pathfinding in AGS.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Dropped Monocle Games on Fri 02/05/2014 11:50:53
Quote from: Calin Leafshade on Thu 01/05/2014 20:53:37
4.

Use a sprite as a kind of "tint mask" to dictate the tinting/lighting of characters stood at that position which allows for gradual blending between tints.

Try starting with a blurred version of the background:

(http://i.imgur.com/qrvZaOH.png)



8-0
I WANT THIS!!
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Grim on Sat 03/05/2014 03:53:02
This TINT/lighting mask... I've been dreaming about it for YEARS...
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Sat 03/05/2014 10:27:26
Thing 5.

Multiplicative tinting

(http://i.imgur.com/dWS6p17.png)

AGS's tinting algorithm is weird and the lighting level is related to the saturation level which doesnt make a lot of sense. Lua is fast enough to tint character sprites on the fly, pixel by pixel, overwriting the default behaviour.

Re: tint mapping. You can do that easily enough without Lua. Just have a DrawingSurface open for your tintmap and grab the pixels every frame. It's the most simple of the things presented here and AGS Script is fast enough for it.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Sat 03/05/2014 22:15:07
Thing 6.

Functions as actions.

Remember this:

Code (ags) Select

function hHotspot1_UseInv()
{
    if (player.ActiveInventory == iFoo)
    {
        player.Say("I don't think i should use the foo with that.");
    }
    else if (player.ActiveInventory == iBar)
    {
        player.Say("Gee, I shouldnt use the Bar with that just now.");
    }
    else if (adInfinitum)
    {
        dieOfBoredom();
    }
    else
    {
        player.Say("that doesn't work");
    }
}


And this has to be repeated for *every* *single* hotspot.

How about this instead:

Code (lua) Select


hHotspot1.UseInv = {
    [iFoo] = function() player:Say("I don't think I should use the foo with that") end,
    [iBar] = function() player:Say("Gee, I shouldn't really use the bar with that.") end
}

--now call it in your main game code:

local func = hHotspot1.UseInv[player.ActiveInventory] or unhandled -- unhandled is our generic "that doesnt work" function
func() -- call the function



Much neater, and the act of using an inventory item with a hotspot is more clearly defined without a bazillion if/else statements.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Monsieur OUXX on Wed 07/05/2014 14:23:42
Deadly.
I think the thing that comes immediately handy to beginners is the dialogs thing. The community slowly got used to all the awkwardness of the built-in dialog editor, but to a newcomer, it's seriously like hell.

I wish AGS wasn't in that sort of in-between situation between old and new, because I would totally consider migrating Seven Cities of Gold to Lua.

Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Tournk on Mon 12/05/2014 14:41:44
Quote from: Calin Leafshade on Sat 03/05/2014 22:15:07

How about this instead:

Code (lua) Select


hHotspot1.UseInv = {
    [iFoo] = function() player:Say("I don't think I should use the foo with that") end,
    [iBar] = function() player:Say("Gee, I shouldn't really use the bar with that.") end
}

--now call it in your main game code:

local func = hHotspot1.UseInv[player.ActiveInventory] or unhandled -- unhandled is our generic "that doesnt work" function
func() -- call the function



Much neater, and the act of using an inventory item with a hotspot is more clearly defined without a bazillion if/else statements.


Wonderful! I like it neat and compact!  :)
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Vince Twelve on Wed 14/05/2014 05:54:23
Calin, is there any up-to-date documentation for the Lua plugin?  All the examples on the site that I've tried have not compiled.  I was able to call a lua function and gat it to display text to the screen, but I couldn't get the functions to return anything.  The compiler says LuaValue doesn't exist, or when I try LuaValueList, I'm not sure how to get it to a string.  There are contradicting examples out there, but they don't seem to work.

Also, I haven't looked into this, but does using this rule out using the iOS/Mac/Android ports as they currently exist?
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Wed 14/05/2014 07:01:40
Hi Vince,

As far as I know all the documentation should still hold true. Nothing has changed since inception.

Generally speaking however, I don't return values from Lua to AGS. Because AGS has no way of dynamically casting objects it makes things very messy so I keep my entire game in the Lua domain.

For example of how I do this see the following link (cached from google because i stupidly deleted the database yesteday)  It includes a full description of interoperation between AGS and Lua with code examples.

http://webcache.googleusercontent.com/search?q=cache:s48HXgtCbOoJ:www.themccarthychronicles.co.uk/+&cd=1&hl=en&ct=clnk&gl=uk

With regards to the ports, the plugins are open source and currently included in the AGS git repo so there's no reason why the current ports couldn't use them (Lua can be compiled on a toaster). I'm not sure if the plugin is compiled by default though. You'd have to ask Crimson Wizard.

Edit: If you'd prefer something more complete, heres my entire AGS-Lua Interop system:

AGS: http://hastebin.com/sixikoruna.c (This is the *only* code in my AGS project)

Lua: http://hastebin.com/eqewuneceq.lua
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: abstauber on Sun 18/05/2014 22:02:22
Hey Calin,
somehow your hastebin content went missing. Any chance for a second glimpse?
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Sun 18/05/2014 23:01:59
Sure thing.

heres my globalscript

Code (ags) Select
int lastRoom = -1;

#ifdef USE_LUA

function game_start()
{

  int i = 1;
  while (i < Game.MouseCursorCount)
  {
    Mouse.DisableMode(i);
    i++;
  }
 
  Mouse.Mode = eModeWalkto;
 
  Lua.SetVar("DebugMode", Lua.BoolValue(false));
  #ifdef DEBUG
  //Debug(4, 1);
  Lua.SetVar("DebugMode", Lua.BoolValue(true));
  #endif
 
  Lua.RunScript("main.lua");

 
  Lua.Call("FireEvent", Lua.StringValue("game_start"));
 
}



function on_key_press(eKeyCode keycode)



#ifdef DEBUG
  if (keycode == eKeyCtrlX)
    Debug(3, 0);
#endif
  LuaValueList *l = Lua.NewValueList();
  l.Add(Lua.StringValue("on_key_press"));
  l.Add(Lua.IntValue(keycode));
  Lua.Call("FireEvent",l);
}

function on_mouse_click (MouseButton button)
{
  LuaValueList *l = Lua.NewValueList();
  l.Add(Lua.StringValue("on_mouse_click"));
  l.Add(Lua.IntValue(button));
  Lua.Call("FireEvent",l);
 
}

function on_event(EventType ev, int data)
{
 
  LuaValueList *l = Lua.NewValueList();
  if (ev == eEventAddInventory) l.Add(Lua.StringValue("AddInventory"));
  else if (ev == eEventEnterRoomBeforeFadein) l.Add(Lua.StringValue("EnterRoomBeforeFadein"));
  else if (ev == eEventLeaveRoom) l.Add(Lua.StringValue("LeaveRoom"));
  else if (ev == eEventGUIMouseDown)
  {
      GUIControl *gc = GUIControl.GetAtScreenXY(mouse.x, mouse.y);
      LuaValueList *lvl = Lua.NewValueList();
      if (Mouse.IsButtonDown(eMouseLeft))
      {
        on_mouse_click(eMouseLeft);
        lvl.Add(Lua.IntValue(eMouseLeft));
      }
      if (Mouse.IsButtonDown(eMouseRight))
      {
        on_mouse_click(eMouseRight);
        lvl.Add(Lua.IntValue(eMouseRight));
      }
     
      if (gc == null)
      {
        GUI *g = GUI.GetAtScreenXY(mouse.x, mouse.y);
        if (g != null)
          g.LuaMethod("OnClick",lvl);
      }
      else if(gc.AsButton != null)
      {
        gc.AsButton.LuaMethod("OnClick",lvl);
      }
      return;
     
  }
 
  l.Add(Lua.IntValue(data));
  Lua.Call("FireEvent",l);
 
 
}

function repeatedly_execute_always()

  Lua.Call("FireEvent", Lua.StringValue("repeatedly_execute_always"));
  Lua.Call("FireEvent", Lua.StringValue("late_repeatedly_execute_always"));
  Lua.SetVar("Blocked", Lua.BoolValue(true));
}

function repeatedly_execute()
{
 
    if (player.Room != lastRoom)
  {
      Lua.Call("FireEvent", Lua.StringValue("EnterRoomAfterFadein"));
      lastRoom = player.Room;
  }
 
    LuaValueList *l = Lua.NewValueList();
  l.Add(Lua.StringValue("LeaveEdge"));
 
  if (player.y > Room.BottomEdge)
  {
    l.Add(Lua.StringValue("bottom"));
    Lua.Call("FireEvent", l);
  }
  else if (player.y < Room.TopEdge)
  {
    l.Add(Lua.StringValue("top"));
    Lua.Call("FireEvent", l);
  }
  else if (player.x < Room.LeftEdge)
  {
    l.Add(Lua.StringValue("left"));
    Lua.Call("FireEvent", l);
  }
  else if (player.x > Room.RightEdge)
  {
    l.Add(Lua.StringValue("right"));
    Lua.Call("FireEvent", l);
  }
 
  Lua.Call("FireEvent", Lua.StringValue("repeatedly_execute"));
  Lua.SetVar("Blocked", Lua.BoolValue(false));
}



function unhandled_event (int what, int type)
{
  LuaValueList *l = Lua.NewValueList();
  l.Add(Lua.StringValue("unhandled_event"));
  l.Add(Lua.IntValue(what));
  l.Add(Lua.IntValue(type));
  Lua.Call("FireEvent",l);
}


#endif
function dialog_request(int param) {
}

and the lua module called interop.lua

Code (lua) Select
-----------------------------------------------------
--
-- Lua Control Module
--
--  Calin Leafshade
--
-- A module to register global events in lua
--
-----------------------------------------------------

local events =
{
delegates = {},
objects = {}
}

function events:registerObject(obj)
table.insert(self.objects,obj)
end

function events:register(event, priority, callback)
 
if type(priority) == "function" then
callback = priority
priority = 100
end
 
local callbacks = self.delegates[event] or {}
self.delegates[event] = callbacks
table.insert(callbacks, {f = callback, priority = priority})
 
table.sort(callbacks, function(a,b)
return a.priority < b.priority
end)
 
end

function events:fire(event, ...)
for i,v in ipairs(self.objects) do
if type(v[event]) == "function" then
if v[event](v,...) then break end
end
end
for i,v in ipairs(self.delegates[event] or {}) do
if v.f(...) then break end
end
end

return events

then my main.lua looks something like this

Code (lua) Select
Events = require('interop.lua')

function FireEvent(...) -- this is a global function to allow AGS easier access to it
Events:fire(...)
end

--then you can use the events module like this in any lua file:

Events:register("game_start", function()
    aAudio:Play()
end)

--you can also make objects like this:

local myObject = {}

function myObject:repeatedly_execute_always()
    -- do this every frame
end

Events:registerObject(myObject)

-- This means that all the events in this object will be run when triggered by interop (if they exist in the object, they dont have to)

These events basically give you everything you need. You need to make your own hotspot interaction system but thats very easy and I can show you how if you need me to.

Any questions let me know!
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: abstauber on Thu 18/09/2014 20:43:07
Sorry to bump this...
Calin, is it possible to have 8-bit palette rotation done by the mighty powers of lua? That's really a thing I've been missing for ages. In 8-bit it's half broken (as you can't control the speed) and in 16,32 bit it not possible at all.

So cycling colors of a dynamic sprite would be super duper cool and a number one reason to finally move to lua.

For all those not familiar with this effect, be stunned right here:
http://www.effectgames.com/demos/canvascycle/


-- edit: it's not half broken in 8-bit ;)
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Thu 18/09/2014 20:45:45
Well Lua can't *do* anything that the main engine can't do really. It's just much faster so you can do things that are prohibitively slow in the main engine.

So if the api exposes the functions (I dont know anything about 8bit stuff) then it would be faster in lua.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: abstauber on Thu 18/09/2014 21:04:49
Ah, okay - thanks for the clarification. I thought that lua could maybe take the sprite, convert it to 8bit, shift the colors around and hand it back to AGS.
There also seems to be ags.palette.setRGB in lua, but I suppose it only works for real 8bit games.
I just want to save some time not to pre-render everthing :)
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Scavenger on Thu 18/09/2014 21:47:28
Quote from: abstauber on Thu 18/09/2014 20:43:07
Sorry to bump this...
Calin, is it possible to have 8-bit palette rotation done by the mighty powers of lua? That's really a thing I've been missing for ages. In 8-bit it's half broken (as you can't control the speed) and in 16,32 bit it not possible at all.

I'm not sure what you mean - CyclePalette just rotates the palette around one slot, if you make your own timer you can slow it down or speed it up. It doesn't have to be called every loop, just call it every X loops, where X is how slow you want it.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: abstauber on Thu 18/09/2014 21:59:22
yeah you're right, I've corrected my post.
I'd still love to achive this in 32bit.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Thu 18/09/2014 22:13:00
If you want to do that then its perfectly possible but you'd need to do some processing and stuff.

You'd have to store your own palette or build one from a sample image and then step through every time you wanted to step it. I reckon that would be easily fast enough in lua.
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: abstauber on Fri 19/09/2014 09:05:58
Sorry for being such a noob:
I suppose in addition to the lua plugin and lua itself, I need some sort of graphics lib like 'CD'? And would the game still be portable afterwards?
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Calin Leafshade on Fri 19/09/2014 09:35:26
Nope, no graphics lib required and lua is included with the lua plugin.

The API is basically the same as ags script.

It would look something like this:

Code (lua) Select


function skipPal(numberOfSlotsToSkip, spriteNum)

    local sprite = ags.DynamicSprite.CreateFromExistingSprite(spriteNum)
    local ds = sprite:GetDrawingSurface()

    for x=0, sprite.Width - 1 do
        for y=0, sprite.Height - 1 do
            local color = ds:GetPixel(x,y)
            -- lookup the color from our palette using a lookup table
            local palIndex = pal.lookup[color]
            -- set the drawing color to the palette number plus the slots to skip
            ds.DrawingColor = pal[palIndex + numberOfSlotsToSkip]
            ds:DrawPixel(x,y)
        end
    end

    ds:Release()

    return sprite
end

Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: abstauber on Fri 19/09/2014 13:12:02
Hey, thanks for the snippet. It really doesn't look all that hard.

Have you managed to compile it for Linux yet?
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: Crimson Wizard on Fri 19/09/2014 13:33:35
Quote from: abstauber on Fri 19/09/2014 13:12:02
Have you managed to compile it for Linux yet?
Lua plugin won't be fully compatible with 64-bit Linux until we completely rewrite AGS plugin API.

By "fully compatible" I mean that it may work, but some things may not.
http://www.adventuregamestudio.co.uk/forums/index.php?topic=45810.msg636451744#msg636451744
Title: Re: Some things I've been doing in AGS made possible by the power of the mighty Lua.
Post by: abstauber on Fri 19/09/2014 14:05:19
Fair enough :)
I think I will try to get something done in Lua first. Once I make enough progress with my project, I'll decide whether to pre-render the effects or to use this lua magic (which I hope to get done until then )