Randall Kliman / Mbed 2 deprecated NEOPUNK

Dependencies:   mbed wave_player 4DGL-uLCD-SE MMA8452

main.cpp

Committer:
Sterofin
Date:
2018-11-30
Revision:
3:664c79e2ceb5
Parent:
2:06c63d567719
Child:
4:af9d6e3b8a29

File content as of revision 3:664c79e2ceb5:

// Project includes
#include "globals.h"
#include "hardware.h"
#include "map.h"
#include "graphics.h"
#include "speech.h"
#include "hash_table.h"

GameInputs in;
int actions;
int update;
bool god;
bool puzzle = false;
bool mapact = 0;
int story = 0;
unsigned int m_z=12434,m_w=33254;
unsigned int rnd() {
    m_z = 36969 * (m_z & 65535) + (m_z >>16);
    m_w = 18000 * (m_w & 65535) + (m_w >>16);
    return ((m_z <<16) + m_w);
}

unsigned int n[4];


// Functions in this file
int get_action (GameInputs inputs);
int update_game (int action);
void draw_game (int init);
void init_main_map ();
int main ();

/**
 * The main game state. Must include Player locations and previous locations for
 * drawing to work properly. Other items can be added as needed.
 */
struct {
    int x,y;    // Current locations
    int px, py; // Previous locations
    int has_key;
    int speed;
    bool can_teleport;
} Player;

struct {
    bool has_boots;
    bool has_teleport;
    bool has_gun;
    bool has_printer;
} Inventory;

/**
 * Given the game inputs, determine what kind of update needs to happen.
 * Possbile return values are defined below.
 */
#define NO_ACTION 0
#define ACTION_BUTTON 1
#define MENU_BUTTON 2
#define GO_LEFT 3
#define GO_RIGHT 4
#define GO_UP 5
#define GO_DOWN 6
#define THRESH 0.3
#define GOD_MODE 7
#define BUTTON_3 8
#define BUTTON_4 9
int walkk;
int get_action(GameInputs inputs)
{
    //pc.printf("%d,%d\r\n",inputs.ax,inputs.ay);
    if(inputs.ax <  -THRESH) return GO_UP;
    if(inputs.ax >= THRESH) return GO_DOWN;
    if(inputs.ay >= THRESH) return GO_RIGHT;
    if(inputs.ay <  -THRESH) return GO_LEFT;
    if(!inputs.b1) return ACTION_BUTTON;
    if(!inputs.b2) return MENU_BUTTON;
    if(!inputs.b3 && !puzzle){
        pc.printf("Button 3 pressed");
        god = !god;
        if(god) uLCD.filled_rectangle(128,0,119,7,WHITE);
        else if(!god) uLCD.filled_rectangle(128,0,119,7,BLACK);
    }
    else if(!inputs.b3) return BUTTON_3;
    if(!inputs.b4) return BUTTON_4;
    return NO_ACTION;
}

int go_up()
{
    if(get_north(Player.x,Player.y)->walkable || god)
    {
        for(walkk = 1;walkk < Player.speed;walkk++){
            if(!get_north(Player.x,Player.y-walkk)->walkable) break;
        }
        Player.y-=walkk;
        return 1;
    }else return 0;
}

int go_down()
{
    if(get_south(Player.x,Player.y)->walkable || god)
    {
        for(walkk = 1;walkk < Player.speed;walkk++){
            if(!get_south(Player.x,Player.y+walkk)->walkable) break;
        }
        Player.y+=walkk;
        return 1;
    }else return 0;
}

int go_left()
{
    if(get_west(Player.x,Player.y)->walkable || god)
    {
        for(walkk = 1;walkk < Player.speed;walkk++){
            if(!get_west(Player.x-walkk,Player.y)->walkable) break;
        }
        Player.x-=walkk;
        return 1;
    }else return 0;
}

int go_right()
{
    if(get_east(Player.x,Player.y)->walkable || god)
    {
        for(walkk = 1;walkk < Player.speed;walkk++){
            if(!get_east(Player.x+walkk,Player.y)->walkable) break;
        }
        Player.x+=walkk;
        return 1;
    }else return 0;
}

