George Sykes ELEC2645 project

Dependencies:   mbed

https://os.mbed.com/media/uploads/el18gs/pixil-frame-0.png

GHOST HUNTER

In a world of ghostly horrors there is much money to be made in underground ghost fighting rings. You've managed to get hold of a Ghostbuster, a special piece of equipment that allows you to catch, train and fight ghosts.

Instructions

Below you will find the instructions for the game. Please note that due to COVID-19 a large part of the game (fighting ghosts) could not be added as it would have required access to a second gamepad which i could not acquire.

Welcome screen

When first started you will be presented with a welcome screen

  • Pot 1 to adjust the contrast on the screen
  • Press A to continue.

Main menu

You have three options, catch ghosts (add ghosts to your inventory), inventory (sell ghosts) or settings(adjust the games settings).

  • Press X and B to move the selection up and down respectively
  • Press A to enter the selected submenu

Catch Ghost

Will now be presented with two challenges. In the first you need to find a ghost, in the second you catch it. Theses stages will start automatically.

Find ghost

Rotate the gamepad on its roll and pitch axis until all the LED's turn on. The ones on the left indicate roll and the right pitch.

  • Rotate the gamepad on it roll and pitch to light up the LED's

Catch ghost

Return the gamepad to a comfortable position and use the joystick to move the crosshairs onto the ghost sprite. When ready press the A button to catch the ghost. You will be told what kind of ghost you have captured and it will be added to your inventory.

  • Press A to catch the ghost
  • Move the joystick to move the crosshairs

Inventory

The inventory allows you to view your ghosts and sell them.

  • Use Pot 1 to scroll through the ghosts
  • Pot 2 to scroll up and down the details of the individual ghosts
  • Press X to prepare to sell a ghost and press again to confirm, if you don't press again the sale screen will disappear after 5 seconds
  • Press Start to return to the main menu

Settings

This menu allows you to adjust some of the settings of the game.

  • Press X to go up one option
  • Press B to go down one option
  • Press A to enter the selected submenu
  • Press Start to return to the main menu

Contrast

Set the contrast of the LCD screen, the contrast will adjust on this screen so you can see the effect (contrast is bounded between 0.4 and 0.6).

  • Pot 1 to increase or decrease the contrast
  • Press A to set the contrast

Button Delay

Set the minimum time between button presses; if this is too low the game will detect two button presses when there was only one, too high and the buttons will seem unresponsive. So as to ensure these issues do not occur while changing the setting button X temporarily operates on the new delay but none of the others will until A is pressed.

  • Pot 1 to increase or decrease the delay
  • Press X to test the new delay, this will toggle the small circle to be filled in or unfilled
  • Press A to save the setting

Inventory/Inventory.cpp

Committer:
el18gs
Date:
2020-05-26
Revision:
17:3ebcf7bba112
Parent:
16:3b298bea3a70

File content as of revision 17:3ebcf7bba112:

#include "Inventory.h"

Inventory::Inventory(SDFileSystem &sd)
{
    printf("creating inventory\n");
    stringvec ghost_list = list_ghosts("/sd/ghosts", sd);

    for(int i = 0; i < ghost_list.size(); i++) {

        std::string path = "/sd/ghosts/";
        path.append(ghost_list[i]);
        printf("Path to import '%s'\n", path.c_str());

        Ghost temp(path, "/sd/ghosts/", sd);
        _ghosts.push_back(temp);
    }
    _gold = 0;
}

void Inventory::regen(SDFileSystem &sd)
{
    printf("Regenerating ghost list\n");
    _ghosts.clear();

    stringvec ghost_list = list_ghosts("/sd/ghosts", sd);

    for(int i = 0; i < ghost_list.size(); i++) {

        std::string path = "/sd/ghosts/";
        path.append(ghost_list[i]);
        printf("Path to import '%s'\n", path.c_str());

        Ghost temp(path, "/sd/ghosts/", sd);
        _ghosts.push_back(temp);
    }

}

std::vector<int> Inventory::list_ghost_uids(void)
{
    std::vector<int> uids;
    for(int i = 0; i < _ghosts.size(); i++) {
        uids.push_back(_ghosts[i].get_uid());
        //printf("Added UID %i to list\n", _ghosts[i].get_uid());
    }

    return uids;
}

Ghost Inventory::get_ghost_by_uid(int uid)
{
    for(int i = 0; i < _ghosts.size(); i++) {
        if(_ghosts[i].get_uid() == uid) {
            return _ghosts[i];
        }
    }
    return _ghosts[0];
}

