/*
 * KkkgPre4.java v0.41 -- formerly Probac*.java
 * még a szkeleton előtti grafikus tesztváltozat. Lefordul, de nem fut!
 * This file is _frozen_ by pts@fazekas.hu at Sun Apr 22 16:27:59 CEST 2001.
 * további doksi: a README-ben és e file legkülső class-ának fejkommentjében
 *
 * Kincskereső Kisgömböc (C) Early May 2001 by eNTitánok (Rév Szilvia,
 * Szabó Péter <pts@inf.bme.hu>, Szurdi Miklós, Weizengruber Attila).
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or   
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* History notes: (história notesz)
 * by pts@fazekas.hu at 2000.03.01 [uristen, mar marcius van??]
 * by pts@fazekas.hu at 2000.03.03
 * by pts@fazekas.hu at 2000.03.09 [tok jo, otos lett a digit szigorlat]
 * by pts@fazekas.hu at 2000.03.15 [nemzeti ünnep, megnéztem A költő visszatér-t (1988)]
 * by pts@fazekas.hu at 2000.03.16 [23:15: össze lehet szedni a gyémántokat!!]
 * Imp: Application-nek a _normális_ ablakméretet beállítani
 * Imp: e-mail, ütemezés stb.
 * Imp: ``click to begin'' if no focus yet
 * Imp: most véd-e a protected vagy nem??
 * Imp: rajzszint
 * Imp: legrovidebb ut (euklideszi!)
 * OK : sprite utkozes
 * Imp: thread safety??
 * Imp: p_001h.gif transparent.
 * Imp: IE-ben megy, de toklassu
 * OK : graf felismerese
 * Imp: Kisgomboc szembol lerajzolva
 * Imp: KkkgPre4.this.stop()
 * Imp: KkkgPre4.this.start()
 * Dat: Java1.1.7-ben Vector.get helyett Vector.elementAt
 */

package eNTitanok.kkkg;
//import java.awt.image.ColorModel;
//import java.awt.image.IndexColorModel;
import java.util.Hashtable;
import java.util.Vector;
import java.applet.Applet;

import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.KeyAdapter;
import java.awt.event.FocusAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.MouseListener;
import java.awt.event.KeyListener;
import java.awt.event.FocusListener;
import java.awt.event.WindowListener;

import java.awt.Frame;
// ^^^ menüsorral, kerettel rendelkező _ablak_. Csak Application-ként futva
//     használjuk
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
// vvv Kepek.java-t mindig újrafordítja (NEM!, de használja), az eredményt a Kepek*.class-ba helyezi
import eNTitanok.gfx.OkosAWT;
import eNTitanok.gfx.Kepek;
import eNTitanok.gfx.Kepek.Kep;
import eNTitanok.gfx.Kepek.Kepbetolto;
import eNTitanok.gfx.Kepek.Sdpts;
import eNTitanok.gfx.Kepek.Utkozteto;
import eNTitanok.gfx.Kepek.Betutipus;

/**
 * Még a szkeleton előtti grafikus tesztváltozat. Lefordul, de nem valószínű,
 * hogy fut, mert azóta a .gif file-okat már máshova raktuk stb. JDK1.1.7 elég
 * neki, viszont a futtatásnál nagyon gagyi lesz.
 */
public final class KkkgPre4 extends Applet {
  public static class HibasAllapotException extends Error {}
  public static class AtmeretezesNemSikerultException extends Error {}
  public static String hexformat(int n, int hossz) {
    // n>=0!!
    // gagyi java, meg egy sprintf()-et se tud, es a stringkezelo fuggvenyei
    // teljesen hasznalhatatlanok, lassuak, nehezkesek.
    String s=java.lang.Integer.toHexString(n);
    int l=s.length();
    return l>=hossz ? s : ("00000000"+s).substring(8+l-hossz,8+l);
  }
  public static String decformat(int n, int hossz) {
    // n>=0!!
    // gagyi java, meg egy sprintf()-et se tud, es a stringkezelo fuggvenyei
    // teljesen hasznalhatatlanok, lassuak, nehezkesek.
    String s=Integer.toString(n);
    int l=s.length();
    return l>=hossz ? s : ("00000000000000"+s).substring(14+l-hossz,14+l);
  }

  public static class Csucs {
    public static class NincsRajtaException extends Error {}
    public static class NemKothetoOsszeException extends Error {}
    public static final int LE=0, FEL=2, JOBB=1, BAL=3, PIHI=4, SEMERRE=5;
    protected Csucs szomsz[];
    protected int x, y;
    public Csucs(int x, int y) {
      this.x=x;
      this.y=y;
      szomsz=new Csucs[4];
    }
    public Csucs getSzomsz(int merre) { return szomsz[merre]}
    public Csucs getSzomsz0(int merre) { return szomsz[merre]!=null ? szomsz[merre]this}
    public int getX() { return x; }
    public int getY() { return y; }
    public void felold() { szomsz[FEL]=szomsz[LE]=szomsz[JOBB]=szomsz[BAL]=null}
    public void osszekot(Csucs masik) {
      /* összeköti ezt a csúcsot egy másikkal */
      if (masik.x==x) {
             if (masik.y<y) { szomsz[FEL]=masik; masik.szomsz[LE]=this}
        else if (masik.y>y) { szomsz[LE]=masik; masik.szomsz[FEL]=this}
        else throw new NemKothetoOsszeException();
      } else if (masik.y==y) {
             if (masik.x<x) { szomsz[BAL]=masik; masik.szomsz[JOBB]=this}
        else if (masik.x>x) { szomsz[JOBB]=masik; masik.szomsz[BAL]=this}
        else throw new NemKothetoOsszeException();
      } else throw new NincsRajtaException();
    }
    public void osszekot_kozelit(Csucs masik) {
      /* összeköti ezt a csúcsot egy másikkal, ha ennek a csúcsnak még nincs
       * közelebbi szomszédja a megfelelő irányban
       */
      // Imp: régi szomsz-ot is átláncolni
      if (masik.x==x) {
             if (masik.y<y) { if (szomsz[FEL]==null || szomsz[FEL].y<masik.y) { szomsz[FEL]=masik; masik.szomsz[LE]=this} }
        else if (masik.y>y) { if (szomsz[LE]==null || szomsz[LE].y>masik.y) { szomsz[LE]=masik; masik.szomsz[FEL]=this} }
        else throw new NemKothetoOsszeException();
      } else if (masik.y==y) {
             if (masik.x<x) { if (szomsz[BAL]==null || szomsz[BAL].x<masik.x) { szomsz[BAL]=masik; masik.szomsz[JOBB]=this} }
        else if (masik.x>x) { if (szomsz[JOBB]==null || szomsz[JOBB].x>masik.x) { szomsz[JOBB]=masik; masik.szomsz[BAL]=this} }
        else throw new NemKothetoOsszeException();
      } else throw new NincsRajtaException();
    }
    public int tavolsag(Csucs masik) {
      /* milyen messze van this és masik -- feltesszük, hogy szomszédosak */
      if (x==masik.x) return Math.abs(y-masik.y);
      else if (y==masik.y) return Math.abs(x-masik.x);
      else throw new NincsRajtaException();
    }
    public int tavolsag(int merre) {
      return szomsz[merre]==null ? 0 : tavolsag(szomsz[merre]);
    }
    public Csucs uj_csucs(int ux, int uy) {
      /* egy új csúcsot hoz létre this szomszédságában
       * Imp: Helyzet-eket update-elni!
       */
      if (ux==x && uy==y) return this;
      Csucs uj=new Csucs(ux, uy);
      int arra;
      if (ux==x) {
             if (uy<y) { arra=FEL; }
        else if (uy>y) { arra=LE; }
        else throw new NemKothetoOsszeException()// never happens!!
      } else if (uy==y) {
             if (ux<x) { arra=BAL; }
        else if (ux>x) { arra=JOBB; }
        else throw new NemKothetoOsszeException()// never happens!!
      } else throw new NincsRajtaException();
      if (szomsz[arra]!=null) {
        int ta=tavolsag(szomsz[arra]);
        int tu=tavolsag(uj);
        if (ta==tu) return szomsz[arra]// uj-t fel lehet szabadítani
        if (ta<tu) throw new NemKothetoOsszeException();
        uj.szomsz[arra]=szomsz[arra];
      }
      uj.szomsz[arra^2]=this;
      return uj;
    }
    public boolean szetvag() {
      /* törli a csúcsot a gráfból ha az elsőfokú vagy vízszintes/függőleges szakasz közepén van
       * @return: töröltük-e ténylegesen
       * Imp: Helyzet-eket update-elni!!
       */
      if (szomsz[FEL]==null && szomsz[LE]==null) {
        if (szomsz[BAL]!=null) szomsz[BAL].szomsz[JOBB]=szomsz[JOBB];
        if (szomsz[JOBB]!=null) szomsz[JOBB].szomsz[BAL]=szomsz[BAL];
        szomsz[BAL]=szomsz[JOBB]=null;
        return true;
      } else if (szomsz[BAL]==null && szomsz[JOBB]==null) {
        if (szomsz[FEL]!=null) szomsz[FEL].szomsz[LE]=szomsz[LE];
        if (szomsz[LE]!=null) szomsz[LE].szomsz[FEL]=szomsz[FEL];
        szomsz[FEL]=szomsz[LE]=null;
        return true;
      }
      return false;
    }
  }

