File: andreas_ghosts.xml

package info (click to toggle)
enigma 1.30%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 76,132 kB
  • sloc: xml: 162,251; cpp: 67,393; ansic: 28,606; makefile: 1,986; sh: 1,298; yacc: 288; perl: 84; sed: 16
file content (665 lines) | stat: -rw-r--r-- 23,474 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<el:level xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://enigma-game.org/schema/level/1 level.xsd" xmlns:el="http://enigma-game.org/schema/level/1">
  <el:protected>
    <el:info el:type="library">
      <el:identity el:title="" el:id="lib/andreas_ghosts"/>
      <el:version el:score="1" el:release="1" el:revision="0" el:status="released"/>
      <el:author  el:name="Andreas Lochmann" el:email="" el:homepage=""/>
      <el:copyright>Copyright © 2006 Andreas Lochmann</el:copyright>
      <el:license el:type="GPL v2.0 or above" el:open="true"/>
      <el:compatibility el:enigma="0.92">
      </el:compatibility>
      <el:modes el:easy="false" el:single="false" el:network="false"/>
      <el:comments>
        <el:code>Lua 5.1 and XML converted by Leveladministrators</el:code>
      </el:comments>
      <el:score el:easy="-" el:difficult="-"/>
    </el:info>
    <el:luamain><![CDATA[

-- andreas_ghosts, a lua-library for Enigma
--
-- Version 1/3
--
--
-- What is this?
--
--  With a "ghost" I mean an actor that's moving along predefined
--  ways ("rails") with possibly random behavior when choosing which
--  rail to follow. In terms of Esprit, these actors have been called
--  "spermbirds". Too avoid further confusion with future additions
--  of these very special actors (they have own images) to Enigma,
--  I call my version of them "ghosts". Take a look at the level
--  "Pac Marble" (andreas22) to see them doing their job.
--
--
-- Usage:
--
--  You have to set up four different kinds of objects:
--
--    (1) the ghosts themselves,
--    (2) the rails, which define the allowed ways for the ghosts,
--    (3) the timer-stone,
--    (4) if you use a level editor, correct the slope force.
--
--  (1)  You can create a ghost via
--
--    ghosts_set_ghost(x,y,actor,rail,alg,attribs)
--
--  with x,y the position of the ghost, actor the type of actor
--  to be used (e.g. "ac-rotor" or "ac-blackball"), rail the number
--  of the rail the ghost might use, alg defining the algorithm to
--  be used (see below) and attribs a table of further attributes
--  for the actor. A typical example would be:
--
--    ghosts_set_ghost(12,13,"ac-top", 1, ghosts_direction_intelligent,
--                                     {range=0, force=5, gohome=FALSE})
--
--  You may use this as a parent for ant.lua, too:
--
--    actors["..."]=cell{parent={{ghosts_set_ghost,"ac-top",1,
--              ghosts_direction_intelligent,{range=0,force=5,gohome=FALSE}}}}
--
--  Remark 1: If you use a top or rotor, remember to set "gohome=FALSE",
--            otherwise the ghost will move unsteady or not at all.
--            Also reduce the range and/or force to sensible values.
--            If you use a marble, you should set "mouseforce=0".
--  Remark 2: Ghosts may not have arbitrary names! The name of a
--            ghost is determined as "ghost_X" with X the number of
--            the ghost, determined in the order of definition.
--  Remark 3: To each of the coordinates the value 0.5 will be added.
--            So, if you transform a set_actor-call, please subtract
--            0.5 from each coordinate.
--
--  (2)  Each ghost may move along paths, called rails. Several ghosts
--  may use the same rails, but each ghost only one rail; different
--  rails may cross. You can define a single floor tile as part of a
--  rail with
--
--    ghosts_set_rail(x,y,rail,floorkind)
--
--  with x,y the position of the floor, rail the rail-number that's
--  also used in the definition of the ghosts and floorkind the kind
--  of floor to be set at x,y. Instead of setting the floorkind with
--  ghosts_set_rail you can set it independently and use an empty
--  string '""' for floorkind, to suppress setting of a new floor.
--  You can use this as a parent for ant.lua, e.g.:
--
--    cells["..."]=cell{parent={{ghosts_set_rail,1,"fl-gray"}}}
--
--  To define a larger area as rail, you can use
--
--    ghosts_set_railarea(x1,y1,x2,y2,rail,floorkind)
--
--  which works analogously to ghosts_set_rail, with x1..x2, y1..y2
--  the rectangular area to be set as rail.
--
--  Remark 1: The movement of a ghost is done via flat gradients,
--            which alter the floor, while the old floor will be
--            reconstructed later. This might look strange when
--            another floor than "fl-metal" or "fl-gray" is used.
--  Remark 2: In the standard settings, rail-floors with walls on
--            them will be totally ignored as if they would not
--            belong to the rail at all. This way you can define
--            the whole area of a level as rail without having
--            to worry about walls, and the ghosts will ignore
--            movable stones instead of bump into them.
--            Yet, this behaviour can be unsatisfying, e.g. when
--            a ghost is expected to go through a grate, an open
--            door or a hollow stone. You can alter this by setting
--
--              ghosts_check_for_walls = 0
--
--            (or = 1 to switch it on again). Notice that a
--            ghost in this setting will bump into walls on its
--            way, which might look stupid. However, the ghost
--            will then reorient and search another way, so there
--            is no need to worry when switching this off.
--  Remark 3: Multiple rails have not been tested yet.
--            Keep lots of bug-spray in reach.
--
--  (3)  You have to set up a timer stone which calls the function
--  ghosts_timercallback in appropriate intervals (e.g. 0.1 seconds).
--  You can do this with the function
--
--    ghosts_init(x,y)
--
--  with a nice position x,y for the timer-stone.
--
--  (4)  The movements of the ghosts work via gradients and
--  thus need correctly set up slope forces. The library initially
--  sets it to 13, which works quite well. Editors like BlackBallEd
--  sometimes redefine this to other values. The code then needs
--  cleaning. You can also use
--
--    enigma.SlopeForce = ...
--
--  to slow the ghosts down or to speed them up. Bear in mind,
--  that too fast ghosts have problems in narrow labyrinths.
--  Yet, in an open area heightening the slope force can be
--  very sensible.
--
--
-- Moving algorithms:
--
--  In the current version of the library, there are four
--  algorithms that can be used in the definition of a ghost:
--
--           ghosts_direction_left : Always turn left at crossings
--          ghosts_direction_right : Always turn right at crossings
--         ghosts_direction_random : Choose ways randomly
--    ghosts_direction_intelligent : Choose rarely used ways
--
--  In the definition, you can also use "nil", then the
--  standard (ghosts_direction_intelligent) will be used.
--  But you might be interested to program an own algorithm
--  to decide the new directions by yourself. For this, you have
--  to define a function of the form
--
--    function my_own_algorithm(rail,posx,posy,oldx,oldy)
--
--  which takes the rail-number, the actual position and the old
--  position (which might be identical with the actual one). It
--  should return a single numerical value giving the direction:
--
--    0 : No possible direction found
--    1 : Go North (up)
--    2 : Go South (down)
--    3 : Go West (left)
--    4 : Go East (right)
--
--  Then define your ghost using this function:
--
--    ghosts_set_ghost(12,13,"ac-rotor", 1, my_own_algorithm,
--                               {range=0, force=5, gohome=FALSE})
--
--  Take a look at the four predefined functions to get a notion
--  of how to do this in a sensible way and which helper functions
--  you might find useful.
--
--
-- Global options:
--
--  There are four options that can be changed:
--
--  (a) ghosts_timerinterval  (default 0.1)
--        Defines the callback interval used by ghosts_init.
--  (b) ghosts_waiting_constant  (default 5)
--        When a ghost can't find a ways, it will repeat it after
--        this number of callback intervals. This number also is
--        used to give the ghost enough time to reach the next
--        adjacent floor tile before redefining its way.
--  (c) ghosts_check_for_walls  (default 1, set to 0 for false)
--        Sets whether ghosts shall ignore walls or not.
--        See section (2), remark 2 for a detailed description.
--  (d) ghosts_marker_i_max  (default 10000)
--        The intelligent direction algorithm uses counters to
--        count the number of times a floor tile has been visited.
--        To avoid an overflow of these counters, their maximum
--        is set to this constant, beyond which the intelligent
--        algorithm will turn into the random one. However, it's
--        improbable to reach this maximum during normal play.
--
--  For normal level-building purposes, only constant (c) should
--  be of interest.
--
--
-- Problem solving:
--
--  The ghost bumps into walls, moves unsteady, changes speed!
--
--    You probably forgot to set "gohome = FALSE".
--
--  The ghost bumps into walls, but moves with constant speed!
--
--    You probably switched ghosts_check_for_walls off, but didn't
--    remove the rail below static walls. The ghost thinks it can
--    go there, bumps into the wall and reorients -- very often.
--
--  The ghost doesn't move at all!
--
--    Have you set up the rail correctly, with the same rail number
--    as the ghost? 
--
--    Have you set "gohome = FALSE"? In combination with a high
--    force-value this might also make the ghosts stop completely.
--
--    Possibly you use a rotor or top as ghost with activated range
--    and force. It then is attracted by your marble; stronger than
--    its gradient. Decrease the force or even better the range of
--    the ghost or turn the range off completely.
--
--    Maybe you renamed the ghost afterwards? This won't work.
--    Please use the predefined name of the ghost.
--
--  The ghost moves too fast or too slow!
--
--    Correct the slope force, c.f. section (4).
--
--  The ghost doesn't react on gradients/space/ice I put into the level!
--
--    The ghosts set up their own gradients they are surfing on,
--    and restore the old floor later. Thus there is no way to
--    make them react on any other floor; sorry.
--
--  I use marbles as ghosts and they react on the mouse movements!
--
--    If you don't want it this way, put "mouseforce = 0" into
--    the attribs.
--
--  The ghost moves somewhat... strange?
--
--    There are many things that can act on the ghosts, like magnets,
--    electricity, wormholes, interactions with other ghosts or actors
--    or the different attraction algorithms of tops and rotors that
--    can be accessed via the attacknearest-option. All of these aren't
--    tested and may lead to unpredictable behaviour of the ghosts.
--    Sorry if this disturbs your level idea.
--



--------------------------------------
--  Global constants and variables  --
--------------------------------------


ghosts_timerinterval = 0.1
ghosts_waiting_constant = 5  -- corresponds to half a second
ghosts_check_for_walls = 1
ghosts_marker_i_max = 10000

enigma.SlopeForce = 13

ghosts_counter = 0
ghosts_rail = {}
ghosts_savedfloor = {}
ghosts_ghost_rail = {}
ghosts_ghost_x = {}
ghosts_ghost_y = {}
ghosts_waiting = {}
ghosts_possible = {}
ghosts_algorithm = {}
ghosts_marker_i = {}
ghosts_floor_x = {}
ghosts_floor_y = {}


-----------------------
--  Helper routines  --
-----------------------


function ghosts_index(rail,x,y)
  return tostring(rail)..";"..tostring(x)..";"..tostring(y)
end

function ghosts_adjacent(posx,posy,dir)
  if dir == 0 then  return posx, posy      end
  if dir == 1 then  return posx, posy - 1  end
  if dir == 2 then  return posx, posy + 1  end
  if dir == 3 then  return posx - 1, posy  end
  if dir == 4 then  return posx + 1, posy  end
end

function ghosts_load_possible_directions(rail,posx,posy)
  -- Test whether the four adjacent floors are allowed destinations
  local j
  for j=1,4 do
    if ghosts_rail[ghosts_index(rail,ghosts_adjacent(posx,posy,j))] == 1 then
      ghosts_possible[j] = 1
    else
      ghosts_possible[j] = 0
    end
    if ghosts_check_for_walls == 1 then
      if enigma.GetStone(ghosts_adjacent(posx,posy,j)) ~= nil then
        ghosts_possible[j] = 0
      end
    end
  end 
end

function ghosts_calculate_original_direction(posx,posy,oldx,oldy)
  local originaldirection = 0
  if (posx == oldx) and (posy == oldy - 1) then  originaldirection = 2  end
  if (posx == oldx) and (posy == oldy + 1) then  originaldirection = 1  end
  if (posy == oldy) and (posx == oldx - 1) then  originaldirection = 4  end
  if (posy == oldy) and (posx == oldx + 1) then  originaldirection = 3  end
  return originaldirection
end

function ghosts_turn_left(dir)
  local newdir = 0
  if dir == 1 then  newdir = 4  end
  if dir == 2 then  newdir = 3  end
  if dir == 3 then  newdir = 1  end
  if dir == 4 then  newdir = 2  end
  return newdir
end

function ghosts_turn_right(dir)
  local newdir = 0
  if dir == 1 then  newdir = 3  end
  if dir == 2 then  newdir = 4  end
  if dir == 3 then  newdir = 2  end
  if dir == 4 then  newdir = 1  end
  return newdir
end

function ghosts_increase_marker_i(rail,posx,posy)
  local gcount = ghosts_marker_i[ghosts_index(rail,posx,posy)]
  if gcount == nil then
    ghosts_marker_i[ghosts_index(rail,posx,posy)] = 1
  else
    if gcount < ghosts_marker_i_max then
      ghosts_marker_i[ghosts_index(rail,posx,posy)] = gcount + 1
    end
  end
end

function ghosts_floor_kind(actual, posx, posy, g)
  local kind = actual
  -- Is there any ghost who saved this floor apart from g?
  for j = 1,ghosts_counter do
    if (ghosts_floor_x[j] == posx) and (ghosts_floor_y[j] == posy) and (j ~= g) then
      kind = ghosts_savedfloor[j]
    end
  end
  if kind == nil then kind = actual end
  return kind
end

function ghosts_gradient(dir)
  --if dir == 1 then return "fl-gradient2" end
  --if dir == 2 then return "fl-gradient1" end
  --if dir == 3 then return "fl-gradient4" end
  --if dir == 4 then return "fl-gradient3" end
  return "fl-gradient"..tostring(dir+12)
end

---------------------------------
--  Several moving algorithms  --
---------------------------------

  -- 1 : Go North (up)
  -- 2 : Go South (down)
  -- 3 : Go West (left)
  -- 4 : Go East (right)

function ghosts_direction_left(rail,posx,posy,oldx,oldy)
  -- Calculate original direction (posx/posy -> oldx/oldy)
  local originaldirection = ghosts_calculate_original_direction(posx,posy,oldx,oldy)
  -- Load possible directions
  ghosts_load_possible_directions(rail,posx,posy)
  -- Are we still at the same position? Set origdir = random => dir = random
  if (posx == oldx) and (posy == oldy) then
    originaldirection = random(1,4)
  end
  -- Turn left till there is a possible way
  local dir = ghosts_turn_left(originaldirection)    
  local j
  for j = 1,3 do
    if ghosts_possible[dir] ~= 1 then
      dir = ghosts_turn_left(dir)
    end
  end
  -- Maybe there is no way out?
  if (dir == originaldirection) and (ghosts_possible[dir] ~= 1) then
    dir = 0
  end
  return dir
end

function ghosts_direction_right(rail,posx,posy,oldx,oldy)
  -- Calculate original direction (posx/posy -> oldx/oldy)
  local originaldirection = ghosts_calculate_original_direction(posx,posy,oldx,oldy)
  -- Load possible directions
  ghosts_load_possible_directions(rail,posx,posy)
  -- Are we still at the same position? -> dir = random
  if (posx == oldx) and (posy == oldy) then
    originaldirection = random(1,4)
  end
  -- Turn left till there is a possible way
  local dir = ghosts_turn_right(originaldirection)    
  local j
  for j = 1,3 do
    if ghosts_possible[dir] ~= 1 then
      dir = ghosts_turn_right(dir)
    end
  end
  -- Maybe there is no way out?
  if (dir == originaldirection) and (ghosts_possible[dir] ~= 1) then
    dir = 0
  end
  return dir
end

function ghosts_direction_random(rail,posx,posy,oldx,oldy)
  -- Calculate original direction (posx/posy -> oldx/oldy)
  local originaldirection = ghosts_calculate_original_direction(posx,posy,oldx,oldy)
  -- Load possible directions
  ghosts_load_possible_directions(rail,posx,posy)
  -- Choose one of them at random  
  local direction = 0
  local j
  for j=1,100 do
    -- Try to find a good direction 100 times, then give up.
    if direction == 0 then
      direction = random(1,4)
      if ghosts_possible[direction] ~= 1 then
        direction = 0
      end
      if direction == originaldirection then
        direction = 0
      end
    end
  end  
  return direction
end

function ghosts_direction_intelligent(rail,posx,posy,oldx,oldy)
  -- Calculate original direction (posx/posy -> oldx/oldy)
  local originaldirection = ghosts_calculate_original_direction(posx,posy,oldx,oldy)
  -- Load possible directions with counters
  ghosts_load_possible_directions(rail, posx, posy)
  -- Save the corresponding markers in ghosts_possible
  local j
  local m
  for j=1,4 do
    m = ghosts_marker_i[ghosts_index(rail,ghosts_adjacent(posx,posy,j))]
    if m == nil then
      ghosts_marker_i[ghosts_index(rail,ghosts_adjacent(posx,posy,j))] = 1
      m = 1
    end
    if ghosts_possible[j] > 0 then
      ghosts_possible[j] = m
    end
  end
  -- Remove directions with highest counters and original direction
  if originaldirection > 0 then
    ghosts_possible[originaldirection] = 0
  end
  local min = 0
  for j = 1,4 do
    if (min == 0) or ((min > ghosts_possible[j]) and (ghosts_possible[j] > 0))
      then min = ghosts_possible[j] end
  end
  for j = 1,4 do
    if min < ghosts_possible[j] then ghosts_possible[j] = 0 end
  end
  -- Choose one of the (hopefully) remaining directions at random  
  local direction = 0
  for j=1,100 do
    -- Like in the random algorithm:
    if direction == 0 then
      direction = random(1,4)
      if ghosts_possible[direction] == 0 then
        direction = 0
      end
      if direction == originaldirection then
        direction = 0
      end
    end
  end  
  return direction
end


-------------------------------
--  Timer callback function  --
-------------------------------


function ghosts_timercallback()
  if ghosts_counter > 0 then
    local g
    for g = 1, ghosts_counter do
      local myactor = enigma.GetNamedObject("ghost_"..tostring(g))
      if myactor ~= nil then
        local posx, posy = enigma.GetPos(myactor)
        local rail = ghosts_ghost_rail[g]
        local oldx = ghosts_ghost_x[g]
        local oldy = ghosts_ghost_y[g]

        -- Are we still at the same position?

        if (oldx == posx) and (oldy == posy) then
          -- Should we wait some more time?
          if ghosts_waiting[g] > 0 then
            -- Wait some more...
            ghosts_waiting[g] = ghosts_waiting[g] - 1
          end
          -- If we waited a too long time, increase the marker.
          -- We'll also delete the original direction now, but
          -- create a new gradient later.
          if ghosts_waiting[g] == 0 then
            ghosts_increase_marker_i(rail, posx, posy)
            ghosts_ghost_x[g] = posx
            ghosts_ghost_y[g] = posy
          end
        else
          -- Create a new gradient without further waiting!
          ghosts_waiting[g] = 0
          -- And increase the local counter.
          ghosts_increase_marker_i(rail, posx, posy)
        end

        -- Shall we restore the old floor?

        local oldfloorx = ghosts_floor_x[g]
        local oldfloory = ghosts_floor_y[g]
        if (oldfloorx ~= posx) or (oldfloory ~= posy) then
          -- Restore the old floor:
          if ghosts_savedfloor[g] == "" then
            ghosts_savedfloor[g] = "fl-normal"
          end
          -- Why not oldx/oldy? Because the actor could have
          -- been bumped onto another field - this would shuffle
          -- the floor-tiles!
          set_floor(ghosts_savedfloor[g], oldfloorx, oldfloory)
        end

        -- Should we create some gradient where we are?

        local dir = 0
        if ghosts_waiting[g] == 0 then
          -- Calculate new direction
          if ghosts_rail[ghosts_index(rail,posx,posy)] == nil then
            -- Oh, that's not good: the actor lost his way.
            -- Maybe we can get it back onto the rail where it came from?            
            if ghosts_rail[ghosts_index(rail,oldx,oldy)] ~= nil then
              dir = ghosts_calculate_original_direction(posx,posy,oldx,oldy)
            end
            if dir == 0 then
              -- Last chance!
              dir = ghosts_direction_random(rail,posx,posy,oldx,oldy)
            end
            if dir == 0 then
              -- No way back? Then just deactivate it:
              ghosts_waiting[g] = -1
            end            
          else
            dir = ghosts_algorithm[g](rail, posx, posy, oldx, oldy)
          end
          -- Any good idea? Then draw the gradient!
          if dir ~= 0 then
            local newfloor = ghosts_gradient(dir)
            if (posx ~= oldfloorx) or (posy ~= oldfloory) 
               or (ghosts_savedfloor[g] == "") then
              local myfloor = enigma.GetFloor(posx,posy)
              if myfloor ~= nil then
                -- Save the old floor kind.
                -- But take care: There might already be a ghost
                -- here, who changed the floor kind!
                ghosts_savedfloor[g] = ghosts_floor_kind(enigma.GetKind(myfloor),posx,posy,g)
                ghosts_floor_x[g] = posx
                ghosts_floor_y[g] = posy
              end
            end
            set_floor(newfloor,posx,posy)
            ghosts_ghost_x[g] = posx
            ghosts_ghost_y[g] = posy
            ghosts_waiting[g] = ghosts_waiting_constant
          else
            -- No direction? Propably a dead-end. Wait some time
            -- and forget where you came from.
            ghosts_ghost_x[g] = posx
            ghosts_ghost_y[g] = posy
            ghosts_waiting[g] = ghosts_waiting_constant
          end
        end

      end
    end
  end
end


-------------------------------------------------
--  Initialization, Setup and ant.lua-parents  --
-------------------------------------------------


function ghosts_init(x,y)
  set_stone("st-timer", x, y, {interval = ghosts_timerinterval,
     action = "callback", target = "ghosts_timercallback"})
end

function ghosts_set_ghost(x,y,actor,rail,alg,attribs)  -- Sets up a ghost
  if alg == nil then  alg = ghosts_direction_intelligent  end
  ghosts_counter = ghosts_counter + 1
  local n = "ghost_"..tostring(ghosts_counter)
  ghosts_ghost_rail[ghosts_counter] = rail
  ghosts_ghost_x[ghosts_counter] = x
  ghosts_ghost_y[ghosts_counter] = y
  ghosts_waiting[ghosts_counter] = 0
  ghosts_savedfloor[ghosts_counter] = ""
  ghosts_algorithm[ghosts_counter] = alg
  local newghost = set_actor(actor,x+0.5,y+0.5,{name=n})
  set_attribs(newghost,attribs)
  if GetAttrib(newghost,"name") ~= n then
    error("Ghosts may not have arbitrary names!")
  end
end

function ghosts_set_rail(x,y,rail,floorkind)  -- This is a parent for a ghost-rail
  if rail == "" then  rail = 0  end
  ghosts_rail[ghosts_index(rail,x,y)] = 1
  if floorkind ~= "" then
    set_floor(floorkind, x, y)
  end
end

function ghosts_set_railarea(x1,y1,x2,y2,rail,floorkind)
  local i,j
  for i=x1,x2 do
    for j=y1,y2 do
      ghosts_set_rail(i,j,rail,floorkind)
    end
  end
end
    ]]></el:luamain>
    <el:i18n>
    </el:i18n>
  </el:protected>
</el:level>