/*
 *                 [[ W4K ]]
 *
 * Copyright (c) 2006 Glenn Sanson.
 *
 * This code is distributed under the GNU General Public License 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2, as published by the Free Software Foundation.
 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * This game is an entry of the javaunlimited.net 4K contest '06
 
 * How to build W4K.jar yourself :
 * > Compile with a java 1.4 target
 *     javac -source 1.4 -target 1.4 W.java
 * > Make a jar file
 *     jar cvf W4K.jar W.class
 * > Use JoGa v0.1(a) [http://www.nq4.de/] to optimize jar
 *     java -jar JoGa.jar (this creates a ./JoGaDIR/W4K_JOGA.jar file)
 * > Unzip W.class from the W4K_JOGA.jar file with 7-zip [http://www.7-zip.org/] or another tool
 *     7za x W4K_jg.jar W.class
 * > Create a META-INF/MANIFEST.MF file 
 *     Main-Class: W (+ 2 empty lines, or it won't work)
 * > Zip it again with Z-zip
 *     7za a -tzip -mx=9 W4K_final.jar W.class META-INF/MANIFEST.MF
 *
 * You should now have a 4096 bytes file named W4K_final.jar 
 *          
 *          [[ http://glenn.sanson.free.fr/w4k/ ]]
 */

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.util.Random;

public class extends Frame implements WindowListener, KeyListener {
        
    Image b; // Double buffer        
    int k; // keyboard management
        