  /*public class LabiCsucs extends Csucs {
    Targy targy; // milyen tárgy található itt
    int ford; // merre kell indulni a Kisgömböc felé?
    int tav; // milyen messze van a Kisgömböc
    public LabiCsucs(int x, int y) { super(x,y); }
  }*/

  public static class Helyzet {
    /* Helyzet: egy mozgó lény (Kisgömböc vagy Szörny) helyét tárolja */
    public static final int H_C1BEN=1, H_JOBBRA=2, H_LEFELE=3;
    private int hol;
    protected int x, y;
    private int ex, ey; // maximum koordinatak c1-bol; c1.getX()<=x<=ex, hasonloan y-ra
    private Csucs c1;
    // ^^^ c2 lejjebb/jobbrább van, mint c1
    // ^^^ (x,y) c1-re eshet, de c2-re csak akkor, ha c2!=c1

    public int getX() { return x; }
    public int getY() { return y; }

    public void ugrik() {
      // ex-et, ey-t, hol-t a semmibol ujraszamolja; c1,x,y mar helyes.
      Csucs c2;
      c2=c1.getSzomsz0(Csucs.JOBB); ex=c2.getX();
      c2=c1.getSzomsz0(Csucs.LE);   ey=c2.getY();
      if (x>c1.getX()) hol=H_JOBBRA;
      else if (y>c1.getY()) hol=H_LEFELE;
      else hol=H_C1BEN;
    }

    public Helyzet() {
      /* gagyi, kamu konstruktor, kesobb csucsba-val lehet korrigalni */
      this.c1=null;
    }
    public Helyzet(Csucs c1) {
      this.c1=c1;
      x=c1.getX(); y=c1.getY();
      ugrik();
    }

    public void csucsba(Csucs c1) {
      this.c1=c1;
      x=c1.getX(); y=c1.getY();
      ugrik();
    }

    protected int halad_alap(int merre, int mennyit) {
      // ne ezt hívd, hanem Mozgo.halad(*,*)-ot. Az ellenőriz és callback-kel is.
      // if (hol==H_C1BEN) System.out.println("Hudok "+merre+" "+mennyit+".");
      // Imp: clean this up (code works, but is ugly)
      int menyi=mennyit;
      if (merre==Csucs.FEL || merre==Csucs.BAL) menyi*=-1;
      if (hol==H_JOBBRA) { x+=menyi;
        if (x==ex) { c1=c1.getSzomsz0(merre); ugrik()}
        else if (x==c1.getX()) hol=H_C1BEN;
        return mennyit;
      }
      if (hol==H_LEFELE) { y+=menyi;
        if (y==ey) { c1=c1.getSzomsz0(merre); ugrik()}
        else if (y==c1.getY()) hol=H_C1BEN;
        return mennyit;
      }
      if (menyi<0) c1=c1.getSzomsz(merre);
      if (merre==Csucs.FEL || merre==Csucs.LE) { y+=menyi; if (y==ey) c1=c1.getSzomsz0(merre)}
                                          else { x+=menyi; if (x==ex) c1=c1.getSzomsz0(merre)}
      ugrik();
      return mennyit;
    }

    public int mennyit_mehet(int merre) {
      /* @return: innen mennyit mehet az akt. élen a megadott irányba */
      if (hol==H_JOBBRA) {
        if (merre==c1.BAL) return x-c1.getX();
        else if (merre==c1.JOBB) return ex-x; // c1.tavolsag(c1.JOBB)-x+c1.getX();
        else return 0;
      } else if (hol==H_LEFELE) {
        if (merre==c1.FEL) return y-c1.getY();
        else if (merre==c1.LE) return ey-y; // c1.tavolsag(c1.LE)-y+c1.getY();
        else return 0;
      }
      //: hol==H_C1BEN
      // System.out.println("MM:"+merre);
      // try { Thread.sleep(1000); } catch (InterruptedException e) {}
      return c1.tavolsag(merre);
    }
  } /// class Helyzet

  // ---

  public abstract static class Lathato extends Helyzet {
    //int regi_x, regi_y;
    //int fx1, fy1, fx2, fy2;
    protected int id; // egyedi azonosító, Labirintus használja
    protected Kep[] kepek;
    protected Kep aktkep;
    protected int akti;

    public void setId(int id) { this.id=id; }
    public int getId() { return id; }
    public String[] getKepnevek() {
      int i;
      java.lang.String[] t=new java.lang.String[kepek.length];
      for (i=0;i<kepek.length;i++) t[i]=kepek[i].getFilenev();
      return t;
    }

    public void utkozes_teszt() {
      Utkozteto u=new Utkozteto(aktkep, aktkep);
      u.dump_teszt();
    }
    public void utkozes_teszt(Lathato masik) {
      Utkozteto u=new Utkozteto(aktkep, masik.aktkep);
      u.dump_teszt();
    }

    // public void setKep(int i, java.awt.Image kep) { kepek[i].setKep(kep); }
    public void mozgat(int ujx, int ujy) {
      x=ujx; y=ujy;
    }
    public void rarajzolArnyek(Sdpts sd) {
      //sd.drawImage(aktkep.kep, x/24+aktkep.bx1, y/24+aktkep.bx1);
      // sd.drawShadow(x/24+aktkep.bx1-5, y/24+aktkep.bx1-5, aktkep.kep.getWidth(null)+10, aktkep.kep.getHeight(null)+10);
      aktkep.felrajzol_arnyek(x/24,y/24);
    }
    public void rarajzol(Sdpts sd) {
      //sd.drawImage(aktkep.kep, x/24+aktkep.bx1, y/24+aktkep.bx1);
      // sd.drawImageCover(aktkep.kep, x/24+aktkep.bx1, y/24+aktkep.bx1);
      // ^^^ még mindig érezhetően lassít
      aktkep.felrajzol_kep(x/24,y/24);
    }
    // public void tisztit() { dirty=false; }

    public boolean utkozik_e(Lathato masik) {
      // Imp: / 0 felé kerekítsen!! (x>=0??)
      return aktkep.utkozik_e(masik.aktkep, -x/24+masik.x/24, -y/24+masik.y/24);
    }

    public boolean akarsz_e_utkozni(Lathato masik) {
      /* Labirintus hívja meg új :Látható felvételekor (az újra és a régiekre is)
       * Pontosan akkor ad vissza true-t, ha kell ütközésvizsgálatot végezni this
       * és `masik' között. Az ütközésvizsgálatot Labirintus végzi this.utkozik_e
       * módszeres hivogatásával.
       * Érdemes átdefiniálni.
       */
      return false;
    }

