예제 #1
0
 public void draw(GOut g) {
   long now = System.currentTimeMillis();
   for (int y = 0; y < gsz.y; y++) {
     for (int x = 0; x < gsz.x; x++) {
       Coord p = bgsz.mul(new Coord(x, y));
       g.image(bg, p);
       Pagina btn = layout[x][y];
       if (btn != null) {
         Tex btex = btn.img.tex();
         g.image(btex, p.add(1, 1));
         if (btn.meter > 0) {
           double m = btn.meter / 1000.0;
           if (btn.dtime > 0) m += (1 - m) * (double) (now - btn.gettime) / (double) btn.dtime;
           m = Utils.clip(m, 0, 1);
           g.chcolor(255, 255, 255, 128);
           g.fellipse(p.add(bgsz.div(2)), bgsz.div(2), 90, (int) (90 + (360 * m)));
           g.chcolor();
         }
         if (btn.newp != 0) {
           if (btn.fstart == 0) {
             btn.fstart = now;
           } else {
             double ph = ((now - btn.fstart) / 1000.0) - (((x + (y * gsz.x)) * 0.15) % 1.0);
             if (ph < 1.25) {
               g.chcolor(255, 255, 255, (int) (255 * ((Math.cos(ph * Math.PI * 2) * -0.5) + 0.5)));
               g.image(glowmask(btn), p.sub(4, 4));
               g.chcolor();
             } else {
               g.chcolor(255, 255, 255, 128);
               g.image(glowmask(btn), p.sub(4, 4));
               g.chcolor();
             }
           }
         }
         if (btn == pressed) {
           g.chcolor(new Color(0, 0, 0, 128));
           g.frect(p.add(1, 1), btex.sz());
           g.chcolor();
         }
       }
     }
   }
   super.draw(g);
   if (dragging != null) {
     final Tex dt = dragging.img.tex();
     ui.drawafter(
         new UI.AfterDraw() {
           public void draw(GOut g) {
             g.image(dt, ui.mc.add(dt.sz().div(2).inv()));
           }
         });
   }
 }
예제 #2
0
 public void reqarea(Coord ul, Coord br) {
   ul = ul.div(cutsz);
   br = br.div(cutsz);
   Coord rc = new Coord();
   for (rc.y = ul.y; rc.y <= br.y; rc.y++) {
     for (rc.x = ul.x; rc.x <= br.x; rc.x++) {
       try {
         getcut(new Coord(rc));
       } catch (Loading e) {
       }
     }
   }
 }
예제 #3
0
 private void makeflavor() {
   @SuppressWarnings("unchecked")
   Collection<Gob>[] fo = (Collection<Gob>[]) new Collection[cutn.x * cutn.y];
   for (int i = 0; i < fo.length; i++) fo[i] = new LinkedList<Gob>();
   Coord c = new Coord(0, 0);
   Coord tc = gc.mul(cmaps);
   int i = 0;
   Random rnd = new Random(id);
   for (c.y = 0; c.y < cmaps.x; c.y++) {
     for (c.x = 0; c.x < cmaps.y; c.x++, i++) {
       Tileset set = tileset(tiles[i]);
       if (set.flavobjs.size() > 0) {
         if (rnd.nextInt(set.flavprob) == 0) {
           Resource r = set.flavobjs.pick(rnd);
           double a = rnd.nextDouble() * 2 * Math.PI;
           Gob g = new Flavobj(c.add(tc).mul(tilesz).add(tilesz.div(2)), a);
           g.setattr(new ResDrawable(g, r));
           Coord cc = c.div(cutsz);
           fo[cc.x + (cc.y * cutn.x)].add(g);
         }
       }
     }
   }
   this.fo = fo;
 }
예제 #4
0
 public Gob findicongob(Coord c) {
   OCache oc = ui.sess.glob.oc;
   synchronized (oc) {
     for (Gob gob : oc) {
       try {
         GobIcon icon = gob.getattr(GobIcon.class);
         if (icon != null) {
           Coord gc = p2c(gob.rc);
           Coord sz = icon.tex().sz();
           if (c.isect(gc.sub(sz.div(2)), sz)) return (gob);
         }
       } catch (Loading l) {
       }
     }
   }
   return (null);
 }