stringvec Inventory::list_ghosts(std::string path, SDFileSystem &sd)
{
    // Connections to SD card holder on K64F (SPI interface)
    //SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS
    //std::string path = "/sd/ghosts";
    printf("Checking directory for ghosts: %s\n", path.c_str());
    DIR *d;
    struct dirent *p;

    stringvec files;

    d = opendir(path.c_str());
    if (d != NULL) {
        while ((p = readdir(d)) != NULL) {
            files.push_back(p->d_name);
        }
    } else {
        printf("Could not open directory!\n");
    }
    closedir(d);

    stringvec correct_files;

    for(int i = 0; i < files.size(); i++) {
        if(hasEnding(files[i], ".ghost")) {
            correct_files.push_back(files[i]);
        }
    }

    return correct_files;
}

void Inventory::sell_ghost_by_uid(int uid, SDFileSystem &sd)
{
    printf("Inside sell function\n");
    for(int i = 0; i < _ghosts.size(); i++) {
        if(_ghosts[i].get_uid() == uid) {
            printf("Sale target found\n");
            int value = _ghosts[i].sell(sd);
            _ghosts.erase(_ghosts.begin() + i);
            _gold = _gold + value;
            if(_gold > 99) {
                _gold = 99;
            }
            break;
        }

    }
}

void Inventory::feed_ghost_by_uid(int uid, SDFileSystem &sd)
{
    printf("Inside feed function\n");
    if(_gold < 10) { return; }
    for(int i = 0; i < _ghosts.size(); i++) {
        if(_ghosts[i].get_uid() == uid) {
            printf("Feed target found\n");
            _ghosts[i].feed(10, sd);
            _gold = _gold - 10;
            break;
        }

    }
}

void Inventory::print_coin(SDFileSystem &sd, N5110 &lcd)
{
    int** ghost = import_sprite("/sd/assets/coin.sprite", sd);
    for(int i = 0; i < 10; i++) { // Iterate Columns: x
        for(int j = 0; j < 10; j++) { // Iterate Rows: y
            lcd.setPixel(i + 74, j, ghost[j][i]);
        }
    }
}