    protected abstract void halad();
    // ^^^ egy lépes egy iterációban; nem feltétlenül mozgás
  } /// class Lathato

  public static abstract class Targy extends Lathato {
    protected void halad() {} // a tárgyak alapból nem haladnak semerre
  } /// class Targy

  public static class Gyemant extends Targy {
    public Gyemant(Labirintus l) {
      kepek=new Kep[1];
      kepek[0]=l.getKepbetolto().betolt("gyemant.gif").initi(l.getSd(),-12,-12,0);
      aktkep=kepek[0];
      akti=0;
    }
  } /// class Gyemant

  public static abstract class Mozgo extends Lathato {
    protected abstract void elfordult();
    // ^^^ akkor hivodik meg, ha a haladasi irany megvaltozik. Feluldefinialando.

    protected int ero; // mennyit lephet most
    protected int max_ero; // mennyi a max sebessege
    protected int irany=Csucs.PIHI; // milyen iranyba lepett legutoljara >=1-et
    public int setMax_ero(int max_ero) { return this.max_ero=max_ero; }
    public int setEro() { return this.ero=this.max_ero; }

    public int halad(int merre, int mennyit) {
      if (merre>=4 || mennyit==0) return 0;
      // System.out.println("Halad "+merre+" "+mennyit+".");
      mennyit=Math.min(mennyit, mennyit_mehet(merre));
      if (mennyit==0) return 0;
      if (irany!=merre) { irany=merre; elfordult()}
      return halad_alap(merre, mennyit);
    }

    public int halad(int merre) {
      // annyit halad az adott iranyba, amennyi az erejebol tellik
      int sikerult=halad(merre, ero);
      ero-=sikerult;
      return sikerult;
    }

    void halad_balra_fordul() {
      //if (irany==El.PIHI) halad(FEL);
      //if (irany==El.PIHI) halad(LE);
      //if (irany==El.PIHI) halad(JOBB);
      //if (irany==El.PIHI) halad(BAL);
      int erobk=0;
      while (erobk!=ero) { // atugorja a csomopontokat
        erobk=ero;
        for (int i=5;i>=2;i--) { if (0<halad((irany+i)%4)) break}
      }
    }
  }

  public static abstract class Szorny extends Mozgo {
  }

  public static class BalraSzorny extends Szorny {
    protected void elfordult() { aktkep=kepek[irany]; akti=irany; }
    protected void halad() { setEro(); halad_balra_fordul()}
    BalraSzorny(Labirintus l) {
      Kepbetolto kepbetolto=l.getKepbetolto();
      Sdpts sd=l.getSd();
      kepek=new Kep[5];
      // vvv nincs árnyéka
      kepek[Csucs.JOBB]=kepbetolto.betolt("szornyj.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL]=kepbetolto.betolt("szornyb.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL]=kepbetolto.betolt("szornyf.gif").initi(sd,-12,-12);
      kepek[Csucs.LE]=kepbetolto.betolt("szornyl.gif").initi(sd,-12,-12);
      kepek[Csucs.PIHI]=kepek[Csucs.JOBB];
      max_ero=40;
      aktkep=kepek[Csucs.JOBB];
      akti=Csucs.JOBB;
    }
  } /// BalraSzorny

  public static class Kisgomboc extends Mozgo {
    protected Labirintus labirintus;
    protected int akar; // melyik iranyba akar menni a player
    protected void fordul(int merre) { akar=merre; }
    protected void halad() {
      /* megprobal kanyarodni; ha nem sikerul, megy tovabb egyenesen
       * tipikusan a player adja meg `merre'-t
       */
      Lathato ut[]=labirintus.getUtkozesek(id);
      if (ut!=null) {
        // for (int i=0;i<ut.length;i++) System.out.println("UTK:"+(int)ut[i].getId());
        for (int i=0;i<ut.length;i++) {
          if (ut[i] instanceof Gyemant) {
            labirintus.gyemantCsokkent();
            labirintus.removeLathato(ut[i].getId());
          }
        }
      }
      setEro();
      int erobk=0;
      while (erobk!=ero) { // atugorja a csomopontokat
        erobk=ero;
        if (0==halad(akar)) halad(irany);
      }
    }
    Kisgomboc(Labirintus l) {
      this.labirintus=l;
      Kepbetolto kepbetolto=l.getKepbetolto();
      Sdpts sd=l.getSd();
      kepek=new Kep[5];
      kepek[Csucs.JOBB]=kepbetolto.betolt("gombocj.gif").initi(sd,-12,-12,5);
      kepek[Csucs.BAL]=kepbetolto.betolt("gombocb.gif").initi(sd,-12,-12,5);
      kepek[Csucs.FEL]=kepbetolto.betolt("gombocf.gif").initi(sd,-12,-12,5);
      kepek[Csucs.LE]=kepbetolto.betolt("gombocl.gif").initi(sd,-12,-12,5);
      kepek[Csucs.PIHI]=kepbetolto.betolt("gombocp.gif").initi(sd,-12,-12,5);
      max_ero=40;
      aktkep=kepek[Csucs.PIHI];
      akti=Csucs.PIHI;
    }
    protected void elfordult() { aktkep=kepek[irany]; akti=irany; }
    public boolean akarsz_e_utkozni(Lathato masik) {
      return masik instanceof Gyemant;
    }
  } /// Kisgomboc

  public static class RepuloGyemant extends Mozgo {
    protected int vx, vy;
    public RepuloGyemant(Labirintus l, int vx, int vy) {
      kepek=new Kep[1];
      kepek[0]=l.getKepbetolto().betolt("kgyemant.gif").initi(l.getSd(),-12,-12,0);
      aktkep=kepek[0];
      irany=akti=0;
      this.vx=vx;
      this.vy=vy;
      //dirty=true;
    }
    protected void elfordult() { aktkep=kepek[irany]; akti=irany; }
    protected void halad() {
      if (x>(320-23)*24) vx*=-1;
      if (x<20*24) vx*=-1;
      if (y<20*24) vy*=-1;
      if (y>(480-32)*24) vy*=-1;
      x+=vx; y+=vy;
    }
    protected void pattan() { vx*=-1; vy*=-1; }
    // java.lang.String[] kepnevek={"pacmanj.gif"};
    // public String[] getKepnevek() { return kepnevek; }
  } /// Lathato

  public static class Jatek extends Thread {
    // Imp: flag-ek, thread safety??
    public static final int A_JATEKKEZDODIK=0, A_SZINTLEPES=1, A_LABKEZDODIK=2, A_FOLYIK=3, A_FELFUGGESZTVE=4, A_VEGE=5;
    protected Kepbetolto kepbetolto;
    protected Labirintus.LabirintusRajzolo lr;
    protected JobboldalRajzolo jr;
    protected Labirintus labirintus;
    protected Idozitett idozitett;
    protected int eletszam, maxeletszam, bombaszam, maxbombaszam, pontszam, szint;
    protected int status; // a `status'-t csak this.run() módosíthatja

    // vvv kívülről jövő, aszinkron ingerek
    volatile protected int uj_irany;
    //protected boolean bombaLerakando;
    //protected boolean szintLependo;
    //protected boolean megallitando;
    public static final int F_BOMBALERAKANDO=1, F_SZINTLEPENDO=2, F_MEGALLITANDO=4, F_INDITANDO=8;
    volatile protected int inger;