//Looks at if there's a block of the desired type next to the player
int checkType(int t)
{
    MapItem* n = get_north(Player.x,Player.y);
    MapItem* s = get_south(Player.x,Player.y);
    MapItem* e = get_east(Player.x,Player.y);
    MapItem* w = get_west(Player.x,Player.y);
    //pc.printf("%d\r\n",n->type);
//    pc.printf("%d\r\n",s->type);
//    pc.printf("%d\r\n",e->type);
//    pc.printf("%d\r\n",w->type);
    if(n->type == t || s->type == t || e->type == t || w->type == t)
    {
        return 1;
    }else return 0;
}

MapItem* find_type(int t)
{
    MapItem* n = get_north(Player.x,Player.y);
    MapItem* s = get_south(Player.x,Player.y);
    MapItem* e = get_east(Player.x,Player.y);
    MapItem* w = get_west(Player.x,Player.y);
    //pc.printf("%d\r\n",n->type);
//    pc.printf("%d\r\n",s->type);
//    pc.printf("%d\r\n",e->type);
//    pc.printf("%d\r\n",w->type);
    if(n->type == t) return n;
    else if(s->type == t) return s;
    else if(e->type == t) return e;
    else if(w->type == t) return w;
    else return NULL;
}

int convert(int num)
{
    if(num == 1) return ACTION_BUTTON;
    else if(num == 2) return MENU_BUTTON;
    else if(num == 3) return BUTTON_3;
    else if(num == 4) return BUTTON_4;
    return 5;
}

#define mx 4
#define my 3
void run_minigame(){
    char buffer[100];
    n[0] = rnd()%4+1;
    n[1] = rnd()%4+1;
    n[2] = rnd()%4+1;
    n[3] = rnd()%4+1;
    sprintf(buffer,"of numbers: %d%d%d%d",n[0],n[1],n[2],n[3]);
    speech(buffer,"");
    int solved = 0;
    while(solved < 4)
    {
        in = read_inputs();   
        actions = get_action(in); 
        if(solved == 0){
            if(actions == convert(n[0])){
                uLCD.locate(mx,my);
                sprintf(buffer," %d - - - ",n[0]);
                uLCD.printf(buffer);
                solved++;
                wait(0.5);
            }
        }
       else if(solved == 1){
            if(actions == convert(n[1])){
                uLCD.locate(mx,my);
                sprintf(buffer," %d %d - - ",n[0],n[1]);
                uLCD.printf(buffer);
                solved++;
                wait(0.5);
            }
        }
        else if(solved == 2){
            if(actions == convert(n[2])){
                uLCD.locate(mx,my);
                sprintf(buffer," %d %d %d - ",n[0],n[1],n[2]);
                uLCD.printf(buffer);
                solved++;
                wait(0.5);
            }
        }
        else if(solved == 3){
            if(actions == convert(n[3])){
                uLCD.locate(mx,my);
                sprintf(buffer," %d %d %d %d ",n[0],n[1],n[2],n[3]);
                uLCD.printf(buffer);
                solved++;
                wait(0.5);
            }
        }
    }
}

/**
 * Update the game state based on the user action. For example, if the user
 * requests GO_UP, then this function should determine if that is possible by
 * consulting the map, and update the Player position accordingly.
 * 
 * Return values are defined below. FULL_DRAW indicates that for this frame,
 * draw_game should not optimize drawing and should draw every tile, even if
 * the player has not moved.
 */