예제 #5
0
 private Pagina bhit(Coord c) {
   Coord bc = c.div(bgsz);
   if ((bc.x >= 0) && (bc.y >= 0) && (bc.x < gsz.x) && (bc.y < gsz.y)) return (layout[bc.x][bc.y]);
   else return (null);
 }
예제 #6
0
 public void draw(GOut g) {
   if (cc == null) return;
   map:
   {
     final Grid plg;
     try {
       plg = ui.sess.glob.map.getgrid(cc.div(cmaps));
     } catch (Loading l) {
       break map;
     }
     final int seq = plg.seq;
     if ((cur == null) || (plg != cur.grid) || (seq != cur.seq)) {
       Defer.Future<MapTile> f;
       synchronized (cache) {
         f = cache.get(new Pair<Grid, Integer>(plg, seq));
         if (f == null) {
           f =
               Defer.later(
                   new Defer.Callable<MapTile>() {
                     public MapTile call() {
                       Coord ul = plg.ul.sub(cmaps).add(1, 1);
                       return (new MapTile(
                           new TexI(drawmap(ul, cmaps.mul(3).sub(2, 2))), ul, plg, seq));
                     }
                   });
           cache.put(new Pair<Grid, Integer>(plg, seq), f);
         }
       }
       if (f.done()) {
         cur = f.get();
         if (save != null) save.update(ui.sess.glob.map, cur.grid.gc);
       }
     }
   }
   if (cur != null) {
     g.image(MiniMap.bg, Coord.z);
     g.image(cur.img, cur.ul.sub(cc).add(sz.div(2)));
     try {
       synchronized (ui.sess.glob.party.memb) {
         for (Party.Member m : ui.sess.glob.party.memb.values()) {
           Coord ptc;
           try {
             ptc = m.getc();
           } catch (MCache.LoadingMap e) {
             ptc = null;
           }
           if (ptc == null) continue;
           ptc = p2c(ptc);
           g.chcolor(m.col.getRed(), m.col.getGreen(), m.col.getBlue(), 128);
           g.image(
               MiniMap.plx.layer(Resource.imgc).tex(),
               ptc.add(MiniMap.plx.layer(Resource.negc).cc.inv()));
           g.chcolor();
         }
       }
     } catch (Loading l) {
     }
   } else {
     g.image(MiniMap.nomap, Coord.z);
   }
   drawicons(g);
 }
예제 #7
0
 public Coord p2c(Coord pc) {
   return (pc.div(tilesz).sub(cc).add(sz.div(2)));
 }
예제 #8
0
 public Rendered getolcut(int ol, Coord cc) {
   return (getgrid(cc.div(cutn)).getolcut(ol, cc.mod(cutn)));
 }
예제 #9
0
 public Collection<Gob> getfo(Coord cc) {
   return (getgrid(cc.div(cutn)).getfo(cc.mod(cutn)));
 }
예제 #10
0
 public MapMesh getcut(Coord cc) {
   return (getgrid(cc.div(cutn)).getcut(cc.mod(cutn)));
 }
예제 #11
0
 public Grid getgridt(Coord tc) {
   return (getgrid(tc.div(cmaps)));
 }
예제 #12
0
public class MCache {
  public static final Coord tilesz = new Coord(11, 11);
  public static final Coord cmaps = new Coord(100, 100);
  public static final Coord cutsz = new Coord(25, 25);
  public static final Coord cutn = cmaps.div(cutsz);
  private final Resource.Spec[] nsets = new Resource.Spec[256];

  @SuppressWarnings("unchecked")
  private final Reference<Resource>[] sets = new Reference[256];

  @SuppressWarnings("unchecked")
  private final Reference<Tileset>[] csets = new Reference[256];

  @SuppressWarnings("unchecked")
  private final Reference<Tiler>[] tiles = new Reference[256];

  Map<Coord, Request> req = new HashMap<Coord, Request>();
  Map<Coord, Grid> grids = new HashMap<Coord, Grid>();
  Session sess;
  Set<Overlay> ols = new HashSet<Overlay>();
  int olseq = 0;
  Random gen = new Random();
  Map<Integer, Defrag> fragbufs = new TreeMap<Integer, Defrag>();
  long lastctick = System.currentTimeMillis();

  public static class LoadingMap extends Loading {
    public LoadingMap() {}

    public LoadingMap(Throwable cause) {
      super(cause);
    }
  }

  private static class Request {
    private long lastreq = 0;
    private int reqs = 0;
  }

  public class Overlay {
    private Coord c1, c2;
    private int mask;

