Pokitto turn based strategy game.

Dependencies:   PokittoLib

wars.cpp

Committer:
trelemar
Date:
2018-03-06
Revision:
13:8a3620166b57
Parent:
12:52184eaf74f4

File content as of revision 13:8a3620166b57:

#include "Pokitto.h"
#include "warsprites.h"
#include "hero_sprites.h"
#include "ui_sprites.h"
uint16_t dark_pal[16];
#include "warfont.cpp"
#include <vector>
#include <stdint.h>

const uint16_t sprite_pal[] = {
4195,16678,12717,19017,33382,13092,53801,29580,23545,54245,33972,27973,54611,28185,57003,57210,
};

Pokitto::Core game;
Pokitto::Display disp;
Pokitto::Buttons btn;

#define SW disp.width
#define SH disp.height

void splashScreen(int id, char * name, int bg_color, int text_color) {
    disp.bgcolor = bg_color;
    disp.clear();
    disp.drawBitmap((SW/2)-16,(SH/2)-16-8, ui_sprites[id]);
    disp.drawBitmap(SW/2, (SH/2)-16-8, ui_sprites[id+1]);
    disp.drawBitmap((SW/2)-16, (SH/2)-8, ui_sprites[id+8]);
    disp.drawBitmap(SW/2,(SH/2)-8, ui_sprites[id+9]);
    disp.setColor(text_color);
    disp.print(SW/2- ((strlen(name)*6)/2),SH-26,name);
    //game.wait(time);
    for (int c=0; c<16;c++) {
        disp.palette[c] = sprite_pal[0];
    }
    disp.update();

    int frame = 0;

    while (frame<180&&!btn.cBtn()) {
        if (frame<60) {
            for (int c = 0; c<16; c++) {
                disp.palette[c] = disp.interpolateColor(disp.palette[c], sprite_pal[c], (255/60)*frame);
            }
        }
        else if (frame<120) {
            disp.load565Palette(sprite_pal);
        }
        else {
            for (int c = 0; c<16; c++) {
                disp.palette[c] = disp.interpolateColor(disp.palette[c], sprite_pal[0], (255/60)*(frame-120));
            }
        }
        disp.update();
        //game.wait(2);
        frame++;
    }

    disp.load565Palette(sprite_pal);
}

void init_dark_palette() {
    for (uint8_t c=1;c<15;c++) {
        dark_pal[c] = disp.interpolateColor(sprite_pal[c], sprite_pal[0], 100);
    }
}

bool loading;
int solids[64] {
    0,1,1,1,1,0,0,0,
    0,0,1,0,1,0,0,0,
    0,0,1,1,1,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,
};
//Sprite sheet:2x1
const uint8_t cursor_sprites [][244] ={
//[0] cell:0x0
{
22,22,
204,0,12,204,204,204,204,204,192,0,204,
192,255,240,204,204,204,204,204,15,255,12,
15,160,12,204,204,204,204,204,192,10,240,
15,12,204,204,204,204,204,204,204,192,240,
15,12,204,204,204,204,204,204,204,192,240,
192,204,204,204,204,204,204,204,204,204,12,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
192,204,204,204,204,204,204,204,204,204,12,
15,12,204,204,204,204,204,204,204,192,240,
15,12,204,204,204,204,204,204,204,192,240,
15,160,12,204,204,204,204,204,192,10,240,
192,255,240,204,204,204,204,204,15,255,12,
204,0,12,204,204,204,204,204,192,0,204,
},
//[1] cell:1x0
{
22,22,
204,204,204,204,204,204,204,204,204,204,204,
204,192,0,204,204,204,204,204,0,12,204,
204,15,255,12,204,204,204,192,255,240,204,
192,250,0,204,204,204,204,204,0,175,12,
192,240,204,204,204,204,204,204,204,15,12,
192,240,204,204,204,204,204,204,204,15,12,
204,12,204,204,204,204,204,204,204,192,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,204,204,204,204,204,204,204,204,204,204,
204,12,204,204,204,204,204,204,204,192,204,
192,240,204,204,204,204,204,204,204,15,12,
192,240,204,204,204,204,204,204,204,15,12,
192,250,0,204,204,204,204,204,0,175,12,
204,15,255,12,204,204,204,192,255,240,204,
204,192,0,204,204,204,204,204,0,12,204,
204,204,204,204,204,204,204,204,204,204,204,
},
};

using namespace std;

int clamp(int low, int n, int high) {return min(max(low, n), high);}

float dist(int x1, int y1, int x2, int y2) {
    int x = x1 - x2;
    int y = y1 - y2;
    float dist;
    dist = pow((float)x,2)+pow((float)y,2);
    dist = sqrt((float)dist);
    return dist;
}

int lerp(int a, int b, float t) {
    return (1-t)*a + t*b;
}

float lerp(float a, float b, float t) {
    return (1-t)*a + t*b;
}

