bootstrap
[www.jankratochvil.net.git] / project / Islet / Islet / Islet.java
1 /*
2  * Islet ICP'98 demonstation
3  * Redistribution permitted under the terms of GNU General Public License version 2
4  *  "ftp://prep.ai.mit.edu/pub/gnu/GPL"
5  * Author: Jan Kratochvil <short@ucw.cz> (no flames for this piece of crap, please)
6  */
7
8 import java.applet.*;
9 import java.awt.*;
10 import java.awt.event.*;
11 import java.awt.image.*;
12 import java.util.*;
13
14 public class Islet extends Applet
15 {
16 Applet app=this;
17
18         private interface ImageLoader
19         { public Image load(String name); }
20
21         static private class CmdLoader implements ImageLoader
22         {
23                 Toolkit kit;
24                 public CmdLoader(Toolkit _kit) { kit=_kit; }
25                 public Image load(String name) { return(kit.getImage(name)); }
26         }
27
28         private class AppLoader implements ImageLoader
29         { public Image load(String name) { return(app.getImage(app.getCodeBase(),name)); } }
30
31         private class AppListener extends MouseAdapter implements MouseListener
32         {
33                 public void mouseClicked(MouseEvent e)
34                 { new IsletThread(false,new AppLoader()); }
35         }
36
37         public void paint(Graphics g)
38         {
39                 super.paint(g);
40                 g.setColor(new Color(100,255,100));
41                 g.fill3DRect(0,0,getSize().width-1,getSize().height-1,true);
42                 g.setColor(Color.black);
43                 g.setFont(new Font("Courier",Font.BOLD,getSize().height*8/10));
44                 g.drawString("Open demo window",getSize().height*2/10,getSize().height*8/10);
45         }
46
47         public void update(Graphics g)
48         { paint(g); } //Leave background garbaged
49
50         public void init()
51         { addMouseListener(new AppListener()); }
52
53         public String getAppletInfo()
54         {
55                 return(
56                         "Islet by Jan Kratochvil <short@ucw.cz> in 1998. Created for purposes of ICP'98 competition.\n"+
57                         "Redistribution permitted under GNU General Public License (AKA GPL) version 2 (exactly) found on ftp://prep.ai.mit.edu/pub/gnu/GPL."
58                         );
59         }
60
61         static public void main(String[] args)
62         { new IsletThread(true,new CmdLoader(Toolkit.getDefaultToolkit())); }
63
64 static private class IntBugCheck extends Thread
65 {
66 Thread t;
67
68         public IntBugCheck(Thread _t)
69         {
70                 t=_t;
71                 setDaemon(true);
72                 start();
73         }
74         
75         public void run()
76         {
77                 try { sleep(30); }
78                 catch (InterruptedException e) {}
79                 t.interrupt();
80         }
81 }
82
83 //! Indentation violation:
84 static private class IsletThread extends Thread
85 {
86 boolean doexit;
87 Frame fview,fcontrol;
88 Imager img;
89 View view;
90 ScrollPane viewpane;
91 FieldWater water;
92 boolean prepared=false;
93 Point mousefld=new Point(-1,-1);
94 boolean mousefldok=false;
95 byte tool;
96 ToolBox tools[];
97 ImageLoader imageloader;
98 TimerQ timerq=new TimerQ();
99 static final int deltax[]={0,1,0,-1},deltay[]={-1,0,1,0};
100 boolean running=false;
101 ERandom rnd=new ERandom();
102 int fldcnt[];
103 Vector fld=new Vector(); //synchronized inside View!
104 final long buggywait=200;
105
106         private Vector getfld(int y)
107         { return((Vector)fld.elementAt(y)); }
108         private Field getfld(Point pt)
109         { return((Field)(getfld(pt.y).elementAt(pt.x))); }
110         private Field getfld(int x,int y)
111         { return(getfld(new Point(x,y))); }
112         private void setfld(int y,Vector v)
113         { fld.setElementAt(v,y); }
114         private void setfld(Point pt,Field f)
115         { getfld(pt.y).setElementAt(f,pt.x); }
116         private void setfld(int x,int y,Field f)
117         { setfld(new Point(x,y),f); }
118
119         private class ERandom extends Random
120         {
121                 public int nextUInt()
122                 { return(Math.abs(nextInt())); }
123         }
124
125         private class Timer
126         {
127         public long when;
128         public Field trig;
129
130                 public Timer(long ms,Field _trig)
131                 {
132                         when=System.currentTimeMillis()+ms;
133                         trig=_trig;
134                         timerq.add(this);
135                 }
136         }
137
138         private class TimerQ
139         {
140         Vector q=new Vector();
141
142                 synchronized public void add(Timer tm)
143                 {
144                         int i;
145                         for (i=0;i<q.size();i++)
146                                 if (((Timer)q.elementAt(i)).when>=tm.when) break;
147                         q.insertElementAt(tm,i);
148                         interrupt();
149                 }
150
151                 public void runday()
152                 { new Timer(1000,null); }
153
154                 synchronized public long getMin()
155                 {
156                         while (!q.isEmpty()) {
157                                 Timer t=(Timer)q.firstElement();
158                                 if (t.when>System.currentTimeMillis()) break;
159                                 Field f=t.trig;
160                                 q.removeElementAt(0);
161                                 if (f!=null) {
162                                         view.kickRobotAss(f);
163                                         continue;
164                                         }
165                                 runday();
166                                 if (daytime.val+1<daytime.getMax()) {
167                                         daytime.inc();
168                                         continue;
169                                         }
170                                 daybox.setState(pertp);
171                                 dayboxdog.itemStateChanged(null);
172                                 }
173                         if (q.isEmpty()) return(Long.MAX_VALUE);
174                         return(Math.max(0,((Timer)q.firstElement()).when-System.currentTimeMillis()));
175                 }
176
177                 synchronized public void clear()
178                         { q.removeAllElements(); }
179         }
180
181         private class Rotator extends ImageFilter
182         {// "Insipired" by Sun's RotateFilter
183                 int imgh;
184
185                 public void setDimensions(int width,int height)
186                 {  consumer.setDimensions((imgh=height),width); }
187
188                 public void setProperties(Hashtable p)
189                 {
190                         p=(Hashtable)p.clone();
191                         Object s=p.get("filters");
192                         if (s==null) p.put("filters",toString());
193                         else if (s instanceof String)
194                                 p.put("filters",((String)s)+toString());
195                         consumer.setProperties(p);
196                 }
197
198                 public void setHints(int flg)
199                 { consumer.setHints(flg&(SINGLEFRAME|SINGLEPASS)); } //RANDOMPIXELORDER?
200
201                 public void setPixels(int x1,int y1,int w,int h,ColorModel model,byte pixels[],int off,int scansize)
202                 {
203                         byte out[]=new byte[w*h];
204                         int dst=0;
205                         for (int y=0;y<h;y++) {
206                                 for (int x=0;x<w;x++)
207                                         out[x*h+h-1-y]=pixels[off++];
208                                 off+=scansize-w;
209                                 }
210                         consumer.setPixels(imgh-y1-h,x1,h,w,model,out,0,h);
211                 }
212
213                 public void setPixels(int x1,int y1,int w,int h,ColorModel model,int pixels[],int off,int scansize)
214                 {
215                         int out[]=new int[w*h];
216                         int dst=0;
217                         for (int y=0;y<h;y++) {
218                                 for (int x=0;x<w;x++)
219                                         out[x*h+h-1-y]=pixels[off++];
220                                 off+=scansize-w;
221                                 }
222                         consumer.setPixels(imgh-y1-h,x1,h,w,model,out,0,h);
223                 }
224         }
225
226         private class Imager
227         {
228         final String names[]={"water","land","wall","food","robotx","roboty"};
229         public final byte WATER =0;
230         public final byte LAND  =1;
231         public final byte WALL  =2;
232         public final byte FOOD  =3;
233         public final byte ROBOTX=4;
234         public final byte ROBOTY=5;
235         public final byte MAXR =(byte)names.length;
236         public final byte MAX  =(byte)((int)MAXR+2*3);
237         public final byte sizex=16,sizey=16;
238         public Image a[]=new Image[MAX];
239
240                 public Imager(ImageLoader loader)
241                 {
242                         tool=LAND;
243                         tools=new ToolBox[MAXR];
244                         fldcnt=new int[MAX];
245                         water=new FieldWater(0,0);
246                         for (byte i=0;i<MAXR;i++) {
247                                 a[i]=loader.load(names[i]+".gif");
248                                 (tools[i]=new ToolBox(i)).addMouseListener(tools[i]);
249                                 }
250                         Rotator rotator=new Rotator();
251                         Toolkit kit=Toolkit.getDefaultToolkit();
252                         for (byte i=2;i<=6;i+=2)
253                         for (byte j=0;j<=1;j++)
254                                 a[ROBOTX+i+j]=kit.createImage(new FilteredImageSource(a[ROBOTX+i-2+j].getSource(),rotator));
255                 }
256                 public void draw(Graphics g,byte tp,Point pt,Color col,ImageObserver obs)
257                 {
258                         g.drawImage(a[tp],pt.x,pt.y,sizex,sizey,obs);
259                         if (col!=null) {
260                                 g.setColor(col);
261                                 g.draw3DRect(pt.x,pt.y,sizex-1,sizey-1,true);
262                         }
263                 }
264         }
265
266         private abstract class Field
267         {
268                 public Point pt;
269                 protected byte tp;
270
271                 public Field(Point _pt)
272                 {
273                         pt=new Point(_pt);
274                 }
275                 private void shiftBy(int how)
276                 {
277                         fldcnt[tp]+=how;
278                         switch (tp) {
279                         case img.FOOD:   foodcnt.setCount(fldcnt[tp]); break;
280                         case img.ROBOTX: sidex  .setCount(fldcnt[tp]); break;
281                         case img.ROBOTY: sidey  .setCount(fldcnt[tp]); break;
282                         }
283                 }
284                 public void setup(byte _tp)
285                 {
286                         tp=_tp;
287                         shiftBy(+1);
288                         if (running) addTimer();
289                 }
290
291                 public Point cellPt(Point _pt)
292                 { return(new Point(_pt.x*img.sizex,_pt.y*img.sizey)); }
293                 public Point cellPt(int x,int y)
294                 { return(cellPt(new Point(x,y))); }
295                 public Point cellPt()
296                 { return(cellPt(pt)); }
297                 public Rectangle cellRect()
298                 {       Point npt=cellPt();
299                         return(new Rectangle(npt.x,npt.y,img.sizex,img.sizey));
300                 }
301
302                 public Point whichCell(Point _pt)
303                 {
304                         Point p=new Point(_pt);
305                         p.x/=img.sizex;
306                         p.y/=img.sizey;
307                         if (!view.validateFld(p)) return(new Point(-1,-1));
308                         return(p);
309                 }
310
311                 public void paint()
312                 {
313                         Rectangle r=cellRect();
314                         view.repaint(r.x,r.y,r.width,r.height);
315                 }
316
317                 public void moveYourAss() {}
318                 public void addTimer() {}
319                 public void dispose()
320                 { shiftBy(-1); pt=null; }
321                 public byte getValue() { return(tp); }
322                 public byte getImgValue() { return(getValue()); }
323                 public boolean isRobot() { return(tp==img.ROBOTX || tp==img.ROBOTY); }
324                 public Field create(Point _pt,byte _tp)
325                 {
326                         switch (_tp) {
327                         case img.WATER:  return(new FieldWater (_pt));
328                         case img.LAND:   return(new FieldLand  (_pt));
329                         case img.WALL:   return(new FieldWall  (_pt));
330                         case img.FOOD:   return(new FieldFood  (_pt));
331                         case img.ROBOTX: return(new FieldRobotX(_pt));
332                         case img.ROBOTY: return(new FieldRobotY(_pt));
333                         default: return(null);
334                         }
335                 }
336                 public Field create(int x,int y,byte _tp)
337                 { return(create(new Point(x,y),_tp)); }
338         }
339
340         private class FieldWater extends Field
341         { public FieldWater (Point _pt) { super(_pt); setup(img.WATER);  } public FieldWater (int x,int y) { this(new Point(x,y)); } }
342         private class FieldLand extends Field
343         { public FieldLand  (Point _pt) { super(_pt); setup(img.LAND);   } public FieldLand  (int x,int y) { this(new Point(x,y)); } }
344         private class FieldWall extends Field
345         { public FieldWall  (Point _pt) { super(_pt); setup(img.WALL);   } public FieldWall  (int x,int y) { this(new Point(x,y)); } }
346         private class FieldFood extends Field
347         { public FieldFood  (Point _pt) { super(_pt); setup(img.FOOD);   } public FieldFood  (int x,int y) { this(new Point(x,y)); } }
348
349         private class FieldRobot extends Field
350         {
351         byte orient;
352         Side side;
353         float weight;
354
355                 private void reorient(boolean full)
356                 {
357                         byte oo=orient;
358                         orient=(byte)(rnd.nextUInt()%(full?4:3));
359                         if (full) return;
360                         if (orient==oo) orient=3;
361                         this.paint();
362                 }
363                 private void reorient() { reorient(false); }
364                 public FieldRobot(Point _pt,boolean wh)
365                 {
366                         super(_pt);
367                         weight=1;
368                         reorient(true);
369                         side=(wh?sidey:sidex);
370                 }
371
372                 private void spawn(FieldRobot r)
373                 {
374                         Field f;
375                         if (r.weight<2)  f=new FieldLand(pt);
376                         else {
377                                 if (r.side.wh) f=new FieldRobotY(pt);
378                                 else           f=new FieldRobotX(pt);
379                                 ((FieldRobot)f).orient=orient;
380                                 r.weight-=1;
381                                 }
382                         setfld(pt,f); f.paint();
383                 }
384
385                 public byte getImgValue() { return((byte)(getValue()+2*orient)); }
386                 public void addTimer()
387                 {
388                         new Timer(10000/Math.max(1,side.speed.val),this);
389                 }
390                 public void moveYourAss()
391                 {
392                         if (pt==null || (pertp && !side.wh)) return;
393                         addTimer();
394                         Point npt=new Point(pt.x+deltax[orient],pt.y+deltay[orient]);
395                         if (!view.validateFld(npt)) { reorient(); return; }
396                         Field f=getfld(npt);
397                         switch (f.getValue()) {
398                         case img.WATER:
399                         case img.WALL:
400                                 reorient(); return;
401                         case img.LAND:
402                                 break;
403                         case img.FOOD:
404                                 weight+=((float)foodwght.val)/100;
405                                 break;
406                         case img.ROBOTX:
407                         case img.ROBOTY:
408                                 FieldRobot r=(FieldRobot)f;
409                                 if (r.side.wh==side.wh) { reorient(); return; }
410                                 if (((pertp?fightnight.val:fightday.val)>(rnd.nextUInt()%100))==side.wh) { //we won
411                                         weight+=r.weight;
412                                         break;
413                                         }
414                                 r.weight+=weight;
415                                 r.orient=(byte)(orient^2);
416                                 r.paint();
417                                 spawn(r);
418                                 dispose();
419                                 return;
420                         }
421                         setfld(npt,this);
422                         f.dispose();
423                         spawn(this);
424                         pt=npt;
425                         this.paint();
426                 }
427         }
428         private class FieldRobotX extends FieldRobot
429         { public FieldRobotX(Point _pt) { super(_pt,false); setup(img.ROBOTX); } public FieldRobotX(int x,int y) { this(new Point(x,y)); } }
430         private class FieldRobotY extends FieldRobot
431         { public FieldRobotY(Point _pt) { super(_pt,true ); setup(img.ROBOTY); } public FieldRobotY(int x,int y) { this(new Point(x,y)); } }
432
433         public IsletThread(boolean _doexit,ImageLoader _imageloader)
434         {
435                 doexit=_doexit;
436                 imageloader=_imageloader;
437                 start();
438         }
439
440         private class View extends Panel implements MouseListener,MouseMotionListener,AdjustmentListener
441         {
442                 synchronized public void paint(Graphics g)
443                 {
444                         if (!prepared) return;
445                         Rectangle r=g.getClipBounds();
446                         Point pt;
447                         view.validateFld(pt=new Point(r.x/img.sizex,r.y/img.sizey));
448                         int x=pt.x,y=pt.y;
449                         view.validateFld(pt=new Point((r.x+r.width -1)/img.sizex,(r.y+r.height-1)/img.sizey));
450                         int xm=pt.x,ym=pt.y;
451                         for (;y<=ym;y++) {
452                                 Vector v=getfld(y);
453                                 for (int xw=x;xw<=xm;xw++) {
454                                         Field f=(Field)v.elementAt(xw);
455                                         img.draw(g,f.getImgValue(),f.cellPt(),(xw==mousefld.x && y==mousefld.y?Color.black:null),this);
456                                         }
457                                 }
458                 }
459                 public void update(Graphics g)
460                 { paint(g); } //Leave background garbaged
461
462                 synchronized public void kickRobotAss(Field f)
463                 { f.moveYourAss(); }
464
465                 public boolean validateFld(Point pt)
466                 {
467                         boolean v=true;
468                         if (pt.x>=sizex.val) { pt.x=sizex.val-1; v=false; }
469                         if (pt.y>=sizey.val) { pt.y=sizey.val-1; v=false; }
470                         if (pt.x<0) { pt.x=0; v=false; }
471                         if (pt.y<0) { pt.y=0; v=false; }
472                         return(v);
473                 }
474
475                 synchronized public Point getAnyFld(byte tp)
476                 {
477                         if (fldcnt[tp]<=0) return(null);
478                         int skip=rnd.nextUInt()%fldcnt[tp],x=0,y=0;
479                         while (skip>=0 && y<sizey.val) {
480                                 Vector v=getfld(y);
481                                 while (x<sizex.val) {
482                                         Field f=(Field)v.elementAt(x);
483                                         if (f.getValue()==tp)
484                                                 if (--skip<=0) break;
485                                         x++;
486                                         }
487                                 if (x>=sizex.val) { x=0; y++; }
488                                 }
489                         if (skip>0) return(null); //Shouldn't happen!
490                         return(new Point(x,y));
491                 }
492
493                 synchronized public void mousePressed (MouseEvent e)
494                 {
495                         mouseMoved(e);
496                         if (!mousefldok) return;
497                         Field f=getfld(mousefld),fnew;
498                         if (f.getValue()==tool) return;
499                         setfld(mousefld,(fnew=water.create(mousefld,tool)));
500                         f.dispose();
501                         fnew.paint();
502                 }
503
504                 synchronized public void paintAt(Point pt)
505                 {
506                         if (mousefldok)
507                                 getfld(mousefld).paint();
508                 }
509
510                 synchronized public void fldupdate(Point pt)
511                 {
512                         if (pt.equals(mousefld)) return;
513                         paintAt(mousefld);
514                         mousefld=pt;
515                         mousefldok=view.validateFld(new Point(mousefld));
516                         paintAt(mousefld);
517                 }
518
519                 public void mouseClicked (MouseEvent e) {}
520                 public void mouseEntered (MouseEvent e) {}
521                 public void mouseReleased(MouseEvent e) {}
522                 public void mouseExited  (MouseEvent e)
523                 { fldupdate(new Point(-1,-1)); }
524                 public void mouseDragged (MouseEvent e)
525                 { mousePressed(e); }
526                 public void mouseMoved   (MouseEvent e)
527                 { fldupdate(water.whichCell(e.getPoint())); }
528
529                 public Dimension getPreferredSize()
530                 { Point pt=water.cellPt(sizex.val,sizey.val);
531                         return(new Dimension(pt.x,pt.y));
532                         }
533                 public Dimension getMinimumSize()
534                 { return(getPreferredSize()); }
535
536                 synchronized public void adjustmentValueChanged(AdjustmentEvent e)
537                 {
538                 int x,y,xval,xnewval,yval,ynewval;
539
540                         if (sizex==null || sizey==null) return;
541                         xval=sizex.val; xnewval=sizex.newval;
542                         yval=sizey.val; ynewval=sizey.newval;
543                         if (xval>xnewval) sizex.val=xnewval;
544                         if (yval>ynewval) sizey.val=ynewval;
545                         if (xval>xnewval)
546                                 for (y=0;y<yval;y++) {
547                                         for (x=xnewval;x<xval;x++)
548                                                 getfld(x,y).dispose();
549                                         getfld(y).setSize(xnewval);
550                                         }
551                         else if (xval<xnewval)
552                                 for (y=0;y<yval;y++) {
553                                         getfld(y).setSize(xnewval);
554                                         for (x=xval;x<xnewval;x++)
555                                                 setfld(x,y,new FieldWater(x,y));
556                                         }
557                         if (yval>ynewval) {
558                                 for (y=ynewval;y<yval;y++)
559                                         for (x=0;x<xnewval;x++)
560                                                 getfld(x,y).dispose();
561                                 fld.setSize(ynewval);
562                                 }
563                         else if (yval<ynewval) {
564                                 fld.setSize(ynewval);
565                                 for (y=yval;y<ynewval;y++) {
566                                         setfld(y,new Vector(xnewval));
567                                         getfld(y).setSize(xnewval);
568                                         for (x=0;x<xnewval;x++)
569                                                 setfld(x,y,new FieldWater(x,y));
570                                         }
571                                 }
572                         sizex.val=xnewval;
573                         sizey.val=ynewval;
574                         Point pt2=water.cellPt(xnewval,ynewval);
575                         if (xval<xnewval) {
576                                 Point pt1=water.cellPt(xval,0);
577                                 view.repaint(pt1.x,pt1.y,pt2.x-pt1.x,pt2.y-pt1.y);
578                                 }
579                         if (yval<ynewval) {
580                                 Point pt1=water.cellPt(0,yval);
581                                 view.repaint(pt1.x,pt1.y,pt2.x-pt1.x,pt2.y-pt1.y);
582                                 }
583                         //viewpane.setSize(pt2.x,pt2.y);
584                         fview.pack();
585                 }
586
587                 synchronized public void addTimers(byte tp)
588                 {
589                         for (int y=0;y<sizey.val;y++) {
590                                 Vector v=getfld(y);
591                                 for (int x=0;x<sizex.val;x++) {
592                                         Field f=(Field)v.elementAt(x);
593                                         if (tp==img.MAX || tp==f.getValue())
594                                                 f.addTimer();
595                                         }
596                                 }
597                 }
598
599                 public void addAllTimers()
600                 { addTimers(img.MAX); }
601
602                 synchronized boolean putFieldToField(byte tpd,byte tps)
603                 {
604                         Point pt;
605                         if ((pt=view.getAnyFld(tps))==null) return(true);
606                         Field f=getfld(pt),newf;
607                         setfld(pt,(newf=water.create(pt,tpd)));
608                         f.dispose(); newf.paint();
609                         return(false);
610                 }
611         }
612
613         private class ToolBox extends Panel implements MouseListener
614         {
615         byte tp;
616
617                 public ToolBox(byte _tp)
618                 {
619                         tp=_tp;
620                 }
621                 public void paint(Graphics g)
622                 { img.draw(g,tp,new Point(0,0),(tp==tool?Color.black:null),this); }
623                 public void update(Graphics g)
624                 { paint(g); }
625                 public void mouseClicked (MouseEvent e) {}
626                 public void mouseEntered (MouseEvent e) {}
627                 public void mouseReleased(MouseEvent e) {}
628                 public void mouseExited  (MouseEvent e) {}
629                 public void mousePressed (MouseEvent e)
630                 {
631                         if (tool==tp) return;
632                         tools[tool].repaint();
633                         tool=tp;
634                         repaint();
635                 }
636                 public Dimension getPreferredSize()
637                 { return(new Dimension(img.sizex,img.sizey)); }
638                 public Dimension getMinimumSize()
639                 { return(getPreferredSize()); }
640         }
641
642         private void shutdown()
643         {
644                 fview.dispose(); fcontrol.dispose();
645                 if (doexit) System.exit(0);
646                 stop();
647         }
648
649         private class WindowClose implements WindowListener
650         {
651                 public void windowOpened     (WindowEvent e) {}
652                 public void windowClosed     (WindowEvent e) {}
653                 public void windowIconified  (WindowEvent e) {}
654                 public void windowDeiconified(WindowEvent e) {}
655                 public void windowActivated  (WindowEvent e) {}
656                 public void windowDeactivated(WindowEvent e) {}
657                 public void windowClosing    (WindowEvent e)
658                 { shutdown(); }
659         }
660
661         private class ButtonQuit implements ActionListener
662         {
663                 public void actionPerformed(ActionEvent e)
664                 { shutdown(); }
665         }
666
667         private class ButtonStartStop implements ActionListener
668         {
669         Button b;
670
671                 public ButtonStartStop(Button _b)
672                 { b=_b; }
673
674                 public void actionPerformed(ActionEvent e)
675                 {
676                         running=!running;
677                         if (!running) {
678                                 timerq.clear();
679                                 b.setLabel("Start");
680                                 return;
681                                 }
682                         b.setLabel("Stop");
683                         timerq.runday();
684                         view.addAllTimers();
685                 }
686         }
687
688         private class EScrollbar extends Scrollbar
689         {
690                 public EScrollbar(int i1,int i2,int i3,int i4,int i5)
691                 { super(i1,i2,i3,i4,i5); }
692                 public Dimension getPreferredSize()
693                 { return(new Dimension(100,super.getPreferredSize().height)); }
694         }
695
696         private class ScrollBarVal implements AdjustmentListener
697         {
698         public int val,newval;
699         public Panel panel;
700
701         Scrollbar bar;
702         Label prelab,lab;
703         protected int visible=2; //divisor!
704         AdjustmentListener listener;
705         String suffix="";
706
707                 private int getVis(int val)
708                 { return(Math.max(1,val/visible)); }
709
710                 public ScrollBarVal(String lval,int _val,int min,int max,AdjustmentListener _listener)
711                 {
712                         val=0;
713                         listener=_listener;
714                         panel=new Panel();
715                         panel.add(prelab=new Label(lval+":"));
716                         panel.add(bar=new EScrollbar(EScrollbar.HORIZONTAL,0,getVis(max),min,max+getVis(max)));
717                         bar.setSize(300,bar.getSize().height);
718                         panel.add(lab=new Label(Integer.toString(val)));
719                         bar.addAdjustmentListener(this);
720                         setValue(_val);
721                 }
722
723                 synchronized public void adjustmentValueChanged(AdjustmentEvent e)
724                 {
725                         newval=bar.getValue();
726                         lab.setText(Integer.toString(newval)+suffix);
727                         if (newval==val) return;
728                         if (listener!=null)
729                                 listener.adjustmentValueChanged(e);
730                         val=newval;
731                 }
732
733                 public void setValue(int _val)
734                 { bar.setValue(_val); adjustmentValueChanged(null); }
735                 public void dec()
736                 { if (val>0) setValue(val-1); }
737                 public void inc()
738                 { if (val<bar.getMaximum()+visible) setValue(val+1); }
739                 public void setMax(int _val)
740                 { bar.setVisibleAmount(getVis(_val)); bar.setMaximum(_val+bar.getVisibleAmount()); adjustmentValueChanged(null); }
741                 public int getMax()
742                 { return(bar.getMaximum()-bar.getVisibleAmount()); }
743
744                 public void setSuffix(String s)
745                 { suffix=s; adjustmentValueChanged(null); }
746         }
747
748         private abstract class Controller implements AdjustmentListener
749         {
750         protected ScrollBarVal cnt;
751         byte tp;
752         boolean silent=false;
753
754                 public void setup(byte _tp,String s)
755                 {
756                         tp=_tp;
757                         cnt=new ScrollBarVal(s,0,0,200,this);
758                         }
759                 public void setCount(int _cnt)
760                 { if (!silent) cnt.setValue(_cnt); }
761
762                 public void adjustmentValueChanged(AdjustmentEvent e)
763                 { //cnt
764                 Point pt;
765                         if (cnt==null) return;
766                         if (cnt.newval==fldcnt[tp]) return;
767                         silent=true;
768                         while (cnt.newval<fldcnt[tp])
769                                 if (view.putFieldToField(img.LAND,tp)) break;
770                         while (cnt.newval>fldcnt[tp])
771                                 if (view.putFieldToField(tp,img.LAND)) break;
772                         silent=false;
773                         setCount(fldcnt[tp]);
774                 }
775         }
776
777         private class Side extends Controller implements AdjustmentListener
778         {
779         ScrollBarVal speed;
780         boolean wh;
781         public Panel control;
782
783                 public String toString() { return(wh?"Y":"X"); }
784                 public Side(boolean _wh,int _speed)
785                 {
786                         setup((_wh?img.ROBOTY:img.ROBOTX),"Count");
787                         wh=_wh;
788                         control=new Panel();
789                         control.setBackground(Color.gray);
790                         control.setLayout(new GridLayout(0,1));
791                         control.add(new Label(toString()+" control:"));
792                         control.add(cnt.panel);
793                         control.add((speed=new ScrollBarVal("Speed",_speed,1,100,null)).panel);
794                         }
795         }
796
797         private class FoodCnt extends Controller implements AdjustmentListener
798         { public FoodCnt() { setup(img.FOOD,"Food count"); } }
799
800 Side sidex,sidey;
801 ScrollBarVal sizex,sizey,lenx,leny,fightday,fightnight,daytime,foodwght;
802 boolean pertp;
803 ItemListener dayboxdog;
804 Checkbox daybox;
805 FoodCnt foodcnt;
806
807         private class DayLengther implements AdjustmentListener,ItemListener
808         {
809         boolean b;
810
811                 public DayLengther(boolean _b)
812                 { b=_b; }
813                 
814                 public void adjustmentValueChanged(AdjustmentEvent e)
815                 {
816                         if (b==pertp && daytime!=null)
817                                 daytime.setMax((b?leny:lenx).newval-1);
818                 }
819
820                 public void itemStateChanged(ItemEvent e)
821                 {
822                         if (pertp==!daybox.getState()) return;
823                         pertp=!pertp;
824                         daytime.prelab.setText(pertp?"Night time:":"Day time:");
825                         daytime.setMax((pertp?leny:lenx).newval-1);
826                         daytime.setValue(0);
827                         if (!pertp) view.addTimers(img.ROBOTX);
828                 }
829         }
830
831         public void run()
832         {
833                 img=new Imager(imageloader);
834                 Frame fr;
835                 fr=fview=new Frame("Islet Island View");
836                 fr.addWindowListener(new WindowClose());
837                 //viewpane=new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
838                 //viewpane.add(view=new View());
839                 //fr.add(viewpane);
840                 fr.add(view=new View());
841                 view.addMouseListener(view);
842                 view.addMouseMotionListener(view);
843                 fr=fcontrol=new Frame("Islet Control Panel");
844                 fview.setLocation(300,10);
845                 fcontrol.setLocation(10,10);
846                 fcontrol.setSize(280,660);
847                 fr.addWindowListener(new WindowClose());
848                 fr.setLayout(new FlowLayout());
849                 { Panel p=new Panel();
850                         p.setBackground(Color.gray);
851                         p.setLayout(new GridLayout(0,1));
852                         p.add((sizex=new ScrollBarVal("Isle width" ,0,0,100,view)).panel);
853                         p.add((sizey=new ScrollBarVal("Isle height",0,0,100,view)).panel);
854                         fr.add(p);
855                 }
856                 { Panel p=new Panel();
857                         p.setBackground(Color.gray);
858                         p.add(new Label("Tools:"));
859                         for (byte i=0;i<tools.length;i++)
860                                 p.add(tools[i]);
861                         fr.add(p);
862                 }
863                 { Panel p=new Panel();
864                         p.setBackground(Color.gray);
865                         p.setLayout(new GridLayout(0,1));
866                         p.add((lenx=new ScrollBarVal("Day length"  ,20,1,200,new DayLengther(false))).panel);
867                         p.add((leny=new ScrollBarVal("Night length",20,1,200,new DayLengther(true ))).panel);
868                         { Panel q=new Panel();
869                                 q.add(daybox=new Checkbox("Day?",true));
870                                 p.add(q);
871                         }
872                         daybox.addItemListener(dayboxdog=new DayLengther(false));
873                         p.add((daytime=new ScrollBarVal("Day time"  ,0,0,20,null)).panel);
874                         fr.add(p);
875                 }
876                 { Panel p=new Panel();
877                         p.setBackground(Color.gray);
878                         p.setLayout(new GridLayout(0,1));
879                         p.add((fightday=new ScrollBarVal("X<day>Y",20,0,100,null)).panel);
880                         p.add((fightnight=new ScrollBarVal("X<night>Y",80,0,100,null)).panel);
881                         fr.add(p);
882                 }
883                 { Panel p=new Panel();
884                         p.setBackground(Color.gray);
885                         p.setLayout(new GridLayout(0,1));
886                         p.add((foodwght=new ScrollBarVal("Food weight",50,0,200,null)).panel);
887                         foodwght.setSuffix("%");
888                         p.add((foodcnt=new FoodCnt()).cnt.panel);
889                         fr.add(p);
890                 }
891                 fr.add((sidex=new Side(false,15)).control);
892                 fr.add((sidey=new Side(true ,10)).control);
893                 { Panel p=new Panel();
894                         p.setBackground(Color.gray);
895                         { Button b=new Button("Start");
896                                 b.addActionListener(new ButtonStartStop(b));
897                                 p.add(b);
898                         }
899                         { Button b=new Button("Quit");
900                                 b.addActionListener(new ButtonQuit());
901                                 p.add(b);
902                         }
903                         fr.add(p);
904                 }
905                 sizex.setValue(20);
906                 sizey.setValue(20);
907                 sizex.bar.setMinimum(1);
908                 sizey.bar.setMinimum(1);
909                 prepared=true; view.repaint();
910                 fview.show(); fcontrol.show();
911
912                 new IntBugCheck(this);
913                 boolean buggy=true;
914                 try { sleep(100); }
915                 catch (InterruptedException e) { buggy=false; }
916                 System.out.println(toString()+" - check for Netscape Communicator 4.05 Preview Release 1 (AWT 1.1.5) interrupt() bug: "
917                         +(buggy?"FOUND, workarounding it.":"none, OK"));
918
919                 for (;;) {
920                         try {
921                                 long l=timerq.getMin();
922                                 if (l>buggywait && buggy) l=buggywait;
923                                 sleep(l);
924                                 }
925                         catch (InterruptedException e) {}
926                         }
927         }
928 }//IsletThread
929 }//Islet