    public Overlay(Coord c1, Coord c2, int mask) {
      this.c1 = c1;
      this.c2 = c2;
      this.mask = mask;
      ols.add(this);
      olseq++;
    }

    public void destroy() {
      ols.remove(this);
    }

    public void update(Coord c1, Coord c2) {
      if (!c1.equals(this.c1) || !c2.equals(this.c2)) {
        olseq++;
        this.c1 = c1;
        this.c2 = c2;
      }
    }
  }

  public class Grid {
    public final int tiles[] = new int[cmaps.x * cmaps.y];
    public final int z[] = new int[cmaps.x * cmaps.y];
    public final int ol[] = new int[cmaps.x * cmaps.y];
    private final Cut cuts[];
    int olseq = -1;
    private Collection<Gob>[] fo = null;
    public final Coord gc, ul;
    public long id;
    String mnm;

    private class Cut {
      MapMesh mesh;
      Defer.Future<MapMesh> dmesh;
      Rendered[] ols;
      int deftag;
    }

    private class Flavobj extends Gob {
      private Flavobj(Coord c, double a) {
        super(sess.glob, c);
        this.a = a;
      }

      public Random mkrandoom() {
        Random r = new Random(Grid.this.id);
        r.setSeed(r.nextInt() ^ rc.x);
        r.setSeed(r.nextInt() ^ rc.y);
        return (r);
      }
    }

    public Grid(Coord gc) {
      this.gc = gc;
      this.ul = gc.mul(cmaps);
      cuts = new Cut[cutn.x * cutn.y];
      for (int i = 0; i < cuts.length; i++) cuts[i] = new Cut();
    }

    public int gettile(Coord tc) {
      return (tiles[tc.x + (tc.y * cmaps.x)]);
    }

    public int getz(Coord tc) {
      return (z[tc.x + (tc.y * cmaps.x)]);
    }

    public int getol(Coord tc) {
      return (ol[tc.x + (tc.y * cmaps.x)]);
    }

    private void makeflavor() {
      @SuppressWarnings("unchecked")
      Collection<Gob>[] fo = (Collection<Gob>[]) new Collection[cutn.x * cutn.y];
      for (int i = 0; i < fo.length; i++) fo[i] = new LinkedList<Gob>();
      Coord c = new Coord(0, 0);
      Coord tc = gc.mul(cmaps);
      int i = 0;
      Random rnd = new Random(id);
      for (c.y = 0; c.y < cmaps.x; c.y++) {
        for (c.x = 0; c.x < cmaps.y; c.x++, i++) {
          Tileset set = tileset(tiles[i]);
          if (set.flavobjs.size() > 0) {
            if (rnd.nextInt(set.flavprob) == 0) {
              Resource r = set.flavobjs.pick(rnd);
              double a = rnd.nextDouble() * 2 * Math.PI;
              Gob g = new Flavobj(c.add(tc).mul(tilesz).add(tilesz.div(2)), a);
              g.setattr(new ResDrawable(g, r));
              Coord cc = c.div(cutsz);
              fo[cc.x + (cc.y * cutn.x)].add(g);
            }
          }
        }
      }
      this.fo = fo;
    }

    public Collection<Gob> getfo(Coord cc) {
      if (fo == null) makeflavor();
      return (fo[cc.x + (cc.y * cutn.x)]);
    }

    private Cut geticut(Coord cc) {
      return (cuts[cc.x + (cc.y * cutn.x)]);
    }

    public MapMesh getcut(Coord cc) {
      Cut cut = geticut(cc);
      if (cut.dmesh != null) {
        if (cut.dmesh.done() || (cut.mesh == null)) {
          cut.mesh = cut.dmesh.get();
          cut.dmesh = null;
        }
      }
      return (cut.mesh);
    }

    public Rendered getolcut(int ol, Coord cc) {
      int nseq = MCache.this.olseq;
      if (this.olseq != nseq) {
        for (int i = 0; i < cutn.x * cutn.y; i++) cuts[i].ols = null;
        this.olseq = nseq;
      }
      Cut cut = geticut(cc);
      if (cut.ols == null) cut.ols = getcut(cc).makeols();
      return (cut.ols[ol]);
    }