enum GameState {MAIN, PAUSE, MENU} State = MENU;

#define KEY_REPEAT 5

#define TASK_MOVE 0
#define TASK_ATTACK 1
#define TASK_ITEM 2
#define TASK_WAIT 3
#define TASK_SPAWN 4
#define TASK_NONE 5
#define TEAM_USER 0
#define TEAM_CPU 1

int current_team = TEAM_USER;
uint8_t selected_task = 0;
uint8_t current_task = TASK_NONE;
uint8_t game_turn = 1;

static char task_names[4][7] {
    {"MOVE"},
    {"ATTACK"},
    {"TRAIT"},
    {"WAIT"},
};
int task_colors[4] {
    11,9,6,8
};

int map_x, map_y, cursor_x, cursor_y;

bool center_cursor = true;

void centerCursor() {
    map_x = cursor_x - 3;
    map_y = cursor_y - 2;
}

static void print(char text[], uint8_t color) {
    disp.setColor(color);
    disp.print(text);
}

static void printb(int x, int y, int text) {
    disp.setColor(0);
    disp.print(x,y-1,text);
    disp.print(x,y+1,text);
    disp.print(x+1,y,text);
    disp.print(x-1,y,text);
    disp.setColor(15);
    disp.print(x,y,text);
}
static void printb(int x, int y, char text[]) {
    disp.setColor(0);
    disp.print(x,y-1,text);
    disp.print(x,y+1,text);
    disp.print(x+1,y,text);
    disp.print(x-1,y,text);
    disp.setColor(15);
    disp.print(x,y,text);
}

struct Dialog {
    char text[20];
    int start_time;
    int position;
    Dialog(char _text[20]) {
        strcpy(text, _text);
        position = 0;
        start_time = game.frameCount;
    };
    void update() {
        position = min(position + 1, 19);
    };
    void draw(int x, int y) {
        disp.setCursor(x, y);
        for (int p=0;p<position;p++) {
            disp.print(text[p]);
        }
    };
};

struct Transition {
    int on_val, off_val, val;
    bool enabled;
    Transition() {};
    Transition(int _onv, int _offv, bool _enabled) {
        on_val = _onv;
        off_val = _offv;
        enabled = _enabled;
        if (enabled) val=on_val;
        else val = off_val;
    };
    void toggle() {enabled=!enabled;};
    void update() {
        if (enabled) val = lerp(val, on_val, 0.2);
        else val = lerp(val, off_val, 0.2);
    };
};

struct Vec2 {
    int x, y;
    Vec2(int _x, int _y) {x=_x; y=_y;};
};

struct Item {
    int id, x, y;
    Item(int _id, int _x, int _y) {
        id = _id;
        x = _x;
        y = _y;
    };
    void Draw() {
        int dx = (x-map_x)*16;
        int dy = (y-map_y)*16;
        //disp.setColor(1);
        //disp.fillRectangle(dx+4,dy+12,8,3);
        //disp.drawBitmap(dx, dy+(sin(game.frameCount/4))*2, sprites[id]);
    };
};

#define ID_SOLDIER 0
#define ID_HEAVY 1
#define ID_SNIPER 2
#define ID_SUPPORT 3
#define ID_HUNTER 4
#define ID_WARRIOR 5
#define ID_SHAMAN 6

const int sprite_ids[16] {
    0,     //SOLDIER
    2,     //HEAVY
    4,     //SNIPER
    6,
    9,     //HUNTER
    11,    //WARRIOR
    13,    //SHAMAN
    15,    //SPIDER
    18,
    20,
    22,
    24,
};
char id_names[][10] {
    //GI-BROS
    {"SOLDIER"},
    {"HEAVY"},
    {"SNIPER"},
    {"SUPPORT"},

    //SPACE GRUNKS
    {"HUNTER"},
    {"WARRIOR"},
    {"SHAMAN"},
    {"SPIDER"},

    //TEAM GLOOM
    {"BONES"},
    {"SLIME"},
    {"KNIGHT"},
    {"FLYER"},
};

char Faction[][14] {
    {"GI-BROS"},
    {"SPIDERLINGS"},
    {"TEAM GLOOM"}
};

int Faction_colors[] {
    11,
    6,
};

char TRAITS[][8] {
    {""},
    {"FAST"},
    {"HULKISH"},
};