    public Jatek(Kepbetolto kepbetolto, Labirintus.LabirintusRajzolo lr, JobboldalRajzolo jr, Idozito id) {
      this.kepbetolto=kepbetolto;
      this.lr=lr;
      this.jr=jr;
      idozitett=new Idozitett(id);
      // ^^^ Imp: new Idozitett()-et megengedi, noha nincs is ilyen konstruktor
      maxeletszam=5;
      maxbombaszam=3;

      eletszam=maxeletszam;
      bombaszam=maxbombaszam;
      pontszam=0;
      // `szint=0;' esetén fog az első szintről indulni
      szint=0;
      status=A_JATEKKEZDODIK;
    }
    public Sdpts getLabSd() { return lr.getSd()}
    public Kepbetolto getKepbetolto() { return kepbetolto; }
    public Labirintus getLabirintus() { return labirintus; }

    /*
    public synchronized void bombatLerak() {
      if (status==A_FOLYIK) bombaLerakando=true;
    }
    public synchronized int getStatus() { return status; }
    protected synchronized void setStatus(int status) { this.status=status; }
    public synchronized void megallit() {
      if (status==A_FOLYIK) status=A_FELFUGGESZTVE;
      else if (status==A_FELFUGGESZTVE) status=A_FOLYIK;
    }

    public void szintlepes() {
      // ezt nem lehet akárhonnan hívni.
      int status=getStatus();
      if (status!=A_JATEKKEZDODIK && status!=A_FOLYIK) throw new HibasAllapotException();
      setStatus(A_SZINTLEPES);
      szint++;
      if (labirintus!=null) labirintus.feloszlat();
      labirintus=null;
      labirintus=new Labirintus(this, szint);
      bombaszam=0;
    }*/

    public synchronized int getStatus() { return status; }
    // protected synchronized void setStatus(int uj_status) { this.uj_status=status; }

    public synchronized void szintlepes() { inger|=F_SZINTLEPENDO; }
    public synchronized void fordulj(int irany) {
      // System.out.println("EHOL!");
      if (status==A_LABKEZDODIK) { uj_irany=irany; inger|=F_INDITANDO; }
      else if (status==A_FOLYIK) { uj_irany=irany; }
      // else System.out.println("EHOLLLL!");
    }
    public synchronized void bombatLerak() {inger|=F_BOMBALERAKANDO; }
    public synchronized void megallit() {inger|=F_MEGALLITANDO; }
    // ^^^ Imp: szinkronizálás...

    protected synchronized int ingerTorles() { int i=inger; inger=0; return i; }

    public void run() {
      // ez _volt_ a KkkgPre4 run() metodusa, ami kulon szalban fut.
      // ez a szal frissiti a jatekallast (,,mozgatja'' a jatekot),
      // tovabba ez a szal rajzol az `sd'-re.
      super.setPriority(Thread.MIN_PRIORITY)// !! fontos az allando sebesseghez. Miert??

      while (true) {
        // System.out.println("megint "+status+";;"+uj_irany);
        // Imp: sync, Thread safe
        if (status==A_VEGE) break;
        int inger=ingerTorles();
        if (0!=(inger&F_SZINTLEPENDO)) {
          // if (status!=A_JATEKKEZDODIK && status!=A_FOLYIK) throw new HibasAllapotException();
          if (status==A_JATEKKEZDODIK || status==A_FOLYIK) {
            status=A_SZINTLEPES;
            // Imp: érvénytelenítés előtt várakozás stb.
            lr.ervenytelenit("Szintlépés");
            lr.paintMost();
            Idozito.alszik(1000);
            szint++; statRajzolando=true;
            if (labirintus!=null) labirintus.feloszlat();
            labirintus=null;
            // System.out.println("SZISZ");
            labirintus=new Labirintus(this, szint);
            bombaszam=0;
            uj_irany=Csucs.PIHI;
            kepbetolto.mind_meglegyen();
            labirintus.palya_betoltve();
            lr.ervenyesit(labirintus);
            lr.setDebugUzenet("csuhaj");
            labirintus.elorajzol();
            // !!!
            statRajzol();
            jr.paintMost()// Imp: nem mindig
            jr.repaint();
            lr.paintMost();
            status=A_LABKEZDODIK;
            // !!! az egészet újrarajzolni, nem csak a labirintust
            idozitett.ujraindit()// idozito.kezdd_ujra();
          }
        } else if (0!=(inger&F_MEGALLITANDO)) {
          if (status==A_FOLYIK) status=A_FELFUGGESZTVE;
          else if (status==A_FELFUGGESZTVE) status=A_FOLYIK;
        } else if (0!=(inger&F_INDITANDO)) {
          if (status==A_LABKEZDODIK) status=A_FOLYIK;
        }

        // if (status==A_VEGE) break;

        if (status==A_LABKEZDODIK || status==A_FELFUGGESZTVE) { idozitett.altass_el()continue}
        if (status!=A_FOLYIK) throw new HibasAllapotException();

        // iter=idozitett.getMegteve();
        lr.setDebugUzenet("megt="+idozitett.getMegteve()+" lass="+idozitett.getSikerultPeriodus()+"/"+
          idozitett.getEloirtPeriodus()+"  "+idozitett.getLassuMuveletSzazalek()+"%/100%");

        labirintus.getKisgomboc().fordul(uj_irany);
        labirintus.mozgat();
        //if (aludtunk || nem_rajzoltunk>50)
        if (idozitett.lehet_lassu_muvelet()) {
          // most jön a rajzolás sd-re. Ez egy lassú művelet, úgyhogy csak
          // akkor végezzük, ha jól állunk időben
          labirintus.elorajzol();
          statRajzol();
          jr.paintMost();
          lr.paintMost();
          idozitett.lassu_muvelet()//rajzoltunk_osszesen++; //nem_rajzoltunk=0; idozito.altass_el(this);
        } else {
          idozitett.gyors_muvelet()// nem_rajzoltunk++; nem_rajzoltunk_osszesen++; idozito.altass_el(this);
        }
      } // WHILE(true)
    } /// run()

    protected boolean statRajzolando;
    protected void statValtozott() { statRajzolando=true}
    protected void statRajzol(Graphics g) {
      g.setColor(Color.black);
      g.fillRect(0,0,160,100);
      g.setColor(Color.white);
      g.drawString("gy.mar: "+labirintus.getGyemantc(),10,20);
      g.drawString("pontszám: "+pontszam,10,40);
      g.drawString("bombaszám: "+bombaszam,10,60);
      g.drawString("életszám: "+eletszam,10,80);
    } /// statRajzol()
    protected void statRajzol() {
      // if (true) return;
      if (!statRajzolando) return;
      Graphics g=jr.getSd().getBackgroundGraphics();
      jr.getSd().dirtyClear();
      statRajzol(g);
      // g.dispose(); // tilos hívni!!
      jr.getSd().dirtyAddClear();
      // statRajzol(jr.getGraphics());
      // jr.getSd().dirtyAddMax();
      // Clear();
      System.out.println("KKK: "+labirintus.getGyemantc());
      statRajzolando=false;
    } /// statRajzol()
    protected void pontszamNovel(int mennyivel) {
      pontszam+=mennyivel;
      statRajzolando=true;
    }
  } /// class Jatek

  public static class SdRajzolo extends Canvas {
    /* olyan komponens, ami egy Sdpts-t jelenít meg */
    protected Sdpts sd;
    protected Dimension dim=new Dimension(1,1);
    public Dimension getPreferredSize() { return dim; }
    public Dimension getMinimumSize() { return dim; }
    public Dimension getMaximumSize() { return dim; }
    // ^^^ őrült Java már megint okosabb akar lenni a programozónál.
    //     Nem lehet megmondani neki, hogy a komponens márpedig _pontsan_
    //     akkora legyen, mint amekorrát a programozó akar. Nem olyan nagy
    //     kérés ez, a Java mégis képtelen rá. (Szűkebben: a GridLayout
    //     képtelen 1/n-edrésznél szélesebbre venni a komponens szélességét.)
    public void update(Graphics g) {
      // alapesetben kirajzolja az egesz teglalapot hatterszinnel teliti meg,
      // majd meghivja a paint-et. Azert rossz megis az alapeset, mert a
      // bongeszo csak a paint-et hivja, mig a repaint() az update-et.
      this.paint(g);
    }
    public void paint(Graphics g) { // Canvas újrarajzolás
      sd.renderAll(g, 0, 0);
    }
    public void paintMost() {
      Graphics g=this.getGraphics();
      if (g!=null) {
        // sd.renderAll(g, 0, 0);
        paint(g)// valószínűleg át van definiálva
        g.dispose();
      }
    }
    protected void init_sd() {
      this.sd=new Sdpts(this.getSize().width, this.getSize().height, this);
    }
    public Sdpts getSd() { return sd; }
    public void atmeretez(int w, int h) { dim=new Dimension(w, h)super.setSize(w, h)}
  } /// class Sdrajzolo