#define NO_RESULT 0
#define GAME_OVER 1
#define FULL_DRAW 2
MapItem* boi;
int update_game(int action)
{
    // Save player previous location before updating
    Player.px = Player.x;
    Player.py = Player.y;
    
    // Do different things based on the each action.
    // You can define functions like "go_up()" that get called for each case.
    switch(action)
    {
        case GO_UP:
            go_up();
            break;
        case GO_LEFT:
            go_left();
            break;         
        case GO_DOWN:
            go_down();
            break;
        case GO_RIGHT:
            go_right();
            break;
        case ACTION_BUTTON:
            pc.printf("Action Button Pressed\r\n");
            if(checkType(NPORTAL))
            {
                if(story == 2 || story == 3 || story == 4){
                    speech("Don't leave! The","hack is almost");
                    speech("finished!","");
                    return FULL_DRAW;
                }
                pc.printf("Entering Portal");
                if(!mapact){
                    set_active_map(1);
                    mapact = 1;
                    Player.x = 2;
                    Player.y = 5;
                }
                else if(mapact){
                    set_active_map(0);
                    mapact = 0;
                    Player.x = 37;
                    Player.y = 44;
                }
                uLCD.filled_rectangle(0,0,127,9, 0x0);
                return FULL_DRAW;
            }
            else if(checkType(NPC))
            {
                if(story == 0){
                    speech("Hey, want to make","some quick cash?");
                    speech("Head over to the","netPortal next");
                    speech("door. Hack","BULLETCORPs server");
                    speech("so we can steal","some of their");
                    speech("advanced tech.","That is, if");
                    speech("you're up for","the job");
                    story++;
                }
                else if(story == 1)
                {
                    speech("C'mon! What are","you waiting for?");                    
                }
                else if(story == 6)
                {
                    speech("Thanks for the","codes. here's a ");
                    speech("chip that will","let you into");
                    speech("BULLETCORP's","secret tech room");
                    Player.has_key = true;
                }
                return FULL_DRAW;               
            }
            else if(checkType(TERMINAL))
            {
                if(story == 1){  
                    speech("Pondsmith:","~ksshhk~");
                    speech("Nice, you're in.","Use the terminals");
                    speech("to decypher the","BULLETCORP access");
                    speech("codes. There are","4 codes. Each");
                    speech("terminal will","give one of the");
                    speech("access codes.","");
                    uLCD.cls();
                    puzzle = true;
                    uLCD.locate(mx,my);
                    uLCD.printf(" - - - - ");
                    speech("Ok, here is","the first string");
                    run_minigame();
                    story++;
                    if((boi = find_type(TERMINAL))){
                        boi->type = HACKED_TERMINAL;
                        boi->draw = draw_hacked_terminal;
                    }
                    puzzle = false;   
                    return FULL_DRAW;
                }
                else if(story == 2){
                    uLCD.cls();
                    puzzle = true;
                    uLCD.locate(mx,my);
                    uLCD.printf(" - - - - ");
                    speech("Ok, here is","the second string");
                    run_minigame();
                    story++;
                    if((boi = find_type(TERMINAL))){
                        boi->type = HACKED_TERMINAL;
                        boi->draw = draw_hacked_terminal;
                    }   
                    puzzle = false; 
                    return FULL_DRAW;
                }
                else if(story == 3){
                    uLCD.cls();
                    puzzle = true;
                    uLCD.locate(mx,my);
                    uLCD.printf(" - - - - ");
                    speech("Ok, here is","the third string");
                    run_minigame();
                    story++;
                    if((boi = find_type(TERMINAL))){
                        boi->type = HACKED_TERMINAL;
                        boi->draw = draw_hacked_terminal;
                    }   
                    puzzle = false; 
                    return FULL_DRAW;
                }
                else if(story == 4){
                    uLCD.cls();
                    puzzle = true;
                    uLCD.locate(mx,my);
                    uLCD.printf(" - - - - ");
                    speech("Ok, here is","the fourth string");
                    run_minigame();
                    story++;
                    if((boi = find_type(TERMINAL))){
                        boi->type = HACKED_TERMINAL;
                        boi->draw = draw_hacked_terminal;
                    }   
                    puzzle = false; 
                    return FULL_DRAW;
                }
            }
            else if(checkType(DOOR) && Player.has_key == true){
                if(boi = find_type(DOOR)) boi->walkable = true;
            }
            else if(checkType(TELEPORT)){
                Inventory.has_teleport = true;
                if(boi = find_type(TELEPORT)) map_erase(boi->x, boi->y);
            }
            else if(checkType(KILL)){
                Inventory.has_gun = true;
                if(boi = find_type(KILL)) map_erase(boi->x, boi->y);
            }
            else if(checkType(BOOTS)){
                Inventory.has_boots = true;
                Player.speed = 2;
                if(boi = find_type(BOOTS)) map_erase(boi->x, boi->y);
            }
            else if(checkType(PRINTER)){
                Inventory.has_printer = true;
                if(boi = find_type(PRINTER)) map_erase(boi->x, boi->y);
            }
            break;
        case MENU_BUTTON:
            pc.printf("Menu Button Pressed\r\n");
            break;
        case BUTTON_4:
            pc.printf("Button 4 Pressed\r\n");
            //NVIC_SystemReset();
            break;
        default:        break;
    }
    return NO_RESULT;
}