struct Hero {
    unsigned int index, team, id, x, y;
    uint8_t atk, def, hp, max_hp;
    float range;
    int spr;
    int hurt_time;
    bool tasks[4], flip;
    char * traits;
    Hero(int _x, int _y, int _id, int _team) {
        hurt_time = 0;
        x = _x; y = _y; flip = false;
        id = _id; team = _team;
        if (_team == TEAM_USER) {
        }
        else {flip=true;}
        spr = sprite_ids[id];
        max_hp = 10;
        atk = 5;
        def = 2;
        range = 2.1;
        if (id == ID_HEAVY) {atk+=3; def++; range-=.5; max_hp+=2;}
        if (id == ID_SNIPER) {def--; atk--; range+=1.5; max_hp-=2;}
        hp = max_hp;
        NewTurn();
    };
    void NewTurn() {
        for (int i=0;i<4;i++) {tasks[i]=true;}
    };
    void update(int i) {
        index = i;
    };
    void Draw() {
        int ox = 0;
        int oy = 0;
        int dx = (x-map_x)*16;
        int dy = (y-map_y)*16;
        bool draw = true;
        if (game.frameCount-hurt_time<10) {
            ox = random(-2,2);
            oy = random(-2,2);
            if (game.frameCount%2==0) {draw=false;}
        }
        int spr_id = spr + (game.frameCount/10)%2;
        disp.invisiblecolor = 13;
        if (draw) disp.drawBitmap((dx)+ox,(dy)+oy,hero_sprites[spr_id], 0, flip);
        disp.invisiblecolor = 12;
        if (id==ID_SNIPER&&team==TEAM_USER) {
            int lx = dx+ox+16;
            int ly = dy+oy+5;
            if (game.frameCount/10%2==1) ly++;
            if (flip) lx-=18;

            disp.setColor(0);
            disp.drawLine(lx,ly,lx+1,ly);
        }
    };
    bool inRange(Hero * enemy) {
        return (dist(x, y, enemy->x, enemy->y)<=range);
    };
    bool inRange(int dx, int dy) {
        return (dist(x, y, dx, dy)<=range);
    };
    void AIhandle(int &ai_index, vector<Hero> &heros) {
        Hero * target=NULL;
        for (int i=0; i<heros.size(); i++) {
            if (inRange(&heros[i])&&tasks[TASK_ATTACK]) {
                target = &heros[i];
                break;
            }
        }
        if (target!=NULL&&tasks[TASK_ATTACK]) {
            target->hurt_time=game.frameCount;
            target->hp-= (atk-target->def);
            tasks[TASK_ATTACK] = 0;
        }
    };
};

struct Base {
    int x, y, id, team;
    int hp;
    int spawn_points;
    int faction;
    Base() {};
    Base(int _x, int _y, int _id, int _team, int _faction) {
        x = _x;
        y = _y;
        id = _id;
        team = _team;
        faction = _faction;
        spawn_points = 10;
    };

    void Draw() {
        int dx = (x-map_x)*16;
        int dy = (y-map_y)*16;
        disp.drawBitmap(dx, dy, sprites[id]);

    };

    void Spawn(int x, int y, int id, vector<Hero> &heros) {

    };
};

Hero * cursor_hero = NULL;
Hero * current_hero = NULL;
vector<Hero> * hptr;
Base bases[2];
Base * current_base = NULL;

void DrawCursorBaseUI(Base * b, int x, int y) {

}

void DrawCursorHeroUI (Hero * h, int x, int y) {
    float bw = 24;
    float hw = (bw/h->max_hp) * h->hp;
    disp.setColor(0);
    disp.drawRoundRect(x-1,y-1,bw+2,5,2); //HEALTH BAR
    disp.fillRoundRect(x-1, y+26,bw+2,7,2);  //TEXT BG BOX
    disp.setColor(6);
    disp.fillRect(x, y, bw, 2);
    disp.setColor(11);
    disp.fillRect(x, y, hw, 2);
    disp.setColor(11);
    disp.print(x,y+27,"^");
    disp.setColor(15);
    disp.print((int)h->atk);
    disp.setColor(6);
    disp.print("n");
    disp.setColor(15);
    disp.print((int)h->def);
}
//COLORS FOR EACH TEIR OF HERO
int prog_colors[4] {
    14,9,11,8
};

void DrawSelectedBaseUI(Base * base, int y) {
    disp.setColor(0);
    disp.fillRoundRect(1,y-5,SW-28,88-68+6,3);
    if (!base) return;
    disp.setColor(15);

    disp.print(3,y-4,id_names[(base->faction*4)+selected_task]);

    disp.setCursor(SW-28-(6*4), y-4);
    disp.setColor(prog_colors[selected_task]);
    disp.print(2+(selected_task*2));
    disp.print(" SP");

    disp.setColor(15);
    printb(18,(-y)+68,Faction[base->faction]);
    printb(18,(-y)+75, "BASE");

    for (int i=0; i<4; i++) {
        disp.invisiblecolor = 13;
        int spr = (base->faction*9)+(i*2);
        int x = 3+i*20;
        disp.setColor(15);
        if (i==selected_task) {
            disp.fillRect(x+1,y+3,16,15);
        }
        disp.drawBitmap(x,y+3,hero_sprites[spr]);
        disp.setColor(prog_colors[i]);
        disp.drawRoundRect(x,y+2,18,18, 3);
    }
}

