Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: Api's Adventure -puzzlepeli Limbo-kielellä

jalski [26.04.2010 15:29:30]

#

Api's Adventure on tulevaa Infernon peliohjelmointia käsittelevää opastani varten tekemäni esimerkki.

Peli on Infernon Limbo toteutus MBasic:in mukana tulevasta esimerkki pelistä: Pitman.

Pelissä ohjataan Kiinanpalatsikoira Apia ja yritetään kerätä kaikki pelikentällä olevat luut.

Peli on vielä hiukan keskeneräinen, mutta jo nyt mukava ja haastava pelattava.

Pelipaketti datatiedostoineen: http://www.tip9ug.jp/who/jalih/game.zip

#
# Just another crappy game from jalski's game factory
#
# It's still unfinished...
# You can do what you like with it.
#
implement ApiAdventure;

include "sys.m";
   sys : Sys;

include "draw.m";
   draw : Draw;
   Context, Display, Point, Rect, Image, Screen, Font: import draw;

include "tk.m";
   tk: Tk;
   Toplevel : import tk;

include   "tkclient.m";
   tkclient : Tkclient;

include "keyboard.m";
   Up, Down, Right, Left: import Keyboard;

include "bufio.m";
   bufio : Bufio;
   Iobuf : import bufio;



ApiAdventure: module
{
   init:   fn(ctxt: ref Context, argv: list of string);
};



EMPTY, WALL, LADDER, WALL2 : con iota;
ROCK, BONE : con iota;


TILEX : con 49;
TILEY : con 49;

ROWS : con 8;
COLUMNS : con 11;

LEFT : con Point(-1, 0);
RIGHT : con Point(1, 0);
UP : con Point(0, -1);
DOWN : con Point(0, 1);


AUDIO_MAGIC : con "rate";
AUDIO_DATA : con "/dev/audio";
AUDIO_CTL : con "/dev/audioctl";
AUDIO_BUF_SIZE : con Sys->ATOMICIO;
NULL_DEVICE : con "/dev/null";
#SOUND1 : con "./sounds/chord.iaf";
audio_data : string;



FONTPATH : con "/fonts/lucida/unicode.18.font";
MSG : con "LEVEL COMPLETE";
font : ref Font;

display : ref Display;
buffer : ref Image;
t: ref Toplevel;


tiles := array [4] of ref Image;
player_img, player_mask : ref Image;
rock_img, rock_mask : ref Image;
bone_img, bone_mask : ref Image;


# Pelaaja "luokka"
Player : adt
{
   pos : Point;
   img : ref Image;
   new : fn(x : int, y : int, img : ref Image) : ref Player;
   draw : fn(player : self ref Player);
   if_can_fall : fn(player : self ref Player);
};


# Objekti "luokka" pelin objekteja varten (luut ja kivet).
Object : adt
{
   id : int;
   pos : Point;
   img : ref Image;
   mask : ref Image;
   new : fn(id : int, x : int, y : int, img : ref Image, mask : ref Image) : ref Object;
};


# Objektilista "luokka"
Objects : adt
{
   objects : array of ref Object;
   new : fn() : ref Objects;
   add : fn(objects : self ref Objects, id : int, x : int, y : int, img : ref Image, mask : ref Image);
   del : fn(objects : self ref Objects, index : int);
   sort : fn(objects : self ref Objects);
   draw : fn(objects : self ref Objects);
   search_pos : fn(objects : self ref Objects, pos : Point) : (int , ref Object);
};


# Pelikenttä "luokka"
Level : adt
{
   bones : int;
   map : array of array of int;
   objects : ref Objects;
   player : ref Player;
   new : fn() : ref Level;
   draw : fn(l : self ref Level);
   copy : fn(l : self ref Level) : ref Level;
   can_objects_fall : fn(l : self ref Level);
};



level : ref Level;  # Käsiteltävä kenttä.
levels : list of ref Level; # kenttälista.
back_list : list of ref Level; # Lista kenttien taaksepäin selaamista varten.
currentl : int; # Nykyisen kentän numero.



# Käyttöliittymän määrittelyt
gameui_cfg := array[] of {
   "frame .f",
   "button .f.left -bitmap small_color_left.bit -bd 0 -command {send cmdch prevl}",
   "button .f.right -bitmap small_color_right.bit -bd 0 -command {send cmdch nextl}",
   "button .f.reset -bitmap sadsmiley.bit -bd 0 -command {send cmdch reset}",
   "label .f.l -text {level: }",
   "label .f.level",
   "pack .f.left .f.right -side left",
   "pack .f.l -side left",
   "pack .f.level -side left",
   "pack .f.reset -side right",
   "pack .f -fill x",
};



