lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Fri, Jul 28, 2000 at 04:32:07PM -0300, Falko Poiker wrote:
> I realize I haven't explained a certain aspect of what I want lua
> to do for my game.  I would like to define sequential scripted
> commands whereby I can create a file that looks like the following:
> 
> function attack (target)
>     if (not infiringrange(target))
>         moveto(firingrange(target))
> 	  -- execution of the lua function attack "stops" here until 
> 	  -- the attacking soldier has reached firing range
> 	      -- game execution (as well as lua reading other
> 		-- lua files) continues
>     end
> 	-- the soldier is now within firing range
>     openfire(target)
> end
> 
> 
> In this simplistic example, I demonstrate something I haven't been
> able to achieve with lua yet, that is blocking functions.  Is 
> there a way to do this?  

I know what you are trying to do and there really isn't a
straightforward way to do this in Lua. I recommend you follow the
advice of others on here and use non-blocking style for these
functions. 

However, if you think you really want to do blocking style
functions, here is some more information: 

-----
First, explaining blocking (or "continuation") style.
-----

The code you wrote above is not actually in a blocking (or
"continuation") style anyhow. "infiringrange()" would likely block
until in firing range, so it wouldn't ever make sense do to "not
infiringrange()" because the function would never return false.

It would either be (blocking style):

function attack(target)
  while mystate == attacking do
    moveto(firingrange(target)) -- does not return until we're there
    openfire(target)
  end
end

Or it would be (non-blocking style):

function do_ai(target)
  if mystate == attacking then
    if infiringrange(target) then
      fireat(target)
    else
      moveto(target)
    end
  end
end

----
How to implement the blocking style.
----

If you really wanted to implement the above blocking style, there is
only one method with Lua. You would have to create a separate C-stack
for every entry into a blocking Lua function. These would be like
separate "threads". They don't necessarily have to be preemptively
threaded. However, you would:

 a) allocate a C-Stack
 b) call the attack() function in lua from C
 c) when the Lua code called into one of your blocking functions,
    such as moveto(), your C code would do the computation, 
    send the object moving, mark that stack as "blocked
    waiting to arrive at a given location", and then it would
    switch to the next waiting C-stack.

The trouble with doing this is that you end up having to pre-allocate
LOTS of C-stack space that you are not going to use, because there has
to be a separate C-stack for every entry into Lua you do. This type of
programming construct is more commonly called a "continuation" or
"call with continuation". It's normally only used in systems where the
"stack" of the language is allocated on the heap, instead of being
part of a C-like stack. (for example: in Lisp)

> One way I can think of is for my game to manually read the lua 
> files line by line - every line would return to the game whether 
> it's a "blocked" line or not, and what the condition of that 
> block is (what game event causes it to unblock). 

If you really want to do this, you would be better off writing a
simple sequencing language of your own, which is compiled into a token
list, and which you do your own continuation style processing of. Or
try to incorporate a Lisp engine with call-cc into your game.

When writing blocking ai-logic for an object, a "function" is more of
a "trait" for an object. Many traits would be required to make an
object whole. For example, you might have:

function trigger_finger()
  while 1 do
    targetlist = waitfortargets() -- blocks until targets are here
    my_target = best_target(targetlist) -- not blocking
    shootat(my_target)
  end
end

function flee_when_dying()
  while 1 do
    waitfordamageat(10) -- this is a "low" damage value
                        -- so I'm going to die!
    waitformoveto(safety)
  end
end

function find_enemy()
  while 1 do
    enemy = nearestenemy()
    waitformoveto(enemy)
  end
end


However, I recommend you use the simpler non-blocking style to write
the event logic.


-- 
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + jeske@chat.net