void DrawSelectedHeroUI(Hero * h, int y) {
    disp.setColor(0);
    //disp.fillRect(0,66,SW,88-66);
    disp.fillRoundRect(1,y,SW-2,88-67,3);
    //disp.setColor(15);
    if (!h) return;
    disp.setColor(8);
    disp.print(3,y+3,">");
    disp.setColor(15);
    disp.print((int)h->atk);
    disp.print("  ATK");
    disp.setColor(6);
    disp.print(3,y+9,"n");
    disp.setColor(15);
    disp.print((int)h->def);
    disp.print("  DEF");
    disp.setColor(11);
    disp.print(3,y+15,"^");
    disp.setColor(15);
    disp.print((int)h->range);
    disp.print("  RNG");
    printb(18,(-y)+68,task_names[selected_task]);

    for (int i=0;i<4;i++) {
        int spr = i+8;
        if (!h->tasks[i]) spr-=8;
        else if (selected_task==i) spr+=8;
        disp.drawBitmap(44+(i*16), y+4, ui_sprites[spr]);
    }
    int bw = 62;
    int hw = (bw/h->max_hp) * h->hp;
    disp.setColor(0);
    disp.drawRoundRect(44,y-4,bw+2,7,3);
    disp.setColor(6);
    disp.fillRoundRect(45,y-3,bw,5,2);
    disp.setColor(11);
    disp.fillRoundRect(45,y-3,hw+2,5,2);
    disp.setColor(15);
    printb(50+(bw/2)-10,y-3,(int)h->hp);

    printb(3,y-3,id_names[h->id]);
}

void DrawTraitList(Hero * h, int x) {
    //disp.setColor(0);
    //disp.fillRoundRect(32,y,SW-63,12,3);
    //disp.setColor(15);
    //for (int i = 0; i<4; i++) {
        //disp.drawRoundRect(34+(i*11),y+1,10,10,2);
    //}
    int y = 17;
    disp.setColor(0);
    disp.fillRoundRect(x, y-1, 12, 45, 3);
    disp.setColor(15);
    for (int i=0; i<4; i++) {
        disp.drawRoundRect(x+1,y+(i*11), 10, 10, 2);
    }
    disp.print(x+4,y+2, "f");
    if (selected_task!=TASK_ITEM) return;
    disp.setColor(0);

    disp.fillRoundRect(x+13, y-1+6, 64, 6*3+1, 3);
    disp.setColor(15);
    //disp.print(x+28,y,"~WIMP~");
    printb(x+14,y,"< ~HULKISH~");
    disp.setColor(7);
    disp.print(x+15, y+6, "MOVEMENT");
    disp.setColor(6);
    disp.print("nn");
    disp.setColor(7);
    disp.print(x+15, y+12, "MAX HP");
    disp.setColor(11);
    disp.print("^^");
    disp.setColor(7);
    disp.print(x+15, y+18, "^ATK ^DEF");
}

void DrawTurnCounter(vector<Hero> &_heros) {
    disp.invisiblecolor = 13;
    int spr = 32+bases[current_team].faction;
    disp.drawBitmap(0, 0, ui_sprites[spr]);
    disp.invisiblecolor = 12;
    int count = 0;
    for (int i=0; i<_heros.size();i++) {
        if (_heros[i].team == current_team) count++;
    }
    printb(11,10,(int)count);

}


#define MAP_WIDTH 12
#define MAP_HEIGHT 12
int Map[MAP_HEIGHT][MAP_WIDTH] {
{0,8,0,5,10,8,8,1,8,8,0,8},
{1,0,0,21,15,14,8,0,8,0,1,0},
{0,8,0,8,10,5,8,8,0,9,8,8},
{0,1,8,0,10,5,1,8,8,8,0,8},
{8,0,9,0,18,7,3,3,3,4,8,1},
{0,8,8,0,0,5,0,0,0,12,8,13},
{0,0,1,8,8,5,8,1,8,11,0,5},
{8,0,8,0,8,5,8,0,0,10,0,5},
{8,8,0,8,1,21,6,30,6,15,6,22},
{8,0,0,8,8,0,0,5,8,12,0,0},
{0,1,8,9,0,8,1,5,8,18,3,3},
{0,0,8,8,8,8,0,5,8,0,8,0},
};

void loadTileMap(char * filename) {
    disp.enableDirectPrinting(true);
    disp.fillLCD(disp.palette[0]);
    disp.directBitmap(110-16,176/2-16,ui_sprites[7],4,2);
    disp.directbgcolor = disp.palette[0];
    disp.fontSize = 2;
    disp.directcolor = disp.palette[15];
    disp.print(24,164,"LOADING CONTENT");
    int inc = 220/144;
    #ifdef POK_SIM
        game.wait(20);
    #endif

    pokInitSD();
    int success = fileOpen(filename,FILE_MODE_BINARY);
    if (!isThisFileOpen(filename)) {
        disp.directcolor = disp.palette[6];
        disp.print(0,16,"SD LOADING ERROR");
        while (!btn.aBtn()) {
            game.wait(100);
        }
    }
    for (int i = 0; i<144; i++) {
        int x = i%MAP_WIDTH;
        int y = (i-x)/MAP_WIDTH;
        //fileSetPosition(i);
        Map[y][x] = (int)filePeek(i);
        #ifdef POK_SIM
            game.wait(10);
        #endif // POK_SIM
        disp.directRectangle(inc*(i*2),0,inc,8,disp.palette[15]);
    }
    fileClose();
    disp.enableDirectPrinting(false);
}