# Pääohjelma. Ohjelman suoritus alkaa tästä.
init(ctxt: ref Context, nil: list of string)
{
   sys = load Sys Sys->PATH;
   draw = load Draw Draw->PATH;
   tk = load Tk Tk->PATH;
   tkclient = load Tkclient Tkclient->PATH;
   bufio = load Bufio Bufio->PATH;

   sys->pctl(Sys->NEWPGRP, nil);

   tkclient->init();

   if(ctxt == nil)
      ctxt = tkclient->makedrawcontext();

   display = ctxt.display;

   font = Font.open(display, FONTPATH);

   menubut : chan of string;
   (t, menubut) = tkclient->toplevel(ctxt, "", "Api's Adventure (with doggy style)", 0);

   cmdch := chan of string;
   tk->namechan(t, cmdch, "cmdch");

   for (i := 0; i < len gameui_cfg; i++)
      cmd(t, gameui_cfg[i]);

   center(t);
   tkclient->onscreen(t, "exact");
   tkclient->startinput(t, "ptr"::"kbd"::nil);

   #setup_audio();
   load_images();
   load_levels("./levels/levels.txt");

   currentl = 1;  # Ekasta kentästä aloitellaan.
   cmd(t, ".f.level configure -text " + string currentl);

   back_list = hd levels :: back_list;
   level = (hd levels).copy();

   cmd(t, "panel .p -bd 3 -relief flat");
   cmd(t, "pack .p -fill both -expand 1");
   tk->putimage(t, ".p", buffer, nil);

   level.draw();
   level.player.draw();
   level.objects.draw();

   cmd(t, ".p dirty; update");



   # Tk-ohjelman viestien käsittely silmukka
   for(;;) alt {
   s := <-t.ctxt.kbd =>
      processkbd(s); # Käsitellään näppäimen painallus omassa aliohjelmassa.
   s := <-t.ctxt.ptr =>
      tk->pointer(t, *s);
   s := <-t.ctxt.ctl or
   s = <-t.wreq or
   s = <-menubut =>
      tkclient->wmctl(t, s);

   c := <- cmdch =>
      case c {
         "nextl" => # Nuoli oikealle nappulaa painettu
            if (tl levels != nil)
            {
               back_list = hd levels :: back_list;
               levels = tl levels;
               level = (hd levels).copy();
               currentl ++;
               cmd(t, ".f.level configure -text " + string currentl);
               level.draw();
               level.player.draw();
               level.objects.draw();
               #cmd(t, "focus .p");
               cmd(t, ".p dirty; update");
            }

         "prevl" => # Nuoli vasemmalle nappulaa painettu.
            if (tl back_list != nil)
            {
               levels = hd back_list :: levels;
               back_list = tl back_list;
               level = (hd levels).copy();
               currentl --;
               cmd(t, ".f.level configure -text " + string currentl);
               level.draw();
               level.player.draw();
               level.objects.draw();
               #cmd(t, "focus .p");
               cmd(t, ".p dirty; update");
            }

         "reset" =>  # Surunaama nappulaa painettu
            level = (hd levels).copy();
            level.draw();
            level.player.draw();
            level.objects.draw();
            #cmd(t, "focus .p");
            cmd(t, ".p dirty; update");

      }

   }

}