 Betutipus betutipus;
  public class JobboldalRajzolo extends SdRajzolo {
    // nem statikus. Kell neki: `betűtípus'.
    JobboldalRajzolo() {
      super.atmeretez(160, 480);
      this.setBackground(Color.red);
      init_sd();
    }
    public void paintz(Graphics g) { // Canvas újrarajzolás
      g.setColor(Color.white);
      g.drawString("Csiribá", 10, 50);
      if (betutipus!=null) {
        betutipus.nyomtat(g,10,80,"Tősgyökeres Űrkikötőkerülő");
      }
    }
  } /// class Jobboldalrajzolo

  public static class KepKonstansok {
    public static final int D_SEMMI=Kep.C_FEKETE, D_UT=Kep.C_FEHER, D_GYEMANT=Kep.C_PIROS,
      D_BOMBA=Kep.C_SARGA, D_GOC=Kep.C_ZOLD, D_SZEL=Kep.C_KEK, D_KOMMENT=Kep.C_LILA,
      D_KISGOMBOC=Kep.C_TURKIZ;
  }

  public static class Labirintus {
    public static final int U_MINDEGY=0, U_NEMUTKOZIK=1, U_UTKOZIK=2;

    protected Kep palya_alja;
    protected Kep palya_teteje;
    protected Kep palya_arnyeka;
    protected Kep palya_grafja;
    protected Sdpts sd;
    protected Jatek jatek;
    protected Csucs kezdocsucs;

    protected int gyemantc;
    // private Vector csucsok; // num->Csucs

    int getGyemantc() { return gyemantc; }
    void gyemantCsokkent() {
      if (gyemantc<1) return;
      gyemantc--;
      if (gyemantc==7) jatek.szintlepes();
      System.out.println("HURRÁ");
      jatek.pontszamNovel(23);
      jatek.statValtozott();
    }
    protected Lathato lathatok[];
    protected int utkozesek[][];
    protected int utkozesc[];
    protected int addLathatoI; // a legutolsó index, ahova addLathato adott
    protected Lathato addLathato(Lathato lathato) {
      /* egy új :Látható-t helyez el this.lathatok-ban */
      int i=addLathatoI+1;
      while (i!=addLathatoI) {
        i%=lathatok.length;
        if (lathatok[i]==null) {
          lathato.setId(i);
          lathatok[i]=lathato;
          for (int j=0;j<lathatok.length;j++) if (i!=j && lathatok[j]!=null) {
            utkozesek[i][j]=lathatok[i].akarsz_e_utkozni(lathatok[j])?U_NEMUTKOZIK:U_MINDEGY;
            utkozesek[j][i]=lathatok[j].akarsz_e_utkozni(lathatok[i])?U_NEMUTKOZIK:U_MINDEGY;
          }
          addLathatoI=i;
          return lathato;
        }
      }
      throw new ArrayIndexOutOfBoundsException();
    }
    public void removeLathato(int i) {
      if (lathatok[i]==null) return;
      lathatok[i].setId(-1);
      int u[]=utkozesek[i];
      for (int j=0;j<lathatok.length;j++) u[j]=U_MINDEGY;
      for (int j=0;j<lathatok.length;j++) utkozesek[j][i]=U_MINDEGY;
      lathatok[i]=null;
    }

    public void feloszlat() {
      /* amikor a :Játék felszabadítja, akkor hívódik meg */
    }
    public void elorajzol() {
      sd.dirtyClear();
      for (int i=0;i<lathatok.length;i++) if (lathatok[i]!=null) lathatok[i].rarajzolArnyek(sd);
      // ^^^ előbb az _összes_ árnyékot felrajzoljuk
      for (int i=0;i<lathatok.length;i++) if (lathatok[i]!=null) lathatok[i].rarajzol(sd);
      // sd.dirtyCover(); // az sprite-okat fedje a falrács
      // sd.fullCover(); // az egészet fedje a falrács
      // KkkgPre4.this.repaint(); // rögtön visszatér, de összevissza bufferel
    }

    public Labirintus(Jatek jatek, int sorszam) {
      Kepbetolto kepbetolto=jatek.getKepbetolto();
      this.jatek=jatek;
      this.sd=jatek.getLabSd();
      String ss=KkkgPre4.decformat(sorszam, 3);
      palya_alja=   kepbetolto.betolt("p_"+ss+"h.gif").initi(sd,0,0);
      palya_teteje= kepbetolto.betolt("p_"+ss+"e.gif").initi(sd,0,0);
      palya_arnyeka=kepbetolto.betolt("p_"+ss+"g.gif").initi(sd,0,0);
      palya_grafja= kepbetolto.betolt("p_"+ss+"g.gif").initi(sd,0,0);
      lathatok=new Lathato[20]// 20: elég nagy, hogy a legsűrűbb játékállás is beleférjen
      addLathatoI=lathatok.length-1;
      utkozesek=new int[lathatok.length][];
      utkozesc=new int[lathatok.length];
      for (int i=0;i<lathatok.length;i++) utkozesek[i]=new int[lathatok.length];

      addLathato(new Kisgomboc(this));
      addLathato(new BalraSzorny(this));
      new Gyemant(this)// csak azért, hogy a képét letöltse
      for (int i=0;i<8;i++) addLathato(new RepuloGyemant(this,48-i,24-i)).mozgat(50*24,50*24);
      // a képek betöltődésére várni kell, a további inicializalast a
      // palya_betoltve() vegzi
    }
    public Jatek getJatek() { return jatek; }
    public Kepbetolto getKepbetolto() { return jatek.getKepbetolto()}
    public Sdpts getSd() { return sd; }
    public Kisgomboc getKisgomboc() { return (Kisgomboc)lathatok[0]}
    public void kezdocsucsba(Helyzet h) { h.csucsba(kezdocsucs)}
    // ^^^ public void kezdocsucsba(Helyzet h) { h.csucsba((Csucs)csucsok.get(0)); }
    public int getUtkozesc(int id) { return utkozesc[id]}
    public Lathato[] getUtkozesek(int id) {
      if (utkozesc[id]<1) return null;
      Lathato t[]=new Lathato[utkozesc[id]];
      int i=0;
      int u[]=utkozesek[id];
      for (int j=0;j<u.length;j++) if (u[j]==U_UTKOZIK) t[i++]=lathatok[j];
      return t;
    }

    public void palya_betoltve() {
      /* inicializálás miután a pálya már betöltődött */
      jatek.getKepbetolto().elfelejt(palya_alja.getFilenev());
      jatek.getKepbetolto().elfelejt(palya_teteje.getFilenev());
      jatek.getKepbetolto().elfelejt(palya_arnyeka.getFilenev());
      jatek.getKepbetolto().elfelejt(palya_grafja.getFilenev());
      grafot_felepit();
      // lathatok[0].utkozes_teszt(lathatok[2]);
      //System.out.println(lathatok[0].mennyit_mehet(Csucs.BAL));
      //System.out.println(lathatok[0].mennyit_mehet(Csucs.FEL));
      this.kezdocsucsba((Helyzet)lathatok[0]);
      this.kezdocsucsba((Helyzet)lathatok[1]);
    }