void saveTileMap() {

}

void DrawTileMap(int8_t x, int8_t y, Hero * hero) {
    disp.setColor(15);
    for (int map_x=0; map_x<7; map_x++) {
        for (int map_y=0; map_y<6; map_y++) {
            int spr;
            if (map_x+x<0||x+map_x>MAP_WIDTH-1||y+map_y<0||y+map_y>MAP_HEIGHT-1) {
                spr = 9;
            }
            else {
                spr = Map[map_y+y][map_x+x];
            }

            float distance;

            disp.drawBitmap((map_x*16), (map_y*16),sprites[spr]);

            //RANGE BOXES
            if (hero && (current_task == TASK_MOVE || current_task == TASK_ATTACK)) {
                distance = dist(map_x+x, map_y+y, hero->x, hero->y);
                if (distance<hero->range&&x+map_x<MAP_WIDTH&&y+map_y<MAP_HEIGHT&&x+map_x>=0&&y+map_y>=0) {
                    disp.setColor(8);
                    if (solids[Map[map_y+y][map_x+x]]) {disp.setColor(6);}
                    disp.drawRoundRect(map_x*16+2, map_y*16+2, 12, 12,3);
                    //disp.print(map_x*16,map_y*16,(float)distance);
                }
            }
        }
    }
}

void showRoundScreen() {
    disp.clear();
    DrawTileMap(map_x, map_y, current_hero);
    disp.load565Palette(sprite_pal);
    disp.update();
    disp.textWrap = false;
    disp.enableDirectPrinting(false);

    for (int frame = 0; frame< 140; frame++) {
        disp.setColor(0);
        if (frame<6) {
            disp.drawLine(0,SH/2+frame, SW, SH/2+frame);
            disp.drawLine(0,SH/2-frame, SW, SH/2-frame);
        }
        else if (frame>=6) {
            disp.setColor(0);
            disp.fillRect(0,SH/2-6, SW, 12);
            disp.setColor(15);
            disp.setCursor(frame-6-(6*7), (SH/2)-5);
            disp.setColor(10);
            disp.print("> ROUND ");
            disp.setColor(15);
            disp.print((int)game_turn/2);
            disp.setCursor(SW+6-frame, (SH/2)+1);
            disp.setColor(Faction_colors[current_team]);
            disp.print(Faction[current_team]);
            disp.setColor(10);
            disp.print(" TURN <");
        }

        disp.update();
        //game.wait(2);
    }

    disp.textWrap = true;
}

void DrawCursor(int x, int y) {
    //uint8_t spr = 52 + (game.frameCount/12)%2;
    disp.drawBitmap(x*16-3, y*16-3,cursor_sprites[(game.frameCount/4)%2]);
}

Hero * getHeroAtCoords(int x, int y, vector<Hero> &herovect) {
    Hero *h = NULL;
    bool found = false;
    for (int i=0;i<herovect.size();i++) {
        if (herovect[i].x==x&&herovect[i].y==y) {
            h = &herovect[i];
            break;
        }
    }
    return h;
}



void CursorInput() {
    int last_x=cursor_x;
    int last_y=cursor_y;
    if (btn.repeat(BTN_UP,KEY_REPEAT)) {
        if (cursor_y-map_y<=0) {
            map_y=max(map_y-1,0);
        }
        cursor_y=max(cursor_y-1,0);
    }
    if (btn.repeat(BTN_DOWN,KEY_REPEAT)) {
        if (cursor_y-map_y>=4) {
            map_y=min(map_y+1,MAP_HEIGHT-6);
        }
        cursor_y=min(cursor_y+1,MAP_HEIGHT-1);

    }
    if (btn.repeat(BTN_LEFT,KEY_REPEAT)) {
        if (cursor_x-map_x<=0) {
            map_x=max(map_x-1,0);
        }
        cursor_x=max(cursor_x-1,0);
    }
    if (btn.repeat(BTN_RIGHT,KEY_REPEAT)) {
        if (cursor_x-map_x>=6) {
            map_x=min(map_x+1,MAP_WIDTH-7);
        }
        cursor_x=min(cursor_x+1,MAP_WIDTH-1);
    }

    if (center_cursor) {
        centerCursor();
    }
}