    private void buildcut(final Coord cc) {
      final Cut cut = geticut(cc);
      final int deftag = ++cut.deftag;
      cut.dmesh =
          Defer.later(
              new Defer.Callable<MapMesh>() {
                public MapMesh call() {
                  Random rnd = new Random(id);
                  rnd.setSeed(rnd.nextInt() ^ cc.x);
                  rnd.setSeed(rnd.nextInt() ^ cc.y);
                  return (MapMesh.build(MCache.this, rnd, ul.add(cc.mul(cutsz)), cutsz));
                }
              });
    }

    public void ivneigh(Coord nc) {
      Coord cc = new Coord();
      for (cc.y = 0; cc.y < cutn.y; cc.y++) {
        for (cc.x = 0; cc.x < cutn.x; cc.x++) {
          if ((((nc.x < 0) && (cc.x == 0)) || ((nc.x > 0) && (cc.x == cutn.x - 1)) || (nc.x == 0))
              && (((nc.y < 0) && (cc.y == 0))
                  || ((nc.y > 0) && (cc.y == cutn.y - 1))
                  || (nc.y == 0))) {
            buildcut(new Coord(cc));
          }
        }
      }
    }

    public void tick(int dt) {
      if (fo != null) {
        for (Collection<Gob> fol : fo) {
          for (Gob fo : fol) fo.ctick(dt);
        }
      }
    }

    private void invalidate() {
      for (int y = 0; y < cutn.y; y++) {
        for (int x = 0; x < cutn.x; x++) buildcut(new Coord(x, y));
      }
      fo = null;
      for (Coord ic :
          new Coord[] {
            new Coord(-1, -1),
            new Coord(0, -1),
            new Coord(1, -1),
            new Coord(-1, 0),
            new Coord(1, 0),
            new Coord(-1, 1),
            new Coord(0, 1),
            new Coord(1, 1)
          }) {
        Grid ng = grids.get(gc.add(ic));
        if (ng != null) ng.ivneigh(ic.inv());
      }
      loaded = true;
    }

    public void fill(Message msg) {
      String mmname = msg.string().intern();
      if (mmname.equals("")) mnm = null;
      else mnm = mmname;
      int[] pfl = new int[256];
      while (true) {
        int pidx = msg.uint8();
        if (pidx == 255) break;
        pfl[pidx] = msg.uint8();
      }
      Message blob = msg.inflate();
      id = blob.int64();
      for (int i = 0; i < tiles.length; i++) tiles[i] = blob.uint8();
      for (int i = 0; i < z.length; i++) z[i] = blob.int16();
      for (int i = 0; i < ol.length; i++) ol[i] = 0;
      while (true) {
        int pidx = blob.uint8();
        if (pidx == 255) break;
        int fl = pfl[pidx];
        int type = blob.uint8();
        Coord c1 = new Coord(blob.uint8(), blob.uint8());
        Coord c2 = new Coord(blob.uint8(), blob.uint8());
        int ol;
        if (type == 0) {
          if ((fl & 1) == 1) ol = 2;
          else ol = 1;
        } else if (type == 1) {
          if ((fl & 1) == 1) ol = 8;
          else ol = 4;
        } else {
          throw (new RuntimeException("Unknown plot type " + type));
        }
        for (int y = c1.y; y <= c2.y; y++) {
          for (int x = c1.x; x <= c2.x; x++) {
            this.ol[x + (y * cmaps.x)] |= ol;
          }
        }
      }
      invalidate();
    }

    /* ===== BD Code Start ===== */
    private BufferedImage gridImage;
    private boolean loaded = false;
    private boolean rendered = false;

    private int getz(int x, int y) {
      return (z[x + (y * cmaps.x)]);
    }

    public BufferedImage getGridImage() {
      if (rendered) return gridImage;

      if (!loaded) throw new Loading();

      gridImage = TexI.mkbuf(cmaps);

      BufferedImage[] texes = new BufferedImage[256];

      Coord c = new Coord();
      for (c.y = 0; c.y < cmaps.y; c.y++) {
        for (c.x = 0; c.x < cmaps.x; c.x++) {
          int t = gettile(c);
          BufferedImage tex = tileimg(t, texes);
          if (tex != null)
            gridImage.setRGB(
                c.x,
                c.y,
                tex.getRGB(
                    Utils.floormod(c.x, tex.getWidth()), Utils.floormod(c.y, tex.getHeight())));
        }
      }
      for (c.y = 1; c.y < cmaps.y - 1; c.y++) {
        for (c.x = 1; c.x < cmaps.x - 1; c.x++) {
          int t = gettile(c);
          if ((gettile(c.add(-1, 0)) > t)
              || (gettile(c.add(1, 0)) > t)
              || (gettile(c.add(0, -1)) > t)
              || (gettile(c.add(0, 1)) > t)) gridImage.setRGB(c.x, c.y, Color.BLACK.getRGB());
        }
      }
      rendered = true;
      return gridImage;
    }
    /* ===== BD Code End ===== */
  }

