/* * map.hh - game map definitions header for Bombermaze * written by Sydney Tang * * 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 * * For more details see the file COPYING. */ #ifndef _BOMBER_MAP_H_ #define _BOMBER_MAP_H_ #include "ui.hh" #include #include class MapSquare; class GameMap; class Bomb; /////////////////////////////////////////////////////////////////////////////// enum Direction { DIR_NORTH = 0, DIR_EAST = 1, DIR_SOUTH = 2, DIR_WEST = 3, NUMBER_OF_DIRECTIONS = 4, DIR_NONE = 5, }; void get_direction_increments(Direction dir, int &x, int &y); int normalize(int n); struct Coordinate { int x; int y; }; gint compare_coordinates (gconstpointer a, gconstpointer b); /////////////////////////////////////////////////////////////////////////////// class Entity { public: enum EntityType { ENTITY_UNDEFINED, ENTITY_PLAYER, ENTITY_BOMB, ENTITY_FIRE, ENTITY_BRICK, ENTITY_WALL, ENTITY_POWERUP }; Entity(GameMap *gm); virtual ~Entity(); Sprite *sprite; virtual EntityType get_entity_type(void); virtual bool check_for_barrier_entity(Entity *entity); void update_ui(UIDrawable *drawable, UIGraphicsContext *gc, bool draw_top); unsigned get_frame(void); unsigned get_x(void); unsigned get_y(void); void get_coordinates(int &x_coordinate, int &y_coordinate); int get_y_step(void); bool check_if_delete_pending(void); virtual void animate(void); static unsigned get_square_steps(void); static void set_steps_to_middle_of_square(unsigned steps); protected: enum EntityConstants { STEPS_PER_SQUARE_MINIMUM = 0, DEFAULT_STEPS_PER_SQUARE = 2 }; static unsigned Steps_To_Middle_Of_Square; GameMap *maze; unsigned frame; int AnimationDelay; int move_delay; int x_step, y_step; int x_step_normalized, y_step_normalized; int dx, dy; int x, y; int x_old, y_old; int x_dest, y_dest; Direction moving_direction; bool DeletePending; bool start_moving(Direction dir, unsigned delay); bool continue_moving(void); void finish_moving(void); void update_location(void); void flag_overlapped_squares_for_update(void); }; /////////////////////////////////////////////////////////////////////////////// class Player: public Entity { public: enum PlayerStatus { PLAYER_INACTIVE, PLAYER_TOASTED, PLAYER_IDLE, PLAYER_MOVING, PLAYER_MOVING_FINISHED }; enum PlayerAction { PLAYER_MOVE_NORTH, PLAYER_MOVE_EAST, PLAYER_MOVE_SOUTH, PLAYER_MOVE_WEST, PLAYER_DROP_BOMB, PLAYER_SPECIAL, NUMBER_OF_PLAYER_ACTIONS }; enum PlayerFrameSet { PLAYER_FRAME_NORTH, PLAYER_FRAME_EAST, PLAYER_FRAME_SOUTH, PLAYER_FRAME_WEST, PLAYER_FRAME_TOASTED, NUMBER_OF_PLAYER_FRAMESETS }; enum PlayerMoveFrame { PLAYER_FRAME_MOVE_R_STEP, PLAYER_FRAME_MOVE_R_PUSH, PLAYER_FRAME_MOVE_R_BACK, PLAYER_FRAME_MOVE_R_LIFT, PLAYER_STANDING_STILL, NUMBER_OF_PLAYER_MOVE_FRAMES }; enum PlayerDieFrame { PLAYER_FRAME_START_DYING = 0, NUMBER_OF_PLAYER_DIE_FRAMES = NUMBER_OF_PLAYER_MOVE_FRAMES }; enum PlayerConstants { MAX_NUMBER_OF_PLAYERS = 4, MAX_NUMBER_OF_LOCAL_PLAYERS = 4, PLAYER_MOVE_DELAY_MINIMUM = 1, MOVEMENT_MODULUS = 4, DIE_FRAME_DELAY = 4, PLAYER_FRAME_TOTAL = NUMBER_OF_PLAYER_FRAMESETS * NUMBER_OF_PLAYER_MOVE_FRAMES }; static Sprite sprite[MAX_NUMBER_OF_PLAYERS]; Player(); Player(int player_id); ~Player(); Entity::EntityType get_entity_type(void); bool check_for_barrier_entity(Entity *entity); static bool load_sprite(void); /* Player actions */ void perform_action(PlayerAction action); bool activate(void); bool move(Direction dir); void set_facing_direction(Direction dir); bool drop_bomb(); void decrement_bombs_dropped(void); void special_action(void); void die(void); void animate(void); void animate_movement(void); void animate_idle(void); void animate_dying(void); /* status queries */ int get_id(void); PlayerStatus get_status(void); Direction get_facing_direction(void); /* player settings */ void reset_fields(void); void set_id(int new_id); void set_game_map(GameMap *gm); void set_starting_coordinates(unsigned starting_x, unsigned starting_y); unsigned get_blast_radius(void); unsigned get_max_bombs(void); void increment_blast_radius(void); void increment_max_bombs(void); void increase_speed(void); void set_trigger_bombs(bool ability); void set_kick_bombs(bool ability); static void set_initial_move_delay(unsigned delay_frames = DEFAULT_PLAYER_MOVE_DELAY); static void set_initial_max_bombs(unsigned bombs = DEFAULT_BOMBS_PER_PLAYER); static void set_initial_blast_radius(unsigned radius = DEFAULT_BOMB_BLAST_RADIUS); protected: enum DefaultPlayerParameters { DEFAULT_PLAYER_MOVE_DELAY = 3, DEFAULT_BOMBS_PER_PLAYER = 1, DEFAULT_BOMB_BLAST_RADIUS = 2 }; static const unsigned FrameSetStart[NUMBER_OF_PLAYER_FRAMESETS]; static unsigned Initial_Move_Delay; static unsigned Initial_Max_Bombs; static unsigned Initial_Blast_Radius; int id; unsigned frameset_index; PlayerStatus status; Direction facing_direction; Direction pending_move_direction; int x_initial, y_initial; unsigned player_move_delay; unsigned max_bombs; unsigned bombs_dropped; unsigned bomb_blast_radius; bool can_trigger_bombs; bool can_kick_bombs; void trigger_bombs(void); void finish_dying(void); }; // class Player /////////////////////////////////////////////////////////////////////////////// class Bomb: public Entity { public: enum BombStatus { BOMB_INACTIVE, BOMB_ACTIVE, BOMB_EXPLODING, BOMB_IMPENDING_EXPLOSION }; enum BombFrames { BOMB_FRAME_ACTIVE_START, BOMB_FRAME_ACTIVE_1, BOMB_FRAME_ACTIVE_2, BOMB_FRAME_ACTIVE_END, BOMB_FRAME_TRIGGERABLE, BOMB_FRAME_INACTIVE, BOMB_FRAME_TOTAL }; enum BombConstants { BOMB_ACTIVE_ANIMATION_MODULUS = BOMB_FRAME_ACTIVE_END - BOMB_FRAME_ACTIVE_START + 1 }; static Sprite sprite; Bomb(GameMap *gm, Player *owner_of_bomb); ~Bomb(); Entity::EntityType get_entity_type(void); bool check_for_barrier_entity(Entity *entity); void drop(unsigned new_x, unsigned new_y); void explode(void); void chain_explode(void); bool move(Direction dir); void deactivate(void); void set_triggerable(bool setting); bool is_active(void); bool is_exploded(void); bool is_triggerable(void); bool check_if_player_is_owner(Player *player); unsigned get_blast_radius(void); static bool load_sprite(void); void animate(void); static void set_initial_countdown(float count_seconds = DEFAULT_COUNTDOWN_SECONDS); static void set_chain_reaction_delay(unsigned frame_delay = DEFAULT_CHAIN_REACTION_DELAY); protected: enum DefaultBombParameters { DEFAULT_MOVE_DELAY = 1, DEFAULT_INITIAL_COUNTDOWN = 80, DEFAULT_CHAIN_REACTION_DELAY = 0 }; static const float DEFAULT_COUNTDOWN_SECONDS; static unsigned Bomb_Move_Delay; static unsigned Initial_Countdown; static unsigned Chain_Reaction_Delay; BombStatus status; bool triggerable; bool moving; Player *owner; }; // class Bomb /////////////////////////////////////////////////////////////////////////////// class Fire: public Entity { public: enum FlameDirection { FLAME_0 = 0x00, FLAME_N = 0x01, FLAME_E = 0x02, FLAME_NE = 0x03, FLAME_S = 0x04, FLAME_NS = 0x05, FLAME_ES = 0x06, FLAME_NES = 0x07, FLAME_W = 0x08, FLAME_NW = 0x09, FLAME_EW = 0x0A, FLAME_NEW = 0x0B, FLAME_SW = 0x0C, FLAME_NSW = 0x0D, FLAME_ESW = 0x0E, FLAME_NESW= 0x0F, NUMBER_OF_FLAME_TYPES }; enum DefaultFlameParameters { DEFAULT_FLAME_DURATION = 25 }; Entity::EntityType get_entity_type(void); bool check_for_barrier_entity(Entity *entity); static const FlameDirection DirectionFlagsLeading[NUMBER_OF_DIRECTIONS]; static const FlameDirection DirectionFlagsLagging[NUMBER_OF_DIRECTIONS]; static Sprite sprite; Fire(GameMap *gm, int new_x, int new_y, FlameDirection dir = FLAME_0); ~Fire(); static bool load_sprite(void); void animate(void); void set_direction_flags(Fire::FlameDirection flags); static void set_flame_duration(unsigned frame_duration = DEFAULT_FLAME_DURATION); protected: static unsigned Duration; FlameDirection directions; int FadeDelay[NUMBER_OF_DIRECTIONS]; }; // class Fire /////////////////////////////////////////////////////////////////////////////// class Brick: public Entity { public: enum BrickState { BRICK_NORMAL, BRICK_SHATTERED, }; enum BrickFrames { BRICK_FRAME_NORMAL, BRICK_FRAME_SHATTER_START, BRICK_FRAME_SHATTER_MID, BRICK_FRAME_SHATTER_END, BRICK_FRAME_TOTAL, }; enum BrickConstants { DEFAULT_BRICK_SHATTER_DURATION = 6, BRICK_SHATTER_FRAMES = BRICK_FRAME_SHATTER_END-BRICK_FRAME_SHATTER_START+1 }; static Sprite sprite; Brick(GameMap *gm, int new_x, int new_y); ~Brick(); Entity::EntityType get_entity_type(void); bool check_for_barrier_entity(Entity *entity); static bool load_sprite(void); void animate(void); void shatter(void); static void set_shatter_duration(unsigned total_frame_duration = DEFAULT_BRICK_SHATTER_DURATION * BRICK_SHATTER_FRAMES); protected: static unsigned Shatter_Frame_Duration; BrickState state; void animate_shatter(void); }; // class Brick /////////////////////////////////////////////////////////////////////////////// class Wall: public Entity { public: enum WallFrames { WALL_FRAME, WALL_FRAME_TOTAL }; static Sprite sprite; Wall(GameMap *gm, int new_x, int new_y); ~Wall(); Entity::EntityType get_entity_type(void); bool check_for_barrier_entity(Entity *entity); static bool load_sprite(void); void animate(void); protected: }; // class Wall /////////////////////////////////////////////////////////////////////////////// class PowerUp: public Entity { public: enum PowerUpType { POWERUP_EXTRA_BOMB, POWERUP_EXTRA_RANGE, POWERUP_TRIGGER_BOMB, POWERUP_KICK_BOMB, POWERUP_EXTRA_SPEED, POWERUP_FIREBALL, POWERUP_DESTROYED_START, POWERUP_DESTROYED_MID, POWERUP_DESTROYED_END, NUMBER_OF_POWERUP_TYPES }; enum PowerUpConstants { NUMBER_OF_CREATABLE_POWERUPS = 5, DEFAULT_PROBABILITY_OF_POWERUP = 30, DEFAULT_POWERUP_SHATTER_DURATION = 6, POWERUP_SHATTER_FRAMES = POWERUP_DESTROYED_END - POWERUP_DESTROYED_START + 1 }; static Sprite sprite; PowerUp(GameMap *gm, int new_x, int new_y); ~PowerUp(); Entity::EntityType get_entity_type(void); bool check_for_barrier_entity(Entity *entity); static bool load_sprite(void); void animate(void); void destroy(void); static bool randomly_create_powerup(void); static void set_probability_of_powerup(unsigned percent_probability = DEFAULT_PROBABILITY_OF_POWERUP); static void set_probability_of_each_powerup_type (int percent_probability[NUMBER_OF_CREATABLE_POWERUPS]); static void set_shatter_duration(unsigned total_frame_duration = DEFAULT_POWERUP_SHATTER_DURATION * POWERUP_SHATTER_FRAMES); protected: PowerUpType power; private: static unsigned Shatter_Frame_Duration; static float Probability_Of_PowerUp; static const float PowerUp::DefaultProbability[NUMBER_OF_CREATABLE_POWERUPS]; static float Probability[NUMBER_OF_CREATABLE_POWERUPS]; void determine_powerup_type(void); void animate_shatter(void); }; // class PowerUp /////////////////////////////////////////////////////////////////////////////// class MapSquare { public: enum SquareStatus { SQUARE_EMPTY, SQUARE_WALL, SQUARE_BRICK, SQUARE_BOMB, SQUARE_FIRE, SQUARE_POWERUP, SQUARE_INVALID }; enum SquareStatusCharacter { CHAR_SQUARE_EMPTY = '.', CHAR_SQUARE_WALL = '#', CHAR_SQUARE_BRICK = '=', CHAR_SQUARE_RANDOM = '*', CHAR_SQUARE_RANDOM_EMPTY_OR_BRICK = '-', CHAR_SQUARE_RANDOM_EMPTY_OR_WALL = '|', CHAR_SQUARE_RANDOM_BRICK_OR_WALL = '+', CHAR_SQUARE_BOMB = '@', CHAR_SQUARE_FIRE = '*' }; enum SquareConstants { DEFAULT_SQUARE_WIDTH = 32, DEFAULT_SQUARE_HEIGHT = 32 }; //static Sprite FloorSprite; Coordinate location; Coordinate PixelLocation; bool RepaintRequired; GSList *EntityList; MapSquare(void); ~MapSquare(); static int get_square_width(); static int get_square_height(); SquareStatus get_status(void); int assign_status(char ch); int get_player_who_starts_here(void); bool check_if_square_is_clear(Entity *entity); bool check_if_square_is_clear(void); bool check_if_bomb_exists(void); void set_fire(void); void clear_fire(void); void destroy_brick(void); void set_powerup(void); void destroy_powerup(void); static bool load_sprite(void); protected: static int Square_Width; static int Square_Height; SquareStatus status; int PlayerWhoStartsHere; static void set_square_dimensions(int x, int y); /* friend gint repaint_floor (gpointer key, gpointer value, gpointer data); friend gint repaint_entities (gpointer key, gpointer value, gpointer data); friend gint repaint_display (gpointer key, gpointer value, gpointer data); */ }; // class MapSquare /////////////////////////////////////////////////////////////////////////////// class ParsedMap { public: ParsedMap(); ~ParsedMap(); void allocate_map(int w, int h); void deallocate_map(void); unsigned get_width(); unsigned get_height(); bool set_square(char square_type, unsigned x, unsigned y); char get_square(unsigned x, unsigned y); void set_valid(bool validity); bool check_if_valid(void); protected: char **map; unsigned width; unsigned height; bool valid; }; /////////////////////////////////////////////////////////////////////////////// class GameMap { public: enum GameMapStatus { MAP_INVALID, MAP_NORMAL }; GameMap(void); ~GameMap(); static int parse_map(const char *MapName, ParsedMap *TemplateMap); void assign_map_from_parsed_map(ParsedMap *TemplateMap); void populate_map(void); void depopulate_map(void); GameMapStatus get_status(void); void set_ui_target( UIDrawable *target, UIGraphicsContext *context, UIDrawable *buffer); UIDrawable * get_ui_target(void); MapSquare::SquareStatus get_square_status(int x, int y); bool check_if_square_is_clear(Entity *entity, int x, int y); bool check_if_bomb_exists(int x, int y); bool check_if_fire_exists(int x, int y); void get_starting_coordinates_of_player(int player, int &x, int &y); int get_allowable_number_of_players(void); int get_width(void); int get_height(void); int check_if_repaint_required(int x, int y); void set_repaint_required(bool requirement, int x, int y); void update_ui(void); void repaint_offscreen(void); void repaint_floor(void); void repaint_entities(void); void repaint_display(void); GSList *get_entity_list(int x, int y); void remove_entity(Entity *entity, int x, int y); void move_entity_to_top(Entity *entity, int x, int y); void move_entity_to_bottom(Entity *entity, int x, int y); void animate_map_entities(void); void trim_entity_list(GSList **EntityList); void clear_entity_list(GSList **EntityList); void insert_into_unconditional_update_list(Entity *entity); Bomb *create_bomb(Player *player, int x, int y); void explode_bombs_belonging_to_player(Player *player); void kick_bomb(Direction dir, int x, int y); void create_explosion(unsigned radius, int x, int y); void propagate_fire(Direction dir, int radius, int cx, int cy); void create_fire(int x, int y); void clear_fire(int x, int y); void set_flame_direction_flags(Fire::FlameDirection flags, int x, int y); void destroy_brick(int x, int y); void create_powerup(int x, int y); void destroy_powerup(int x, int y); static void set_walled_perimeter(bool walled, bool top_only); protected: GameMapStatus status; MapSquare **map; static bool WalledPerimeter; static bool WalledPerimeterTopOnly; int width; int height; int AllowableNumberOfPlayers; int PlayerStartingCoordinateX[Player::MAX_NUMBER_OF_PLAYERS]; int PlayerStartingCoordinateY[Player::MAX_NUMBER_OF_PLAYERS]; GSList *BombList; GSList *FireList; GSList *BrickList; GSList *WallList; GSList *PowerUpList; //GTree *SquaresToBeRepainted; UIDrawable *DisplayBuffer; UIDrawable *DisplayWindow; UIGraphicsContext *DisplayContext; void allocate_map(MapSquare ***m); void deallocate_map(MapSquare ***m); void set_square_coordinates(int x, int y); void set_boundaries_by_perimeter( int &w, int &h, int &w_min, int &h_min, int &w_max, int &h_max, int &w_read_offset, int &h_read_offset ); void set_player_starting_coordinate(int w, int h); void assign_perimeter_map_squares(void); static int determine_map_dimensions(FILE *MapFile, int *w, int *h); void determine_allowable_number_of_players(void); /* friend gint repaint_floor (gpointer key, gpointer value, gpointer data); friend gint repaint_entities (gpointer key, gpointer value, gpointer data); friend gint repaint_display (gpointer key, gpointer value, gpointer data); */ }; // class GameMap /////////////////////////////////////////////////////////////////////////////// #endif