struct PauseMenu {
    char items[3][12];
    unsigned int selected_item;
    Transition lb; //letterbox
    PauseMenu() {
        lb.off_val=0;
        lb.on_val=16;
        lb.enabled=true;
        lb.val = lb.off_val;
        selected_item = 0;
        strcpy(items[0], "RESUME");
        strcpy(items[1], "END TURN");
        strcpy(items[2], "QUIT GAME");
    };
    void endTurn(vector<Hero> * _heros) {
        for (int i=0; i<0+_heros->size(); i++) {
            _heros->at(i).NewTurn();
        }
        game_turn++;
    };
    void update() {
        lb.update();
        for (int i = 1; i<15; i++) {
            disp.palette[i] = disp.interpolateColor(disp.palette[i],dark_pal[i], 80);
        }
        if (btn.pressed(BTN_DOWN)) {
            selected_item++;
            selected_item%=3;
        }
        else if (btn.pressed(BTN_UP)) {
            selected_item--;
            selected_item%=3;
        }

        if (btn.pressed(BTN_A)) {
            lb.val = lb.off_val;
            //disp.load565Palette(sprite_pal);
            switch (selected_item) {
            case 0:
                State = MAIN;
            break;
            case 1:
                current_team=(current_team+1) % 2;
                endTurn(hptr);
                State = MAIN;
                showRoundScreen();
            break;
            case 2:
                State = MENU;
            break;
            }
        }
    };
    void draw() {
        //disp.fillRoundRect()
        DrawTileMap(map_x, map_y, current_hero);
        disp.setColor(0);
        disp.fillRect(0,0,SW,lb.val);
        disp.fillRect(0,SH-lb.val,SW,lb.on_val);
        disp.setColor(15);
        disp.setCursor(0,lb.val+2);
        disp.println("PAUSED");
        disp.print("CURRENT TEAM ");
        disp.println(current_team);
        disp.println(selected_item);
        for (int i=0;i<3; i++) {
            int color = 3;
            if (selected_item==i) {
                color = 15;
            }
            disp.setColor(0);
            disp.print(32, 33+ (i*6), items[i]);
            disp.setColor(color);
            disp.print(32, 32+ (i*6), items[i]);
        }
    };
};

struct LevelList {
    int pos;
    int files;
    char * fname;
    void init() {
        pokInitSD();
        pos = 0;
        files = 0;
        fname = getFirstFile("war");
        files++;
        while(fname!=NULL) {
            fname = getNextFile("war");
            files++;
        }
        fname = getFirstFile("war");
    };

    void update() {
        if (btn.pressed(BTN_DOWN)) {
            fname = getNextFile("war");
            if (fname==NULL) {
                fname = getFirstFile("war");
            }
        }
        if (btn.pressed(BTN_A)&&fname!=NULL) {
            loadTileMap(fname);
        }
    };
    void draw() {
        disp.setFont(font5x7);
        disp.bgcolor=0;
        disp.clear();
        disp.setColor(15);
        disp.setCursor(2,2);
        disp.print((int)files);
        disp.print(" MAPS FOUND");
        disp.print(2,SH/2-3, fname);
        disp.setFont(fontWAR);

        disp.bgcolor = 12;
    };

};
#define MENU_STATE_MAIN 0
#define MENU_STATE_LEVEL 1
struct MainMenu {
    int state;
    struct Transition trans;
    char items[3][10];
    int selected_item;
    int box_x;
    int box_target;
    MainMenu() {
        state = MENU_STATE_MAIN;
        box_x = 0;
        box_target = 0;
        trans.off_val=SH+16;
        trans.on_val = SH-12;
        trans.val=trans.off_val;
        trans.enabled=true;
        strcpy(items[0], "CAMPAIGN");
        strcpy(items[1], "SKIRMISH");
        strcpy(items[2], "OPTIONS");
        selected_item = 1;
    };
    void update(LevelList *l) {
        switch (state) {
        case MENU_STATE_MAIN:
        box_x = lerp(box_x, box_target, 0.50);
        trans.update();
        if (btn.pressed(BTN_RIGHT)) {
            selected_item = min(selected_item + 1, 2);
            trans.val=trans.off_val;
        }
        if (btn.pressed(BTN_LEFT)) {
            selected_item = max(selected_item - 1, 0);
            trans.val=trans.off_val;
        }

        if (btn.pressed(BTN_A)) {
            switch (selected_item){
            case (0):   //CAMPAIGN
                break;
            case (1):   //SKIRMISH
                disp.clear();
                disp.print("LOADING");
                pokInitSD();
                loadTileMap("file_out.war");
                State = MAIN;
                break;
            case (2):   //OPTIONS
                state = MENU_STATE_LEVEL;
                break;
            }
        }
        break;
        case (MENU_STATE_LEVEL):
            if (btn.pressed(BTN_B)) {
                state = MENU_STATE_MAIN;
            }
            l->update();
        break;
        }//SWITCH
    };
    void draw(LevelList *l) {
        switch (state) {
        case (MENU_STATE_MAIN):
        disp.bgcolor=0;
        disp.clear();
        disp.setColor(15);
        disp.print(2,2,"POKIT WARS");
        disp.setColor(15);
        disp.print(SW/2-(strlen(items[selected_item])*6/2),trans.val, items[selected_item]);
        disp.fillRoundRect(box_x, SH/2, 16, 16,2);
        for (int i=0; i<3; i++) {
            int x = (SW/4)*(i+1)-8;
            int spr = 4+i;
            if (i==selected_item) {
                box_target = x;
                if (box_x-2<x&&box_x+2>x) {
                    box_x = x;
                }
            }
            disp.drawBitmap(x, SH/2, ui_sprites[spr]);
        }
        disp.bgcolor=12;
        break;
        case (MENU_STATE_LEVEL):
            l->draw();
        break;
        }//SWITCH
    };
};