    public void mozgat() {
      int i, j, u[], uc;
      // vvv megvizsgáljuk az ütközéseket minden párra
      for (i=0;i<lathatok.length;i++) {
        u=utkozesek[i];
        uc=0;
        for (j=0;j<lathatok.length;j++) if (u[j]!=U_MINDEGY)
          if (lathatok[i].utkozik_e(lathatok[j])) { u[j]=U_UTKOZIK; uc++; } else { u[j]=U_NEMUTKOZIK; }
        utkozesc[i]=uc;
      }
      // lathatok[0].mozgat(400-lathatok[0].getX(), lathatok[0].getY());
      // for (int i=2;i<lathatok.length;i++) if (lathatok[i]!=null && lathatok[0].utkozik_e(lathatok[i])) ((RepuloGyemant)lathatok[i]).pattan();

      // vvv meghívjuk a halad-ot minden :Látható-ra (a halad már felhasználja az ütközési táblázatot
      for (i=0;i<lathatok.length;i++) if (lathatok[i]!=null) lathatok[i].halad();
      // ((Helyes)lathatok[0]).halad_amerre_fordul();
    }

    // --- most jönnek a gráfot felépítő segédrutinok

    public static class HibasGrafException extends Error {}
    public static class KisgombocHianyzikException extends HibasGrafException {}
    private boolean hatarcsucs_e(int[][] tt, int x, int y) {
      /* visszaadja, hogy az adott csúcs határcsúcs-e */
      if (tt[y][x]==KepKonstansok.D_SEMMI) return false;
      if (tt[y][x]!=KepKonstansok.D_UT) return true;
      // ^^^ !!! a bekanyarodás lehal
      boolean fel=tt[y-1][x]!=KepKonstansok.D_SEMMI;
      boolean le=tt[y+1][x]!=KepKonstansok.D_SEMMI;
      boolean jobb=tt[y][x+1]!=KepKonstansok.D_SEMMI;
      boolean bal=tt[y][x-1]!=KepKonstansok.D_SEMMI;
      return !((fel&&le&&!jobb&&!bal) || (!fel&&!le&&jobb&&bal));

    }
    public void grafot_felepit() {
      int tt[][]=palya_grafja.getPixelttnot();
      Csucs ki[][]=new Csucs[tt.length][];
      kezdocsucs=null;
      // Hashtable ht=new Hashtable(); // (y<<16+x)->Csucs; SUXX: nem lehet int-tel indexelni
      // System.out.println(tt.length);
      // System.out.println(tt[0].length);

      //for(i=1;i<=10;i++) cout<<i<<"\n"; // by Szilvi

      gyemantc=0;
      Csucs cs=null;
      for (int y=tt.length-2;y>=1;y--) {
        int uu[]=tt[y];
        ki[y]=new Csucs[uu.length];
        for (int x=uu.length-2;x>=1;x--) {
          if (uu[x]==KepKonstansok.D_KOMMENT) uu[x]=KepKonstansok.D_SEMMI;
          if (!hatarcsucs_e(tt, x, y)) continue;
          cs=new Csucs(x*24, y*24);
          if (uu[x]==KepKonstansok.D_KISGOMBOC) kezdocsucs=cs;
          else if (uu[x]==KepKonstansok.D_GYEMANT) {
            gyemantc++;
            addLathato(new Gyemant(this)).csucsba(cs);
         }
          ki[y][x]=cs;
          // csucsok.addElement(cs);
          if (uu[x+1]!=KepKonstansok.D_SEMMI) { // összekötünk jobbra
            int i=x+1;
            while (!hatarcsucs_e(tt, i, y)) i++;
            cs.osszekot(ki[y][i]);
          }
          if (tt[y+1][x]!=KepKonstansok.D_SEMMI) { // összekötünk le
            int i=y+1;
            while (!hatarcsucs_e(tt, x, i)) i++;
            cs.osszekot(ki[i][x]);
          }
        } // NEXT x
      } // NEXT y
      if (kezdocsucs==null) kezdocsucs=cs;
      if (kezdocsucs==null) throw new KisgombocHianyzikException();
      // System.exit(42); // applet-ből SecurityException-t ad
      palya_grafja.pixelt_felejt();
    }

    public static class LabirintusRajzolo extends SdRajzolo {
      protected String miertErvenytelen;
      protected String debugUzenet;

      public LabirintusRajzolo() {
        super.atmeretez(320, 480);
        init_sd();
        miertErvenytelen="Inicializálok...";
      }

      public void ervenytelenit(String miert) { miertErvenytelen=miert; }
      public void setDebugUzenet(String miert) { debugUzenet=miert; }
      public void ervenyesit(Labirintus l) {
        Graphics g=this.sd.getBackgroundGraphics()/// !!!
        l.palya_alja.rarajzol(g,0,0);
        // g.setColor(Color.pink); g.fillRect(100,100,200,200);
        // sd.dirtyAdd(0,0,screenW,screenH);
        this.sd.dirtyAddClear();
        // g.dispose(); // Tilos hívni!

        // g=this.sd.getCoverGraphics(); l.palya_teteje.rarajzol(g,0,0); g.dispose();
        this.sd.setCover(l.palya_teteje.getKep());

        // g=this.sd.getShadowGraphics(); l.palya_arnyeka.rarajzol(g,0,0); g.dispose();
        this.sd.setShadow(l.palya_grafja.getKep());

        this.sd.dirtyAdd(0,0,this.sd.getWidth(),this.sd.getHeight());
        this.sd.dirtyClear();
        miertErvenytelen=null;
      }

      public void paint(Graphics g) { // Canvas újrarajzolás
        // if (true) { } else
        if (miertErvenytelen!=null) {
          g.setColor(java.awt.Color.green.darker());
          g.fillRect(0, 0, this.sd.getWidth()this.sd.getHeight());
          g.setColor(java.awt.Color.red.brighter());
          // g.drawString("Épp töltögetek...", 10, 20);
          g.drawString(miertErvenytelen, 10, 20);
        } else {
          this.sd.renderAll(g, 0, 0);
          // ^^^ az egész ablakot cakumpakk újrarajzoljuk

          // g.setColor(java.awt.Color.white);
          // for (int i=0;i<elek.length;i++) { elek[i].rarajzol(g); }
          // ^^^ csak debug, már nem kell

          // if (sebesseg!=0) {}
          if (debugUzenet!=null) {
            // if (true) throw new NullPointerException();
            g.setColor(java.awt.Color.white);
            //g.drawString("Lassúság: eddig="+sebesseg+"/"+1000*idozito.getInterval()+
            //  " rajzolás="+(100*(rajzoltunk_osszesen)/(rajzoltunk_osszesen+nem_rajzoltunk_osszesen))+
            //  "%.",10,20);
            g.drawString(debugUzenet, 10, 20);
          }
          //frissitesre_varunk=false;
        }
        //palya_teteje.rarajzol(g, 0, 0);
      } /// paint()
    } /// class LabirintusRajzolo
  } /// class Labirintus

  public void update(Graphics g) { this.paint(g)}
  // Panel.this.paint()-et meghagyjuk

  public static class Idozitett {
    protected Idozito idozito;
    protected long megteve;
    protected boolean utoljara_aludtunk;
    protected long nem_rajzoltunk; // az utolsó rajzolás óta hányszor nem rajzoltunk
    protected long nem_rajzoltunk_osszesen;
    protected long rajzoltunk_osszesen;
    protected long mikor_inditottak; // időpont ms-ben