  public MCache(Session sess) {
    this.sess = sess;
  }

  public void ctick() {
    long now = System.currentTimeMillis();
    int dt = (int) (now - lastctick);
    synchronized (grids) {
      for (Grid g : grids.values()) {
        g.tick(dt);
      }
    }
    lastctick = now;
  }

  public void invalidate(Coord cc) {
    synchronized (req) {
      if (req.get(cc) == null) req.put(cc, new Request());
    }
  }

  public void invalblob(Message msg) {
    int type = msg.uint8();
    if (type == 0) {
      invalidate(msg.coord());
    } else if (type == 1) {
      Coord ul = msg.coord();
      Coord lr = msg.coord();
      trim(ul, lr);
    } else if (type == 2) {
      trimall();
    }
  }

  private Grid cached = null;

  public Grid getgrid(Coord gc) {
    synchronized (grids) {
      if ((cached == null) || !cached.gc.equals(cached)) {
        cached = grids.get(gc);
        if (cached == null) {
          request(gc);
          throw (new LoadingMap());
        }
      }
      return (cached);
    }
  }

  public Grid getgridt(Coord tc) {
    return (getgrid(tc.div(cmaps)));
  }

  public int gettile(Coord tc) {
    Grid g = getgridt(tc);
    return (g.gettile(tc.sub(g.ul)));
  }

  public int getz(Coord tc) {
    Grid g = getgridt(tc);
    return (g.getz(tc.sub(g.ul)));
  }

  public float getcz(float px, float py) {
    float tw = tilesz.x, th = tilesz.y;
    Coord ul = new Coord(Utils.floordiv(px, tw), Utils.floordiv(py, th));
    float sx = Utils.floormod(px, tw) / tw;
    float sy = Utils.floormod(py, th) / th;
    return (((1.0f - sy) * (((1.0f - sx) * getz(ul)) + (sx * getz(ul.add(1, 0)))))
        + (sy * (((1.0f - sx) * getz(ul.add(0, 1))) + (sx * getz(ul.add(1, 1))))));
  }

  public float getcz(Coord pc) {
    return (getcz(pc.x, pc.y));
  }

  public int getol(Coord tc) {
    Grid g = getgridt(tc);
    int ol = g.getol(tc.sub(g.ul));
    for (Overlay lol : ols) {
      if (tc.isect(lol.c1, lol.c2.add(lol.c1.inv()).add(new Coord(1, 1)))) ol |= lol.mask;
    }
    return (ol);
  }

  public MapMesh getcut(Coord cc) {
    return (getgrid(cc.div(cutn)).getcut(cc.mod(cutn)));
  }

  public Collection<Gob> getfo(Coord cc) {
    return (getgrid(cc.div(cutn)).getfo(cc.mod(cutn)));
  }

  public Rendered getolcut(int ol, Coord cc) {
    return (getgrid(cc.div(cutn)).getolcut(ol, cc.mod(cutn)));
  }

  public void mapdata2(Message msg) {
    Coord c = msg.coord();
    synchronized (grids) {
      synchronized (req) {
        if (req.containsKey(c)) {
          Grid g = grids.get(c);
          if (g == null) grids.put(c, g = new Grid(c));
          g.fill(msg);
          req.remove(c);
          olseq++;
        }
      }
    }
  }

  public void mapdata(Message msg) {
    long now = System.currentTimeMillis();
    int pktid = msg.int32();
    int off = msg.uint16();
    int len = msg.uint16();
    Defrag fragbuf;
    synchronized (fragbufs) {
      if ((fragbuf = fragbufs.get(pktid)) == null) {
        fragbuf = new Defrag(len);
        fragbufs.put(pktid, fragbuf);
      }
      fragbuf.add(msg.blob, 8, msg.blob.length - 8, off);
      fragbuf.last = now;
      if (fragbuf.done()) {
        mapdata2(fragbuf.msg());
        fragbufs.remove(pktid);
      }

      /* Clean up old buffers */
      for (Iterator<Map.Entry<Integer, Defrag>> i = fragbufs.entrySet().iterator(); i.hasNext(); ) {
        Map.Entry<Integer, Defrag> e = i.next();
        Defrag old = e.getValue();
        if (now - old.last > 10000) i.remove();
      }
    }
  }