int main() {
    MainMenu main_menu;
    PauseMenu pause_menu;
    Transition tTrans(66,96,false);
    Transition itemlist(1,-16,false);
    game.begin();
    game.initClock();
    game.initRandom();
    game.setFrameRate(30);
    disp.invisiblecolor = 12;
    disp.bgcolor=12;
    disp.persistence = 1;
    disp.directbgcolor = disp.palette[0];
    disp.directcolor = disp.palette[15];
    disp.load565Palette(sprite_pal);
    disp.textWrap=false;
    init_dark_palette();
    disp.setFont(fontWAR);
    map_x=0;
    map_y=0;
    cursor_x=4;
    cursor_y=6;
    vector<Hero> heros;
    hptr = &heros;
    pokInitSD();

    char dir[3];
    strcpy(dir, "War");

    LevelList level_menu;
    level_menu.init();

    bases[0] = Base(2,2,24,TEAM_USER, 0);
    bases[1] = Base(10,10,25,TEAM_CPU, 1);

    heros.push_back(Hero(4,5,ID_SOLDIER, TEAM_USER));
    heros.push_back(Hero(5,6,ID_SNIPER, TEAM_USER));
    heros.push_back(Hero(3,8,ID_HEAVY, TEAM_USER));
    heros.push_back(Hero(8,5,ID_HUNTER, TEAM_CPU));
    heros.push_back(Hero(8,7,ID_HUNTER, TEAM_CPU));
    heros.push_back(Hero(5,9,ID_HUNTER, TEAM_CPU));

    //Hero * cursor_hero = NULL;
    //Hero * current_hero = NULL;
    game.wait(10);
    splashScreen(48,"TRELEMAR", 7, 15);
    splashScreen(50,"VONBEDNAR", 15, 0);

    while (game.isRunning()) {
        if (game.update()) {
            switch (State) {
            case MENU:
                main_menu.update(&level_menu);
                main_menu.draw(&level_menu);
            break;
            case MAIN:
            tTrans.update();
            itemlist.update();
            //If no current hero or current task is to move our current hero, accept cursor movement.
            if ((!current_base&&!current_hero)||current_task==TASK_MOVE||current_task==TASK_ATTACK||current_task==TASK_SPAWN) {
                CursorInput();
                cursor_hero = getHeroAtCoords(cursor_x,cursor_y, heros);
            }
            //This will call when there is a current hero and not in a current task
            else if (current_hero||current_base) {
                //TASK SELECTOR
                int dir = 0;
                if (btn.pressed(BTN_RIGHT)) {
                    selected_task=min(selected_task+1,3);
                }
                if (btn.pressed(BTN_LEFT)) {
                    selected_task=max(selected_task-1,0);
                }
                if (selected_task==TASK_ITEM) {
                    itemlist.enabled = true;
                }
                else itemlist.enabled = false;
                //selected_task=selected_task%4;
            }

            DrawTileMap(map_x, map_y, current_hero);
            for (int i = 0; i<heros.size(); i++) {
                heros[i].Draw();
                heros[i].update(i);
            }
            for (int i=0; i<2; i++) {
                bases[i].Draw();
            }
            DrawCursor(cursor_x-map_x,cursor_y-map_y);
            disp.setColor(15);

            if (btn.pressed(BTN_A)) {
                if (!current_hero&&current_base&&current_task==TASK_SPAWN) {
                    int8_t id = selected_task + (current_base->faction*4);
                    selected_task = TASK_MOVE;
                    heros.push_back(Hero(cursor_x, cursor_y, id, current_team));
                    current_task = TASK_NONE;
                    current_hero = &heros[heros.size()-1];
                    current_base=NULL;
                }
                if (current_hero&&current_task!=TASK_NONE) {
                    //THIS IS WITHIN A TASK, EX: SELECTING A MOVE LOCATION OR ATTACK TARGET.
                    switch (current_task) {
                        case TASK_MOVE:
                            //MOVE HERO TO CURSOR, NO COLISSIONS YET.
                            //ONLY IF IN RANGE AND NOT SOLID
                            //FIX STACKABLE HEROS
                            if (current_hero->inRange(cursor_x, cursor_y)&&!getHeroAtCoords(cursor_x, cursor_y, heros)&&!solids[Map[cursor_y][cursor_x]]) {
                                if (cursor_x<current_hero->x) current_hero->flip=true;
                                else if (cursor_x>current_hero->x) current_hero->flip=false;
                                current_hero->x = cursor_x;
                                current_hero->y = cursor_y;

                                current_task = TASK_NONE;
                                current_hero->tasks[TASK_MOVE] = false;
                            }
                        break;
                        case TASK_ATTACK:
                            if (cursor_hero&&current_hero->inRange(cursor_hero)) {
                                //FOUND TARGET AT CURSOR.
                                cursor_x = current_hero->x;
                                cursor_y = current_hero->y;
                                int8_t result = cursor_hero->hp - (current_hero->atk-cursor_hero->def);
                                cursor_hero->hp = result;
                                cursor_hero->hurt_time=game.frameCount;
                                if (result<=0) {
                                        heros.erase(heros.begin()+cursor_hero->index);
                                        cursor_hero = NULL;
                                }

                                current_task = TASK_NONE;
                                current_hero->tasks[TASK_ATTACK] = false;
                            }
                            else {
                                //NO TARGET FOUND, ERROR SOUND SHOULD PLAY.
                            }
                        break;

                        //DUMMY CODE, THESE ARE CALLED BELOW. NOT HERE.
                        case TASK_ITEM:
                            current_task = TASK_NONE;
                            current_hero->tasks[TASK_ITEM] = false;
                        break;
                        case TASK_WAIT:
                            current_task = TASK_NONE;
                            current_hero->tasks[TASK_WAIT] = false;
                        break;
                    }
                }
                else if (current_hero&&current_hero->tasks[selected_task]==true) {
                    //TASK SWITCH HERE
                    //THIS HAPPENS DIRECTLY AFTER PRESSING BTN_A ON A NEW TASK.
                    current_task=selected_task;

                    switch (selected_task) {
                        case TASK_ITEM:
                            current_task = TASK_NONE;
                            current_hero->tasks[TASK_ITEM] = false;
                        break;
                        case TASK_WAIT:
                            current_task = TASK_NONE;
                            current_hero->tasks[TASK_WAIT] = false;
                        break;
                    }
                }
                else if (cursor_hero) {
                    //NO CURRENT HERO, SELECT A HERO ONLY IF IN CURSOR HERE.
                    if (cursor_hero->team == current_team) {
                        current_hero = cursor_hero;
                        selected_task = TASK_MOVE;
                        tTrans.enabled = true;
                    }
                }
                else if (current_base) {
                    current_task = TASK_SPAWN;
                }
                else if (bases[current_team].x==cursor_x&&bases[current_team].y==cursor_y) {
                    current_base = &bases[current_team];
                    tTrans.enabled = true;
                }
            }
            if (btn.pressed(BTN_B)) {
                if (current_task!=TASK_NONE) {
                        //BACK OUT OF CURRENT TASK.
                        current_task=TASK_NONE;
                        if (current_hero) {
                            cursor_x = current_hero->x;
                            cursor_y = current_hero->y;
                        }
                        if (current_base) {
                            cursor_x = current_base->x;
                            cursor_y = current_base->y;
                        }
                }
                else if (current_hero&&current_task==TASK_NONE) {
                        tTrans.enabled=false; current_hero = NULL; //UNSELECT HERO.
                }
                else if (current_base&&current_task==TASK_NONE) {
                        tTrans.enabled=false; current_base = NULL; //UNSELECT BASE
                }
            }
            if (btn.pressed(BTN_C)&& !current_hero) {
                //heros.push_back(Hero(cursor_x,cursor_y,0,0));
                //for (int i=0;i<heros.size();i++) heros[i].NewTurn();
                State = PAUSE;
                //disp.print("PAUSED");
                //tTrans.toggle();
            }
            if (cursor_hero&&cursor_hero!=current_hero&&current_task) {
                DrawCursorHeroUI(cursor_hero, (cursor_hero->x-map_x)*16-4,(cursor_hero->y-map_y)*16-7);
            }
            if (tTrans.val==tTrans.on_val&&!current_base) {
                DrawTraitList(current_hero, itemlist.val);
            }

            if (!current_base) {
                DrawSelectedHeroUI(current_hero, tTrans.val);
            }
            else if (!current_hero) {
                DrawSelectedBaseUI(current_base, tTrans.val);
            }
            disp.setCursor(0,0);
            DrawTurnCounter(heros);
            //disp.print(0,32,dtest.text);
            //disp.print(1,SH-6,(int)game.battery.level);
            //disp.print(" ");
            break;
            case PAUSE:
                pause_menu.update();
                pause_menu.draw();
            break;
        }//GAME STATE SWITCH

        }//UPDATE
    }//IS RUNNING
    return 1;
}