/*  
    level.h

    Copyright (C) 2010-2019 Amf

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version. 

    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#define MOVE_LEFT           0
#define MOVE_UP             1
#define MOVE_RIGHT          2
#define MOVE_DOWN           3
#define MOVE_NONE           4
#define MOVE_SWAP           5
#define MOVE_SWAPPED        6
#define MOVE_UNKNOWN        7
#define MOVE_REDO           8

#define MOVER_FAST          1
#define MOVER_UNDO          2
#define MOVER_STORE         4

#define LEVELFLAG_MOVES     1
#define LEVELFLAG_STARS     2
#define LEVELFLAG_SWITCH    4
#define LEVELFLAG_EXIT      8
#define LEVELFLAG_SOLVED    16
#define LEVELFLAG_FAILED    32
#define LEVELFLAG_PAUSED    64
#define LEVELFLAG_UNDO      128
#define LEVELFLAG_TESTING   256
#define LEVELFLAG_MAP       512
#define LEVELFLAG_NOUNDO    1024

#ifdef XOR_COMPATIBILITY
#define MAPPED_TOP_LEFT     1
#define MAPPED_TOP_RIGHT    2
#define MAPPED_BOTTOM_LEFT  4
#define MAPPED_BOTTOM_RIGHT 8
#endif

enum {
    PIECE_SPACE = 0,
    PIECE_WALL = 1,
    PIECE_PLAYER_ONE = 2,
    PIECE_PLAYER_TWO = 3,
    PIECE_STAR = 4,
    PIECE_DOTS = 5,
    PIECE_DOOR = 6,
    PIECE_CIRCLE = 7,
    PIECE_ARROW_RED_LEFT = 8,           /* PIECE_ARROW_RED_LEFT % 4 must = 0 */
    PIECE_ARROW_RED_UP = 9,
    PIECE_ARROW_RED_RIGHT = 10,
    PIECE_ARROW_RED_DOWN = 11,
    PIECE_BOMB_RED_LEFT = 12,
    PIECE_BOMB_RED_UP = 13,
    PIECE_BOMB_RED_RIGHT = 14,
    PIECE_BOMB_RED_DOWN = 15,
    PIECE_ARROW_GREEN_LEFT = 16,
    PIECE_ARROW_GREEN_UP = 17,
    PIECE_ARROW_GREEN_RIGHT = 18,
    PIECE_ARROW_GREEN_DOWN = 19,
    PIECE_BOMB_GREEN_LEFT = 20,
    PIECE_BOMB_GREEN_UP = 21,
    PIECE_BOMB_GREEN_RIGHT = 22,
    PIECE_BOMB_GREEN_DOWN = 23,
    PIECE_ARROW_BLUE_LEFT = 24,
    PIECE_ARROW_BLUE_UP = 25,
    PIECE_ARROW_BLUE_RIGHT = 26,
    PIECE_ARROW_BLUE_DOWN = 27,
    PIECE_BOMB_BLUE_LEFT = 28,
    PIECE_BOMB_BLUE_UP = 29,
    PIECE_BOMB_BLUE_RIGHT = 30,
    PIECE_BOMB_BLUE_DOWN = 31,

#ifdef ENIGMA_COMPATIBILITY
    PIECE_CIRCLE_DOUBLE,
    PIECE_DOTS_DOUBLE,
#endif

#ifdef XOR_COMPATIBILITY
    PIECE_DOTS_X,
    PIECE_DOTS_Y,
    PIECE_SWITCH,
    PIECE_TELEPORT,
    PIECE_MAP_TOP_LEFT,
    PIECE_MAP_TOP_RIGHT,
    PIECE_MAP_BOTTOM_LEFT,
    PIECE_MAP_BOTTOM_RIGHT,
    PIECE_DARKNESS,
#endif

    PIECE_EXPLOSION_RED_LEFT,
    PIECE_EXPLOSION_RED_HORIZONTAL,
    PIECE_EXPLOSION_RED_RIGHT,
    PIECE_EXPLOSION_RED_TOP,
    PIECE_EXPLOSION_RED_VERTICAL,
    PIECE_EXPLOSION_RED_BOTTOM,
    PIECE_EXPLOSION_GREEN_LEFT,
    PIECE_EXPLOSION_GREEN_HORIZONTAL,
    PIECE_EXPLOSION_GREEN_RIGHT,
    PIECE_EXPLOSION_GREEN_TOP,
    PIECE_EXPLOSION_GREEN_VERTICAL,
    PIECE_EXPLOSION_GREEN_BOTTOM,
    PIECE_EXPLOSION_BLUE_LEFT,
    PIECE_EXPLOSION_BLUE_HORIZONTAL,
    PIECE_EXPLOSION_BLUE_RIGHT,
    PIECE_EXPLOSION_BLUE_TOP,
    PIECE_EXPLOSION_BLUE_VERTICAL,
    PIECE_EXPLOSION_BLUE_BOTTOM,

    PIECE_EXPLOSION_NEW_RED_LEFT,
    PIECE_EXPLOSION_NEW_RED_HORIZONTAL,
    PIECE_EXPLOSION_NEW_RED_RIGHT,
    PIECE_EXPLOSION_NEW_RED_TOP,
    PIECE_EXPLOSION_NEW_RED_VERTICAL,
    PIECE_EXPLOSION_NEW_RED_BOTTOM,
    PIECE_EXPLOSION_NEW_GREEN_LEFT,
    PIECE_EXPLOSION_NEW_GREEN_HORIZONTAL,
    PIECE_EXPLOSION_NEW_GREEN_RIGHT,
    PIECE_EXPLOSION_NEW_GREEN_TOP,
    PIECE_EXPLOSION_NEW_GREEN_VERTICAL,
    PIECE_EXPLOSION_NEW_GREEN_BOTTOM,
    PIECE_EXPLOSION_NEW_BLUE_LEFT,
    PIECE_EXPLOSION_NEW_BLUE_HORIZONTAL,
    PIECE_EXPLOSION_NEW_BLUE_RIGHT,
    PIECE_EXPLOSION_NEW_BLUE_TOP,
    PIECE_EXPLOSION_NEW_BLUE_VERTICAL,
    PIECE_EXPLOSION_NEW_BLUE_BOTTOM,

    PIECE_CURSOR,
    PIECE_GONE,
    PIECE_UNKNOWN
};