void Inventory::display_inventory(SDFileSystem &sd,
                                  N5110 &lcd,
                                  Gamepad &pad,
                                  volatile int &g_buttonX_flag,
                                  volatile int &g_buttonStart_flag,
                                  volatile int &g_buttonA_flag)
{
    int which_ghost_state = 0;
    int which_view_state = 0;
    int new_which_view_state = 0;

    std::vector<inven_state> ghost_fsm;

    bool regen_inven = true;
    bool scroll_ghost = false;
    bool update = true;

    while(1) {
        if(regen_inven) {
            regen(sd);
            ghost_fsm = gen_ghost_fsm();
            regen_inven = false;
            which_ghost_state = 0;
            which_view_state = 0;
        }

        if(update) {
            update = false;

            if(scroll_ghost) {
                wait_ms(750);
                scroll_ghost = false;
            }

            lcd.clear();
            char buffer [64];
            sprintf(buffer, "Inventory:%d", _gold);
            lcd.printString(buffer, 0, 0);

            print_coin(sd, lcd);

            if(ghost_fsm.size() == 0) {
                lcd.printString("No ghosts", 0, 1);
                lcd.printString("found, exiting", 0, 2);
                lcd.refresh();
                wait(1);
                return;
            } else {

                if(which_view_state <= 0) {
                    sprintf(buffer, "%s", ghost_fsm[which_ghost_state].type.c_str());
                    lcd.printString(buffer, 0, 1 - which_view_state);
                }

                if(which_view_state <= 1) {
                    sprintf(buffer, "Name: %s", ghost_fsm[which_ghost_state].name.c_str());
                    lcd.printString(buffer, 0, 2 - which_view_state);
                }

                if(which_view_state <= 2) {
                    sprintf(buffer, "Attack: %d", ghost_fsm[which_ghost_state].attack);
                    lcd.printString(buffer, 0, 3 - which_view_state);
                }

                if(which_view_state <= 3) {
                    sprintf(buffer, "Defense: %d", ghost_fsm[which_ghost_state].defense);
                    lcd.printString(buffer, 0, 4 - which_view_state);
                }

                if(which_view_state <= 4) {
                    sprintf(buffer, "Level: %d", ghost_fsm[which_ghost_state].level);
                    lcd.printString(buffer, 0, 5 - which_view_state);
                }

                if(which_view_state <= 5) {
                    sprintf(buffer, "Value: %d", ghost_fsm[which_ghost_state].value);
                    lcd.printString(buffer, 0, 6 - which_view_state);
                }

                if(which_view_state <= 6) {
                    sprintf(buffer, "HP Max: %d", ghost_fsm[which_ghost_state].hp_max);
                    lcd.printString(buffer, 0, 7 - which_view_state);
                }

                if(which_view_state <= 7) {
                    sprintf(buffer, "HP: %d", ghost_fsm[which_ghost_state].hp);
                    lcd.printString(buffer, 0, 7 - which_view_state);
                }

                lcd.refresh();
            }

        }

        if(pad.read_pot2() <= (double) 0.33) {
            new_which_view_state = 0;
        } else if(pad.read_pot2() <= (double) 0.66) {
            new_which_view_state = 1;
        } else {
            new_which_view_state = 2;
        }

        if(new_which_view_state != which_view_state) {
            update = true;
            which_view_state = new_which_view_state;
        }

        if(pad.read_pot1() < (double) 0.33) {
            which_ghost_state = ghost_fsm[which_ghost_state].next[1];
            scroll_ghost = true;
        } else if(pad.read_pot1() > (double) 0.66) {
            which_ghost_state = ghost_fsm[which_ghost_state].next[0];
            scroll_ghost = true;
        }

        if(scroll_ghost) {
            update = true;
        }

        if(g_buttonX_flag) {
            printf("X button pressed\n");
            update = true;
            g_buttonX_flag = 0;
            lcd.drawRect(0,16,84,16, FILL_WHITE);
            lcd.printString("Press again",10,2);
            lcd.printString("to sell",20,3);

            //wait_ms(50);

            Timer t;
            t.start();

            g_buttonX_flag = 0;
            bool sell = false;

            while(t.read() <= 5) {
                int time = t.read();
                bool changed = false;
                if(time == 0) {
                    lcd.printString("5",60,3);
                    changed = true;
                } else if (time == 1) {
                    lcd.printString("4",60,3);
                    changed = true;
                } else if (time == 2) {
                    lcd.printString("3",60,3);
                    changed = true;
                } else if (time == 3) {
                    lcd.printString("2",60,3);
                    changed = true;
                } else if (time == 4) {
                    lcd.printString("1",60,3);
                    changed = true;
                } else if (time == 5) {
                    lcd.printString("0",60,3);
                    changed = true;
                }

                if(g_buttonX_flag) {
                    printf("button X pressed\n");
                    g_buttonX_flag = 0;
                    sell = true;
                }

                if(changed) {
                    lcd.refresh();
                }

                if(sell) {
                    printf("Exiting to sell\n");
                    break;
                }
            }

            if(sell) {
                printf("Running sell function\n");
                sell_ghost_by_uid(ghost_fsm[which_ghost_state].uid, sd);
                regen_inven = true;
                update = true;
            }


        } else if(g_buttonStart_flag) {
            g_buttonStart_flag = 0;
            return;
        } else if(g_buttonA_flag == 1) {
            g_buttonA_flag = 0;
            feed_ghost_by_uid(ghost_fsm[which_ghost_state].uid, sd);
            regen_inven = true;
            update = true;
        }

    }

}

std::vector<inven_state> Inventory::gen_ghost_fsm()
{
    std::vector<inven_state> ghost_fsm;

    std::vector<int> uids = list_ghost_uids();

    sort(uids.begin(), uids.end());

    for(int i = 0; i < uids.size(); i++) {
        Ghost ghost_temp = get_ghost_by_uid(uids[i]);
        inven_state temp;
        temp.uid = ghost_temp.get_uid();
        temp.name = ghost_temp.get_name();
        temp.type = ghost_temp.get_type_string();
        temp.attack = ghost_temp.get_attack();
        temp.defense = ghost_temp.get_defense();
        temp.level = ghost_temp.get_level();
        temp.xp = ghost_temp.get_xp();
        temp.value = ghost_temp.get_value();
        temp.hp_max = ghost_temp.get_hp_max();
        temp.hp = ghost_temp.get_hp();

        ghost_fsm.push_back(temp);
        //printf("Added Ghost UID %i to fsm\n", temp.uid);
        printf("%s\n", temp.name.c_str());
    }

    for(int i = 0; i < ghost_fsm.size(); i++) {
        if (i == 0) {
            int next[2] = {1, ghost_fsm.size() - 1};
            ghost_fsm[i].next[0] = next[0];
            ghost_fsm[i].next[1] = next[1];
        } else if (i == ghost_fsm.size() - 1) {
            int next[2] = {0, ghost_fsm.size() - 2};
            ghost_fsm[i].next[0] = next[0];
            ghost_fsm[i].next[1] = next[1];
        } else {
            int next[2] = {i + 1, i - 1};
            ghost_fsm[i].next[0] = next[0];
            ghost_fsm[i].next[1] = next[1];
        }
    }

    return ghost_fsm;
}