/**
 * Entry point for frame drawing. This should be called once per iteration of
 * the game loop. This draws all tiles on the screen, followed by the status 
 * bars. Unless init is nonzero, this function will optimize drawing by only 
 * drawing tiles that have changed from the previous frame.
 */
void draw_game(int init)
{
    // Draw game border first
    if(init) draw_border();
    
    // Iterate over all visible map tiles
    for (int i = -5; i <= 5; i++) // Iterate over columns of tiles
    {
        for (int j = -4; j <= 4; j++) // Iterate over one column of tiles
        {
            // Here, we have a given (i,j)
            
            // Compute the current map (x,y) of this tile
            int x = i + Player.x;
            int y = j + Player.y;
            
            // Compute the previous map (px, py) of this tile
            int px = i + Player.px;
            int py = j + Player.py;
                        
            // Compute u,v coordinates for drawing
            int u = (i+5)*11 + 3;
            int v = (j+4)*11 + 15;
            
            // Figure out what to draw
            DrawFunc draw = NULL;
            if (i == 0 && j == 0) // Only draw the player on init
            {
                draw_player(u, v, Player.has_key);
                continue;
            }
            else if (x >= 0 && y >= 0 && x < map_width() && y < map_height()) // Current (i,j) in the map
            {
                MapItem* curr_item = get_here(x, y);
                MapItem* prev_item = get_here(px, py);
                if (init || curr_item != prev_item) // Only draw if they're different
                {
                    if (curr_item) // There's something here! Draw it
                    {
                        draw = curr_item->draw;
                    }
                    else // There used to be something, but now there isn't
                    {
                        draw = draw_nothing;
                    }
                }
            }
            else if (init) // If doing a full draw, but we're out of bounds, draw the walls.
            {
                draw = draw_wall;
            }

            // Actually draw the tile
            if (draw) draw(u, v);
        }
    }

    // Draw status bars
    draw_upper_status(Player.x,Player.y);
    draw_lower_status();
}


/**
 * Initialize the main world map. Add walls around the edges, interior chambers,
 * and plants in the background so you can see motion.
 */
void init_main_map()
{
    Map* map = set_active_map(0);
        
    pc.printf("Adding walls!\r\n");
    add_wall(0,              0,              HORIZONTAL, map_width());
    add_wall(0,              map_height()-1, HORIZONTAL, map_width());
    add_wall(0,              0,              VERTICAL,   map_height());
    add_wall(map_width()-1,  0,              VERTICAL,   map_height());
    
    
    add_wall(0,38,HORIZONTAL,4);
    add_wall(6,38,HORIZONTAL,15);
    add_wall(0,29,HORIZONTAL,2);
    add_wall(4,29,HORIZONTAL,26);
    add_door(2,29,false);
    add_door(3,29,false);
    add_boots(3,22);
    add_teleport(5,24);
    add_orgprint(8,21);
    add_kill(15,19);
    add_wall(0,17,HORIZONTAL,40);
    add_wall(0,13,HORIZONTAL,2);
    add_door(2,13,false);
    add_door(3,13,false);
    add_wall(4,13,HORIZONTAL,36);
    add_wall(39,0,VERTICAL,13);
    add_wall(11,0,VERTICAL,13);
    add_wall(39,17,VERTICAL,13);
    add_wall(39,38,VERTICAL,12);
    add_wall(26,38,VERTICAL,10);
    add_wall(21,38,VERTICAL,4);
    add_wall(21,44,VERTICAL,5);
    add_wall(31,38,HORIZONTAL,9);
    add_wall(27,38,HORIZONTAL,2);
    add_netPortal(38,44);
    add_NPC(5,42);
    pc.printf("Walls done!\r\n");

    //print_map();
}