  public Resource tilesetr(int i) {
    synchronized (sets) {
      Resource res = (sets[i] == null) ? null : (sets[i].get());
      if (res == null) {
        if (nsets[i] == null) return (null);
        res = nsets[i].get();
        sets[i] = new SoftReference<Resource>(res);
      }
      return (res);
    }
  }

  public Tileset tileset(int i) {
    synchronized (csets) {
      Tileset cset = (csets[i] == null) ? null : (csets[i].get());
      if (cset == null) {
        Resource res = tilesetr(i);
        if (res == null) return (null);
        try {
          cset = res.layer(Resource.tileset);
        } catch (Loading e) {
          throw (new LoadingMap(e));
        }
        csets[i] = new SoftReference<Tileset>(cset);
      }
      return (cset);
    }
  }

  public Tiler tiler(int i) {
    synchronized (tiles) {
      Tiler tile = (tiles[i] == null) ? null : (tiles[i].get());
      if (tile == null) {
        Tileset set = tileset(i);
        if (set == null) return (null);
        tile = set.tfac().create(i, set);
        tiles[i] = new SoftReference<Tiler>(tile);
      }
      return (tile);
    }
  }

  public void tilemap(Message msg) {
    while (!msg.eom()) {
      int id = msg.uint8();
      String resnm = msg.string();
      int resver = msg.uint16();
      nsets[id] = new Resource.Spec(resnm, resver);
    }
  }

  public void trimall() {
    synchronized (grids) {
      synchronized (req) {
        grids.clear();
        req.clear();
      }
    }
  }

  public void trim(Coord ul, Coord lr) {
    synchronized (grids) {
      synchronized (req) {
        for (Iterator<Map.Entry<Coord, Grid>> i = grids.entrySet().iterator(); i.hasNext(); ) {
          Map.Entry<Coord, Grid> e = i.next();
          Coord gc = e.getKey();
          Grid g = e.getValue();
          if ((gc.x < ul.x) || (gc.y < ul.y) || (gc.x > lr.x) || (gc.y > lr.y)) i.remove();
        }
        for (Iterator<Coord> i = req.keySet().iterator(); i.hasNext(); ) {
          Coord gc = i.next();
          if ((gc.x < ul.x) || (gc.y < ul.y) || (gc.x > lr.x) || (gc.y > lr.y)) i.remove();
        }
      }
    }
  }

  public void request(Coord gc) {
    synchronized (req) {
      if (!req.containsKey(gc)) req.put(gc, new Request());
    }
  }

  public void reqarea(Coord ul, Coord br) {
    ul = ul.div(cutsz);
    br = br.div(cutsz);
    Coord rc = new Coord();
    for (rc.y = ul.y; rc.y <= br.y; rc.y++) {
      for (rc.x = ul.x; rc.x <= br.x; rc.x++) {
        try {
          getcut(new Coord(rc));
        } catch (Loading e) {
        }
      }
    }
  }

  public void sendreqs() {
    long now = System.currentTimeMillis();
    synchronized (req) {
      for (Iterator<Map.Entry<Coord, Request>> i = req.entrySet().iterator(); i.hasNext(); ) {
        Map.Entry<Coord, Request> e = i.next();
        Coord c = e.getKey();
        Request r = e.getValue();
        if (now - r.lastreq > 1000) {
          r.lastreq = now;
          if (++r.reqs >= 5) {
            i.remove();
          } else {
            Message msg = new Message(Session.MSG_MAPREQ);
            msg.addcoord(c);
            sess.sendmsg(msg);
          }
        }
      }
    }
  }

  /* ===== BD Code Start ===== */
  private BufferedImage tileimg(int t, BufferedImage[] texes) {
    BufferedImage img = texes[t];
    if (img == null) {
      Resource r = tilesetr(t);
      if (r == null) return (null);
      Resource.Image ir = r.layer(Resource.imgc);
      if (ir == null) return (null);
      img = ir.img;
      texes[t] = img;
    }
    return (img);
  }
  /* ===== BD Code End ===== */
}