    public Idozitett(Idozito idozito) {
      this.idozito=idozito;
      ujraindit();
    }
    public boolean altass_el() {
      if (megteve++<idozito.getHoltart()) {
        Thread.yield();
        return utoljara_aludtunk=false;
      } else {
        idozito.var(megteve);
        return utoljara_aludtunk=true;
      }
    } /// altass_el()
    public void lassu_muvelet() {
      rajzoltunk_osszesen++;
      nem_rajzoltunk=0;
      altass_el();
    }
    public void gyors_muvelet() {
      nem_rajzoltunk++;
      nem_rajzoltunk_osszesen++;
      altass_el();
    }
    public boolean lehet_lassu_muvelet() { // állapotlekérdezés
      return utoljara_aludtunk || nem_rajzoltunk>50;
    }
    public void ujraindit() {
      utoljara_aludtunk=true;
      megteve=nem_rajzoltunk=nem_rajzoltunk_osszesen;
      if (!idozito.isAlive()) idozito.start()// tényleg isAlive kell ide??
      mikor_inditottak=System.currentTimeMillis();
      rajzoltunk_osszesen=1;
    }

    public long getMegteve() { return megteve; }
    public long getEloirtPeriodus() { /*micros-ban*/ return 1000L*idozito.getInterval()}
    public long getSikerultPeriodus() { /*micros-ban*/
      return megteve==0?0:1000L*(System.currentTimeMillis()-mikor_inditottak)/megteve;
    }
    public long getLassuMuveletSzazalek() {
      return 100L*(rajzoltunk_osszesen)/(rajzoltunk_osszesen+nem_rajzoltunk_osszesen);
    }
  } /// class Idozitett

  public static class Idozito extends Thread {
    /* egyetlen objektum időzítését látja el (lehet, hogy többre is működsne,
     * de az tetsztelni kéne
     */
    // Imp: több objektumot időzít
    // Imp: volatile
    protected volatile boolean futunk_e_meg=true;
    // volatile int hatravan; // volatile: ne cache-elje
    protected volatile int holtart, varakozok;
    protected long interval_ms;

    Idozito(int interval_ms_) { interval_ms=interval_ms_; }

    public int getInterval() { return (int)interval_ms; }
    public int getHoltart() { return holtart; }

    public void var(long meddig) {
      // kívülről hivandó, pl :Időzített-ből
      do { // általában csak egyszer fut le a ciklusmag
        synchronized(this) {
          varakozok++;
          try { super.wait(interval_ms)} catch (InterruptedException e) { }
          varakozok--;
        }
      } while (meddig>holtart);
    }

    public static void alszik(int mennyit) {
      // millisec
      try { Thread.sleep(mennyit)} catch (InterruptedException e) {}
    }

    public void stopp() { futunk_e_meg=falsethis.interrupt()}
    public void run() {
      long logik, van, mennyit_alszom;
      this.setPriority(MAX_PRIORITY);
      mennyit_alszom=interval_ms;
      logik=java.lang.System.currentTimeMillis();
      while (futunk_e_meg) {
        // System.out.println("Mennyit: "+mennyit_alszom+".");
        try { java.lang.Thread.sleep(mennyit_alszom)} catch (InterruptedException e) { System.out.println("IR")}
        logik+=interval_ms;
        van=java.lang.System.currentTimeMillis();
        if (logik<van-200) mennyit_alszom=interval_ms*9/10;
        else if (logik>van+200) mennyit_alszom=interval_ms;
        //hatravan++;
        holtart++;
        if (varakozok>0) { synchronized(this) { super.notifyAll()} }
      }
    } /// run()
  } /// class Idozito

  public static class CsucslistaBejegyzes implements Serializable {
    // `implements Comparable', de az nincs a JDK1.1-ben :-(
    // muszáj `implements Serializable', nem elég Csucslistának
    protected String nev;
    protected int pontszam;
    public CsucslistaBejegyzes(String nev, int pontszam) {
      this.nev=nev;
      this.pontszam=pontszam;
    }
    public int compareTo(Object masik) {
      CsucslistaBejegyzes masikcs=(CsucslistaBejegyzes)masik;
      return this.pontszam==masikcs.pontszam ? 0 :
             this.pontszam> masikcs.pontszam ? 1 : -1;
    }
    public String toString() { return nev+": "+pontszam; }
  }
  public static class Csucslista implements Serializable {
    public static final int MERET=10, NOVEKMENY=100;
    private CsucslistaBejegyzes bejegyzesek[];
    protected void alapErtek() {
      /* alapértékekkel feltöltött :Csúcslistát hoz létre */
      bejegyzesek=new CsucslistaBejegyzes[MERET];
      for (int i=0;i<bejegyzesek.length;i++) bejegyzesek[i]=new CsucslistaBejegyzes("eNTitánok"(bejegyzesek.length-1-i)*NOVEKMENY);
    }
    public Csucslista() { alapErtek()}
    public static Csucslista betolt(String filenev) {
      try {
        FileInputStream f;
        ObjectInputStream o;
        try { f=new FileInputStream(filenev)}
        catch (IOException e) { return new Csucslista()}
        // catch (FileNotFoundException e) { return new Csucslista(); }
        try { o=new ObjectInputStream(f)}
        catch (java.io.StreamCorruptedException e) { return new Csucslista()} 
        catch (IOException e) { return new Csucslista()} 
        try { return (Csucslista)o.readObject()}
        catch (IOException e) { return new Csucslista()}
        catch (ClassNotFoundException e) { return new Csucslista()}
      } catch (Exception e) {
        // hülye böngészők, appletviewerek ezerféle szabványtalan kivételt
        // képesek küldeni.
        return new Csucslista();
      }
    }
    public void kiment(String filenev) {
      FileOutputStream f;
      try {
        f=new FileOutputStream(filenev);
        ObjectOutputStream o=new ObjectOutputStream(f);
        o.writeObject(this);
      }
      //catch (IOException e) {}
      catch (Exception e) {}
    }
    public int felvesz(CsucslistaBejegyzes csb) {
      /* felveszi a bejegyzést a csúcslistába, ha elég nagy a pontszám.
       * Visszadja az indexet, ahová felvételre került, vagy -1.
       */
      int i=0;
      while (i<bejegyzesek.length && csb.compareTo(bejegyzesek[i])<0) i++;
      if (i==bejegyzesek.length) return -1;
      System.arraycopy(bejegyzesek, i, bejegyzesek, i+1, bejegyzesek.length-i-1);
      bejegyzesek[i]=csb;
      return i;
    }
    public void kiir() {
      for (int i=0;i<bejegyzesek.length;i++) System.out.println(bejegyzesek[i].toString());
      System.out.println("");
    }
  } /// class Csucslista

  private static final String CSUCSLISTA_FILENEV="kkkg.csl";
  private boolean application_e; // pontosan akkor true, ha Java Application-ként futunk
  private Jatek jatek;
  private Labirintus.LabirintusRajzolo labirintusRajzolo;
  private JobboldalRajzolo jobboldalRajzolo;

  public KkkgPre4() {}
  private KkkgPre4(boolean application_e) { this.application_e=application_e; }
  public java.net.URL getCodeBase() {
    return application_e?null:super.getCodeBase();
  }