# Täällä käsitellään painallukset näppäimistöltä.
processkbd(kbd: int)
{
   case kbd
   {
      Up =>
         npos := level.player.pos.add(UP);

         if (npos.y >= ROWS || npos.y < 0)
            break;

         (nil, found) := level.objects.search_pos(npos);

         if ((level.map[level.player.pos.x][level.player.pos.y] == LADDER && level.map[npos.x][npos.y] == LADDER) || (level.map[level.player.pos.x][level.player.pos.y] == LADDER && (level.map[npos.x][npos.y] == EMPTY && found == nil)))
         {
            draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
            level.player.pos = npos;
            level.player.draw();
         }

      Down =>
         npos := level.player.pos.add(DOWN);

         if (npos.y >= ROWS || npos.y < 0)
            break;

         (nil, obj) := level.objects.search_pos(npos);
         if (obj != nil)
            break;

         if (level.map[npos.x][npos.y] == LADDER || (level.map[level.player.pos.x][level.player.pos.y] == LADDER && level.map[npos.x][npos.y] == EMPTY))
         {
            draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
            level.player.pos = npos;
            level.player.if_can_fall();
            level.player.draw();
            level.can_objects_fall();
            level.objects.draw();
         }

      Left =>
         npos := level.player.pos.add(LEFT);

         if (npos.x >= COLUMNS || npos.x < 0)
            break;

         if (level.map[npos.x][npos.y] != WALL)
         {
            (index, obj) := level.objects.search_pos(npos);

            if (obj != nil)
            {
               case obj.id
               {
                  ROCK =>
                     nrpos := obj.pos.add(LEFT);

                     if (nrpos.x < COLUMNS && nrpos.x >= 0)
                     {
                        (nil, tobj) := level.objects.search_pos(nrpos);

                        if (tobj == nil)
                           if (level.map[nrpos.x][nrpos.y] == EMPTY)
                           {
                              draw_tile(level.map[obj.pos.x][obj.pos.y], obj.pos);
                              obj.pos = nrpos;

                              draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
                              level.player.pos = npos;

                              if (level.map[level.player.pos.x][level.player.pos.y] != LADDER)
                                 level.player.if_can_fall();

                              level.objects.sort();
                              level.can_objects_fall();
                              level.objects.draw();
                              level.player.draw();
                           }


                     }

                  BONE =>
                     level.objects.del(index);
                     level.bones --;

                     draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
                     draw_tile(level.map[npos.x][npos.y], npos);
                     level.player.pos = npos;

                     if (level.map[level.player.pos.x][level.player.pos.y] != LADDER)
                        level.player.if_can_fall();

                     level.objects.sort();
                     level.can_objects_fall();
                     level.objects.draw();
                     level.player.draw();

               }

            }
            else
            {
               if (level.map[npos.x][npos.y] == WALL2)
               {
                  level.map[npos.x][npos.y] = EMPTY;
                  draw_tile(level.map[npos.x][npos.y], npos);
               }

               draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
               level.player.pos = npos;

               if (level.map[level.player.pos.x][level.player.pos.y] != LADDER)
                  level.player.if_can_fall();

               level.objects.sort();
               level.can_objects_fall();
               level.objects.draw();
               level.player.draw();
            }
         }

      Right =>
         npos := level.player.pos.add(RIGHT);

         if (npos.x >= COLUMNS || npos.x < 0)
            break;

         if (level.map[npos.x][npos.y] != WALL)
         {
            (index, obj) := level.objects.search_pos(npos);

            if (obj != nil)
            {
               case obj.id
               {
                  ROCK =>
                     nrpos := obj.pos.add(RIGHT);

                     if (nrpos.x < COLUMNS && nrpos.x >= 0)
                     {
                        (nil, tobj) := level.objects.search_pos(nrpos);

                        if (tobj == nil)
                           if (level.map[nrpos.x][nrpos.y] == EMPTY)
                           {
                              draw_tile(level.map[obj.pos.x][obj.pos.y], obj.pos);
                              obj.pos = nrpos;

                              draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
                              level.player.pos = npos;

                              if (level.map[level.player.pos.x][level.player.pos.y] != LADDER)
                                 level.player.if_can_fall();

                              level.objects.sort();
                              level.can_objects_fall();
                              level.objects.draw();
                              level.player.draw();
                           }


                     }

                  BONE =>
                     level.objects.del(index);
                     level.bones --;

                     draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
                     draw_tile(level.map[npos.x][npos.y], npos);
                     level.player.pos = npos;

                     if (level.map[level.player.pos.x][level.player.pos.y] != LADDER)
                        level.player.if_can_fall();

                     level.objects.sort();
                     level.can_objects_fall();
                     level.objects.draw();
                     level.player.draw();

               }

            }
            else
            {
               if (level.map[npos.x][npos.y] == WALL2)
               {
                  level.map[npos.x][npos.y] = EMPTY;
                  draw_tile(level.map[npos.x][npos.y], npos);
               }

               draw_tile(level.map[level.player.pos.x][level.player.pos.y], level.player.pos);
               level.player.pos = npos;

               if (level.map[level.player.pos.x][level.player.pos.y] != LADDER)
                  level.player.if_can_fall();

               level.objects.sort();
               level.can_objects_fall();
               level.objects.draw();
               level.player.draw();
            }

         }

      * =>
         return;


   }

   if (level.bones <= 0)
   {
         red := display.color(Draw->Red);
         textw := font.width(MSG);
         texth := font.height;
         buffer.text(Point(COLUMNS * TILEX / 2 - (textw / 2), ROWS * TILEY / 2 - texth), red, Point(0,0), font, MSG);
         cmd(t, ".p dirty; update");
         #play_audio_file(SOUND1);
         sys->sleep(500);

         if (tl levels != nil)
         {
            back_list = hd levels :: back_list;
            levels = tl levels;
            level = (hd levels).copy();
            currentl ++;
            cmd(t, ".f.level configure -text " + string currentl);
            level.draw();
            level.player.draw();
            level.objects.draw();
            cmd(t, ".p dirty; update");
         }
         else
            exit;

   }

   cmd(t, ".p dirty; update");


}



