//Title:      boingo.java
//Version:    
//Copyright:  Copyright (c) 2000
//Author:     SyGem Software

import java.awt.*;
import java.applet.*;
import sygem.jazz3d2_102.*;
public class boingo extends Applet implements Runnable {
    
    Thread m_ce;
    world boingo_world;
    int banner_id;
    int banner2_id = -1;
    int score_id = -1;
    int hit_id = -1;
    int base_id;
    int light1;
    int pid,pid2,pid3,pid4;
    int enemy_object;
    
    int score = 0;
    int level = 1;
    int hit = 0;
    int enemy_step = 3;
    int total = 0;
    
    int bullets[];
    int bullets_display[];
    boolean fired[];
    double xvec[];
    double yvec[];
    
    double xpos[];
    double ypos[];
    
    int current_bullet = 5;
    
    int energy[];
    int enemy_id;
    double temp_y = 0;
    int step = 0;
    int step2 = 100;
    int step3 = 250;
    double bounce[];
    double height = 0;
    int b_step = 0;
    
    double posx,posy,posz;
    double speed = 0.1;
    double bullet_speed = 0.2;
    
    int energy_level = 10;
    
    boolean titlepage = true;
    boolean main_game = false;
    
    boolean redraw = true;
    
    boolean create_new_enemy = true;
    boolean fire_bullet = false;
    boolean game_over = false;
    boolean animate_hit = false;
    boolean animate_hit2 = false;
    
    boolean game_completed = false;
    boolean new_level = true;
    int new_level_frames = 0;
    
    font3d arial;
    
    //Construct the applet
    public boingo() {
    }
    
    //Initialize the applet
    public void init() {
        
        resize(320,240);
        boingo_world = new world(this);
        
        setLayout(new BorderLayout());
        add("Center", boingo_world);
        
        bullets = new int[5];
        bullets_display = new int[6];
        fired = new boolean[5];
        xvec = new double[5];
        yvec = new double[5];
        xpos = new double[5];
        ypos = new double[5];
        
        energy = new int[10];
        
        bounce = new double[360];
        for (int i = 0;i < 360;i++) {
            double temp_y = Math.sin(i*Math.PI/180);
            bounce[i] = Math.abs(temp_y);
        }
        
        arial = new font3d("Arial", boingo_world);
        
        light temp_light = new light(0,0,1);
        light temp_light2 = new light(0,-1,0);
        light1 = boingo_world.addLight(temp_light);
        light1 = boingo_world.addLight(temp_light2);
        
    }
    
    //Start the applet
    public void start() {
        if (m_ce == null) {
            m_ce = new Thread(this);
            m_ce.start();
        }
    }
    
    //Stop the applet
    public void stop() {
        if (m_ce != null) {
            m_ce.stop();
            m_ce = null;
        }
    }
    
    //Destroy the applet
    public void destroy() {
    }
    
    public void run() {
        
        setup_title_page();
        
        while (true) {
            if (game_over) {
                // should go to highscore table
                setup_score_display();
            }
            if (titlepage) {
                title_page_animate();
            }
            if (main_game && ! game_over) {
                main_game_loop();
            }
            boingo_world.redraw();
        }
    }
    
    void setup_title_page() {
        boingo_world.suspend();
        titlepage = true;
        main_game = false;
        game_over = false;
        renderfs wireframe = new renderfs();
        
        boingo_world.deleteAllObjects();
        text3d title_page = new text3d("Boingo!", arial, 0.5, 0.1, 0.1, -0.15, 0.35, 8);
        title_page.rotateLocal(0,0,20);
        title_page.setColour(255,0,0);
        pid = boingo_world.addObject(title_page, wireframe);
        
        sphere3d title_boing = new sphere3d(10,10,0.4,-0.4,7.5);
        title_boing.scaleObject(0.5,0.5,0.5);
        title_boing.setColour(0,255,0);
        pid2 = boingo_world.addObject(title_boing, wireframe); 
        sphere3d title_boing2 = new sphere3d(10,10,0,-0.2,8);
        title_boing2.scaleObject(0.2,0.2,0.2);
        title_boing2.setColour(0,255,255);
        pid3 = boingo_world.addObject(title_boing2, wireframe); 
        sphere3d title_boing3 = new sphere3d(10,10,-0.5,0,8.5);
        title_boing3.scaleObject(0.3,0.3,0.3);
        title_boing3.setColour(0,0,255);
        pid4 = boingo_world.addObject(title_boing3, wireframe); 
        boingo_world.prep();
        boingo_world.resume();
    }
    