void init_sub_map()
{
    set_active_map(1);
    pc.printf("Adding walls!\r\n");
    add_wall(0,              0,              HORIZONTAL, map_width());
    add_wall(0,              map_height()-1, HORIZONTAL, map_width());
    add_wall(0,              0,              VERTICAL,   map_height());
    add_wall(map_width()-1,  0,              VERTICAL,   map_height());
    add_terminal(3,3);
    add_terminal(7,3);  
    add_terminal(3,7);  
    add_terminal(7,7);
    add_netPortal(1,5);   
}

/**
 * Program entry point! This is where it all begins.
 * This function orchestrates all the parts of the game. Most of your
 * implementation should be elsewhere - this holds the game loop, and should
 * read like a road map for the rest of the code.
 */
 

 
int main()
{
    // First things first: initialize hardware
    ASSERT_P(hardware_init() == ERROR_NONE, "Hardware init failed!");
    //hardware_init();
    pc.printf("Initializing Game\r\n");
    in = read_inputs();
    actions = get_action(in);
    uLCD.text_width(2); //4X size text
    uLCD.text_height(2);
    uLCD.color(0x00ffd8);
    uLCD.set_font(FONT_5X7);
    uLCD.text_bold(true);
    uLCD.printf("\n\n  N E O\n");
    uLCD.color(0xff00e4);
    uLCD.printf("\n P U N K\n");
    uLCD.text_width(1); //4X size text
    uLCD.text_height(1);
    uLCD.color(RED);
    bool swap = 0;
    int flash = 0;
    while(actions != ACTION_BUTTON)
    {
        if(flash >= 600){
            swap = !swap;
            flash = 0;
            if(swap) draw_menu_2();
            else if(!swap) draw_menu_1();
        }
        if(swap) flash+=3;
        else if(!swap) flash++;
            
        
        in = read_inputs();
        actions = get_action(in);
    }
    uLCD.cls();
    uLCD.text_width(1); //4X size text
    uLCD.text_height(1);
    uLCD.color(GREEN);
    uLCD.set_font(FONT_7X8);
    // Initialize the maps
    maps_init();
    init_main_map();
    init_sub_map();
    set_active_map(0);
    print_map();
    pc.printf("Map initialized\r\n");
    
    // Initialize game state
    Player.x = 3;
    Player.y = 33;
    Player.speed = 1;
    // Initial drawing
    draw_game(true);

    // Main game loop
    while(1)
    {
        //pc.printf("Game Running\r\n");
        // Timer to measure game update speed
        Timer t; t.start();
        
        // Actually do the game update:
        // 1. Read inputs
        in = read_inputs(); 
        //pc.printf("Gathering Sensor Data\r\n");
        // 2. Determine action (get_action)    
        actions = get_action(in);   
        //pc.printf("Determining Action\r\n"); 
        // 3. Update game (update_game)
        update = update_game(actions);
        //pc.printf("Updating Game State\r\n");
        //pc.printf("Game State: %d\r\n", gameState);
        // 3b. Check for game over
        //if(update == 0) break;
        // 4. Draw frame (draw_game)
        //pc.printf("Drawing Game\r\n");
        draw_game(update);
        
        // 5. Frame delay
        t.stop();
        int dt = t.read_ms();
        if (dt < 100) wait_ms(100 - dt);
        
        if(story == 5){
            speech("Nice! You got","the codes.");
            speech("Come back to me","and i'll");
            speech("compile them into","a security chip");
            speech("you can use to","break into");
            speech("BULLETCORP","");
            story++;
            draw_game(FULL_DRAW);
        }
    }
}