setup_audio()
{
   df := sys->open(AUDIO_DATA, Sys->OWRITE);
   if (df == nil)
      audio_data = NULL_DEVICE;
   else
      audio_data = AUDIO_DATA;
}



play_audio_file(f: string)
{
   buff := array[AUDIO_BUF_SIZE] of byte;
   inf := sys->open(f, Sys->OREAD);
   if (inf == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: could not open %s: %r\n", f);
      return;
   }
   n := sys->read(inf, buff, AUDIO_BUF_SIZE);
   if (n < 0) {
      sys->fprint(sys->fildes(2), "Api's Adventure: could not read %s: %r\n", f);
      return;
   }
   if (n < 10 || string buff[0:4] != AUDIO_MAGIC)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: %s: not an audio file\n", f);
      return;
   }
   i := 0;
   for (;;) {
      if (i == n)
      {
         sys->fprint(sys->fildes(2), "Api's Adventure: %s: bad header\n", f);
         return;
      }
      if (buff[i] == byte '\n')
      {
         i++;
         if (i == n)
         {
            sys->fprint(sys->fildes(2), "Api's Adventure: %s: bad header\n", f);
            return;
         }
         if (buff[i] == byte '\n')
         {
            i++;
            if ((i % 4) != 0)
            {
               sys->fprint(sys->fildes(2), "Api's Adventure: %s: unpadded header\n", f);
               return;
            }
            break;
         }
      }
      else
         i++;
   }


   cf := sys->open(AUDIO_CTL, Sys->OWRITE);
   if (cf != nil)
   {

      if (sys->write(cf, buff, i - 1) < 0)
      {
         sys->fprint(sys->fildes(2), "Api's Adventure: could not write %s: %r\n", AUDIO_CTL);
         exit;
      }

   }

   df := sys->open(audio_data, Sys->OWRITE);
   if (df == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: could not open %s: %r\n", audio_data);
      return;
   }


   if (n > i && sys->write(df, buff[i:n], n - i) < 0)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: could not write %s: %r\n", audio_data);
      return;
   }

   if (sys->stream(inf, df, Sys->ATOMICIO) < 0)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: could not stream %s: %r\n", audio_data);
      return;
   }

}



Player.new(x : int, y : int, img : ref Image) : ref Player
{
   player := ref Player(Point(x,y), img);
   return player;
}



Player.if_can_fall(player : self ref Player)
{
   pos := player.pos;

   if (level.map[pos.x][pos.y] != EMPTY)
      return;

   for(i := pos.y + 1; i < ROWS; i ++)
   {

      (nil, found) := level.objects.search_pos(Point(pos.x, i));

      if (level.map[pos.x][i] != EMPTY || found != nil)
               break;


      pos.y = i;

   }

   if (!player.pos.eq(pos))
   {
      draw_tile(level.map[player.pos.x][player.pos.y], player.pos);
      player.pos = pos;
   }

}



Object.new(id : int, x : int, y : int, img : ref Image, mask : ref Image) : ref Object
{
   object := ref Object(id, Point(x, y), img, mask);
   return object;
}



Objects.new() : ref Objects
{
   objects := ref Objects;

   return objects;
}



Objects.add(objects : self ref Objects, id : int, x : int, y : int, img : ref Image, mask : ref Image )
{
   i := len objects.objects;

   nobjects := array [i + 1] of ref Object;

   (nobjects[0:],  nobjects[i], nobjects[i + 1:]) = (objects.objects[0:i], Object.new(id, x, y, img, mask), objects.objects[i:]);

   objects.objects = nobjects;

}