    void title_page_animate() {
        step+= 2;
        if (step >= 360) step -= 360;
        step2+= 3;
        if (step2 >= 360) step2 -= 360;
        step3+= 4;
        if (step3 >= 360) step3 -= 360;
        boingo_world.rotateObjectLocal(pid,4,0,0);
        boingo_world.setObjectPosition(pid2,0.4,bounce[step]-0.6,7.5);
        boingo_world.rotateObjectLocal(pid2,1,3,2);
        boingo_world.setObjectPosition(pid3,0,(bounce[step2]*0.9)-0.6,8);
        boingo_world.rotateObjectLocal(pid3,0,3,0);
        boingo_world.setObjectPosition(pid4,-0.5,(bounce[step3]*0.8)-0.6,8.5);
        boingo_world.rotateObjectLocal(pid4,5,1,2);
    }
    
    void setup_main_game() {
        boingo_world.suspend();
        titlepage = false;
        main_game = true;
        game_over = false;
        game_completed = false;
        posx = posy = posz = 0;
        enemy_step = 3;
        energy_level = 10;
        current_bullet = 5;
        level = 1;
        boingo_world.deleteAllObjects();
        checkerboard3d base = new checkerboard3d(5,20,0,-0.1,11);
        base.scaleObject(0.5,20,1);
        base.rotateWorld(90,0,0);
        renderfs wireframe = new renderfs();
        base_id = boingo_world.addObject(base,wireframe);
        
        sphere3d enemy = new sphere3d(10,10,0,0,0);
        enemy.scaleObject(0.1,0.1,0.1);
        enemy.setColour(255,0,255);
        enemy_id = boingo_world.addObject(enemy,wireframe);
        
        for (int i = 0;i < 5;i++) {
            sphere3d new_sphere = new sphere3d(5,5,0,0,-2);
            new_sphere.scaleObject(0.10,0.10,0.10);
            bullets[i] = boingo_world.addObject(new_sphere,wireframe);
        }
        for (int i = 0;i < 10;i++) {
            cube3d new_cube = new cube3d(0.85,(i*0.1)-0.2,8);
            new_cube.scaleObject(0.08,0.08,0.08);
            new_cube.setColour(0,255,0);
            energy[i] = boingo_world.addObject(new_cube,wireframe);
        }
        
        text3d zero = new text3d("0", arial, 0.5, 0.1, 0.1, -0.8, 0.1, 8);
        text3d one = new text3d("1", arial, 0.5, 0.1, 0.1, -0.8, 0.1, 8);
        text3d two = new text3d("2", arial, 0.5, 0.1, 0.1, -0.8, 0.1, 8);
        text3d three = new text3d("3", arial, 0.5, 0.1, 0.1, -0.8, 0.1, 8);
        text3d four = new text3d("4", arial, 0.5, 0.1, 0.1, -0.8, 0.1, 8);
        text3d five = new text3d("5", arial, 0.5, 0.1, 0.1, -0.8, 0.1, 8);
        bullets_display[0] = boingo_world.addObject(zero, wireframe);
        bullets_display[1] = boingo_world.addObject(one, wireframe);
        bullets_display[2] = boingo_world.addObject(two, wireframe);
        bullets_display[3] = boingo_world.addObject(three,wireframe);
        bullets_display[4] = boingo_world.addObject(four, wireframe);
        bullets_display[5] = boingo_world.addObject(five, wireframe);
        for (int i = 0;i < 5;i++) {
            boingo_world.setObjectVisible(bullets_display[i],false);
        }
        
        enemy_id = boingo_world.addObject(enemy,wireframe);
        
        text3d score_display = new text3d("0", arial, 0.3,0.01,0.2,-0.7,0.65,8);
        score_display.setColour(0,255,255);
        score_id = boingo_world.addObject(score_display, wireframe);
        
        boingo_world.prepNewObjects();
        boingo_world.resume();
    }
    