#define PIECE_EXPLOSION_FIRST   PIECE_EXPLOSION_RED_LEFT
#define PIECE_EXPLOSION_LAST    PIECE_EXPLOSION_BLUE_BOTTOM
#define PIECE_EXPLOSION_NEW_FIRST   PIECE_EXPLOSION_NEW_RED_LEFT
#define PIECE_EXPLOSION_NEW_LAST    PIECE_EXPLOSION_NEW_BLUE_BOTTOM
#define PIECE_EXPLOSION_NEW_OFFSET  (PIECE_EXPLOSION_NEW_FIRST - PIECE_EXPLOSION_FIRST)
#define PIECE_MOVERS_FIRST  PIECE_ARROW_RED_LEFT
#define PIECE_MOVERS_LAST   PIECE_BOMB_BLUE_DOWN
#define PIECE_MAX       PIECE_GONE

#define isexplosion(x) (x >= PIECE_EXPLOSION_FIRST && x<= PIECE_EXPLOSION_LAST)
#define isnewexplosion(x) (x >= PIECE_EXPLOSION_NEW_FIRST && x <= PIECE_EXPLOSION_NEW_LAST)

enum {
    MODE_CHROMA,
#ifdef XOR_COMPATIBILITY
    MODE_XOR,
#endif
#ifdef ENIGMA_COMPATIBILITY
    MODE_ENIGMA,
#endif
    MODE_MAX
};

struct mover
{
    int x;
    int y;
    int direction;
    int piece;
    int piece_previous;
    int fast;
    struct mover* next;
    struct mover* previous;
};

struct move
{
    int count;
    int direction;
    struct move* previous;
    struct move* next;
    struct mover* mover_first;
    struct mover* mover_last;
};

struct level
{
    int size_x;
    int size_y;

    char *data_pieces;
    char *data_moving;
    char *data_previous;
    char *data_previousmoving;
    char *data_detonator;
    char *data_detonatormoving;
    unsigned int *data_data;

    struct move* move_first;
    struct move* move_last;
    struct move* move_current;

    struct mover* mover_first;
    struct mover* mover_last;

    struct mover* stack_first;
    struct mover* stack_last;

    int player;
    int player_x[3];
    int player_y[3];
    int view_x[3];
    int view_y[3];
    int alive[2];
   
    int moves;

    int stars_caught;
    int stars_exploded;
    int stars_total;

    char *title;

    int flags;

#ifdef XOR_COMPATIBILITY
    int switched;
    int mapped;
#endif

    int mode;
    int level;

    int teleport_x[2];
    int teleport_y[2];
    int view_teleport_x[2];
    int view_teleport_y[2];
};

/* level.c */
char piecetochar(int piece);
int chartopiece(char c);
char directiontochar(int direction);
int chartodirection(char c);

struct level* level_new();
struct level* level_load(char *filename, int partial);
int level_save(struct level* plevel, char *filename, int partial);
struct level* level_copy(struct level*);
void level_addmove(struct level*, int);
void level_fix(struct level*);
struct level* level_create(int, int);
void level_delete(struct level* plevel);

char level_piece(struct level*, int, int);
void level_setpiece(struct level*, int, int, char);
char level_moving(struct level*, int, int);
void level_setmoving(struct level*, int, int, char);
char level_previous(struct level*, int, int);
void level_setprevious(struct level*, int, int, char);
char level_detonator(struct level*, int, int);
void level_setdetonator(struct level*, int, int, char);
char level_detonatormoving(struct level*, int, int);
void level_setdetonatormoving(struct level*, int, int, char);
char level_previousmoving(struct level*, int, int);
void level_setpreviousmoving(struct level*, int, int, char);
unsigned int level_data(struct level*, int, int);
void level_setdata(struct level*, int, int, unsigned int);
void level_settitle(struct level* plevel, char *title);

/* engine.c */
int level_move(struct level*, int);
int level_evolve(struct level*);
int canfall(int p, int into, int d);
struct mover* mover_new(struct level* plevel, int x, int y, int d, int piece, int fast);
struct mover* mover_addtostack(struct level* plevel, int x, int y, int move);
void level_storemovers(struct level*);
int level_undo(struct level*);
struct mover* mover_newundo(struct level* plevel, int x, int y, int d, int piece, int previous, int flags);