  public void initFigyelok() {
    /* mindhárom komponenshez hozzáadja a *Listener-eket. Elvileg elég lenne
     * csak az applet-hez, de Java 1.1.7, Linux alatt mindegyikhez kell,
     * különben nem működik.
     */
    FocusListener myFocusListener=new FocusAdapter() {
      public void focusGained(java.awt.event.FocusEvent e) {
        java.lang.System.out.println("Fokk");
      }
    };
    this.addFocusListener(myFocusListener);
    labirintusRajzolo.addFocusListener(myFocusListener);
    jobboldalRajzolo.addFocusListener(myFocusListener);
    MouseListener myMouseListener=new MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent e) {
        // nem hívódik meg, mert az al-komponensek kapják meg az üzenetet
        // ,elfelejtodik'' meghivodni, ha az eger elmozdult a gomblenyomas
        // es a felengedes kozott
        //KkkgPre4.this.repaint(teglalap_x-40,teglalap_y-25,80,50);

        //teglalap_x=e.getX(); teglalap_y=e.getY();
        java.lang.System.out.println("Klitty x="+java.lang.Integer.toString(e.getX())+
          " y="+java.lang.Integer.toString(e.getY())+".");
        // KkkgPre4.this.repaint(teglalap_x-40,teglalap_y-25,80,50);
        // KkkgPre4.this.repaint();
        KkkgPre4.this.requestFocus();
      }
    };
    this.addMouseListener(myMouseListener);
    labirintusRajzolo.addMouseListener(myMouseListener);
    jobboldalRajzolo.addMouseListener(myMouseListener);
    KeyListener myKeyListener=new KeyAdapter() {
      public void keyTyped(java.awt.event.KeyEvent e) {
        // csak olyan billentyukre hivodik meg, amelyek karakter beszurasat eredemenyezik.
        // tehat peldaul meghivodik A, ó, Enter, szóköz stb-re, de nem hivodik meg
        // pl. Home, Shift, NumLock stb.-re
        // java.text.DecimalFormat f;
        // f=new java.text.DecimalFormat("U+0000");

        // java.lang.System.out.println("Potty karakter Unicode U+"+java.lang.Integer.toHexString(e.getKeyChar())+".");
        // ^^^ jo, de neha tul rovid

        // java.lang.System.out.println("Potty karakter Unicode "+new java.text.DecimalFormat("U+0000").format(e.getKeyChar())+".");
        // ^^^ jo lenne, de 16-os szamrendszerben kellene
        // if (e.getKeyChar==27) // SUXX: appletből nem lehet kilépni...
        java.lang.System.out.println("Potty karakter Unicode U+"+hexformat(e.getKeyChar(),4)+".");
        // ^^^ jo lenne, de 16-os szamrendszerben kellene
      }
      /* vvv for Java version 1.1.7 compatibility */
      public final int VK_KP_UP=0xE0;
      public final int VK_KP_DOWN=0xE1;
      public final int VK_KP_LEFT=0xE2;
      public final int VK_KP_RIGHT=0xE3;
      public void keyPressed(java.awt.event.KeyEvent e) {
        // minden billenyure meghivodik
        int kc=e.getKeyCode();
        // if (kc==e.VK_UP) { menne_fel=true; menne_le=false; }
        // if (kc==e.VK_DOWN) { menne_le=true; menne_le=false; }
        /* if (kc==e.VK_UP || kc==e.VK_KP_UP) jatek.getLabirintus().getKisgomboc().fordul(Csucs.FEL);
        else if (kc==e.VK_DOWN || kc==e.VK_KP_DOWN) jatek.getLabirintus().getKisgomboc().fordul(Csucs.LE);
        else if (kc==e.VK_LEFT || kc==e.VK_KP_LEFT) jatek.getLabirintus().getKisgomboc().fordul(Csucs.BAL);
        else if (kc==e.VK_RIGHT || kc==e.VK_KP_RIGHT) jatek.getLabirintus().getKisgomboc().fordul(Csucs.JOBB); */

        if (kc==e.VK_UP || kc==VK_KP_UP) jatek.fordulj(Csucs.FEL);
        else if (kc==e.VK_DOWN || kc==VK_KP_DOWN) jatek.fordulj(Csucs.LE);
        else if (kc==e.VK_LEFT || kc==VK_KP_LEFT) jatek.fordulj(Csucs.BAL);
        else if (kc==e.VK_RIGHT || kc==VK_KP_RIGHT) jatek.fordulj(Csucs.JOBB);
        else java.lang.System.out.println("Potty le  bilkod="+new Integer(e.getKeyCode()).toString()+".");
      }
      public void keyReleased(java.awt.event.KeyEvent e) {
        // minden billentyure meghivodik
        java.lang.System.out.println("Potty fel bilkod="+new Integer(e.getKeyCode()).toString()+".");
        /*teglalap_x=KkkgPre4.this.getSize().width/2;
        teglalap_y=KkkgPre4.this.getSize().height/2;*/
        KkkgPre4.this.repaint();
      }
    };
    this.addKeyListener(myKeyListener);
    labirintusRajzolo.addKeyListener(myKeyListener);
    jobboldalRajzolo.addKeyListener(myKeyListener);
  }

  public void init() {
    // ezt a fuggvenyt hivja a webbongeszo a jatek indulasakor
    // int t[1];
    //this.resize(320, 480); // appletviewer-nek kell.
    System.out.println("HEELO!");

    OkosAWT.setMainComponent(this);

    // először a megjelenítést inicializáljuk
    this.setBackground(Color.yellow)// sose szabadna látszania!!
    this.resize(480, 480)// appletviewer-nek kell.
    if (this.getSize().width<480 || this.getSize().height<480)
      throw new AtmeretezesNemSikerultException();
    //this.setLayout(new GridLayout(1,2,0,0)); // SUXX, fix méret nem állítható be
    this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
    this.add(labirintusRajzolo=new Labirintus.LabirintusRajzolo());
    this.add(jobboldalRajzolo=new JobboldalRajzolo());
    this.requestFocus();
    // ^^^ enelkul nem kapnank meg a billentyuleuteseket appletviewer-ben
    this.repaint();
    this.requestFocus();

    Kepbetolto kepbetolto=new Kepbetolto();
    // ^^^ ezt még bármilyen kép előtt
    Idozito idozito=new Idozito(16)// 16!!
    idozito.setDaemon(true);
    idozito.start();

    Kep k=kepbetolto.betolt("ss13.gif");
    kepbetolto.mind_meglegyen();
    betutipus=new Betutipus(k,0xFFFFFF);
    jobboldalRajzolo.repaint();

    jatek=new Jatek(kepbetolto, labirintusRajzolo, jobboldalRajzolo, idozito);

    initFigyelok();

    jatek.szintlepes();
    jatek.start();

    this.requestFocus();
    this.repaint()// !!
    this.requestFocus()// nincs hatása JDK1.1.7-ben
    // Thread.yield(); Idozito.alszik(2000);
    labirintusRajzolo.requestFocus();
  }
  public void start() { /* Applet.start() felülírva */
    this.requestFocus()// itt sincs hatása JDK1.1.7-ben
    Csucslista cs=Csucslista.betolt(CSUCSLISTA_FILENEV);
    cs.felvesz(new CsucslistaBejegyzes("Szilvi", 888));
    cs.kiir();
    cs.kiment(CSUCSLISTA_FILENEV);
  }
  public void stop() { /* Applet.stop() felülírva */
  }

  public static void main(String argv[]) {
    System.err.println("Kincskereso Kisgomboc Grafikus tesztvaltozat, 1. verzio\n(C) Spring 2001 by eNTitanok. http://www.inf.bme.hu/~pts/entitanok/\nTHIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!\n");
    Frame f=new Frame("eNTitánok: Kincskereső Kisgömböc");
    // ^^^ esetleg hullámvonalas ő jelenhet meg. \u0151 se lenne jobb, mert
    //     az nem Unicode-os rendszerekben Q betűt eredményezne.
    f.setResizable(false);
    f.setSize(480,480);
    f.setBackground(Color.pink);
    f.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0))// csak semmi kihagyás!
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(java.awt.event.WindowEvent e) {
        ((Frame)e.getComponent()).setVisible(false);
        // ^^^ engedi bezárni az ablakot, de ez nem elég. Mi ki akarunk lépni.
        System.exit(0);
      }
    });
    f.show();
    System.out.println("Megmutattam.");
    Applet a=new KkkgPre4(true);
    f.add(a);
    a.init();
    a.start();
    // `System.exit(0);' rögtön kilép, akár van nyitva :Frame, akár nincs.
    // Viszont ha csak simán lefut a main(), és van nyitva :Frame, akkor a
    // Java belép az eseményfeldolgozó végtelen ciklusba, amiből csak
    // a `System.exit(0);' jelent kiutat (még az utolsó :Frame bezárása sem).
    //   Tehát az a stratégiánk, hogy a main()-ből simán visszatérünk, és ha
    // a :Frame-ünk windowClosing() eseményt kap, ott meghívjuk a
    // `System.exit(0);'-t.
  }
} /// class KkkgPre4