    public W() {
        super("W4K");

        boolean computer = true;
        boolean demo = true;
        
        int[] m = new int[287809];
        Random rand = new Random(System.currentTimeMillis());
        
        MemoryImageSource source = new MemoryImageSource(641449, m, 0641);
        source.setAnimated(true);
        Image img = createImage(source);        
        
        setVisible(true);
        setResizable(false);
        setSize(641449);
        b = createImage(641449);
        Graphics g = b.getGraphics();        
        addWindowListener(this);
        addKeyListener(this);        
        
        while(true) {
            
            int tmpVar = 64;
            
            for (int y=0; y<449 ; y+=tmpVar) {
                for (int x=0; x<641 ; x+=tmpVar) {
                    m[y * 641 + x= rand.nextInt() 256;
                }
            }
            
            for (;tmpVar > ; tmpVar = tmpVar >> 1) {
                for (int y=; y<449 ; y+=tmpVar) {
                    for (int x=tmpVar ; x<641 ; x+=tmpVarm[y*641 + x-(tmpVar >> 1)] (m[y*641 + x-tmpVar+ m[y*641 + x]) >> 1;
                }
                
                for (int y=tmpVar ; y<449 ; y+=tmpVar) {
                    for (int x=; x<641 ; x+=(tmpVar >> 1)) m[(y - (tmpVar >> 1)) 641 + x(m[(y - tmpVar)*641 + x+ m[y * 641 + x]) >> 1;
                }
            }
            
            for (int i=; i<287809 ; i++) {
                if (m[i0) {
                    int top = 1;
                    while(i - top * 641 && m[i - top * 6410xFF0000FFtop++;
                    
                    int bottom = 1;
                    while (i + bottom * 641 287809 && m[i + bottom * 6410bottom++;
                                    
                    if (top < 5m[i= rand.nextInt()>0xFF0DAB0D 0xFF00C800;
                    // Retirer ce cas si pb pour atteindre 4Ko 
                    else if (top == 5)    m[i0xFF007848;
                    else {
                        if (i % 10 == 0m[i0xFFE89058;
                        else m[i(i/10)%== 0xFF985818 0xFFC07830;
                        
                        tmpVar = Math.min(bottom, 16);
                        tmpVar = ((tmpVar * tmpVar>> 3+ rand.nextInt() 10;
                        
                        m[i0xFF000000 
                        (Math.min(255((m[i>> 160xFF+ tmpVar<< 16)
                        (Math.min(255((m[i>> 80xFF+ tmpVar<< 8
                        + Math.min(255(m[i0xFF+ tmpVar);
                    }
                }
                else m[i0xFF0000FF ((i / 641>> 1);
            }
            
            source.newPixels(00641449false);
                            
            // Init worms
            int[][] p = new int[8][8];
            
            // 0, 1 -> Worm position [x, y]
            // 2 -> Direction -1 = left / 1 = right 
            // 3 -> Used for body animation
            // 4 -> Weapon direction in degrees (-90 -> +90)
            // 5 -> Life (init : 100)
            // 6, 7 -> Movement (Explosion)
            
            for (int i=; i<; i++) {
                tmpVar = 0;
                p[i][0320 + rand.nextInt() 300;
                p[i][1220 + rand.nextInt() 200;
    
                while (tmpVar < || m[p[i][0641 (p[i][11)] 0xFF0000FF) {
                    if (m[p[i][0641 * p[i][1]] 0xFF0000FF || (p[i][1449 10) ) {
                        tmpVar = 0;
                        p[i][0320 + rand.nextInt() 300;
                        p[i][1220 + rand.nextInt() 200;
                    }
                    
                    tmpVar++;
                    p[i][1]++;
                }
                p[i][2= -1;
                p[i][5100;
            }        
            
            // Names : Beatles against Daltons
            String[] names = {"John""Joe""Paul""Jack""George""William""Ringo""Averell"};
                    
            int x = 0;
            int y = 0;
            int e = 0;
            
            int power = 0;
            double[] ball = new double[4]// Ball
            ball[0= -1.;
            
            int currentPlayer = 0;
            int refPlayer = 0;
            boolean fired = false;            
            
            tmpVar = 0;
            
            boolean victory = false;
            boolean play = true;
            int blink = 0;
            k = 0;
            
            while (play) {
                long time = System.currentTimeMillis();
                boolean noMoreAction = true;
                
                // Controls demo
                if (demo & k == 38computer = true;
                if (demo & k == 40computer = false;
                if (demo & (k == 32 | k == 10)) {
                    demo = false;
                    victory = true;
                    k = -1;
                }
                
                // Action
                for (int player=; player<; player++) {
                    if (victory & k == -1play = false;
                    if (victory & k == 32) {
                        play = false;
                        demo = true;
                    }
                    else if (p[player][00)// Elimine de la carte
                    else if (p[player][6!= || p[player][7!= 0) {
                        if (p[player][0+ p[player][6
                              || p[player][0+ p[player][6641
                              || p[player][1+ p[player][75
                              || p[player][1+ p[player][7449) {
                            p[player][60;
                            p[player][70;
                            p[player][0= -100;
                            fired = true// Change player
                        }
                        else if (m[p[player][0+ p[player][6(p[player][1+ p[player][7]) 6410xFF0000FF) {
                            p[player][60;
                            p[player][70;
                            noMoreAction = false;
                        }
                        else if (m[p[player][0+ p[player][16410xFF0000FF) {
                            double dx = ((double)p[player][6]) 20.;
                            double dy = ((double)p[player][7]) 20.;
    
                            boolean wall = false;
                            for (int i=; i<20 ; i++)
                                wall |= m[p[player][0(int)(i * dx(p[player][1(int)(i * dy)) 6410xFF0000FF;
    
                            if (wall) {
                                p[player][60;
                                p[player][70;
                            }
    
                            p[player][0+= p[player][6];
                            p[player][1+= p[player][7];                        
                            noMoreAction = false;         
                            
                            if (!wallp[player][7]++;
                        }
                        else {                        
                            p[player][0+= p[player][6];
                            p[player][1+= p[player][7];
                            p[player][7]++;
                            noMoreAction = false;
                        }
                    }
                    else if (m[p[player][0(p[player][116410xFF0000FF) {
                        p[player][71;
                        noMoreAction = false;
                    }
                    else if (player != currentPlayer);
                    // Computer 
                    else if (!fired & (demo | (computer & player % == 1)) & power < tmpVar) {
                        power += 5;
                    }
                    else if (!fired & (demo | (computer & player % == 1)) & tmpVar == 0) {
                        // Find nearest worm
                        int nearest = -1;
                        int dist = << 24;
                        
                        for (int i=((currentPlayer % 2)) ; i<; i+= 2) {
                            if (p[i][0&& p[i][50) {
                                int newDist = (p[player][0- p[i][0]) (p[player][0- p[i][0]) (p[player][1- p[i][1]) (p[player][1- p[i][1]);
                                if (newDist < dist) {
                                    nearest = i;
                                    dist = newDist;
                                }
                            }
                        }
                        
                        if (nearest != -1) { // At least one foe
                            // Orientation
                            p[player][2= p[player][0< p[nearest][0: -1;
                            // New direction (if needed)
                            int angle = (int)(180. * Math.atan(((double)(p[nearest][1- p[player][1])) ((double)Math.abs(p[player][0- p[nearest][0]))) / Math.PI);
                            
                            if (p[player][4< angle) {
                                p[player][4+= 5;
                            }
                            else if (p[player][4> angle + 5) {
                                p[player][4-= 5;
                            }
                            else {
                                p[player][4= angle;
                                tmpVar = + Math.min(95, dist >> 6);
                            }
                        }
                    }
                    // keyboard management 
                    else if ((k == 37 | k == 39& !(demo | (computer & player % == 1))) {
                        p[player][2= k-38;
                        p[player][3]++;
                        p[player][6= p[player][2];
                        p[player][7= -2;
                    }
                    else if (k == 38 & !(demo | (computer & player % == 1))) {
                        if (p[player][4> -90p[player][4-= 5;
                    }
                    else if (k == 40 & !(demo | (computer & player % == 1))) {
                        if (p[player][490p[player][4+= 5;
                    }
                    else if (k == 32 & ball[0== -1. & !(demo | (computer & player % == 1))) {
                        if (power < 100power+= 5;
                    }
                    else if (power > && ball[0== -1.) {
                        ball[0= p[player][0];
                        ball[1= p[player][15;
                        ball[2= p[player][2(double)power * 0.2 * Math.cos(p[player][4* Math.PI / 180.);
                        ball[3(double)power * 0.2 * Math.sin(p[player][4* Math.PI / 180.);
                        fired = true;
                        noMoreAction = false;
                        tmpVar = 0;
                    }
                }
                
                // Redraw
                if (e >= 1) {
                    for (int i=; i<287809 ; i++) {
                        int d = (i % 641 - x(i % 641 - x(i / 641 - y(i / 641 - y)
                        
                        if (d < 400m[i= d + >= e ? 0xFF0000FF ((i / 641>> 10xFFFFFFFF;
                    }        
                    e >>= 1;
                    
                    source.newPixels(00641449false);                
                }
                
                g.drawImage(img, 00this);
                
                g.setFont(new Font(g.getFont().getFontName(), Font.BOLD, 14));
                                
                for (int i=; i<; i++) {
                    g.setColor((i==currentPlayer & ((blink >> 32== 0? Color.RED : Color.WHITE)
                    g.drawString(names[i], p[i][03*names[i].length(), p[i][127);
                    
                    g.setColor(i%2==0?Color.GREEN:Color.YELLOW);
    
                    if (p[i][50) {
                        g.fillOval(p[i][04, p[i][1(p[i][3]%2)88);
                        g.fillOval(p[i][0- p[i][27, p[i][1]-(p[i][3]%2)44);
                        g.setColor(i%2==0?new Color(0x00CA00):new Color(0xCACA00));
                        g.fillOval((int)(p[i][02.5 - p[i][24.5), p[i][1]-(p[i][3]%2)55);
                        g.setColor(Color.PINK);
                        g.fillOval(p[i][0+ p[i][23, p[i][11088);
                        g.setColor(Color.BLACK);
                        g.drawLine(p[i][0* p[i][2], p[i][17, p[i][0* p[i][2], p[i][16);
                        g.drawLine(p[i][0* p[i][2], p[i][17, p[i][0* p[i][2], p[i][16);
                        g.setColor(Color.WHITE);
                        g.drawLine(p[i][0* p[i][2], p[i][18, p[i][0* p[i][2], p[i][18);
                        g.drawLine(p[i][0* p[i][2], p[i][18, p[i][0* p[i][2], p[i][18);     
                        g.drawString(String.valueOf(p[i][5]), p[i][010, p[i][114);
                    }
                    else {
                        g.fillRect(p[i][04, p[i][111911);
                        g.setColor(Color.BLACK);
                        g.drawLine(p[i][0], p[i][18, p[i][0], p[i][12);
                        g.drawLine(p[i][02, p[i][16, p[i][02, p[i][16);
                        g.setColor(Color.WHITE);
                    }                
                }
                            
                // Cross
                if (!fired) {
                    g.drawLine((int)(p[currentPlayer][0+ p[currentPlayer][220 * Math.cos(p[currentPlayer][4* Math.PI / 180.))(int)(p[currentPlayer][120 * Math.sin(p[currentPlayer][4* Math.PI / 180.))(int)(p[currentPlayer][020 * p[currentPlayer][2* Math.cos(p[currentPlayer][4* Math.PI / 180.))(int)(p[currentPlayer][120 * Math.sin(p[currentPlayer][4* Math.PI / 180.)));
                    g.drawLine((int)(p[currentPlayer][0+ p[currentPlayer][220 * Math.cos(p[currentPlayer][4* Math.PI / 180.))(int)(p[currentPlayer][120 * Math.sin(p[currentPlayer][4* Math.PI / 180.))(int)(p[currentPlayer][020 * p[currentPlayer][2* Math.cos(p[currentPlayer][4* Math.PI / 180.))(int)(p[currentPlayer][120 * Math.sin(p[currentPlayer][4* Math.PI / 180.)));
                }
                
                // Power
                if (power != 0) {
                    g.setColor(new Color(0x9999FF));
                       g.fillRect(153010010);
                       for (int i=; i<power ; i++) {
                           g.setColor(new Color(0xFFC800 (i<<9)));
                           g.drawLine(15+i, 2915+i, 41);
                       }
                }
                            
                if (demo) {
                    g.setColor(Color.WHITE);
                    //g.drawString("4K contest '06", 276, 255);                    
                    g.drawString("javaunlimited.net '06"250255);
                    g.setFont(new Font(g.getFont().getFontName(), Font.BOLD, 144));
                    g.drawString("W4K"160240);
                    g.setFont(new Font(g.getFont().getFontName(), Font.BOLD, 32));
                    g.setColor((computer & ((blink >> 32== 0? Color.RED : Color.WHITE);
                    g.drawString("1 Player"260305);
                    g.setColor((!computer & ((blink >> 32== 0? Color.RED : Color.WHITE);
                    g.drawString("2 Players"250340);
                }               
                                   
                // Water
                for (int i=; i>=; i--) {
                    g.setColor(new Color(0x0000FF 0x666600 * i));
                    for (int j=; j<641 ; j++) {
                        g.drawLine(j, (int)(Math.cos((double)(j+(blink<<(3-i))) 10.(5. - i442. - i * 3), j, 449);
                    }
                }                
                
                g.setColor(Color.WHITE);                
                
                // Ball
                if (ball[0!= -1.) {
                    noMoreAction = false;
                                    
                    for (int step=; step<20 ; step++) {
                        ball[0+= ball[220;
                        ball[1+= ball[320;
                        
                        // Test collision avec les vers
                        for (int i=; i<; i++) {
                            if (i != currentPlayer) { 
                                noMoreAction |= ball[0> p[i][0
                                        && ball[0< p[i][01
                                        && ball[1> p[i][18
                                        && ball[1< p[i][1];
                            }
                        }                    
                        
                        if (ball[0|| ball[0641
                                || ball[1|| ball[1449) { 
                            power = 0;
                            ball[0= -1.;
                            noMoreAction = true;
                            break;
                        }
                        else if (m[(int)ball[0(int)ball[16410xFF0000FF || noMoreAction) {
                            x = (int)ball[0];
                            y = (int)ball[1];
                            
                            // Gestion collision explosion + joueurs
                            for (int i=; i<; i++) {
                                int dist = ((p[i][0- x(p[i][0- x(p[i][1- y(p[i][1- y))
                                
                                if (dist < 400) {
                                    p[i][5-= (400 - dist>> 3;                            
                                    p[i][6= noMoreAction ? (int)(ball[22((p[i][0- x/2)// x ejection
                                    p[i][7(dist - 50040// y ejection
                                }
                            }
                            
                            power = 0;                    
                            ball[0= -1.;
                            e = 400;                        
                            noMoreAction = false;
                            break;
                        }
                        
                        if ((!demo & !(computer & (currentPlayer % 2== 1)) | power < 100ball[3+= 0.02;
                    }
                    
                    g.fillOval((int)ball[01(int)ball[1133);
                }
                
                if (fired & noMoreAction) {
                    // Check game statut                
                    byte[] alive = new byte[2];
                    for (int i=; i<; i++) {
                        if (p[i][0&& p[i][50) {
                            alive[i%2]++;
                        }
                    }
                    
                    if (alive[0* alive[1== 0) {
                        if (demo) {
                            play = false;
                        }
                        else {
                            g.setFont(new Font(g.getFont().getFontName(), Font.BOLD, 32));
                            g.drawString((alive[0]==alive[1]?"Draw game!!!":(alive[0]==0?"Dalton":"Beatles")+" Win!")240240);
                            
                            victory = true;
                        }
                    }
                    else {
                        refPlayer++;
                        currentPlayer = refPlayer % 8;                    
                        while (p[currentPlayer][0|| p[currentPlayer][5<= 0) {
                            currentPlayer += 2;
                            currentPlayer %= 8;
                        }
                        
                        fired = false;
                    }
                }
                            
                // Refresh
                try {
                    Thread.sleep(50 + time - System.currentTimeMillis());
                catch (Exception ex) {}
    
                paint(this.getGraphics());
                
                blink++;
                
                if (demo & blink > 2400play = false;
            }
        }
    }
    
    public void paint(Graphics g) {
        if (b != nullg.drawImage(b, 00this);
    }

    public void windowClosing(WindowEvent w) {
        System.exit(0);
    }
    
    public void windowOpened(WindowEvent w) {}
    public void windowClosed(WindowEvent w) {}
    public void windowIconified(WindowEvent w) {}
    public void windowDeiconified(WindowEvent w) {}
    public void windowActivated(WindowEvent w) {}
    public void windowDeactivated(WindowEvent w) {}

    public void keyPressed(KeyEvent e) {
        k = e.getKeyCode();
    }

    public void keyReleased(KeyEvent e) {
        if (k == e.getKeyCode()) {
            k = 0;
        }
    }

    public void keyTyped(KeyEvent e) {}
    
    public static void main(String[] args) {
        new W();
    }    
}
Java2html