    void main_game_loop() {
        for (int i = 0;i < 10;i++) {
            boingo_world.rotateObjectLocal(energy[i],1,2,3);
        }
        if (new_level) {
            new_level_frames++;
            if (new_level_frames > 50) {
                new_level = false;
                boingo_world.deleteObject(banner_id);
                boingo_world.deleteObject(banner2_id);
                boingo_world.setObjectVisible(score_id, true);
            }
            return;
        }
        if (animate_hit) {
            boingo_world.translateObjectWorld(hit_id,0,0,0.3);
            if (boingo_world.getObjectCenter(hit_id).getZ() > 6) {
                animate_hit = false;
                animate_hit2 = true;
            }
            return;
        }
        if (animate_hit2) {
            boingo_world.translateObjectWorld(hit_id,0,0.3,0);
            if (boingo_world.getObjectCenter(hit_id).getY() > 2) {
                animate_hit = false;
                animate_hit2 = false;
                boingo_world.deleteObject(hit_id);
            }
            return;
        }
        if (create_new_enemy) {
            posz = 16;
            posx = (Math.random()*0.5) - 0.25;
            posy = (Math.random()*0.4) + 0.2;
            height = posy;
            boingo_world.setObjectPosition(enemy_id,posx,posy,posz);
            create_new_enemy = false;
            total++;
        }
        b_step += enemy_step;
        if (b_step >= 360) b_step -= 360;
        posz -= speed;
        posy = (height*bounce[b_step])-0.05;
        if (posz <= 0) {
            create_new_enemy = true;
            energy_level--;
            if (energy_level < 0) {
                game_over = true;
            } else {
                boingo_world.setObjectColour(energy[energy_level],255,0,0);
            }
        }
        boingo_world.setObjectPosition(enemy_id,posx,posy,posz);
        for (int i = 0;i < 10;i++) {
            boingo_world.rotateObjectLocal(energy[i],1,2,3);
        }
        for (int i = 0;i < 6;i++) {
            boingo_world.setObjectVisible(bullets_display[i],false);
        }
        boingo_world.setObjectVisible(bullets_display[current_bullet],true);
        for (int i = 0;i < 5;i++) {
            if (fired[i]) {
                if (boingo_world.testCollision(enemy_id,bullets[i])) {
                    score += (posz*level);
                    hit++;
                    fired[i] = false;
                    current_bullet++;
                    boingo_world.setObjectPosition(bullets[i],0,0,-2);
                    create_new_enemy = true;
                    // let's see... at this point, we have just hit an enemy, so we can prolly afford
                    // to generate the new score display on-the-fly...
                    renderfs wireframe = new renderfs();
                    boingo_world.deleteObject(score_id);
                    text3d score_display = new text3d(""+score, arial, 0.3,0.01,0.2,-0.7,0.65,8);
                    score_display.setColour(0,255,255);
                    score_id = boingo_world.addObject(score_display, wireframe);
                    text3d hit_display = new text3d("Hit!", arial, 0.2, 0.02, 0.1,0,0.3,2);
                    hit_display.setColour(255,0,255);
                    hit_id = boingo_world.addObject(hit_display, wireframe);
                    boingo_world.prepNewObjects();
                    animate_hit = true;
                } else {
                    if (boingo_world.getObjectCenter(bullets[i]).getZ() > 16) {
                        fired[i] = false;
                        current_bullet++;
                        boingo_world.setObjectPosition(bullets[i],0,0,-2);
                    } else {
                        boingo_world.translateObjectWorld(bullets[i],xvec[i],yvec[i],bullet_speed);
                    }
                }
            }
        }
        if (total > 10) {
            level++;
            speed += 0.05;
            enemy_step++;
            bullet_speed += 0.05;
            boingo_world.scaleObject(enemy_id,0.8,0.8,0.8);
            boingo_world.setObjectPosition(enemy_id,0,0,-2);
            // move to a new level!
            if (level == 6) {
                // Game completed!!!
                game_over = true;
                game_completed = true;
            }
            if (hit == (total-1)) {
                // perfect!
                displaylevelbanner(level, true);
            } else {
                displaylevelbanner(level, false);
            }
        }
    }
    