Objects.del(objects : self ref Objects, index : int)
{
   if (len objects.objects >= 1)
   {
      objects.objects[index:] = objects.objects[index + 1:];
      objects.objects = objects.objects[:len objects.objects - 1];
   }
}



Objects.search_pos(objects : self ref Objects, pos : Point) : (int, ref Object)
{
   count := len objects.objects;

   if (count < 1)
   {
      return (0, nil);
   }

   for(i := 0; i < count; i ++)
   {
      if (objects.objects[i].pos.eq(pos))
      {
         return (i, objects.objects[i]);
      }
   }

   return (0, nil);
}



Objects.draw(objects : self ref Objects)
{
   count := len objects.objects;

   for(i := 0; i < count; i ++)
   {
      draw_sprite(objects.objects[i].img, objects.objects[i].mask, objects.objects[i].pos);
   }

}



Objects.sort(objects : self ref Objects)
{
   count := len objects.objects;

   for(i := 1; i < count ; i ++)
   {
      v := objects.objects[i];
      j := i;
      while( ( j > 0 ) && ( objects.objects[j - 1].pos.y < v.pos.y ))
      {
         objects.objects[j] = objects.objects[j - 1];
         j --;
      }
      objects.objects[j] = v;
   }

}



load_images()
{

   tiles[0] = display.open("./data/empty.bit");
   if (tiles[0] == nil)
   {
      sys->fprint(sys->fildes(2), "Apis's Adventure: failed to allocate image\n");
      exit;
   }

   tiles[1] = display.open("./data/wall.bit");
   if (tiles[1] == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   tiles[2] = display.open("./data/ladder.bit");
   if (tiles[2] == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   tiles[3] = display.open("./data/wall2.bit");
   if (tiles[3] == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   rock_img = display.open("./data/rock.bit");
   if (rock_img == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   rock_mask = display.open("./data/rock_mask.bit");
   if (rock_mask == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   player_img = display.open("./data/api.bit");
   if (player_img == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   player_mask = display.open("./data/api_mask.bit");
   if (player_mask == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   bone_img = display.open("./data/bone.bit");
   if (bone_img == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   bone_mask = display.open("./data/bone_mask.bit");
   if (bone_mask == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

   r := Rect((0, 0), (COLUMNS * TILEX, ROWS * TILEY));
   buffer = display.newimage(r, t.image.chans, 0, Draw->Black);
   if (buffer == nil)
   {
      sys->fprint(sys->fildes(2), "Api's Adventure: failed to allocate image\n");
      exit;
   }

}



draw_tile(tile : int, p : Point)
{
   p.x = p.x * tiles[tile].r.dx();
   p.y = p.y * tiles[tile].r.dy();

   buffer.draw(tiles[tile].r.addpt(p), tiles[tile], nil, Point(0, 0) );

}



Level.draw(l : self ref Level)
{

   for(row := 0; row < ROWS; row ++)
      for(column := 0; column < COLUMNS; column ++)
      {
         p := Point( column * TILEX, row * TILEY );
         buffer.draw(tiles[l.map[column][row] ].r.addpt(p), tiles[l.map[column][row] ], nil, Point(0, 0) );
      }



}



Level.new() : ref Level
{
   l := ref Level;
   return l;
}



Level.copy(l: self ref Level): ref Level
{
   c := ref *l;
   c.map = array[COLUMNS] of { * => array[ROWS] of int };

   for(i := 0; i < COLUMNS; i++)
      c.map[i][0:] = l.map[i];


   c.objects = Objects.new();

   for(i = 0; i < len l.objects.objects ; i++)
      c.objects.add(l.objects.objects[i].id, l.objects.objects[i].pos.x, l.objects.objects[i].pos.y, l.objects.objects[i].img, l.objects.objects[i].mask);

   c.player = ref *l.player;


   return c;
}



Level.can_objects_fall(l : self ref Level)
{
   count := len l.objects.objects;

   for(j := 0; j < count; j ++)
   {
      pos := l.objects.objects[j].pos;

      for(i := pos.y + 1; i < ROWS; i ++)
      {

         if (l.map[pos.x][i] != EMPTY || Point(pos.x, i).eq(l.player.pos))
            break;

         (nil, found) := l.objects.search_pos(Point(pos.x, i));
         if (found != nil)
            break;

         pos.y = i;

      }

      if (!l.objects.objects[j].pos.eq(pos))
      {
         draw_tile(l.map[l.objects.objects[j].pos.x][l.objects.objects[j].pos.y], l.objects.objects[j].pos);
         l.objects.objects[j].pos = pos;
      }


   }


}



Player.draw(player : self ref Player)
{
   draw_sprite(player.img, player_mask, player.pos);
}



draw_sprite(image : ref Image, mask : ref Image, p : Point)
{
   p.x = p.x * image.r.dx();
   p.y = p.y * image.r.dy();

   buffer.draw(image.r.addpt(p), image, mask, Point(0, 0) );

}



load_levels(file: string)
{
   x := 0;
   y := 0;
   max := Point(0, 0);

   buf := bufio->open(file, Bufio->OREAD);
   if (buf == nil) {
      sys->fprint(sys->fildes(2), "Api's Adventure level parser: cannot load %s: %r", file);
      exit;
   }

   bones := 0;
   map := array [COLUMNS] of { * => array [ROWS] of { * => EMPTY } };
   player := Player.new(0, 0, player_img);

   objects := Objects.new();

   line := 1;

   while((c := buf.getc()) >= 0)
   {
      case c {
      ';' =>
         while((c = buf.getc()) != '\n' && c != Bufio->EOF)
            ;

         line ++;

      '\n' =>
         max.y = ++ y;

         if(x != COLUMNS)
         {
            sys->fprint(sys->fildes(2), "Api's Adventure level parser: error on line: %d. Level map must have %d columns\n", line, COLUMNS);
            exit;
         }

         line ++;
         x = 0;


         if((c = buf.getc()) == '\n' || c == Bufio->EOF)
         {
            if (max.y != ROWS)
            {
               sys->fprint(sys->fildes(2), "Api's Adventure level parser: error on line: %d. Level map must have %d rows\n", line, ROWS);
               exit;
            }

            lev := Level.new();
            lev.bones = bones;
            lev.map = map;
            lev.player = player;
            lev.objects = objects;
            levels = lev :: levels;

            bones = 0;
            map = array[COLUMNS] of { * => array[ROWS] of { * => EMPTY } };
            player = Player.new(0, 0, player_img);
            objects = Objects.new();

            max = Point(0, 0);
            y = 0;
            line ++;
         }
         else
            buf.ungetc();

      '0' =>
         map[x][y] = EMPTY;
         x ++;

      '1' =>
         map[x][y] = WALL;
         x ++;

      '2' =>
         map[x][y] = LADDER;
         x ++;

      '3' =>
         map[x][y] = WALL2;
         x ++;

      '@' =>
         player.pos = Point(x, y);
         x ++;

      'o' =>
         objects.add(ROCK, x, y, rock_img, rock_mask);
         objects.sort();
         x ++;

      'b' =>
         objects.add(BONE, x, y, bone_img, bone_mask);
         objects.sort();
         bones ++;
         x ++;

      * =>
         sys->fprint(sys->fildes(2), "Api's Adventure level parser: impossible character: '%c' for level in line: %d\n", c, line);
         exit;
      }

      if (x > max.x)
         max.x = x;

      if (x >= COLUMNS || y >= ROWS)
      {
         if((c = buf.getc()) != '\n')
         {
            sys->fprint(sys->fildes(2), "Api's Adventure level parser: error on line: %d. Level map must be: %dx%d\n", line, COLUMNS, ROWS);
            exit;
         }
         buf.ungetc();
      }

   }


}



cmd(win: ref Tk->Toplevel, s: string): string
{
   r := tk->cmd(win, s);
   if (len r > 0 && r[0] == '!') {
      sys->print("error executing '%s': %s\n", s, r[1:]);
   }
   return r;
}



# Keskittää peli-ikkunan.
center(t: ref Tk->Toplevel)
{
   org: Point;
   ir := tk->rect(t, ".", Tk->Border|Tk->Required);
   org.x = t.screenr.dx() / 2 - COLUMNS * TILEX / 2;
   org.y = (t.screenr.dy() / 2) - (ir.dy() + (ROWS * TILEY) / 2);

   if (org.y < 0)
      org.y = 0;

   tk->cmd(t, ". configure -x " + string org.x + " -y " + string org.y);
}

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta