APPENDIX B

MARBLES WORLD CLIENT CODE

import java.awt.*;

import java.applet.*;

import java.util.*;

import java.io.*;

import java.net.*;

import java.util.Date;

import vrml.external.field.*;

import vrml.external.Node;

import vrml.external.Browser;

import vrml.external.exception.*;

import netscape.javascript.JSObject;

import dtai.net.*;

 

//  ball.e is currently as follows:

//  #

//  0 - no effect

//  1 - non-collidable

//  2 - anti-gravity

//  3 - stop

//  4 - goal stealing

//  5 - add a fence

//  6 - bigger

 

//-------------------------------------------------------------------

//  This is the main applet class

 

public class Marbles extends Applet implements EventOutObserver  {

 

  TextArea output = null;

  //Main Window for Controls

  MainWindow b;

  // Browser we're using

  Browser browser;

  // Root of the scene graph (to which we add our clumps)

  Node board = null;

  Node pointer = null;

  Node designer  = null;

  Node sides  = null;

  Node slant = null;

  Node pitem[] = {null,null,null,null,null,null,null};

  Node slqu[] = {null,null,null,null};

  Node material = null;



  EventInSFColor diffuseColor = null;

  EventInMFNode addPI[] = {null,null,null,null,null,null,null};

  EventInMFNode removePI[] = {null,null,null,null,null,null,null};

  EventInMFNode addslqu[] = {null,null,null,null};

  EventInMFNode removeslqu[] = {null,null,null,null};

  Node gl[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  EventInMFNode addGoal[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  EventInMFNode removeGoal[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  Node sensor[] = {null,null,null,null,null,null,null};

  Node slantSensor[] = {null,null,null,null};

  Node wrapSensor = null;

  Node root[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  EventInMFNode addChildren[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  EventOutSFVec3f translation_changed[] = {null,null,null,null,null,null,null,null,null,null};

  EventOutSFVec3f pointer_changed = null;

  EventInSFVec3f pointer_translation = null;

  EventInMFNode addSides = null;

  EventInMFNode removeSides = null;

  EventInMFNode removeChildren[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  EventInSFVec3f set_translation[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  EventInSFVec3f slant_translation = null;

  EventInSFVec3f set_scale[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  EventInSFRotation slant_rotation = null;

  EventOutSFTime touchTime[] = {null,null,null,null,null,null,null};

  EventOutSFTime slantTouchTime[] = {null,null,null,null};

  EventOutSFTime wrapTouchTime = null;

  EventOutSFVec3f hitb = null;

  EventOutSFVec3f hitt = null;

  Node[] goalshape[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  Node[] pshape[] = {null,null,null,null,null,null,null,null,null,null};

  Node[] qshape[] = {null,null,null,null};

  Node[] shape = null;

  Node[] bumpers = null;

  Node[] pieceshape[] = {null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null};

  int marker=0;

  int newpiecex=0, newpiecey=0;

  int curnode=0;

  int curtype=0;

  double hitpoint[] = {0.0,0.0,0.0,0.0};

  float offsetx=0.0f,offsety=0.0f,oldx=0.0f,oldy=0.0f,oldz=0.0f;

  int mode = 0;

  boolean speedtest=true;  //test the speed of the animator for each client

  int qno = 103;

  boolean designing = false;

  int lastmodesent = 0;

  Player[] player = new Player[4];  // array of players

  int pn; //client player number

  int nump=0;

  int numplay=0;

  int turncolor=1;

  int sim_type=1;

  public final static int PORT=8765;

  PieceList pl = new PieceList(7);

  EffectList el = new EffectList(7);

  Image image[]={null,null,null,null,null,null,null};

  PortToServer pts;

 

  public void init() {

 

    //

    // Initialize connection to Cosmo Player

    //

 

    JSObject win = JSObject.getWindow(this);

    JSObject doc = (JSObject) win.getMember("document");

    JSObject embeds = (JSObject) doc.getMember("embeds");

    browser = (Browser) embeds.getSlot(0);

 

    try {

 

    pts = new PortToServer(this.getCodeBase().getHost(),PORT,this);

    pts.start();

      for(int x=0;x<100;x++) {

         root[x] = browser.getNode("T" + x);

         addChildren[x] = (EventInMFNode) root[x].getEventIn("addChildren");

         removeChildren[x] = (EventInMFNode) root[x].getEventIn("removeChildren");

         set_translation[x] = (EventInSFVec3f) root[x].getEventIn("translation");

         set_scale[x] = (EventInSFVec3f) root[x].getEventIn("scale");

      }

      for(int x=0;x<4;x++) {

         slantSensor[x] = browser.getNode("SS" + x);

         slantTouchTime[x] = (EventOutSFTime) slantSensor[x].getEventOut("touchTime");

         slantTouchTime[x].advise(this, new Integer(10 + x));

         slqu[x] = browser.getNode("SQ" + x);

         addslqu[x] = (EventInMFNode) slqu[x].getEventIn("addChildren");

         removeslqu[x] = (EventInMFNode) slqu[x].getEventIn("removeChildren");

      }

      for(int x=0;x<7;x++) {

         pitem[x] = browser.getNode("PI" + x);

         addPI[x] = (EventInMFNode) pitem[x].getEventIn("addChildren");

         removePI[x] = (EventInMFNode) pitem[x].getEventIn("removeChildren");

      }

      for(int x=0;x<30;x++) {

         gl[x] = browser.getNode("G" + x);

         addGoal[x] = (EventInMFNode) gl[x].getEventIn("addChildren");

         removeGoal[x] = (EventInMFNode) gl[x].getEventIn("removeChildren");

      }

      board = browser.getNode("TSB");

      slant = browser.getNode("BOARD");

      wrapSensor = browser.getNode("WRAP");

      wrapTouchTime = (EventOutSFTime) wrapSensor.getEventOut("touchTime");

      wrapTouchTime.advise(this, new Integer(14));

      pointer = browser.getNode("T100");

      pointer_translation = (EventInSFVec3f) pointer.getEventIn("translation");

      slant_rotation = (EventInSFRotation) slant.getEventIn("rotation");

      slant_translation = (EventInSFVec3f) slant.getEventIn("translation");

      pointer_changed = (EventOutSFVec3f) pointer.getEventOut("translation_changed");

      designer = browser.getNode("TSD");

      sides = browser.getNode("SIDES");

      addSides = (EventInMFNode) sides.getEventIn("addChildren");

      removeSides = (EventInMFNode) sides.getEventIn("removeChildren");

      for(int x=0;x<7;x++) {

         sensor[x] = browser.getNode("TS" + x);

         touchTime[x] = (EventOutSFTime) sensor[x].getEventOut("touchTime");

         touchTime[x].advise(this, new Integer(x+1));

      }

      // Get the material node...

      material = browser.getNode("MAT");

      // Get the diffuseColor EventIn

      diffuseColor = (EventInSFColor) material.getEventIn("set_diffuseColor");

      // Get Hit Point for Board

      hitb = (EventOutSFVec3f) board.getEventOut("translation_changed");

      hitt = (EventOutSFVec3f) designer.getEventOut("hitPoint_changed");

      // Set up the callback

      hitb.advise(this, new Integer(0));

      hitt.advise(this, new Integer(7));

    }

    catch (InvalidVrmlException e) {

      showStatus("PROBLEMS!: " + e);

    }

    catch (InvalidEventInException e) {

      showStatus("PROBLEMS!: " + e);

    }

    catch (InvalidEventOutException e) {

      showStatus("PROBLEMS!: " + e);

    }

    catch (IOException e) {

      showStatus("PROBLEMS!: " + e.toString());

    }

 

    b = new MainWindow("Controls",true,this);

    b.resize(250,480);

    if(sim_type==0) {b.show();}

    b.start();

 

    for(int x=0;x<4;x++) {

        addPlayer(new Player());

    }

    for(int ww=0;ww<4;ww++) {

        addSlQu(ww,0,true);

    }

    for(int xx=1;xx<8;xx++) {

        pl.AddtoPieceList(xx);

        el.AddtoEffectList(xx);

    }

}

 

public void callback(EventOut who, double when, Object which) {

    Integer whichNum = (Integer) which;

 

if (whichNum.intValue()>0 && whichNum.intValue()<10 ) {

       if(!designing && turncolor==pn && sim_type==0){

          float[] val = hitb.getValue();

          offsetx = val[0];

          offsety = val[1];

          UpdatePointer(0,0,0,30,0,0,0,0);

          oldx = 0;

          oldy = 0;

       }

    }

    if (whichNum.intValue()==0) {

          float[] val = hitb.getValue();

          UpdateVRML(4,curnode,oldx,oldy,oldz,val[0],val[1],offsetx,offsety);

          UpdatePointer(1,oldx,oldy,oldz,val[0],val[1],offsetx,offsety);

    }

    else if (whichNum.intValue()>0 && whichNum.intValue()<8) {

       int iv=whichNum.intValue()-1;

       if (mode==1 && !designing && pl.l[iv]>0 && turncolor==pn && sim_type==0) {

           if(pl.l[iv]==1 || pl.l[iv]==6 || pl.l[iv]==7) {

               curnode=b.anim.num;

           } else {

               curnode=50+b.anim.numo;

           }

           curtype=pl.l[iv];

           addNode(curnode,curtype,0,0,0,0,0);

           designing = true;

       } else if (mode==2) {

           b.anim.ars.AddToArsenal(el.l[iv]);

       } else if (mode==3){

           String eventstring = "3" + ((100*pn) + b.anim.ars.TakeFromArsenal(iv));

           eventstring = eventstring + (b.anim.count+b.anim.eql);

           pts.writeToServer(eventstring);

           ReplaceNode(0,iv,LoadString());

           eventstring = "3" + (100*pn);

           eventstring = eventstring + (b.anim.count+b.anim.eqd);

           pts.writeToServer(eventstring);

       }

    }

    else if (whichNum.intValue()>=10 && whichNum.intValue()<=13) {  //if animating, slant added to queue

        if(mode==1 && lastmodesent==0) { //ignore request for mode change if already made a request -- only server updates mode

            pts.writeToServer("92");

            lastmodesent++;

            //Paletize(2);

        }

        else if(mode==2 && lastmodesent==1) {

            pts.writeToServer("93");

            if(designing==true) {

                  removeChildren[curnode].setValue(pieceshape[curnode]);

                  designing=false;

            }

            UpdatePointer(0,0,0,30,0,0,0,0);

            lastmodesent++;

            Bumpers(1);

            b.anim.wrapon = false;

            //Paletize(3);

        }

        else if(mode==3&&turncolor==pn) {

            pts.writeToServer("2" + (whichNum.intValue()-9));

        }

    }

    else if (whichNum.intValue()==14) {

         if(mode==0) {

              pts.writeToServer("6" + pn);  //request goals for next round

              Paletize(1);

              mode=1;

              UpdateColor(0,turncolor);

              //Four Corner Balls

              b.anim.ball[0].x=500; b.anim.ball[0].y=100; b.anim.ball[0].m=b.anim.bm;

              addNode(0,0,20,1,1,0,0);             

              //if(b.anim.rules.roundtype==0) { addNode(0,0,20,1,1,0,0); }

              //else if(b.anim.rules.roundtype==1) { addNode(0,0,20,0,1,0,0); }

              //else if(b.anim.rules.roundtype==2) { addNode(0,0,20,0,0,1,0); }

              b.anim.ball[1].x=100; b.anim.ball[1].y=500; b.anim.ball[1].m=b.anim.bm;

              addNode(1,0,20,1,0,0,0);

              //if(b.anim.rules.roundtype==0) { addNode(1,0,20,1,0,0,0); }

              //else if(b.anim.rules.roundtype==1) { addNode(1,0,20,.6,1,0,0); }

              //else if(b.anim.rules.roundtype==2) { addNode(1,0,20,1,0,0,0); }

              b.anim.ball[2].x=900; b.anim.ball[2].y=500; b.anim.ball[2].m=b.anim.bm;

              addNode(2,0,20,0,0,1,0);

              //if(b.anim.rules.roundtype==0) { addNode(2,0,20,0,0,1,0); }

              //else if(b.anim.rules.roundtype==1) { addNode(2,0,20,0,1,.6,0); }

              //else if(b.anim.rules.roundtype==2) { addNode(2,0,20,1,.4,0,0); }

              b.anim.ball[3].x=500; b.anim.ball[3].y=900; b.anim.ball[3].m=b.anim.bm;

              addNode(3,0,20,0,1,0,0);

              //if(b.anim.rules.roundtype==0) { addNode(3,0,20,0,1,0,0); }

              //else if(b.anim.rules.roundtype==1) { addNode(3,0,20,0,1,.4,0); }

              //else if(b.anim.rules.roundtype==2) { addNode(3,0,20,0,.6,1,0); }

         }

         else if(mode>1) {

              //Do nothing

         } else {

              if(sim_type==0) {

                  removeChildren[curnode].setValue(pieceshape[curnode]);

                  pts.writeToServer("4" + pn + "" + curtype + (100 + curnode) + (1000 + newpiecex) + (1000 + newpiecey));

                  designing = false;

              }

         }

    }

}

 

public String LoadString() {

     String shapestring;

 

     shapestring  =  "Transform {\n" +

                     "  children [\n" +

                     "      Shape {\n" +

                     "         appearance Appearance {\n";

     shapestring = shapestring +  "   material Material { diffuseColor " + b.anim.ps.GetPiecesString(0);

     shapestring = shapestring + "    }\n]}\n";

     return shapestring;

}

 

public void UpdateVRML (int f, int m, float x, float y, float z, float px, float py, float opx, float opy) {

  float[] val = new float[3];

  if(f==0) {

      val[0] = 6.0f;

      val[1] = y + py - opy;

      val[2] = z - px + opx;

      set_translation[m].setValue(val);

  }

  else if (f==1 || f==4) {

      val[0] = x + px - opx;

      val[1] = y + py - opy;

      if (m==101){

         val[2] = z;

         slant_translation.setValue(val);

      } else {

         val[2] = 0.35f;

         set_translation[m].setValue(val);

      }

      if(f==4) {

         newpiecex = (int)val[0];  //prepare for final location to send to other players

         newpiecey = (int)val[1];

      }

  }

  else if (f==2) {

      val[0] = 0.0f;

      val[1] = 0.0f;

      val[2] = -400.0f;

      slant_translation.setValue(val);

  }

  else if (f==3) {

      val[0] = x;

      val[1] = y;

      val[2] = 0.35f;

      set_translation[m].setValue(val);

  }

}

 

public void UpdatePointer (int f, float x, float y, float z, float px, float py, float opx, float opy) {

  float[] val = new float[3];

  if(f==0) {

      val[0] = 0.0f;

      val[1] = 0.0f;

      val[2] = z;

      pointer_translation.setValue(val);

  }

  else if (f==1) {

      val[0] = x + px - opx;

      val[1] = y + py - opy;

      val[2] = 30.0f;

      pointer_translation.setValue(val);

  }

}

 

public void UpdateRotation (int m, int f) {

  float[] val = new float[4];

  if (f==0) {

      val[0] = 1.0f;

      val[1] = 0.0f;

      val[2] = 0.0f;

      val[3] = -0.4f;

      slant_rotation.setValue(val);

  }

  else if (f==1) {

      val[0] = 0.0f;

      val[1] = 1.0f;

      val[2] = 0.0f;

      val[3] = 0.4f;

      slant_rotation.setValue(val);

  }

  else if (f==2) {

      val[0] = 1.0f;

      val[1] = 0.0f;

      val[2] = 0.0f;

      val[3] = 0.4f;

      slant_rotation.setValue(val);

  }

  else if (f==3) {

      val[0] = 0.0f;

      val[1] = 1.0f;

      val[2] = 0.0f;

      val[3] = -0.4f;

      slant_rotation.setValue(val);

  }

  else {

      val[0] = 1.0f;

      val[1] = 0.0f;

      val[2] = 0.0f;

      val[3] = 0.0f;

      slant_rotation.setValue(val);

  }

}

 

public void UpdateColor (int m, int i) {

  float[] val = new float[3];

  if(i==0) {

      val[0] = 1.0f;

      val[1] = 1.0f;

      val[2] = 1.0f;

  }

  else if (i==1) {

      val[0] = 1.0f;

      val[1] = 0.0f;

      val[2] = 0.0f;

  }

  else if (i==2) {

      val[0] = 0.0f;

      val[1] = 0.0f;

      val[2] = 1.0f;

  }

  else if (i==3) {

      val[0] = 0.0f;

      val[1] = 1.0f;

      val[2] = 0.0f;

  }

  else if (i==4) {

      val[0] = 1.0f;

      val[1] = 1.0f;

      val[2] = 0.0f;

  }

  else {

      val[0] = 1.0f;

      val[1] = 1.0f;

      val[2] = 1.0f;

  }

  if(m==0) { diffuseColor.setValue(val); }

}

 

public void UpdateScale (int i, float x) {

  float[] val = new float[3];

 

  val[0] = x;

  val[1] = x;

  val[2] = x;

  set_scale[i].setValue(val);

}

 

 public void Paletize(int mode) {

     String shapestring = "";

     int n=0;

     int slot=0;

 

     for(int nn=0;nn<7;nn++) {

              if(mode==1) { n=pl.l[nn]; } else if(mode==2) { n=el.l[nn]; } else { n=nn; }

              shapestring  =  "Transform {\n" +

                              "  children [\n" +

                              "      Shape {\n" +

                              "         appearance Appearance {\n";

              if(mode==1||mode==4) {

                   shapestring = shapestring +  "            material Material { diffuseColor " + b.anim.ps.GetPiecesString(n);

                          } else if(mode==2) {

                   shapestring = shapestring +  "            material Material { diffuseColor " + b.anim.es.GetEffectsString(n);

                          } else if (mode==3) {

                   shapestring = shapestring +  "            material Material { diffuseColor " + b.anim.es.GetEffectsString(b.anim.ars.ReadFromArsenal(n));

                          }

              if((mode==1||mode==4)&&n==4) {

                  shapestring = shapestring + "      }\n] rotation 0 0 1 .78 }\n";

              } else if((mode==1||mode==4)&&n==5) {

                  shapestring = shapestring + "      }\n] rotation 0 0 1 -.78 }\n";

              } else {

                  shapestring = shapestring + "      }\n]}\n";

              }

              if(mode==1&&b.anim.round==1) {

                  ReplaceNode(2,slot++,shapestring);

              } else {

                  ReplaceNode(0,slot++,shapestring);

              }

     }

 }

 

 public void addNode(int whichnode, int index, double radius, double bx, double by, double ex, double ey) {

    String shapestring = "";

 

    try {

 

      if(whichnode >= 100) { return; }

 

      shapestring  =       "Transform {\n" +

                           "  children [\n" +

                           "      Shape {\n" +

                           "         appearance Appearance {\n" +

                           "            material Material { diffuseColor ";

 

      if(index==1 || index==6) {

              shapestring = shapestring + b.anim.ps.GetPiecesString(index) +

                              "      }\n" +

                                              "] translation 0 0 15 }\n";

      }

      if(index==0) {

              shapestring  =  shapestring + " " + bx + " " + by + " " + ex + " }\n" +

                              "         }\n" +

                              "         geometry Sphere {radius " + radius + " }\n" +

                              "      }\n" +

                              "]}\n";

      }

      else if(index==4) {

             shapestring = shapestring + b.anim.ps.GetPiecesString(2) +

                              "      }\n" +

                                              "] rotation 0 0 1 .78 }\n";

      }

      else if(index==5) {

              shapestring = shapestring + b.anim.ps.GetPiecesString(2) +

                              "      }\n" +

                                              "] rotation 0 0 1 -.78 }\n";

      }

      else {

              shapestring = shapestring + b.anim.ps.GetPiecesString(index) +

                              "      }\n" +

                                              "]}\n";

      }

      ReplaceNode(1,whichnode,shapestring);

      curnode=whichnode;

    }

    catch (InvalidNodeException e) {

    }

    catch (InvalidEventInException e) {

    }

    catch (InvalidVrmlException e) {

    }

 }

 

 public void ReplaceNode(int where, int ndx, String str) {

    String shapestring = "";

 

    try {

       if(where==0) { //Palette Piece Replace

          removePI[ndx].setValue(pshape[ndx]);

          pshape[ndx] = browser.createVrmlFromString(str);

          addPI[ndx].setValue(pshape[ndx]);

       } else if(where==1) { //Add a Board Piece

          pieceshape[ndx] = browser.createVrmlFromString(str);

          addChildren[ndx].setValue(pieceshape[ndx]);

       } else if(where==2) { //Pallete Piece New

          pshape[ndx] = browser.createVrmlFromString(str);

          addPI[ndx].setValue(pshape[ndx]);

       }

    }

    catch (InvalidNodeException e) {

    }

    catch (InvalidEventInException e) {

    }

    catch (InvalidVrmlException e) {

    }

 }

 

 public void addGoal(int whichgoal, int color, double goalx, double goaly) {

    String shapestring = "";

    String colorstring = "";

 

    try {

 

      if(whichgoal >= b.anim.maxg) { return; }

 

      if(color==0) {

         colorstring = "1 1 0";

      } else if (color==1) {

         colorstring = "1 0 0";

      } else if (color==2) {

         colorstring = "0 0 1";

      } else if (color==3) {

         colorstring = "0 1 0";

      } else colorstring = "0 0 0";

 

      shapestring  =  "Transform {\n" +

                                      "  children [\n" +

                      "      Shape {\n" +

                      "         appearance Appearance {\n" +

                      "            material Material { diffuseColor " + colorstring +  " }\n" +

                      "         }\n" +

                      "         geometry Cylinder {radius 20 height 5 }\n" +

                      "      }\n" +

                                      "] translation " + goalx + " " + goaly + " 0 \n" +

                                      "  rotation 1 0 0 1.57 }\n";

 

     goalshape[whichgoal] = browser.createVrmlFromString(shapestring);

     addGoal[whichgoal].setValue(goalshape[whichgoal]);

    }

    catch (InvalidNodeException e) {

    }

    catch (InvalidEventInException e) {

    }

    catch (InvalidVrmlException e) {

    }

 }

 

 public void addSlQu(int whichslqu, int color, boolean initial) {

    String shapestring = "";

    String colorstring = "";

    String coordstring = "";

    String transstring = "";

 

    try {

 

      if(whichslqu >= 4 || whichslqu < 0) {

         return;

      } else if (whichslqu==0) {

         transstring = "-200 300 0";

      } else if (whichslqu==1) {

         transstring = "-200 400 0";

      } else if (whichslqu==2) {

         transstring = "-200 500 0";

      } else {

         transstring = "-200 600 0";

      }

 

      if (color==1) {

         colorstring = "0 1 0";

         coordstring = "point [ 0 0 25, 100 0 25, 100 100 -25, 0 100 -25 ]";

      } else if (color==2) {

         colorstring = "0 0 1";

         coordstring = "point [ 0 0 25, 100 0 -25, 100 100 -25, 0 100 25 ]";

      } else if(color==3) {

         colorstring = "1 1 0";

         coordstring = "point [ 0 0 -25, 100 0 -25, 100 100 25, 0 100 25 ]";

      } else if (color==4) {

         colorstring = "1 0 0";

         coordstring = "point [ 0 0 -25, 100 0 25, 100 100 25, 0 100 -25 ]";

      } else {

         colorstring = "0 0 0 transparency 1";

      }

 

      if(!initial) {

          removeslqu[whichslqu].setValue(qshape[whichslqu]);

      }

 

      shapestring  =  "Transform {\n" +

                                      "  children [\n" +

                      "      Shape {\n" +

                      "         appearance Appearance {\n" +

                      "            material Material { diffuseColor " + colorstring +  " }\n" +

                      "         }\n" +

                      "         geometry IndexedFaceSet {\n" +

                      "            coord Coordinate {\n" +

                      "               " + coordstring + "\n" +

                      "            }\n" +

                      "            coordIndex [ 0, 1, 2, 3 ]\n" +

                      "         }\n" +

                      "      }\n" +

                                      "  ] translation " + transstring + "\n" +

                                      "}\n";

 

     qshape[whichslqu] = browser.createVrmlFromString(shapestring);

     addslqu[whichslqu].setValue(qshape[whichslqu]);

    }

    catch (InvalidNodeException e) {

    }

    catch (InvalidEventInException e) {

    }

    catch (InvalidVrmlException e) {

    }

 }

 

 public void Bumpers(int whichmode) {

 String colorstring = "";

 

    if(pn==1){colorstring = " 1 0 0 ";}

    else if(pn==2){colorstring = " 0 0 1 ";}

    else if(pn==3){colorstring = " 0 1 0 ";}

    else if(pn==4){colorstring = " 1 1 0 ";}

 

    try {

 

      if(whichmode == 1) {   //Ball

          bumpers  =  browser.createVrmlFromString("Transform {\n" +

                                  "  children [\n" +

                                  "   Transform {\n" +

                                  "    children [\n" +

                                  "      DEF Bumper Shape {\n" +

                                  "         appearance Appearance {\n" +

                                  "              material Material { diffuseColor " + colorstring + "}\n" +

                                  "         }\n" +

                                  "         geometry Box {}\n" +

                                  "      }\n" +

                                  "    ]\n" +

                                  "    scale 30 500 30\n" +

                                  "    translation -30 500 2\n" +

                                  "   },\n" +

                                  "   Transform {\n" +

                                  "     children [\n" +

                                  "      USE Bumper\n" +

                                  "     ]\n" +

                                  "     scale 30 500 30\n" +

                                  "     translation 1030 500 2\n" +

                                  "   },\n" +

                                  "   Transform {\n" +

                                  "     children [\n" +

                                  "      USE Bumper\n" +

                                  "     ]\n" +

                                  "     scale 560 30 30\n" +

                                  "     translation 500 1030 2\n" +

                                  "   },\n" +

                                  "   Transform {\n" +

                                  "     children [\n" +

                                  "      USE Bumper\n" +

                                  "     ]\n" +

                                  "     scale 560 30 30\n" +

                                  "     translation 500 -30 2\n" +

                                  "   },\n" +

                                  "]}\n");

          addSides.setValue(bumpers);

      }

      else {

          removeSides.setValue(bumpers);

      }

    }

    catch (InvalidNodeException e) {

    }

    catch (InvalidEventInException e) {

    }

    catch (InvalidVrmlException e) {

    }

 }

 

 public void addPlayer(Player p) {

    if (nump<4) player[nump++] = p;

 }

 

 public void stop() {

   if (b!=null) b.stop();

 }

          //{{DECLARE_CONTROLS

          //}}

}

 

//-------------------------------------------------------------------

//  This class controls the main window

 

class MainWindow extends Frame {

  Animator anim;

  Ticker tick;

  Thread anim_thread;

  Thread tick_thread;

  boolean is_applet;

  Marbles i;

  MyFrame pwindow;

  Scrollbar mgrav,fric,rest;

  TextField grav;

  Label label1,label2,label3,label4,label5,label6,label7,label8,label9,inst;

  Checkbox trace,collide,mush,wrap,smooth,filled,cb1,cb2,cb3,cb4,cb5,cb6,cb7,cb8,cb9;

 

  //  This method creates layout and main objects.

 

  MainWindow(String title, boolean isapp, Marbles i_in) {

    super(title);

    is_applet = isapp;

    i = i_in;

    Panel p = new Panel();                // control panel

    Label n = new Label("Marbles 1.0");

    p.setLayout(new GridLayout(0,1)); // vertical layout

    p.setFont(new Font("Helvetica",Font.BOLD,12));

    n.setFont(new Font("TimesRoman",Font.BOLD,16));

    p.add(n);

    p.add(new Button("quit"));

    p.add(inst=new Label(""));

    p.add(grav=new TextField(40));

    grav.setText("");

    p.add(label1=new Label(""));

    p.add(cb1=new Checkbox(""));

    p.add(label2=new Label(""));

    p.add(cb2=new Checkbox(""));

    p.add(label3=new Label(""));

    p.add(cb3=new Checkbox(""));

    p.add(label4=new Label(""));

    p.add(cb4=new Checkbox(""));

    p.add(label5=new Label(""));

    p.add(cb5=new Checkbox(""));

    p.add(label6=new Label(""));

    p.add(cb6=new Checkbox(""));

    p.add(label7=new Label(""));

    p.add(cb7=new Checkbox(""));

    p.add(label8=new Label(""));

    p.add(cb8=new Checkbox(""));

    p.add(label9=new Label(""));

    p.add(cb9=new Checkbox(""));

    //Qgov();

    Qctime();

    tick = new Ticker(p); // pace maker for the animator

    anim = new Animator(tick,p,this);

    setLayout(new BorderLayout(2,2));

    add("Center",anim);

    add("West",p);

    pwindow = new MyFrame("Choose Pieces",i);

    pwindow.resize(400,480);

    pwindow.hide();

}

 

  //  This starts the threads.

 

  public void start() {

    if (anim_thread==null) {

      anim_thread = new Thread(anim);

      anim_thread.start();    // start new thread

    }

    if (tick_thread==null) {

      tick_thread = new Thread(tick);

      tick_thread.start();   // start new thread

    }

  }

 

  //  This stops the threads.

 

  public void stop() {

    if (anim_thread!=null) {

      anim_thread.stop();    // kill the thread

      anim_thread = null;     // release object

    }

    if (tick_thread!=null) {

      tick_thread.stop();      // kill the thread

      tick_thread = null;       // release object

    }

  }

 

  //  These handle user input events.

 

  public boolean action(Event e, Object arg) {

    if (e.target instanceof Button) {

      if (((String)arg).equals("quit")) {

               stop();

               hide(); // I don't know if all this is necessary.

               removeAll();

               dispose();

               if (!is_applet) System.exit(0);

      }

      else return false;

      return true;

    }

    if(cb1.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "0");

          cb1.setState(false);

    }

    else if(cb2.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "1");

          cb2.setState(false);

    }

    else if(cb3.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "2");

          cb3.setState(false);

    }

    else if(cb4.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "3");

          cb4.setState(false);

    }

    else if(cb5.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "4");

          cb5.setState(false);

    }

    else if(cb6.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "5");

          cb6.setState(false);

    }

    else if(cb7.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "6");

          cb7.setState(false);

    }

    else if(cb8.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "7");

          cb8.setState(false);

    }

    else if(cb9.getState()==true) {

          i.pts.writeToServer("1" + i.qno + "" + i.pn + "8");

          cb9.setState(false);

    }

    return false;

  }

 

  protected void Qgov() {

       labelCheckBoxes("What Government Type?","Democratic","Democratic Hi-Lo",

                       "Autocratic","","","","","","");

  }

 

  protected void Qlibrary() {

       labelCheckBoxes("Library Game or Players Rules","Library","Players",

                       "","","","","","","");

  }

 

  protected void Qchange() {

       labelCheckBoxes("Which Do You Want To Change Next Round?","Government","Objects",

                       "Events","Physics","Rules","Winning","","","");

  }

 

  protected void QnumEvents() {

       labelCheckBoxes("How Many Event Types Would You Like?","1","2",

                       "3","4","5","6","7","","");

  }

 

  protected void QnumPieces() {

       labelCheckBoxes("How Many Piece Types Would You Like?","1","2",

                       "3","4","5","6","7","","");

  }

 

  protected void QnumArsenal() {

       labelCheckBoxes("How Many Arsenal Items Would You Like?","1","2",

                       "3","4","5","6","7","","");

  }

 

  protected void Qctime() {

       labelCheckBoxes("How Much Time To Make Choices?","5 seconds","10 seconds",

                       "15 seconds","20 seconds","25 seconds","30 seconds","45 seconds",

                       "1 minute","2 minutes");

  }

 

  protected void QslantQtype() {

       labelCheckBoxes("How Should the Slant Queue Work?","Take Turns",

                       "FIFO","Random","","","","","","");

  }

 

  protected void QslantQwrap() {

       labelCheckBoxes("Should the Slant Queue Wrap to Next Round?","YES",

                       "NO","","","","","","","");

  }

 

  protected void QslantQtime() {

       labelCheckBoxes("How Often Should Slant Change?","20 frames","40 frames",

                       "60 frames","80 frames","100 frames","120 frames","150 frames",

                       "","");

  }

 

  protected void Qbumpers() {

       labelCheckBoxes("Should There Be Bumpers?","YES",

                       "NO","Change w/Turns","","","","","","");

  }

 

  protected void Qwinning() {

       labelCheckBoxes("How Compensated for Winning?","More Goals","Bigger Ball",

                       "More Points/Goal","","","","","","");

  }

 

  protected void QnextRound() {

       labelCheckBoxes("What Type of Round Next?","Competitive","Collaborative",

                       "Teams of 2","","","","","","");

  }

 

  protected void QeventQlag() {

       labelCheckBoxes("How Many Frames for Event Queue Lag?","20 frames","30 frames",

                       "40 frames","50 frames","60 frames","70 frames","","","");

  }

 

  protected void QeventDuration() {

       labelCheckBoxes("How Many Frames Is Event Active?","40 frames","60 frames",

                       "80 frames","100 frames","120 frames","150 frames","","","");

  }

 

  protected void Qgravity() {

       labelCheckBoxes("How High Gravity (1-low,9-high)?","1","2",

                       "3","4","5","6","7","8","9");

  }

 

  protected void Qrestitution() {

       labelCheckBoxes("How High Restitution (1-low,9-high)?","1","2",

                       "3","4","5","6","7","8","9");

  }

 

  protected void Qmass() {

       labelCheckBoxes("How High Mass (1-low,9-high)?","1","2",

                       "3","4","5","6","7","8","9");

  }

 

  protected void Qviscosity() {

       labelCheckBoxes("How High Viscosity (1-low,9-high)?","1","2",

                       "3","4","5","6","7","8","9");

  }

 

  protected void Qpieces() {

       for(int x=1;x<7;x++) {

           i.image[x-1]=i.getImage(i.getCodeBase(), "images/" + x + ".gif");

       }

       pwindow.label11.setText("Small Spherical Barrier");

       pwindow.label12.setText("Horizontal Stick Barrier");

       pwindow.label13.setText("Vertical Stick Barrier");

       pwindow.label14.setText("Vertical Rotated 45 Degrees");

       pwindow.label15.setText("Vertical Rotated -45 Degrees");

       pwindow.label16.setText("Variable Size Spherical Barrier");

       pwindow.label17.setText("Pendulum");

       pwindow.label18.setText("Rotating Cross");

       pwindow.label19.setText("");

       pwindow.label20.setText("");

       pwindow.show(); //.hide() will hide the window.

  }

 

  protected void Qeffects() {

       for(int x=1;x<7;x++) {

           i.image[x-1]=null;

           i.image[x-1]=i.getImage(i.getCodeBase(), "images/10" + x + ".gif");

       }

       pwindow.label11.setText("No Collisions");

       pwindow.label12.setText("Anti-Gravity");

       pwindow.label13.setText("Stop");

       pwindow.label14.setText("Grab A Goal");

       pwindow.label15.setText("Create a New Barrier");

       pwindow.label16.setText("Double Ball Radius");

       pwindow.label17.setText("");

       pwindow.label18.setText("");

       pwindow.label19.setText("");

       pwindow.label20.setText("");

       pwindow.show(); //.hide() will hide the window.

  }

 

  protected void labelCheckBoxes(String txt, String cblbl1, String cblbl2, String cblbl3,

                                 String cblbl4, String cblbl5, String cblbl6,

                                 String cblbl7, String cblbl8, String cblbl9) {

       inst.setText(txt);

       label1.setText(cblbl1);

       label2.setText(cblbl2);

       label3.setText(cblbl3);

       label4.setText(cblbl4);

       label5.setText(cblbl5);

       label6.setText(cblbl6);

       label7.setText(cblbl7);

       label8.setText(cblbl8);

       label9.setText(cblbl9);

  }

          //{{DECLARE_CONTROLS

          //}}

          //{{DECLARE_MENUS

          //}}

}

 

class MyFrame extends Frame {

   Checkbox cb11,cb12,cb13,cb14,cb15,cb16,cb17,cb18,cb19,cb20;

   Label label11,label12,label13,label14,label15,

         label16,label17,label18,label19,label20;

   MyCanvas pPictures;

   Marbles m;

   int fmode=0;

 

   MyFrame(String title, Marbles m_in) {

       super(title);

       m = m_in;

       setLayout(new GridLayout(1,3,0,0));

       Panel one=new Panel();

       Panel three=new Panel();

       add("first",one);

       pPictures = new MyCanvas(this);

       pPictures.setBackground(Color.black);

       add(pPictures);

       add("third",three);

       one.setLayout(new GridLayout(11,1,0,0));

       one.add(cb11=new Checkbox(""));

       one.add(cb12=new Checkbox(""));

       one.add(cb13=new Checkbox(""));

       one.add(cb14=new Checkbox(""));

       one.add(cb15=new Checkbox(""));

       one.add(cb16=new Checkbox(""));

       one.add(cb17=new Checkbox(""));

       one.add(cb18=new Checkbox(""));

       one.add(cb19=new Checkbox(""));

       one.add(cb20=new Checkbox(""));

       //one.add(new Button("OK"));

       three.setLayout(new GridLayout(11,1,0,0));

       three.add(label11=new Label(""));

       three.add(label12=new Label(""));

       three.add(label13=new Label(""));

       three.add(label14=new Label(""));

       three.add(label15=new Label(""));

       three.add(label16=new Label(""));

       three.add(label17=new Label(""));

       three.add(label18=new Label(""));

       three.add(label19=new Label(""));

       three.add(label20=new Label(""));

   }

 

   public boolean action(Event e, Object arg) {

     if(cb11.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "1");

       cb11.setState(false);

     }

     if(cb12.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "2");

       cb12.setState(false);

     }

     if(cb13.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "3");

       cb13.setState(false);

     }

     if(cb14.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "4");

       cb14.setState(false);

     }

     if(cb15.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "5");

       cb15.setState(false);

     }

     if(cb16.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "6");

       cb16.setState(false);

     }

     if(cb17.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "7");

       cb17.setState(false);

     }

     if(cb18.getState()==true) {

       m.pts.writeToServer("1" + m.qno + "" + m.pn + "8");

       cb18.setState(false);

     }

     return true;

   }

          //{{DECLARE_CONTROLS

          //}}

          //{{DECLARE_MENUS

          //}}

}

 

class MyCanvas extends Canvas {

   MyFrame f;

 

   MyCanvas(MyFrame f_in) {

       f=f_in;

   }

 

   public void drawPieces() {

   }

 

   public void paint(Graphics g) {

      for(int x=0;x<6;x++) {

          g.drawImage(f.m.image[x],5,(x*40)+5,this);

      }

   }

}

 

//-------------------------------------------------------------------

//  This class performs the animation in the main canvas.

 

class Animator extends Canvas implements Runnable {

  final int max = 50;

  final int maxeg = 30;

  final int maxp = 20;

  int maxg = 10;

  int num=0;            // number of balls

  int numo=0;           // number of obstacles

  int numg=0;           // number of goals

  int captg=0;          // number of captured goals

  int round=1;

  Ball[] ball = new Ball[max];          // array of balls

  Obstacle[] obstacle = new Obstacle[max];   // array of obstacles

  SlantQueue sq = new SlantQueue(60);

  EffectsQueue eq = new EffectsQueue(60);

  Effects es = new Effects(20);

  Arsenal ars = new Arsenal(7);

  Pieces ps = new Pieces(20);

  Goal[] goal = new Goal[maxeg];     // array of goals

  int goalvalue[]={100,100,100,100};  //current goal values

  int[] rs = {0,0,0,0};                     // round scores

  Physics[] phys = new Physics[maxp]; // array of physics

  Ticker tick;

  long starttime;

  boolean timeOK=true;

  Date theDate;

  long count=0;

  MainWindow mw;

  Rules rules = new Rules();            // Rules Structure

  boolean clearAll;

 

  //  The following are some "physical" properties.  Each property

  //  has a value and a control.  The values are updated once per

  //  animation loop (this is for efficiency).

 

  public double g,vg,hg,mg,f,r,bm;

  public boolean trc,col,mu,wrapon,sm;

  public int xsize,ysize,sqt,eql,eqd;

 

  Animator(Ticker t, Panel p, MainWindow m) {

    tick = t;

    mw = m;

    setBackground(Color.black);

    xsize = 1000; //width of playing board

    ysize = 1000; //height of playing board

    vg = 0.0;

    hg = 0.0;

    sqt = 100;

    eql = 50;

    eqd = 150;

    f = .50;  //effect of viscosity

    g = .25;  //effect of gravity

    r = .75;  //effect of restitution

    bm = 64;  //ball mass

    col = true;

    wrapon = true;

    loadPhysics();

  }

  //  The run method updates the locations of the balls.

  public void run() {

   while(true) {

    while (captg<numg || numg==0) {

     if(mw.i.mode>2 || mw.i.speedtest) {

       if(mw.i.speedtest && count==0) {

              addBall(new Ball(64,20,Color.blue,500,100,0.0,0.0,this,0));

              mw.i.addNode(num-1,0,20,1,1,1,0);

              addBall(new Ball(64,20,Color.blue,100,500,0.0,0.0,this,0));

              mw.i.addNode(num-1,0,20,1,1,1,0);

              addBall(new Ball(64,20,Color.blue,900,500,0.0,0.0,this,0));

              mw.i.addNode(num-1,0,20,1,1,1,0);

              addBall(new Ball(64,20,Color.blue,500,900,0.0,0.0,this,0));

              mw.i.addNode(num-1,0,20,1,1,1,0);

              vg=.33;

              theDate = new Date();

                    starttime =  theDate.getTime();

       }

       for (int i=0; i<num; ++i) {

         if(ball[i].e!=1) { //e=1 means not collidable

                   for (int j=0; j<numo; ++j) {  //look for collisions with obstacles

                       ball[i].interact(obstacle[j]);

             }

                   for (int j=i+1; j<num; ++j)  { //look for collisions with balls

                       ball[i].interact(ball[j]);

             }

         }

         if(i<4) { //ball is one of the players

                 for (int j=0; j<numg; ++j)  { //look for collisions with goals

                    if (ball[i].interact(goal[j])) {

                       if(goal[j].c > 3 || ball[i].e==4) { //ball effect=4 is goal stealing

                           mw.i.removeGoal[j].setValue(mw.i.goalshape[j]);

                           if(goal[j].c > 3) {captg++;}

                       if(rules.roundtype==0) { goal[j].c = i; }

                       else if(rules.roundtype==1) { goal[j].c=3; }

                       else if(rules.roundtype==2) {

                           if(i==0||i==3) {

                               goal[j].c=2;

                           } else { goal[j].c=1; }

                       }

                           rs[i]=rs[i]+goalvalue[i];  //value for each goal

                           mw.i.addGoal(j,goal[j].c,goal[j].x,goal[j].y);

                       }

                    }

                 }

         }

      }

      for (int j=0; j<num; ++j) {

               if(ball[j].t==0)  {

                   if(ball[j].e==3) { //e=3 is ball stoppage

                   ball[j].vx = 0.0;

                   ball[j].vy = 0.0;

                   } else {

                   ball[j].update();

               }

           }

               if(ball[j].t==1)  {

                ball[j].vx = 0.0;

                ball[j].vy = 0.0;

           }

           if(ball[j].t==2||ball[j].t==8)  {  //Pendulum

                if(count%40==0) {

                    if(ball[j].t==2){

                       for(int k=1;k<5;k++) {

                           ball[j+k].x=ball[j].x-(21.25*k);

                           ball[j+k].y=ball[j].y-(10*k);

                           ball[j+k].vx=phys[k].x[0];

                           ball[j+k].vy=phys[k].y[0];

                       }

                    } else {

                       ball[j+1].y=ball[j].y+60;

                       ball[j+2].x=ball[j].x+60;

                       ball[j+3].y=ball[j].y-60;

                       ball[j+4].x=ball[j].x-60;

                       for(int k=1;k<5;k++) {

                           ball[j+k].vx=phys[k].x[0];

                           ball[j+k].vy=phys[k].y[0];

                       }

                    }

                } else {

                    int index=0;

                    while(count%40>=phys[1].t[index]) {

                        index++;

                    }

                    for(int k=1;k<5;k++) {

                        if(ball[j].t==2){

                           ball[j+k].vx=phys[k].x[index];

                           ball[j+k].vy=phys[k].y[index];

                        } else {

                           ball[j+k].vx=phys[k+5].x[index];

                           ball[j+k].vy=phys[k+5].y[index];

                        }

                    }

                }

                for(int k=0;k<5;k++) {

                       ball[j+k].y += ball[j+k].vy;

                       ball[j+k].x += ball[j+k].vx;

                       mw.i.UpdateVRML(3,j+k,(float)ball[j+k].x,(float)ball[j+k].y,0,0,0,0,0);

                }

                j=j+4;

            }

            if(ball[j].t==3)  {  //Increasing Scale

                   ball[j].vx = 0.0;

                   ball[j].vy = 0.0;

                   ball[j].z *= 1.1;

                   mw.i.UpdateScale(j,(float)(ball[j].z/40));

                   if(ball[j].z > 40.0) {

                        ball[j].t = 4;

                   }

             }

             if(ball[j].t==4)  {  //Decreasing Scale

                   ball[j].vx = 0.0;

                   ball[j].vy = 0.0;

                   ball[j].z *= (1/1.1);

                   mw.i.UpdateScale(j,(float)(ball[j].z/40));

                   if(ball[j].z < 2.0) {

                        ball[j].t = 3;

                   }

             }

        }

      }

      DrawBalls();

      tick.poll();                 // wait for tick

      if (mw.i.mode>2 || mw.i.speedtest) {

        if (count%sqt==0) {

          int qs=sq.TakeFromSlantQueue();

          if (qs==1) {

            vg = g;

            hg = 0.0;

            mw.i.UpdateRotation(0,0);

            mw.i.UpdateVRML(1,101,0,0,100,0,0,0,0);

          }

          else if (qs==2) {

            vg = 0.0;

            hg = g;

            mw.i.UpdateRotation(0,1);

            mw.i.UpdateVRML(1,101,0,0,100,0,0,0,0);

          }

          else if (qs==3) {

            vg = -g;

            hg = 0.0;

            mw.i.UpdateRotation(0,2);

            mw.i.UpdateVRML(2,101,0,0,0,0,0,0,0);

          }

          else if (qs==4) {

            vg = 0.0;

            hg = -g;

            mw.i.UpdateRotation(0,3);

            mw.i.UpdateVRML(2,101,0,0,0,0,0,0,0);

          }

          int val=sq.InterrogateSlantQueue(0);

          if((val==-1)&&(mw.i.pn==mw.i.turncolor)&&(mw.i.mode>2)) {

              val=(int)((Math.random()*4)+1);

              mw.i.pts.writeToServer("2" + val); //can't have an empty slant queue at any point in time

          }

          mw.i.addSlQu(0,val,false); //show next queue

          val=-1;

          for(int ww=1;ww<4;ww++) { //Show upcoming slants

             val=sq.InterrogateSlantQueue(ww);

             if(val>=0 && val<=4) { mw.i.addSlQu(ww,val,false); }

             else if(val==-1) { mw.i.addSlQu(ww,0,false); }

          }

        }

        //HandleEventsQueue

        if (eq.GetEffectsQueueTime(0)<count) {

          int cureffect = eq.GetEffectsQueueEffect(0);  //cureffect is ball number plus event -- example: 101

          int curballno = cureffect/100;

          if(ball[curballno].e==6) { //e=6 is grow marble

              ball[curballno].z = ball[curballno].z/2;

              mw.i.UpdateScale(curballno,1);

          }

          ball[curballno].e = eq.TakeFromEffectsQueue()%100;

          if(ball[curballno].e==5) {  //e=5 is add an obstacle

             mw.i.curnode=50+numo;

             mw.i.removeChildren[mw.i.curnode].setValue(mw.i.pieceshape[mw.i.curnode]);

             mw.i.pts.writeToServer("4" + mw.i.pn + "" + "2" + (100 + mw.i.curnode) +

                              (1000 + (int) ball[curballno].x) + (1000 + (int) ball[curballno].y-25));

          } else if(ball[curballno].e==6) { //e=6 is make ball bigger

              ball[curballno].z = ball[curballno].z*2;

              mw.i.UpdateScale(curballno,2);

          }

        }

        count++;

        if(count%50==0 && !mw.i.speedtest) {  //coordinate speed with server

            theDate = new Date();

            mw.i.pts.writeToServer("8" + mw.i.pn + "" + (count/50 + 100) + "" + (theDate.getTime() - starttime));

            starttime=theDate.getTime();

            //timeOK=false;

        //} else if((count-40)%100==0 && !mw.i.speedtest) {  //make sure have a valid time back

        //    if(timeOK=false){ tick.speed=2000; } //someone has not reported in yet

        } else if(mw.i.speedtest && count==50) {

            theDate = new Date();

            mw.i.pts.writeToServer("8" + mw.i.pn + "100" + (theDate.getTime() - starttime));

            mw.i.speedtest=false;

            count=0;

            mw.i.UpdateColor(0,mw.i.pn);  //show player who they are

            for(int xz=0;xz<4;xz++) {

                mw.i.removeChildren[xz].setValue(mw.i.pieceshape[xz]);

                ball[xz].vx=0.0; ball[xz].vy=0.0;

            }

            vg=0.0;

        }

        mw.i.showStatus("count= " + count + " speed " + tick.speed);

        if(count==2000) { //too long to wait -- end turn

            mw.i.pts.writeToServer("98" + captg);

            numg=captg;

        }   

      }

    } //end while loop

    if(count<2000) { //write out number of frames to finish

        mw.i.pts.writeToServer("99" + count);

    }   

    ResetGame();

    round++;

   }

  }

 

  public void ResetGame() {   //HGC

      double share=0.0;

 

      //TALLY RESULTS FROM LAST ROUND

      for(int i=0;i<4;i++) {

          if(rules.roundtype==0) { mw.i.player[i].IncreasePlayerScore(rs[i]); }

          else if(rules.roundtype==1&&rules.winning==0) {

               if(numg/maxg>.8) { if(maxg<29) { maxg=maxg+2; } }

               else if(numg/maxg>.5) { if(maxg<30) { maxg++; } }

               else if(numg/maxg>.2) { if(maxg>2) { maxg=maxg-1; } }

               else { if(maxg>3) { maxg=maxg-2; } }

          }

          else if(rules.roundtype==2) {

               if(i==0||i==3) {

                  mw.i.player[i].IncreasePlayerScore((rs[0] + rs[3])/2);

               } else {

                  mw.i.player[i].IncreasePlayerScore((rs[1] + rs[2])/2);

               }

          }

      }

      if(rules.winning==1) {

         for(int i=0;i<4;i++) {

            if(rules.roundtype==0) {

               share=rs[i]/((rs[0]+rs[1]+rs[2]+rs[3])/4);

               if(share==0) { ball[i].z=ball[i].z*.7; }

               else if(share<.15) { ball[i].z=ball[i].z*.85; }

               else if(share<.35) { } //No Change

               else if(share<.55) { ball[i].z=ball[i].z/.85; }

               else if(share<=1)  { ball[i].z=ball[i].z/.7; }

            }

            else if(rules.roundtype==1) {

               if(numg/maxg>.8) { if(maxg<29) { ball[i].z=ball[i].z/.7; } }

               else if(numg/maxg>.5) { if(maxg<30) { ball[i].z=ball[i].z/.85; } }

               else if(numg/maxg>.35) { if(maxg>2) { } }

               else if(numg/maxg>.2) { if(maxg>2) { ball[i].z=ball[i].z*.85;} }

               else { if(maxg>3) { ball[i].z=ball[i].z*.7; } }

            }

            else if(rules.roundtype==2) {

               if(i==0||i==3) {

                   share=(rs[0]+rs[3])/((rs[0]+rs[1]+rs[2]+rs[3])/4);

               }

               else {

                   share=(rs[1]+rs[2])/((rs[0]+rs[1]+rs[2]+rs[3])/4);

               }

               if(share==0) { ball[i].z=ball[i].z*.7; }

               else if(share<.3) { ball[i].z=ball[i].z*.85; }

               else if(share<.7) { } //No Change

               else if(share<1) { ball[i].z=ball[i].z/.85; }

               else if(share==1)  { ball[i].z=ball[i].z/.7; }

            }

         }

      }

      else if(rules.winning==2) {

         for(int i=0;i<4;i++) {

            if(rules.roundtype==0) {

               share=rs[i]/((rs[0]+rs[1]+rs[2]+rs[3])/4);

               if(share==0) { goalvalue[i]=goalvalue[i]-16; }

               else if(share<.15) { goalvalue[i]=goalvalue[i]-8; }

               else if(share<.35) { } //No Change

               else if(share<.55) { goalvalue[i]=goalvalue[i]+8; }

               else if(share<=1)  { goalvalue[i]=goalvalue[i]+16; }

            }

            else if(rules.roundtype==1) {

               if(numg/maxg>.8) { goalvalue[i]=goalvalue[i]+16; }

               else if(numg/maxg>.5) { goalvalue[i]=goalvalue[i]+8; }

               else if(numg/maxg>.35) { }

               else if(numg/maxg>.2) { goalvalue[i]=goalvalue[i]-8; }

               else { goalvalue[i]=goalvalue[i]-16; }

            }

            else if(rules.roundtype==2) {

               if(i==0||i==3) {

                   share=(rs[0]+rs[3])/((rs[0]+rs[1]+rs[2]+rs[3])/4);

               }

               else {

                   share=(rs[1]+rs[2])/((rs[0]+rs[1]+rs[2]+rs[3])/4);

               }

               if(share==0) { goalvalue[i]=goalvalue[i]-16; }

               else if(share<.3) { goalvalue[i]=goalvalue[i]-8; }

               else if(share<.7) { } //No Change

               else if(share<1) { goalvalue[i]=goalvalue[i]+8; }

               else if(share==1)  { goalvalue[i]=goalvalue[i]+16; }

            }

         }

      }

      mw.i.showStatus("Team Score Time:  " + count + " Captured Goals: " + captg);

      //mw.i.showStatus("Current Score:  Yellow " + mw.i.player[0].GetPlayerScore() +

      //                               " Red " + mw.i.player[1].GetPlayerScore() +

      //                               " Blue " + mw.i.player[2].GetPlayerScore() +

      //                               " Green " + mw.i.player[3].GetPlayerScore());

      for(int xx=0;xx<4;xx++) {

          rs[xx]=0;

      }

      mw.i.mode=0;

      mw.i.lastmodesent=0;

      for(int x=0;x<50;x++) { //put balls and obstacles back

          if(x>3) {

             mw.i.removeChildren[x].setValue(mw.i.pieceshape[x]);

             ball[x]=null;

          }

          mw.i.removeChildren[x+50].setValue(mw.i.pieceshape[x+50]);

          obstacle[x]=null;

      }

      for(int j=0; j<numg; ++j)  { //put goals back

          mw.i.removeGoal[j].setValue(mw.i.goalshape[j]);

          goal[j]=null;

      }

      ball[0].x = 500;

      ball[0].vx = 0.0;

      ball[0].y = 100;

      ball[0].vy = 0.0;

      mw.i.UpdateVRML(3,0,(float)ball[0].x,(float)ball[0].y,0,0,0,0,0);

      ball[1].x = 100;

      ball[1].vx = 0.0;

      ball[1].y = 500;

      ball[1].vy = 0.0;

      mw.i.UpdateVRML(3,1,(float)ball[1].x,(float)ball[1].y,0,0,0,0,0);

      ball[2].x = 900;

      ball[2].vx = 0.0;

      ball[2].y = 500;

      ball[2].vy = 0.0;

      mw.i.UpdateVRML(3,2,(float)ball[2].x,(float)ball[2].y,0,0,0,0,0);

      ball[3].x = 500;

      ball[3].vx = 0.0;

      ball[3].y = 900;

      ball[3].vy = 0.0;

      mw.i.UpdateVRML(3,3,(float)ball[3].x,(float)ball[3].y,0,0,0,0,0);

      numo=0; num=4; numg=0; captg=0;

      mw.i.UpdateRotation(0,4);

      mw.i.UpdateVRML(1,101,0,0,0,0,0,0,0);

      if(rules.slantQclear==true) { //reset slant queue if chosen

          for(int zz=0;zz<60;zz++) {

              sq.t[zz]=-1;

              sq.size=0;

              sq.head=0;

              sq.tail=0;

          }

          for(int xx=0;xx<4;xx++) {

              mw.i.addSlQu(xx,0,false);

          }

      }

      for(int yy=0;yy<60;yy++) { //reset event queue

          eq.t[yy]=-1;

          eq.e[yy]=-1;

          eq.size=0;

          eq.head=0;

          eq.tail=0;

      }

      mw.i.Paletize(4);

      mw.i.Bumpers(1);

      wrapon=false;

      mw.i.UpdatePointer(0,0,0,30,0,0,0,0);

      mw.i.pts.goalcount=0;

      //mw.i.lst.createGoals(maxg);

  }

 

  //  The DrawBalls method displays objects.

 

  public void DrawBalls() {

    int j=0;

    float x=0,y=0;

 

    for (j=0; j<num; ++j) {

      x = (float) (ball[j].x);

      y = (float) (ball[j].y);

      if(ball[j].t<1)

          mw.i.UpdateVRML(1,j,x,y,0,0,0,0,0);

      }

  }

 

  //  These adds balls

 

  public void addMoving(int m,int r,float x,float y,int t,int c0,int c1,int c2) {

      addBall(new Ball(m,r,Color.pink,x,y,0.0,0.0,this,t));

      mw.i.addNode(num-1,0,r,c0,c1,c2,0);

      x=(float)ball[num-1].x;

      y=(float)ball[num-1].y;

      addBall(new Ball(m,r,Color.pink,x,y,3.0,1.5,this,t));

      mw.i.addNode(num-1,0,r,c0,c1,c2,0);

      mw.i.UpdateVRML(1,num-1,x,y,0,0,0,0,0);

      addBall(new Ball(m,r,Color.pink,x,y,6.0,3.0,this,t));

      mw.i.addNode(num-1,0,r,c0,c1,c2,0);

      mw.i.UpdateVRML(1,num-1,x,y,0,0,0,0,0);

      addBall(new Ball(m,r,Color.pink,x,y,9.0,4.5,this,t));

      mw.i.addNode(num-1,0,r,c0,c1,c2,0);

      mw.i.UpdateVRML(1,num-1,x,y,0,0,0,0,0);

      addBall(new Ball(m,r,Color.pink,x,y,12.0,6.0,this,t));

      mw.i.addNode(num-1,0,r,c0,c1,c2,0);

      mw.i.UpdateVRML(1,num-1,x,y,0,0,0,0,0);

  }

 

  public void addBall(Ball b) {

    if (num<max) ball[num++] = b;

  }

 

  //  This adds obstacles.

 

  public void addObstacle(Obstacle o) {

    if (numo<max) obstacle[numo++] = o;

  }

 

  public void addGoal(Goal g) {

    if (numg<maxg) goal[numg++] = g;

    if(numg==1) {

        sq.AddtoSlantQueue((int)((goal[0].x%4)+1)); //start with a random slant (can't be empty)

        sq.AddtoSlantQueue((int)((goal[0].y%4)+1)); //and one random slant in queue (can't be empty)

        for(int ww=0;ww<4;ww++) { //Show upcoming slants

            int val=sq.InterrogateSlantQueue(ww);

            if(val>=0 && val<=4) { mw.i.addSlQu(ww,val,false); }

            else if(val==-1) { mw.i.addSlQu(ww,0,false); }

        }

    }

  }

 

  public void loadPhysics() {

    phys[0] = new Physics(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,

                          0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[1] = new Physics(2.125,2.125,-2.125,-2.125,0.0,0.0,0.0,0.0,

                          -1.0,1.0,-1.0,1.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[2] = new Physics(4.25,4.25,-4.25,-4.25,0.0,0.0,0.0,0.0,

                          -2.0,2.0,-2.0,2.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[3] = new Physics(6.375,6.375,-6.375,-6.375,0.0,0.0,0.0,0.0,

                          -3.0,3.0,-3.0,3.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[4] = new Physics(8.5,8.5,-8.5,-8.5,0.0,0.0,0.0,0.0,

                          -4.0,4.0,-4.0,4.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[5] = new Physics(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,

                          0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[6] = new Physics(6.0,-6.0,-6.0,6.0,0.0,0.0,0.0,0.0,

                          -6.0,-6.0,6.0,6.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[7] = new Physics(-6.0,-6.0,6.0,6.0,0.0,0.0,0.0,0.0,

                          -6.0,6.0,6.0,-6.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[8] = new Physics(-6.0,6.0,6.0,-6.0,0.0,0.0,0.0,0.0,

                          6.0,6.0,-6.0,-6.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

    phys[9] = new Physics(6.0,6.0,-6.0,-6.0,0.0,0.0,0.0,0.0,

                          6.0,-6.0,-6.0,6.0,0.0,0.0,0.0,0.0,

                          10,20,30,40,0,0,0,0);

  }

 

  //  This returns the index of the ball nearest to x,y

  //  excluding ex.  (wrap is not taken into account).

 

  int nearestBall(int x, int y, int ex) {

    double d=1e20,t; int j=0;

    for (int i=0; i<num; ++i) {

      t = Ball.hypot(x - ball[i].x, y - ball[i].y);

      if (t < d && i!=ex) { d = t; j = i; }

    }

    return j;

  }

 

  void rotate(int j) {

    double d,mm,dx,dy,tt;

    d = Ball.hypot(ball[j].x-ball[j-1].x,ball[j].y-ball[j-1].y);

    if (d<1e-20) return;     // too close

    mm = ball[j].m + ball[j-1].m;

    if (mm<1e-50 && mm>-1e-50) return;  // too small

    tt = Math.sqrt(20/mm/d)/d;

    dy = tt*(ball[j].x - ball[j-1].x);   // perpendicular direction vector

    dx = tt*(ball[j-1].y - ball[j].y);

 

    ball[j].vx = - dx*ball[j-1].m;

    ball[j].vy = - dy*ball[j-1].m;

  }

 

  // This adjusts the frame of reference so that the total momentum becomes zero.

 

  void zeroMomentum() {

    double mx=0,my=0,M=0;

    for (int i=0; i<num; ++i) {

      mx += ball[i].vx * ball[i].m;

      my += ball[i].vy * ball[i].m;

      M += ball[i].m;

    }

    if (M != 0)

      for (int i=0; i<num; ++i) {

          ball[i].vx -= mx/M;

          ball[i].vy -= my/M;

      }

  }

 

  //  This adjusts the centroid to the center of the canvas.

  //  Note, the "while" loops here could be simply use %= but some

  //  interpreters have bugs with %=.

 

  void centerMass() {

    double x,y,cx=0,cy=0,M=0;

    for (int i=0; i<num; ++i) {

      x = ball[i].x;  y = ball[i].y;

      if (wrapon) {    // if wrap, convert the top 1/4 to negative

          if (x > xsize*0.75) x -= xsize;

          if (y > ysize*0.75) y -= ysize;

      }

      cx += ball[i].x * ball[i].m;

      cy += ball[i].y * ball[i].m;

      M += ball[i].m;

    }

    if (M != 0)

      for (int i=0; i<num; ++i) {

          ball[i].x += xsize/2 - cx/M;

          ball[i].y += ysize/2 - cy/M;

          while (ball[i].x < 0) ball[i].x += xsize;

          while (ball[i].x > xsize) ball[i].x -= xsize;

          while (ball[i].y < 0) ball[i].y += ysize;

          while (ball[i].y > ysize) ball[i].y -= ysize;

      }

  }

}

 

//--------------------------------------------------------------------------------------------

//  The Ball class

 

class Ball {

  double x,y;                    // location

  double z;                            // radius

  double vx,vy;                                // velocity

  Color c;                              // color

  double m;                           // mass

  boolean hit;                   // scratch field

  double ox,oy;                                // old location (for smooth redraw)

  final double vmin = 1e-20;              // a weak force to prevent overlapping

  Animator a;

  boolean iok;                   // image is ok.

  Image img;                     // a bitmap to use in "filled" mode

  int t;             // type of Ball

  int e;             // current effect on the ball

 

  Ball(double mass, double radius, Color color,

       double px, double py, double sx, double sy, Animator an, int typ) {

    m=mass; z=radius-0.5; c=color; t=typ;

    if (z<0.5) z = Math.min(Math.sqrt(Math.abs(m)),Math.min(px,py));

    if (z<0.5) z=0.5;

    x=px; y=py; vx=sx; vy=sy;

    iok = false;

    a = an;

    e = 0;

    if(color==Color.white) t=1;

  }

 

  //  This updates a ball according to the physical universe.

  //  The reason I exempt a ball from gravity during a hit is

  //  to simulate "at rest" equilibrium when the ball is resting

  //  on the floor or on another ball.

 

  void UpdateBall(double dx, double dy) {

      x=dx; y=dy;

  }

 

  void AddBallEffect(int ex) {

      e=ex;

  }

 

  public void update() {

    x += vx;

    if (x+z > a.xsize)

      if (a.wrapon) {

         x -= a.xsize;

      } else {

          if (vx > 0) vx *= a.r;                              // restitution

          vx = -Math.abs(vx)-vmin;     // reverse velocity

          x = a.xsize-z;

          hit = true;

          //  Check if location is completely off screen

          if (x-z > a.xsize) x = a.xsize + z;

      }

    if (x-z < 0)

      if (a.wrapon) x += a.xsize;

      else {

          if (vx < 0) vx *= a.r;      // restitution

          vx = Math.abs(vx)+vmin;     // reverse velocity

          x = z;

          hit = true;

          if (x+z < 0) x = -z;

      }

    y += vy;

    if (y+z > a.ysize) {

      if (a.wrapon) y -= a.ysize;

      else {

        vy = -1*vy;

        y = a.ysize-z;

      }

    }

    if (y-z < 0) {

      if (a.wrapon) {

        y += a.ysize;

      }

      else {

        vy = -1*vy;

        y = z;

      }

          }

    if (a.f > 0 && m != 0) {                              // viscosity

      double t = 100/(100 + a.f*hypot(vx,vy)*z*z/m);

      vx *= t; vy *= t;

    }

    if (!hit) {

       if (e==2) {     // effect of 2 means anti-gravity

         vy -= a.vg;              // if not hit, exert anti-gravity

         vx -= a.hg;

       } else {

         vy += a.vg;             // if not hit, exert gravity

         vx += a.hg;

       }

    }

    hit = false;                   // reset flag

  }

 

  //  This computes the interaction of two balls, either collision

  //  or gravitational force.

 

  public boolean interact(Goal g) {

      double p = g.x - x;

      double q = g.y - y;

      double h2 = p*p + q*q;

      double h = Math.sqrt(h2);

      if (h < z+g.r) {                                          // HIT

              hit = true;

              return true;

      } else {

              return false;

      }

  }

 

  public boolean interact(Ball b) {

    double p = b.x - x;

    double q = b.y - y;

    if (a.wrapon) {            // wrap around, use shortest distance

      if (p > a.xsize/2) p-=a.xsize;

      else if (p < -a.xsize/2) p+=a.xsize;

      if (q > a.ysize/2) q-=a.ysize;

      else if (q < -a.ysize/2) q+=a.ysize;

    }

    double h2 = p*p + q*q;

    double h = Math.sqrt(h2);

    if (a.col) {        // collisions enabled

      if (h < z+b.z) {         // HIT

              hit = b.hit = true;

              if (h > 1e-10) {

                //  Compute the elastic collision of two balls.

 

          double v1,v2,r1,r2,s,t2,v;

            p /= h;  q /= h;                     // normalized impact direction

            v1 = vx*p + vy*q;

            v2 = b.vx*p + b.vy*q;                        // impact velocity

            r1 = vx*q - vy*p;

            r2 = b.vx*q - b.vy*p;                          // remainder velocity

            if (v1<v2) return false;

            s = m + b.m;                                        // total mass

            if (s==0) return false;

          t2 = (v1*m + v2*b.m)/s;

          if(t==0) {

              v = t2 + a.r*(v2 - v1)*b.m/s;

                    vx = v*p + r1*q;

                    vy = v*q - r1*p;

          }

          if(b.t==0) {

                    v = t2 + a.r*(v1 - v2)*m/s;

                    b.vx = v*p + r2*q;

                    b.vy = v*q - r2*p;

          }

              }

      }

    }

    if (a.mg != 0 && h2 > 1e-10 &&

          !hit && !b.hit) {   // gravity is enabled

      double dv;

      if(t==0) {

          dv = a.mg*b.m/h2/h;             // for ver 2.2 added '/h'

          vx += dv*p;

          vy += dv*q;

      }

      if(b.t==0) {

          dv = a.mg*m/h2/h;

          b.vx -= dv*p;

          b.vy -= dv*q;

      }

    }

    return false;

  }

 

  public boolean interact(Obstacle b) {

    double p,q,h,e,n,h2,yadj;

 

    if (a.col) {                                    // collisions enabled

       p = b.x - x;

       q = b.y - y;

       h2 = p*p + q*q;

       h = Math.sqrt(h2);

       p = b.xend - x;

       q = b.yend - y;

       h2 = p*p + q*q;

       e = Math.sqrt(h2);

       if ((b.s >100 || b.s < -100) && x>b.x-z && x<b.xend+z && y>b.y && y<b.yend) { //hit vertical

             hit = true;

             vx = vx*-a.r;

             if(x>b.x){x=b.x+z;} else {x=b.x-z;}

      }

      else if ((b.s <0 && x<b.x && x>b.xend)||(b.s >=0 && x>b.x && x<b.xend)) { //If x within x of obst.

             yadj = b.y + (x-b.x)*b.s;

             p = 0.0;

             q = yadj - y;

             h2 = p*p + q*q;

             n = Math.sqrt(h2);

             if (n < z+b.z) {  // If collide with length of obstacle

                hit = true;

                if (b.s<.001 && b.s>-.001) { //hit horizontal

                    vy = vy*-a.r;

                    if(y>b.y){y=b.y+z;} else {y=b.y-z;}

                } else {

                         if (n > 1e-10) {

                    //  Compute the elastic collision

 

                      double v1,v2,r1,r2,s,t,v;

                      p = b.s*((y-yadj)/2)/n;

                      q = Math.abs(1/b.s)*((yadj-y)/2)/n;   // normalized impact direction

                      v1 = vx*p + vy*q;

                    v2 = (-vx)*p + (-vy)*q;   // impact velocity

                            r1 = vx*q - vy*p;

                    r2 = (-vx)*q - (-vy)*p;                // remainder velocity

                    if (v1<v2) return false;

                    s = m + b.m;                                // total mass

                    if (s==0) return false;

                    t = (v1*m + v2*b.m)/s;

                    v = t + a.r*(v2 - v1)*b.m/s;

                    vx = v*p + r1*q;

                    vy = v*q - r1*p;

                        v = t + a.r*(v1 - v2)*m/s;

                    }

                }

             }

       }

       else if (h < z+b.z) { // If collide with head of obstacle

          hit = true;

          if (h > 1e-10) {

                //  Compute the elastic collision of two balls.

                //  The math involved here is not for the faint of heart!

 

                    double v1,v2,r1,r2,s,t,v;

            p = (b.x - x)/h;  q = (b.y - y)/h;  // normalized impact direction

            v1 = vx*p + vy*q;

            v2 = 0.0*p + 0.0*q;            // impact velocity

            r1 = vx*q - vy*p;

            r2 = 0.0*q - 0.0*p;              // remainder velocity

            if (v1<v2) return false;

            s = m + b.m;                        // total mass

            if (s==0) return false;

            t = (v1*m + v2*b.m)/s;

            v = t + a.r*(v2 - v1)*b.m/s;

            vx = v*p + r1*q;

            vy = v*q - r1*p;

            v = t + a.r*(v1 - v2)*m/s;

          }

       }

       else if (e < z+b.z) {  // If collide with tail of obstacle

          hit = true;

          if (e > 1e-10) {

            //  Compute the elastic collision of two balls.

            //  The math involved here is not for the faint of heart!

 

            double v1,v2,r1,r2,s,t,v;

            p = (b.xend - x)/e;  q = (b.yend - y)/e;   // normalized impact direction

            v1 = vx*p + vy*q;

            v2 = 0.0*p + 0.0*q;   // impact velocity

            r1 = vx*q - vy*p;

            r2 = 0.0*q - 0.0*p;              // remainder velocity

            if (v1<v2) return false;

            s = m + b.m;                        // total mass

            if (s==0) return false;

            t = (v1*m + v2*b.m)/s;

            v = t + a.r*(v2 - v1)*b.m/s;

            vx = v*p + r1*q;

            vy = v*q - r1*p;

            v = t + a.r*(v1 - v2)*m/s;

          }

       }

    }

    return false;

  }

 

  static double hypot(double x,double y) {

    return Math.sqrt(x*x + y*y);

  }

}

 

//--------------------------------------------------------------------------------------------

class Obstacle {

  double x,y;                    // head location

  double xend,yend;  // tail location

  double z;                       // width

  Color c;                         // color

  double m;                      // mass

  double s;                        // slope

  int t;

 

  Obstacle(double mass, double width, Color color,

       double bx, double by, double ex, double ey, int typ) {

    m=mass; z=width; c=color; t=typ;

    if (by<=ey) { x=bx;y=by;xend=ex;yend=ey; }

        else { x=ex;y=ey;xend=bx;yend=by; }

    if(color==Color.white) t=1;

    if(xend==x) {

        s=10000;

    } else {

        s = (yend-y)/(xend-x);

    }

  }

 

  void UpdateObstacle(double dx, double dy) {

      double oldx=x, oldy=y;

      x=dx+((oldx-xend)/2); y=dy+((oldy-yend)/2); xend=dx+((xend-oldx)/2); yend=dy+((yend-oldy)/2);

  }

}

 

//-------------------------------------------------------------------------------------------

class Goal {

  double x,y;    // head location

  double r;      // radius

  int c;         // color

 

  Goal(double radius, int color, double bx, double by) {

    c=color;x=bx;y=by;r=radius;

  }

}

 

class Player {

  long score;    // score

 

  Player() {

    score=0;

  }

 

  public long GetPlayerScore() {

     return score;

  }

 

  public int IncreasePlayerScore(int v) {

     score = score + v;

     return 1;

  }

}

 

class SlantQueue {

  int[] t={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

  int size;      // queue size

  int head;      // head number of queue

  int tail;      // tail number of queue

 

  SlantQueue(int s) {

    size=s;

    head=0;

    tail=0;

  }

 

  public int InterrogateSlantQueue(int slant) {

    if(head+slant+1>size){

        return t[head+slant+1-size];

    } else {

        return t[head+slant+1];

    }

  }

 

  public void AddtoSlantQueue(int slant) {

    tail++;

    if(tail>=size){tail=0;}

    t[tail]=slant;

  }

 

  public int TakeFromSlantQueue() {

    int headval;

    if(head!=tail){

       head++;

       if(head>=size){head=0;}

       headval=t[head];

       t[head]=-1;

       return headval;

    }

    return -1;

  }

}

 

class EffectsQueue {

  long[] t={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};                 // queue values

  int size;      // queue size

  int head;      // head number of queue

  int tail;      // tail number of queue

  int[] e={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};            // queue values

 

  EffectsQueue(int s) {

    size=s;

    head=0;

    tail=0;

  }

 

  public int GetEffectsQueueEffect(int eq) {

    if(head+eq+1>size){

        return e[head+eq+1-size];

    } else {

        return e[head+eq+1];

    }

  }

 

  public long GetEffectsQueueTime(int eq) {

    if(head+eq+1>size){

        return t[head+eq+1-size];

    } else {

        return t[head+eq+1];

    }

  }

 

  public void AddtoEffectsQueue(long eqt, int eqe) {

    int f=head;

    int x=0;

    boolean found=false;

   

    tail++;

    if(tail>=size){tail=0;}

    while(!found && f!=tail) { //Find appropriate place in queue

        if(t[f]>eqt) {

            found=true; //f is the right place

        } else {

            f++;

            if(f>=size){f=0;}

        }

    }

    if(!found) {

        t[tail]=eqt;  //if not found, tail is right place

        e[tail]=eqe;

    } else {

        x=tail;       //if found, work back to make room for f

        while(x!=f) {

           if(x==0) {

              t[0]=t[size-1];

              e[0]=e[size-1];

              x=size-1;

           } else {  

              t[x]=t[x-1];

              e[x]=e[x-1];

              x--;

           }

        }

        t[f]=eqt;    // fill f with new queue item

        e[f]=eqe;

    }   

  }

 

  public int TakeFromEffectsQueue() {

    if(head!=tail){

       head++;

       if(head>=size){head=0;}

       return e[head];

    }

    return 0;

  }

}

 

class Effects {

  String[] es={"","","","","","","","","","","","","","","","","","","",""};  // VRMLstrings

  int maxe;

 

  Effects(int m) {

      maxe = m;

      es[0] = " 1 1 0 transparency 1 }\n" +  "         }\n" + //already used

              "         geometry Sphere {radius 30}\n";

      es[1] = " 1 1 0 }\n" +  "         }\n" +                //no collision

              "           geometry IndexedFaceSet {\n" +

              "              coord Coordinate { point [\n" +

              "                71.01 39.43 0, 92.72 -21.44 0, 67 0.9883 0, 64.59 -22.23 0, \n" +

              "                46.94 -4.622 0, 40.54 -20.62 0, 29.33 -2.231 0, 6.145 -28.59 0, \n" +

              "                -27.35 0.934 0, -44.85 -21.38 0, -50.42 4.107 0, -67.09 -10.23 0, \n" +

              "                -69.47 12.05 0, -98.79 -1.492 0, -70.27 45.47 0, -21.77 14.49 0, \n" +

              "                31.73 15.36 0, 71.01 39.43 20, 92.72 -21.44 20, \n" +

              "                67 0.9883 20, 64.59 -22.23 20, 46.94 -4.622 20, 40.54 -20.62 20, \n" +

              "                29.33 -2.231 20, 6.145 -28.59 20, -27.35 0.934 20, \n" +

              "                -44.85 -21.38 20, -50.42 4.107 20, -67.09 -10.23 20, -69.47 12.05 20, \n" +

              "                -98.79 -1.492 20, -70.27 45.47 20, -21.77 14.49 20, 31.73 15.36 20]\n" +

              "              }\n" +

              "              coordIndex [\n" +

              "                17, 18, 1, 0 -1, 18, 19, 2, 1, -1, 19, 20, 3, 2, -1, \n" +

              "                20, 21, 4, 3, -1, 21, 22, 5, 4, -1, 22, 23, 6, 5, -1, \n" +

              "                23, 24, 7, 6, -1, 24, 25, 8, 7, -1, 25, 26, 9, 8, -1, \n" +

              "                26, 27, 10, 9, -1, 27, 28, 11, 10, -1, 28, 29, 12, 11, \n" +

              "                -1, 29, 30, 13, 12, -1, 30, 31, 14, 13, -1, 31, 32, \n" +

              "                15, 14, -1, 32, 33, 16, 15, -1, 33, 17, 0, 16, \n" +

              "                -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, \n" +

              "                -1, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \n" +

              "                -1]\n" +

              "              }\n";

      es[2] = " 1 0 1 }\n" +  "         }\n" +                //anti-gravity

              "         geometry IndexedFaceSet {\n" +

                          " coord Coordinate { point [\n" +

                          " 51.09 5.645 0, 21.21 6.609 0, 21.21 -44.48 0, -18.32 -44.48 0, \n" +

                          " -18.32 5.645 0, -58.8 5.645 0, 1.928 65.4 0, 51.09 5.645 20, \n" +

                          " 21.21 6.609 20, 21.21 -44.48 20, -18.32 -44.48 20, \n" +

                          " -18.32 5.645 20, -58.8 5.645 20, 1.928 65.4 20]\n" +

                          " }\n" +

                          " coordIndex [\n" +

                          " 7, 8, 1,, 0, -1, 8, 9, 2, 1 -1, 9, 10, 3, 2, -1, 10, 11, 4, \n" +

                          " 3, -1, 11, 12, 5, 4, -1, 12, 13, 6, 5, -1, 13, 7, 0, 6, \n" +

                          " -1, 5, 6, 0, 1, 2, 3, 4, -1, 10, 9, 8, 7, 13, 12, 11, -1]\n" +

                        "}\n";

      es[3] = " 1 0 0 }\n" +  "         }\n" +                //stop (pause)

                          "   geometry DEF NGon01-FACES IndexedFaceSet {\n" +

                          "      coord DEF NGon01-COORD Coordinate { point [\n" +

                          "         64.29 0 0, 45.46 -45.46 0, 0 -64.29 0, -45.46 -45.46 0, \n" +

                          "         -64.29 0 0, -45.46 45.46 0, 0 64.29 0, 45.46 45.46 0, \n" +

                          "         64.29 0 20, 45.46 -45.46 20, 0 -64.29 20, -45.46 -45.46 20, \n" +

                          "         -64.29 0 20, -45.46 45.46 20, 0 64.29 20, 45.46 45.46 20]\n" +

                          "       }\n" +

                          "       coordIndex [\n" +

                          "         8, 9, 1, 0, -1, 10, 9, 2, 1, -1, 10, 11, 3, 2, -1, \n" +

                          "         11, 12, 4, 3, -1, 12, 13, 5, 4, -1, 13, 14, 6, 5, -1, \n" +

                          "         14, 15, 7, 6, -1, 15, 8, 0, 7, -1, 7, 0, 1, 2, 3, 4, 5, 6, \n" +

                          "         -1, 13, 12, 11, 10, 9, 8, 15, 14, -1]\n" +

                          "       }\n";

      es[4] = " 1 1 1 }\n" +  "         }\n" +                //goal stealing

              "          geometry DEF Line01-FACES IndexedFaceSet {\n" +

              "              coord DEF Line01-COORD Coordinate { point [\n" +

              "                10.74 3.404 0, 25.14 40.18 0, 38.76 36.21 0, 29.15 -0.5878 0, \n" +

              "                52.4 8.221 0, 61.23 -4.585 0, 35.56 -31.78 0, 11.54 -48.53 0, \n" +

              "                13.14 -68.51 0, -11.62 -67.64 0, -10.83 -46.89 0, -41.91 -26.91 0, \n" +

              "                -55.43 20.91 0, -45.89 26.5 0, -30.76 -3.789 0, -37.13 37.67 0, \n" +

              "                -22.79 41.68 0, -13.22 0.2021 0, -14.02 42.5 0, 5.946 41.74 0, \n" +

              "                10.74 3.404 20, 25.14 40.18 20, 38.76 36.21 20, \n" +

              "                29.15 -0.5878 20, 52.4 8.221 20, 61.23 -4.585 20, \n" +

              "                35.56 -31.78 20, 11.54 -48.53 20, 13.14 -68.51 20, \n" +

              "                -11.62 -67.64 20, -10.83 -46.89 20, -41.91 -26.91 20, -55.43 20.91 20, \n" +

              "                -45.89 26.5 20, -30.76 -3.789 20, -37.13 37.67 20, -22.79 41.68 20, \n" +

              "                -13.22 0.2021 20, -14.02 42.5 20, 5.946 41.74 20]\n" +

              "              }\n" +

              "              coordIndex [\n" +

              "                20, 21, 1, 0, -1, 21, 22, 2, 1, -1, 22, 23, 3, 2, -1, \n" +

              "                23, 24, 4, 3, -1, 24, 25, 5, 4, -1, 25, 26, 6, 5, -1, \n" +

              "                26, 27, 7, 6, -1, 27, 28, 8, 7, -1, 28, 29, 9, 8, -1, \n" +

              "                29, 30, 10, 9, -1, 30, 31, 11, 10, -1, 31, 32, 12, \n" +

              "                11, -1, 32, 33, 13, 12, -1, 33, 34, 14, 13, -1, 34, \n" +

              "                35, 15, 14, -1, 35, 36, 16, 15, -1, 36, 37, 17, 16, \n" +

              "                -1, 37, 38, 18, 17, -1, 38, 39, 19, 18, -1, 39, 20, \n" +

              "                0, 19, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, \n" +

              "                19, 0, 1, 2, 3, 4, 5, 6, 7, -1, 26, 25, 24, 23, 22, 21, \n" +

              "                20, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, -1]\n" +

              "              }\n";

      es[5] = " 0 1 1 }\n" +  "         }\n" +                //add an obstacle

              "         geometry DEF Line01-FACES IndexedFaceSet {\n" +

              "          coord DEF Line01-COORD Coordinate { point [\n" +

              "            -50 0 -18, 49 0 -18, 50 0 2.5, 55 0 7.5, \n" +

              "            40 0 7.5, 46 0 2.5, 45 0 -3, -45 0 -2.5, \n" +

              "            -45 0 2.5, -40 0 8, -55 0 8, -50 0 3, \n" +

              "            -50 12 -18, 49 12 -18, 50 12 2.5, 55 12 7.5, \n" +

              "            40 12 7.5, 46 12 2.5, 45 12 -3, -45 12 -2.5, \n" +

              "            -45 12 2.5, -40 12 8, -55 12 8, -50 12 3] \n" +

              "          }\n" +

              "          coordIndex [\n" +

              "            12, 13, 1, 0, -1, 13, 14, 2, 1, -1, \n" +

              "            14, 15, 3, 2, -1, 15, 16, 4, 3, -1, 16, 17, 5, 4, -1, \n" +

              "            17, 18, 6, 5, -1, 18, 19, 7, 6, -1, 19, 20, 8, 7, -1, \n" +

              "            20, 21, 9, 8, -1, 21, 22, 10, 9, -1, 22, 23, 11, 10, \n" +

              "            -1, 23, 12, 0, 11, -1, 4,5,6,7,8,9,10,11,0,1,2,3,-1,\n" +

              "            14,13,12,23,22,21,20,19,18,17,16,15,-1]\n" +

              "          }\n";

      es[6] = " 1 1 1 }\n" +  "         }\n" +                //bigger ball

              "         geometry Sphere {radius 50}\n";

      es[7] = " .00001 0 0 }\n" +  "         }\n" +           //goal clearing

              "         geometry Sphere {radius 30}\n";

  }

 

  public String GetEffectsString(int en) {

    if(en < maxe) {

         return es[en];

    }

    return null;

  }

}

 

class Pieces {

  String[] ps={"","","","","","","","","","","","","","","","","","","",""};  // VRMLstrings

  int maxp;

 

  Pieces(int m) {

      maxp = m;

      ps[0] = "0 0 1 transparency 1 }\n" +  "         }\n" +

              "         geometry Sphere {radius 30}\n";

      ps[1] = "1 0 1 }\n" +  "         }\n" +

              "         geometry Sphere {radius 20}\n";

      ps[2] = "1 1 0 }\n" +  "         }\n" +

              "         geometry IndexedFaceSet {\n" +

              "          coord Coordinate { point [\n" +

              "            -50 0 2, 49 0 2, 50 0 22.5, 55 0 27.5, \n" +

              "            40 0 27.5, 46 0 22.5, 45 0 17, -45 0 17.5, \n" +

              "            -45 0 22.5, -40 0 28, -55 0 28, -50 0 23, \n" +

              "            -50 16 2, 49 16 2, 50 16 22.5, 55 16 27.5, \n" +

              "            40 16 27.5, 46 16 22.5, 45 16 17, -45 16 17.5, \n" +

              "            -45 16 22.5, -40 16 28, -55 16 28, -50 16 23] \n" +

              "          }\n" +

              "          coordIndex [\n" +

              "            12, 13, 1, 0, -1, 13, 14, 2, 1, -1, \n" +

              "            14, 15, 3, 2, -1, 15, 16, 4, 3, -1, 16, 17, 5, 4, -1, \n" +

              "            17, 18, 6, 5, -1, 18, 19, 7, 6, -1, 19, 20, 8, 7, -1, \n" +

              "            20, 21, 9, 8, -1, 21, 22, 10, 9, -1, 22, 23, 11, 10, \n" +

              "            -1, 23, 12, 0, 11, -1, 4,5,6,7,8,9,10,11,0,1,2,3,-1,\n" +

              "            14,13,12,23,22,21,20,19,18,17,16,15,-1]\n" +

              "          }\n";

      ps[3] = "1 1 0 }\n" +  "         }\n" +

              "         geometry IndexedFaceSet {\n" +

              "          coord Coordinate { point [\n" +

              "            0 -50 2, 0 49 2, 0 50 22.5, 0 55 27.5, \n" +

              "            0 40 27.5, 0 46 22.5, 0 45 17, 0 -45 17.5, \n" +

              "            0 -45 22.5, 0 -40 28, 0 -55 28, 0 -50 23, \n" +

              "            16 -50 2, 16 49 2, 16 50 22.5, 16 55 27.5, \n" +

              "            16 40 27.5, 16 46 22.5, 16 45 17, 16 -45 17.5, \n" +

              "            16 -45 22.5, 16 -40 28, 16 -55 28, 16 -50 23] \n" +

              "          }\n" +

              "          coordIndex [\n" +

              "            12, 13, 1, 0, -1, 13, 14, 2, 1, -1, \n" +

              "            14, 15, 3, 2, -1, 15, 16, 4, 3, -1, 16, 17, 5, 4, -1, \n" +

              "            17, 18, 6, 5, -1, 18, 19, 7, 6, -1, 19, 20, 8, 7, -1, \n" +

              "            20, 21, 9, 8, -1, 21, 22, 10, 9, -1, 22, 23, 11, 10, \n" +

              "            -1, 23, 12, 0, 11, -1, 4,5,6,7,8,9,10,11,0,1,2,3,-1,\n" +

              "            14,13,12,23,22,21,20,19,18,17,16,15,-1]\n" +

              "          }\n";

              // "         geometry Box {size 20 100 20}\n";

      ps[4] = ps[2];

      ps[5] = ps[2];

      ps[6] = "1 1 1 }\n" +  "         }\n" +

              "         geometry Sphere {radius 40}\n";

      ps[7] = "0 1 1 }\n" +  "         }\n" +

              "         geometry Sphere {radius 20}\n";

      ps[8] = "1 1 0 }\n" +  "         }\n" +

              "         geometry Sphere {radius 20}\n";

  }

 

  public String GetPiecesString(int pn) {

    if(pn < maxp) {

         return ps[pn];

    }

    return null;

  }

}

 

class Arsenal {

  int[] a={0,0,0,0,0,0,0,0,0,0};         // e values

  int numa;

  int maxa;

 

  Arsenal(int m) {

    numa=0;

    maxa=m;

  }

 

  public int AddToArsenal(int ae) {

    if(numa<maxa){

        a[numa]=ae;

        numa++;

        return 1;

    }

    return 0;

  }

 

  public int ReadFromArsenal(int ae) {

    if(ae<maxa) {

        return a[ae];

    }

    return 0;

  }

 

  public int TakeFromArsenal(int ae) {

    int n;

    if(ae<maxa) {

          n=a[ae];

          a[ae]=0;

          return n;

    }

    return 0;

  }

}

 

class Physics {

  double[] x = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; // x increment

  double[] y = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; // y increment

  int[] t = {0,0,0,0,0,0,0,0}; // max time

 

  Physics(double x0, double x1, double x2, double x3, double x4, double x5, double x6,

          double x7, double y0, double y1, double y2, double y3, double y4, double y5,

          double y6, double y7, int t0, int t1, int t2, int t3, int t4, int t5, int t6,

          int t7 ) {

 

    x[0]=x0;x[1]=x1;x[2]=x2;x[3]=x3;x[4]=x4;x[5]=x5;x[6]=x6;x[7]=x7;

    y[0]=y0;y[1]=y1;y[2]=y2;y[3]=y3;y[4]=y4;y[5]=y5;y[6]=y6;y[7]=y7;

    t[0]=t0;t[1]=t1;t[2]=t2;t[3]=t3;t[4]=t4;t[5]=t5;t[6]=t6;t[7]=t7;

  }

}

 

class PieceList {

  int[] l={0,0,0,0,0,0,0,0,0,0};          // e values

  int nump;

  int maxp;

 

  PieceList(int m) {

    nump=0;

    maxp=m;

  }

 

  public int AddtoPieceList(int pe) {

    if(nump<maxp){

        l[nump++]=pe;

        return 1;

    }

    return 0;

  }

}

 

class EffectList {

  int[] l={0,0,0,0,0,0,0,0,0,0};          // e values

  int nume;  //max Effects

  int maxe;

 

  EffectList(int m) {

    nume=0;

    maxe=m;

  }

 

  public int AddtoEffectList(int pe) {

    if(nume<maxe){

        l[nume++]=pe;

        return 1;

    }

    return 0;

  }

}

 

class Rules {

  int gov=0;               // communications type

  int regov=0;           // whether to choose a different communication type for next round

  //int vetos=0;         // number of vetos allowed

  //int portals=0;       // portal rules type

  int order=0;           // order of play

  int winning=0;         // rules for winning

  int roundtype=1;       // rulestype of round: 0-competitive, 1-collaborative, 2-teams

  int end=0;             // rules for end of round

  int slantQmgmt=0;      // Slant Queue Management Type

  boolean slantQclear=true; // Slant Queue Cleared Between Rounds

  double gravity=0.0;    // value of gravity parameter

  double viscosity=0.0;  // value of viscosity parameter

  double restitution=0.0; // value of restitution parameter

  int timelimit=0;       // time limit for a round

  int queuedelay=0;      // delay for event queue after select

  int dictator=0;        // number of player who is dictator

 

  Rules() {

  }

}

 

//-------------------------------------------------------------------

//  To use the Ticker class, create an object and create a thread

//  to run it.      Thereafter, any other thread can use it as a

//  pacemaker.

 

class Ticker implements Runnable {

  int t;                              // ticks elapsed

  int speed=20;                // animation rate

 

  Ticker(Panel p) {

    speed=20;

  }

  public void run() {

    while (true) {

      try { Thread.sleep(speed); }

      catch (InterruptedException e) {}

    }

  }

  public void setSpeed(int s) {

    speed = s;

  }

  public int getSpeed() {

    return speed;

  }

  void poll(int eat) {        // poll for non-zero tick

    while (t==0) {

      try { Thread.sleep(speed); }

      catch (InterruptedException e) {}

      t++;

    }

    if (eat > t) t = 0;

    else t-=eat;

  }

  void poll() { poll(30000); }

}

 

// Connect to world server to exchange information

class PortToServer extends NetPortToServer {

       Marbles i;

       int playerno;

       int goalx;

       int goalcount;

       public PortToServer (String host, int port, Marbles i_in) throws IOException {

            super (host,port);

            i = i_in;

            playerno = -1;

            goalcount=0;

       }

 

       protected void readInput() throws IOException {

           String line = readUTF();

           i.showStatus("LINE= " + line);

           int value;

           int value2,value3,value4;

           value = line.charAt(0);

           if (value=='0') {  //players

                if(playerno == -1) {

                    playerno = Integer.parseInt("" + line.charAt(1));

                    i.pn = playerno;

                }

                i.numplay = Integer.parseInt("" + line.charAt(1));

                i.sim_type = Integer.parseInt("" + line.charAt(2));

           } else if (value=='1') { //rules

               value=Integer.parseInt("" + line.charAt(1)+ line.charAt(2)+ line.charAt(3));

               value2=Integer.parseInt("" + line.substring(7));

               //Process Value from Previous Question

               if(value==101) { i.b.anim.rules.gov = value2; }

               else if(value==103) {

                   i.b.grav.setText("" + (value2/1000) + " seconds to choose");

               } //server maintains time limit for choosing

               else if(value==104) {

                   value2++;

                   i.b.grav.setText("Max " + value2 + " Pieces");

                   i.pl.maxp=value2;

               }

               else if(value==105) {

                   value2++;

                   i.b.grav.setText("Max " + value2 + " Events");

                   i.el.maxe=value2;

               }

               else if(value==106) {

                   value2++;

                   i.b.grav.setText("Max " + value2 + " in Arsenal");

                   i.b.anim.ars.maxa=value2;

               }

               else if(value==107) {

                   i.b.anim.rules.slantQmgmt=value2;

               }

               else if(value==108) {

                   if(value2==0) { i.b.anim.rules.slantQclear=false; }

                   else { i.b.anim.rules.slantQclear=true; }

 

               }

               else if(value==109) {

                   if(value2==0)      { i.b.anim.sqt=20; }

                   else if(value2==1) { i.b.anim.sqt=40; }

                   else if(value2==2) { i.b.anim.sqt=60; }

                   else if(value2==3) { i.b.anim.sqt=80; }

                   else if(value2==4) { i.b.anim.sqt=100; }

                   else if(value2==5) { i.b.anim.sqt=120; }

                   else if(value2==6) { i.b.anim.sqt=150; }

                   i.b.grav.setText("slant queue changes every " + i.b.anim.sqt + " frames");

               }

               else if(value==110) {

                   i.b.anim.rules.winning=value2;

               }

               else if(value==111) {

                   i.b.anim.rules.roundtype=value2;

               }

               else if(value==112) {

                   if(value2==0)      { i.b.anim.eql=20; }

                   else if(value2==1) { i.b.anim.eql=30; }

                   else if(value2==2) { i.b.anim.eql=40; }

                   else if(value2==3) { i.b.anim.eql=50; }

                   else if(value2==4) { i.b.anim.eql=60; }

                   else if(value2==5) { i.b.anim.eql=70; }

                   i.b.grav.setText("effects active after " + i.b.anim.eql + " frames");

               }

               else if(value==113) {

                   if(value2==0)      { i.b.anim.eqd=40; }

                   else if(value2==1) { i.b.anim.eqd=60; }

                   else if(value2==2) { i.b.anim.eqd=80; }

                   else if(value2==3) { i.b.anim.eqd=100; }

                   else if(value2==4) { i.b.anim.eqd=120; }

                   else if(value2==5) { i.b.anim.eqd=150; }

                   i.b.grav.setText("effects active for " + i.b.anim.eqd + " frames");

               }

               else if(value==114) {

                   i.b.anim.g=.1 + value2*.04;

                   i.b.grav.setText("gravity coefficient= " + i.b.anim.g);

               }

               else if(value==115) {

                   i.b.anim.r=.5 + value2*.05;

                   i.b.grav.setText("restitution coefficient= " + i.b.anim.r);

               }

               else if(value==116) {

                   i.b.anim.bm=5 + value2*10;

                   i.b.grav.setText("mass coefficient= " + i.b.anim.bm);

               }

               else if(value==117) {

                   i.b.anim.f=value2*.005;

                   i.b.grav.setText("viscosity coefficient= " + i.b.anim.f);

               }

               else if(value==200) {

                   i.pl.AddtoPieceList(value2);

               }

               else if(value==201) {

                   i.el.AddtoEffectList(value2);

               }

               i.qno=Integer.parseInt("" + line.charAt(4)+ line.charAt(5)+ line.charAt(6));

               if(i.sim_type==0) {

                  if(i.qno<200) { i.b.show(); }

                  if(i.qno==102) { i.b.Qlibrary(); }

                  else if(i.qno==103) { i.b.Qctime(); }

                  else if(i.qno==104) { i.b.QnumPieces(); }

                  else if(i.qno==105) { i.b.QnumEvents(); }

                  else if(i.qno==106) { i.b.QnumArsenal(); }

                  else if(i.qno==107) { i.b.QslantQtype(); }

                  else if(i.qno==108) { i.b.QslantQwrap(); }

                  else if(i.qno==109) { i.b.QslantQtime(); }

                  else if(i.qno==110) { i.b.Qwinning(); }

                  else if(i.qno==111) { i.b.QnextRound(); }

                  else if(i.qno==112) { i.b.QeventQlag(); }

                  else if(i.qno==113) { i.b.QeventDuration(); }

                  else if(i.qno==114) { i.b.Qgravity(); }

                  else if(i.qno==115) { i.b.Qrestitution(); }

                  else if(i.qno==116) { i.b.Qmass(); }

                  else if(i.qno==117) { i.b.Qviscosity(); }

                  else if(i.qno==200) { i.b.Qpieces();

                                     i.b.hide();

                                     i.b.pwindow.setTitle("Choose Pieces");

                  }

                  else if(i.qno==201) { i.b.Qeffects();

                                     i.b.hide();

                                     i.b.pwindow.setTitle("Choose Effects");

                  }

                  else if(i.qno==999) { i.b.pwindow.hide(); i.b.hide(); }

               }

           } else if (value=='2') { //slant queue

                i.b.anim.sq.AddtoSlantQueue(Integer.parseInt("" + line.charAt(1)));

                i.turncolor++;

                if(i.turncolor>i.numplay) {i.turncolor=1;}

                i.UpdateColor(0,i.turncolor);

           } else if (value=='3') { //events queue

                i.b.anim.eq.AddtoEffectsQueue(Integer.parseInt("" + line.substring(4)),

                     Integer.parseInt("" + line.charAt(1)+ line.charAt(2)+ line.charAt(3)));

           } else if (value=='4') { //objects

                value=Integer.parseInt("" + line.charAt(3)+ line.charAt(4)+ line.charAt(5))-100;

                value2=Integer.parseInt("" + line.charAt(2));

                i.removeChildren[value].setValue(i.pieceshape[value]);

                if (value2==1) {

                   i.b.anim.addBall(new Ball(64,18,Color.white,0,0,0.0,0.0,i.b.anim,1));

                   i.addNode(value,1,0,1,0,1,0);

                } else if (value2==2) {

                   i.b.anim.addObstacle(new Obstacle(64,5,Color.gray,-50,0,50,0,0));

                   i.addNode(value,2,0,-50,0,50,0);

                } else if (value2==3) {

                   i.b.anim.addObstacle(new Obstacle(64,5,Color.gray,0,50,0,-50,0));

                   i.addNode(value,3,0,0,50,0,-50);

                } else if (value2==4) {

                   i.b.anim.addObstacle(new Obstacle(64,5,Color.gray,35,35,-35,-35,0));

                   i.addNode(value,4,0,0,0,0,0);

                } else if (value2==5) {

                   i.b.anim.addObstacle(new Obstacle(64,5,Color.gray,-35,35,35,-35,0));

                   i.addNode(value,5,0,0,0,0,0);

                } else if (value2==6) {

                   i.b.anim.addBall(new Ball(64,40,Color.pink,0,0,0.0,0.0,i.b.anim,4));

                   i.addNode(value,0,40,1,1,1,0);

                } else if (value2==7) {

                   i.b.anim.addMoving(64,20,0,0,2,0,1,1);

                } else if (value2==8) {

                   i.b.anim.addMoving(4,20,0,0,8,1,1,0);

                }

                value3=Integer.parseInt("" + line.charAt(6)+ line.charAt(7)+ line.charAt(8) + line.charAt(9))-1000;

                value4=Integer.parseInt("" + line.charAt(10)+ line.charAt(11)+ line.charAt(12) + line.charAt(13))-1000;

                i.UpdateVRML(1,value,value3,value4,0,0,0,0,0);  //Update visual

                if(value>=50) {   //Update virtual machine

                     i.b.anim.obstacle[value-50].UpdateObstacle(value3,value4);

                }

                else {

                     i.b.anim.ball[value].UpdateBall(value3,value4);

                }

                i.turncolor = Integer.parseInt("" + line.charAt(1));

                i.UpdateColor(0,i.turncolor);

           } else if (value=='6') { //goals

                value3=Integer.parseInt("" + line.charAt(1)+ line.charAt(2)+ line.charAt(3) + line.charAt(4))-1000;

                value4=Integer.parseInt("" + line.charAt(5)+ line.charAt(6)+ line.charAt(7) + line.charAt(8))-1000;

                i.b.anim.addGoal(new Goal(20,5,value3,value4));

                i.addGoal(goalcount,5,value3,value4);

                goalcount++;

           } else if (value=='8') { //timer speed

                i.b.anim.tick.setSpeed(Integer.parseInt("" + line.substring(1)));

                i.b.anim.timeOK=true;

           } else if (value=='9') { //world mode

                i.mode = Integer.parseInt("" + line.charAt(1));

                if(i.mode==3) {

                    i.b.anim.theDate = new Date();

                    i.b.anim.starttime = i.b.anim.theDate.getTime();

                }

                i.lastmodesent = 1;

                i.Paletize(i.mode);

           }

       }

 

       protected void writeToServer(String outgoing) {

           try {

               writeUTF(outgoing);

               flush();

           }

           catch(IOException e) {}

       }

}