    void displaylevelbanner(int id,boolean t) {
        boingo_world.setObjectVisible(score_id, false);
        renderfs wireframe = new renderfs();
        text3d banner = new text3d("Level "+id, arial, 0.5,0.01,0.2,0,0.60,8);
        banner.setColour(255,255,0);
        banner_id = boingo_world.addObject(banner, wireframe);
        if (t) {
            text3d banner2 = new text3d("Perfect!", arial, 0.3,0.01,0.2,0,0.15,8);
            banner2.setColour(0,255,0);
            banner2_id = boingo_world.addObject(banner2, wireframe);
        }
        boingo_world.prepNewObjects();
        new_level = true;
        new_level_frames = 0;
        create_new_enemy = true;
        total = 0;
        hit = 0;
        current_bullet = 5;
        for (int i = 0;i < 5;i++) {
            fired[i] = false;
            boingo_world.setObjectPosition(bullets[i],0,0,-2);
        }
    }
    
    void setup_score_display() {
        renderfs wireframe = new renderfs();
        for (int j = 0;j < 10;j++) {
            for (int i = 0;i < 10;i++) {
                boingo_world.translateObjectWorld(energy[i],0.1,0,0);
            }
            for (int i = 0;i < 6;i++) {
                boingo_world.translateObjectWorld(bullets_display[i],-0.1,0,0);
            }
            boingo_world.redraw();
        }
        for (int j=0;j < 10;j++) {
            boingo_world.translateObjectWorld(base_id,0,-0.1,0);
            boingo_world.redraw();
        }
        int fr = 0;
        for (int j = 0;j < 20;j++) {
            boingo_world.translateObjectWorld(score_id,0.035,-0.04,-0.2);
            boingo_world.redraw();
        }
        text3d congrats = new text3d("Congratulations!", arial, 0.3,0.02,0.4,0,0.55,8);
        int cid = boingo_world.addObject(congrats, wireframe);
        text3d congrats2 = new text3d("You scored", arial, 0.35,0.02,0.4,0,0.15,8);
        int cid2 = boingo_world.addObject(congrats2, wireframe);
        boingo_world.prepNewObjects();
        while (fr < 100) {
            fr++;
            boingo_world.redraw();
        }
        setup_title_page();
    }
    
    public boolean mouseUp(Event e, int x, int y) {
        if (titlepage) {
            setup_main_game();
            displaylevelbanner(level, false);
        } else {
                if (current_bullet > 0) {
                    // find out which bullet we can fire next
                    int new_bullet = 0;
                    for (int i = 0;i < 5;i++) {
                        if ( ! fired[i]) new_bullet = i;
                    }
                    fired[new_bullet] = true;
                    x -= 160;
                    y -= 120;
                    double xt = x/160.0;
                    xt *= 1.9;
                    xvec[new_bullet] = xt / (16/bullet_speed);
                    double yt = y/120.0;
                    yt *= 1.4;
                    yvec[new_bullet] = -yt / (16/bullet_speed);
                    boingo_world.setObjectPosition(bullets[new_bullet],0,0,0);
                    current_bullet--;
                }
        }
        return true;
    }
}