/* * ui.cc - UI-specific code 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. */ #include #include #include #include #include #include "map.hh" #include "ui.hh" #include "preferences.hh" #include "input.hh" #include "game.hh" #include #ifdef ENABLE_NLS #include #include #endif ////////////////////////////////////////////////////////////////////////////// const char *WINDOW_TITLE = N_("BomberMaze"); const gchar *COPYRIGHT = N_("(C) 2000 Sydney Tang"); const gchar *AUTHORS[] = { "Sydney Tang", NULL }; const gchar *COMMENTS = N_("Send comments and bug reports to: \n" " stang@users.sourceforge.net\n"); const gchar *LOGO = NULL; const int INITIAL_DRAWING_AREA_WIDTH = 720; const int INITIAL_DRAWING_AREA_HEIGHT = 600; ////////////////////////////////////////////////////////////////////////////// static char *ThemeDirectory = NULL; static bool ThemeIsValid = false; static bool PendingThemeApplication = false; static UIDisplayInterface DrawingDisplay = { NULL, NULL }; static GtkWidget *AppWindow; static GtkWidget *StatusBar; static GtkWidget *GameDisplay; static GtkWidget *RoundLabel; static GtkWidget *PlayerLabel[Player::MAX_NUMBER_OF_PLAYERS]; static GtkWidget *PlayerScoreLabel[Player::MAX_NUMBER_OF_PLAYERS]; static GdkPixmap *CurrentDisplayPixmap; static GdkPixbuf *TitlePixbuf; static int TitleWidth; static int TitleHeight; static GdkPixmap *TitlePixmap; static Sprite FloorSprite; static GdkPixmap *MazePixmap = NULL; static bool AlreadyPaused = false; ////////////////////////////////////////////////////////////////////////////// static gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ); static void destroy( GtkWidget *widget, gpointer data ); static gboolean realize_game_display( GtkWidget *widget, gpointer data ); static gboolean focus_in_event( GtkWidget *widget, GdkEventFocus *event, gpointer data); static gboolean focus_out_event( GtkWidget *widget, GdkEventFocus *evt, gpointer data); static void ui_about(GtkWidget *widget, gpointer data); static void ui_properties(GtkWidget *widget, gpointer data); static void ui_menu_quit_game(GtkWidget *widget, gpointer data); static bool ui_create_widgets(void); static void ui_create_status_bar_widgets(GtkWidget *bar); static void ui_unref_widgets(void); static bool ui_load_title_screen(void); static bool ui_load_images(void); static bool ui_load_theme(void); static bool ui_load_theme_and_check_success(void); static void ui_set_theme_directory(const char *directory); static void ui_release_images(void); static void ui_release_theme(void); int main( int argc, char *argv[] ); ////////////////////////////////////////////////////////////////////////////// GnomeUIInfo Game_Menu[] = { GNOMEUIINFO_MENU_PAUSE_GAME_ITEM(game_toggle_pause, NULL), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_NEW_ITEM(N_("New 2 player game"), NULL, game_start_new, 2), GNOMEUIINFO_MENU_NEW_ITEM(N_("New 3 player game"), NULL, game_start_new, 3), GNOMEUIINFO_MENU_NEW_ITEM(N_("New 4 player game"), NULL, game_start_new, 4), GNOMEUIINFO_ITEM_NONE(N_("Quit game"), N_("Quit game"), ui_menu_quit_game), GNOMEUIINFO_END }; GnomeUIInfo Settings_Menu[] = { GNOMEUIINFO_MENU_PREFERENCES_ITEM (ui_properties, NULL), GNOMEUIINFO_END }; GnomeUIInfo Help_Menu[] = { GNOMEUIINFO_HELP((void *)PACKAGE), GNOMEUIINFO_MENU_ABOUT_ITEM(ui_about, NULL), GNOMEUIINFO_END }; GnomeUIInfo Menu_Bar[] = { GNOMEUIINFO_MENU_GAME_TREE(Game_Menu), GNOMEUIINFO_MENU_SETTINGS_TREE(Settings_Menu), GNOMEUIINFO_MENU_HELP_TREE(Help_Menu), GNOMEUIINFO_END }; ////////////////////////////////////////////////////////////////////////////// void ui_quit_game(void) { game_terminate(); ui_release_images(); preferences_uninitialize(); ui_unref_widgets(); gtk_main_quit(); } void ui_clear_status_message(void) { gnome_appbar_clear_stack(GNOME_APPBAR(StatusBar)); } void ui_clear_score_display(void) { gtk_label_set_text (GTK_LABEL(RoundLabel), _("-")); for (int i = 0; i < Player::MAX_NUMBER_OF_PLAYERS; i++) { gtk_label_set_text (GTK_LABEL(PlayerScoreLabel[i]), _("-")); } } bool ui_set_theme(const char *directory) { if (directory == NULL) { ThemeIsValid = false; return false; } if ((ThemeDirectory != NULL) && (strcmp(directory, ThemeDirectory) == 0)) { return true; } ui_set_theme_directory(directory); Sprite::set_source_directory(ThemeDirectory); if ((CurrentDisplayPixmap != NULL) && (CurrentDisplayPixmap == MazePixmap)) { PendingThemeApplication = true; char *message = _("New theme will be applied at the\n" "beginning of the next round."); if (AppWindow != NULL) { gnome_ok_dialog_parented (message, GTK_WINDOW(AppWindow)); } else { gnome_ok_dialog (message); } return true; } else { return ui_load_theme_and_check_success(); } } bool ui_check_for_valid_theme(void) { return ThemeIsValid; } bool ui_apply_pending_theme_change(void) { if (PendingThemeApplication == true) { return ui_load_theme_and_check_success(); } return true; } void ui_notify_invalid_theme(void) { gnome_warning_dialog_parented (_("Current theme has invalid format.\n" "Please select another one from the\n" "Preferences dialog."), GTK_WINDOW(AppWindow)); } void ui_notify_invalid_map(void) { gnome_warning_dialog_parented (_("Current map file has invalid format.\n" "Please select another one from the\n" "Preferences dialog."), GTK_WINDOW(AppWindow)); } void ui_warning_dialog(GtkWidget *parent, char *message) { GtkWidget *dialog_parent; if (parent != NULL) { dialog_parent = parent; } else { dialog_parent = AppWindow; } gnome_warning_dialog_parented (message, GTK_WINDOW(dialog_parent)); } ////////////////////////////////////////////////////////////////////////////// gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ) { return FALSE; } void destroy( GtkWidget *widget, gpointer data ) { ui_quit_game(); } gboolean realize( GtkWidget *widget, gpointer data ) { UIDisplayInterface *display = (UIDisplayInterface *)data; display->gc = widget->style->fg_gc[widget->state]; display->window = widget->window; return TRUE; } gboolean realize_game_display( GtkWidget *widget, gpointer data ) { realize(widget, data); Sprite::set_source_window(DrawingDisplay.window); return TRUE; } gboolean expose_event( GtkWidget *widget, GdkEventExpose *event, gpointer data) { GdkDrawable *source = *((GdkDrawable **)data); if (source == NULL) return FALSE; GdkGC *gc = widget->style->fg_gc[widget->state]; gdk_window_clear_area (widget->window, event->area.x, event->area.y, event->area.width, event->area.height); gdk_gc_set_clip_rectangle (gc, &event->area); gdk_draw_pixmap(widget->window, gc, source, 0, 0, 0, 0, -1, -1); gdk_gc_set_clip_rectangle (gc, NULL); return TRUE; } gboolean focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) { if (AlreadyPaused == false) { game_set_pause(false); } return TRUE; } gboolean focus_out_event(GtkWidget *widget, GdkEventFocus *evt, gpointer data) { AlreadyPaused = game_get_pause(); if (AlreadyPaused == false) { game_set_pause(true); } return TRUE; } ////////////////////////////////////////////////////////////////////////////// void ui_about(GtkWidget *widget, gpointer data) { static GtkWidget *AboutDialog; if (AboutDialog == NULL) { AboutDialog = gnome_about_new (_(WINDOW_TITLE), VERSION, _(COPYRIGHT), AUTHORS, _(COMMENTS), LOGO); gtk_signal_connect (GTK_OBJECT(AboutDialog), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &AboutDialog); gnome_dialog_set_parent(GNOME_DIALOG(AboutDialog), GTK_WINDOW(AppWindow)); gtk_widget_show(AboutDialog); } else { } } void ui_properties(GtkWidget *widget, gpointer data) { preferences_show_dialog(); } void ui_menu_quit_game(GtkWidget *widget, gpointer data) { ui_quit_game(); } ////////////////////////////////////////////////////////////////////////////// bool ui_create_widgets(void) { gdk_rgb_init(); gtk_widget_set_default_colormap (gdk_rgb_get_cmap()); gtk_widget_set_default_visual (gdk_rgb_get_visual()); AppWindow = gnome_app_new (PACKAGE, _(WINDOW_TITLE)); gtk_window_set_policy ((GtkWindow *)AppWindow, false, false, true); GameDisplay = gtk_drawing_area_new(); gtk_drawing_area_size ((GtkDrawingArea *)GameDisplay, INITIAL_DRAWING_AREA_WIDTH, INITIAL_DRAWING_AREA_HEIGHT); gtk_widget_set_usize ((GtkWidget *)GameDisplay, INITIAL_DRAWING_AREA_WIDTH, INITIAL_DRAWING_AREA_HEIGHT); gtk_widget_show (GameDisplay); StatusBar = gnome_appbar_new(FALSE, TRUE, GNOME_PREFERENCES_NEVER); ui_create_status_bar_widgets(StatusBar); gtk_signal_connect (GTK_OBJECT (AppWindow), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL); gtk_signal_connect (GTK_OBJECT (AppWindow), "destroy", GTK_SIGNAL_FUNC (destroy), NULL); gtk_signal_connect (GTK_OBJECT (GameDisplay), "realize", GTK_SIGNAL_FUNC (realize_game_display), &DrawingDisplay); gtk_signal_connect (GTK_OBJECT (GameDisplay), "expose_event", GTK_SIGNAL_FUNC (expose_event), &CurrentDisplayPixmap); gtk_signal_connect (GTK_OBJECT (AppWindow), "focus_in_event", GTK_SIGNAL_FUNC (focus_in_event), NULL); gtk_signal_connect (GTK_OBJECT (AppWindow), "focus_out_event", GTK_SIGNAL_FUNC (focus_out_event), NULL); gtk_signal_connect (GTK_OBJECT (AppWindow), "key_press_event", GTK_SIGNAL_FUNC (handle_keypress), NULL); gtk_signal_connect (GTK_OBJECT (AppWindow), "key_release_event", GTK_SIGNAL_FUNC (handle_keyrelease), NULL); gtk_widget_add_events (AppWindow, GDK_KEY_RELEASE_MASK); gtk_container_set_border_width (GTK_CONTAINER (AppWindow), 0); gnome_app_set_contents (GNOME_APP(AppWindow), GameDisplay); gnome_app_create_menus (GNOME_APP(AppWindow), Menu_Bar); gnome_app_set_statusbar(GNOME_APP(AppWindow), GTK_WIDGET(StatusBar)); gnome_app_install_menu_hints(GNOME_APP(AppWindow), Menu_Bar); gtk_widget_show (AppWindow); return true; } void ui_create_status_bar_widgets(GtkWidget *bar) { char *label_name; GtkWidget *label; GtkWidget *separator; GtkWidget *table; table = gtk_table_new (1, 3 + 3*(Player::MAX_NUMBER_OF_PLAYERS), FALSE); gtk_table_set_row_spacings (GTK_TABLE(table), 0); gtk_table_set_col_spacings (GTK_TABLE(table), GNOME_PAD); gtk_container_border_width (GTK_CONTAINER (table), 0); gtk_widget_show(table); label = gtk_label_new(_("round:")); gtk_widget_show(label); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, 0, 1); RoundLabel = gtk_label_new(_("-")); gtk_widget_show(RoundLabel); gtk_table_attach_defaults (GTK_TABLE(table), RoundLabel, 1, 2, 0, 1); separator = gtk_vseparator_new(); gtk_widget_show(separator); gtk_table_attach_defaults (GTK_TABLE(table), separator, 2, 3, 0, 1); for (int i = 0; i < Player::MAX_NUMBER_OF_PLAYERS; i++) { label_name = g_strdup_printf(_("%d:"), i+1); PlayerLabel[i] = gtk_label_new(label_name); g_free(label_name); label_name = NULL; gtk_widget_show(PlayerLabel[i]); gtk_table_attach_defaults (GTK_TABLE(table), PlayerLabel[i], 3 + 3*i + 0 + i, 3 + 3*i + 1 + i, 0, 1); PlayerScoreLabel[i] = gtk_label_new(_("-")); gtk_widget_show(PlayerScoreLabel[i]); gtk_table_attach_defaults (GTK_TABLE(table), PlayerScoreLabel[i], 3 + 3*i + 1 + i, 3 + 3*i + 2 + i, 0, 1); separator = gtk_vseparator_new(); gtk_widget_show(separator); gtk_table_attach_defaults (GTK_TABLE(table), separator, 3 + 3*i + 2 + i, 3 + 3*i + 3 + i, 0, 1); } gtk_box_pack_start (GTK_BOX(bar), table, FALSE, TRUE, 0); } void ui_unref_widgets(void) { return; } bool ui_load_title_screen(void) { char *desiredfile = g_strconcat("pixmaps", PATH_SEP_STR, "title.png", NULL); char *actualfile = preferences_get_data_file(desiredfile); g_free(desiredfile); desiredfile = NULL; if (actualfile == NULL) return false; TitlePixbuf = gdk_pixbuf_new_from_file(actualfile); g_free(actualfile); actualfile = NULL; TitleWidth = gdk_pixbuf_get_width(TitlePixbuf); TitleHeight = gdk_pixbuf_get_height(TitlePixbuf); TitlePixmap = gdk_pixmap_new (DrawingDisplay.window, TitleWidth, TitleHeight, -1); gdk_pixbuf_render_to_drawable (TitlePixbuf, TitlePixmap, DrawingDisplay.gc, 0, 0, 0, 0, TitleWidth, TitleHeight, GDK_RGB_DITHER_MAX, 0, 0); gdk_pixbuf_unref(TitlePixbuf); TitlePixbuf = NULL; CurrentDisplayPixmap = TitlePixmap; return true; } bool ui_load_images(void) { if (false == ui_load_title_screen()) return false; //ui_load_theme_and_check_success(); // already done by preferences init MazePixmap = NULL; return true; } bool ui_load_theme(void) { PendingThemeApplication = false; ui_release_theme(); if (false == MapSquare::load_sprite()) return false; if (false == Player::load_sprite()) return false; if (false == Bomb::load_sprite()) return false; if (false == Fire::load_sprite()) return false; if (false == Brick::load_sprite()) return false; if (false == Wall::load_sprite()) return false; if (false == PowerUp::load_sprite()) return false; return true; } bool ui_load_theme_and_check_success(void) { if (true == ui_load_theme()) { ThemeIsValid = true; return true; } else { ThemeIsValid = false; return false; } } void ui_set_theme_directory(const char *directory) { if (ThemeDirectory != NULL) { g_free(ThemeDirectory); } ThemeDirectory = g_strdup(directory); } void ui_release_images(void) { ui_release_theme(); gdk_pixmap_unref(TitlePixmap); TitlePixmap = NULL; if (ThemeDirectory != NULL) { g_free(ThemeDirectory); ThemeDirectory = NULL; } } void ui_release_theme(void) { PowerUp::sprite.deallocate_frames(); Wall::sprite.deallocate_frames(); Brick::sprite.deallocate_frames(); Fire::sprite.deallocate_frames(); Bomb::sprite.deallocate_frames(); for (int i = 0; i < Player::MAX_NUMBER_OF_PLAYERS; i++) { Player::sprite[i].deallocate_frames(); } FloorSprite.deallocate_frames(); } ////////////////////////////////////////////////////////////////////////////// int main( int argc, char *argv[] ) { int status; #ifdef HAVE_GETTEXT setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, GNOMELOCALEDIR); textdomain (PACKAGE); #endif status = gnome_init(PACKAGE, VERSION, argc, argv); if (status != 0) { fprintf(stderr,_("Error: gnome_init failed; return value = %d\n"),status); return status; } if (ui_create_widgets() == false) { fprintf(stderr, _("Error: widget creation failed\n")); return 1; } if (preferences_initialize() == false) { fprintf(stderr, _("Error: failed to initialize preferences\n")); return 1; } if (ui_load_images() == false) { fprintf(stderr, _("Error: failed to load images\n")); return 1; } game_initialize(AppWindow); gtk_main (); return 0; } ////////////////////////////////////////////////////////////////////////////// // UI-related method definitions ////////////////////////////////////////////////////////////////////////////// SpriteFrame::SpriteFrame() { pixmap = NULL; mask = NULL; } SpriteFrame::~SpriteFrame() { if (pixmap != NULL) { gdk_pixmap_unref(pixmap); pixmap = NULL; } if (mask != NULL) { gdk_bitmap_unref(mask); mask = NULL; } } ////////////////////////////////////////////////////////////////////////////// const int Sprite::SPRITE_MASK_ALPHA_THRESHOLD = 127; char *Sprite::Source_Directory = NULL; GdkWindow *Sprite::Source_Window = NULL; unsigned Sprite::Standard_Width = 45; unsigned Sprite::Standard_Height = 40; unsigned Sprite::X_Step_Size = 9; unsigned Sprite::Y_Step_Size = 8; Sprite::Sprite() { frame = NULL; frames = 0; width = -1; height = -1; excess_height = 0; } Sprite::~Sprite() { deallocate_frames(); } void Sprite::deallocate_frames(void) { if (frame != NULL) { delete[] frame; frame = NULL; } } void Sprite::set_source_directory(char *directory) { Source_Directory = directory; } void Sprite::set_source_window(GdkWindow *win) { Source_Window = win; } void Sprite::set_standard_dimensions(unsigned w, unsigned h) { Standard_Width = w; Standard_Height = h; X_Step_Size = Standard_Width / (2*Entity::get_square_steps()+1); Y_Step_Size = Standard_Height / (2*Entity::get_square_steps()+1); } void Sprite::get_standard_dimensions(unsigned &w, unsigned &h) { w = Standard_Width; h = Standard_Height; } void Sprite::draw_sprite (unsigned frame_index, GdkDrawable *drawable, GdkGC *gc, int x, int y, int x_step, int y_step) { x *= Standard_Width; y *= Standard_Height; int x_offset = x_step * X_Step_Size; int y_offset = y_step * Y_Step_Size; gdk_gc_set_clip_origin (gc, x + x_offset, y + y_offset - excess_height); gdk_gc_set_clip_mask (gc, frame[frame_index].mask); gdk_draw_pixmap (drawable, gc, frame[frame_index].pixmap, 0, 0, x + x_offset, y + y_offset - excess_height, -1, -1); gdk_gc_set_clip_origin (gc, 0, 0); gdk_gc_set_clip_rectangle (gc, NULL); return; } void Sprite::draw_bottom_of_sprite (unsigned frame_index, GdkDrawable *drawable, GdkGC *gc, int x_step, int y_step) { int x_offset = x_step * X_Step_Size; int y_offset = y_step * Y_Step_Size; gdk_gc_set_clip_origin (gc, x_offset, y_offset - excess_height); gdk_gc_set_clip_mask (gc, frame[frame_index].mask); gdk_draw_pixmap (drawable, gc, frame[frame_index].pixmap, 0, 0 + excess_height, x_offset, y_offset, -1, MapSquare::get_square_height()); gdk_gc_set_clip_origin (gc, 0, 0); gdk_gc_set_clip_rectangle (gc, NULL); return; } void Sprite::draw_top_of_sprite (unsigned frame_index, GdkDrawable *drawable, GdkGC *gc, int x_step, int y_step) { if (excess_height == 0) { return; } int h_offset = MapSquare::get_square_height()-excess_height; int x_offset = x_step * X_Step_Size; int y_offset = y_step * Y_Step_Size; gdk_gc_set_clip_origin (gc, x_offset, y_offset + h_offset); gdk_gc_set_clip_mask (gc, frame[frame_index].mask); gdk_draw_pixmap (drawable, gc, frame[frame_index].pixmap, 0, 0, x_offset, y_offset + h_offset, -1, excess_height); gdk_gc_set_clip_rectangle (gc, NULL); return; } bool Sprite::load_sprite_from_file( char *file, unsigned cols, unsigned rows, unsigned n_frames ) { char *actualfile = g_strconcat (Source_Directory, PATH_SEP_STR, file, NULL); if (actualfile == NULL) return false; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(actualfile); g_free(actualfile); actualfile = NULL; if (pixbuf == NULL) { fprintf(stderr, _("Error: cannot load sprite file '%s'\n"), file); return false; } int w, h; w = gdk_pixbuf_get_width(pixbuf); h = gdk_pixbuf_get_height(pixbuf); if ((n_frames > cols * rows) || ((w % cols) != 0) || ((h % rows) != 0)) { fprintf(stderr,_("Error: sprite file '%s' has invalid dimensions\n"),file); gdk_pixbuf_unref(pixbuf); pixbuf = NULL; return false; } frames = n_frames; width = w / cols; height = h / rows; deallocate_frames(); frame = new SpriteFrame[frames]; unsigned i, x, y; i = 0; for (y = 0; y < rows; y++) { for (x = 0; x < cols; x++) { if (frame[i].pixmap != NULL) gdk_pixmap_unref(frame[i].pixmap); if (frame[i].mask != NULL) gdk_bitmap_unref(frame[i].mask); frame[i].pixmap = gdk_pixmap_new(Source_Window, width, height, -1); frame[i].mask = gdk_pixmap_new(Source_Window, width, height, 1); gdk_pixbuf_render_to_drawable (pixbuf, frame[i].pixmap, DrawingDisplay.gc, x*width, y*height, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0); gdk_pixbuf_render_threshold_alpha (pixbuf, frame[i].mask, x*width, y*height, 0, 0, width, height, SPRITE_MASK_ALPHA_THRESHOLD); i++; if (i >= frames) break; } if (i >= frames) break; } gdk_pixbuf_unref(pixbuf); pixbuf = NULL; return true; } bool Sprite::load_sprite_from_file_and_validate( char *file, unsigned cols, unsigned rows, unsigned n_frames ) { if (false == load_sprite_from_file(file, cols, rows, n_frames)) return false; if (validate_sprite_dimensions(file) == false) return false; determine_excess_height(); return true; } bool Sprite::validate_sprite_dimensions(char *name) { if (height > (int)(2*Standard_Height)) { fprintf(stderr, _("Error: '%s' is taller than two map squares\n"), name); return false; } else if (width > (int)(Standard_Width)) { fprintf(stderr, _("Error: '%s' is wider than one map square\n"), name); return false; } return true; } void Sprite::determine_excess_height(void) { if (Standard_Height > 0) { excess_height = height - Standard_Height; } else { excess_height = height - width; } if (excess_height < 0) { excess_height = 0; } } unsigned Sprite::get_number_of_frames(void) { return frames; } int Sprite::get_width(void) { return width; } int Sprite::get_height(void) { return height; } ////////////////////////////////////////////////////////////////////////////// void Entity::update_ui(GdkDrawable *drawable, GdkGC *gc, bool draw_top) { sprite->draw_sprite(frame, drawable, gc, x, y, x_step, y_step); return; if (draw_top == true) { sprite->draw_top_of_sprite(frame, drawable, gc, x_step, y_step); } else { sprite->draw_bottom_of_sprite(frame, drawable, gc, x_step, y_step); } } ////////////////////////////////////////////////////////////////////////////// bool MapSquare::load_sprite(void) { if (FloorSprite.load_sprite_from_file("floor.png", 1, 1, 1) == false) return false; set_square_dimensions(FloorSprite.get_width(), FloorSprite.get_height()); Sprite::set_standard_dimensions (FloorSprite.get_width(), FloorSprite.get_height()); return true; } bool Player::load_sprite(void) { int i; bool success = true; gchar *PlayerImageFilename; for (i = 0; i < Player::MAX_NUMBER_OF_PLAYERS; i++) { PlayerImageFilename = g_strdup_printf("player%d.png", i+1); success = sprite[i].load_sprite_from_file_and_validate(PlayerImageFilename, NUMBER_OF_PLAYER_MOVE_FRAMES, NUMBER_OF_PLAYER_FRAMESETS, PLAYER_FRAME_TOTAL); g_free(PlayerImageFilename); PlayerImageFilename = NULL; if (success == false) return false; } return true; } bool Bomb::load_sprite(void) { return sprite.load_sprite_from_file_and_validate ("bomb.png", BOMB_FRAME_TOTAL, 1, BOMB_FRAME_TOTAL); } bool Fire::load_sprite(void) { return sprite.load_sprite_from_file_and_validate ("fire.png", NUMBER_OF_FLAME_TYPES, 1, NUMBER_OF_FLAME_TYPES); } bool Brick::load_sprite(void) { return sprite.load_sprite_from_file_and_validate ("brick.png", BRICK_FRAME_TOTAL, 1, BRICK_FRAME_TOTAL); } bool Wall::load_sprite(void) { return sprite.load_sprite_from_file_and_validate ("wall.png", WALL_FRAME_TOTAL, 1, WALL_FRAME_TOTAL); } bool PowerUp::load_sprite(void) { return sprite.load_sprite_from_file_and_validate ("powerup.png", NUMBER_OF_POWERUP_TYPES, 1, NUMBER_OF_POWERUP_TYPES); } ////////////////////////////////////////////////////////////////////////////// void GameStateMachine::ui_dependent_initialization(UIWidget *widget) { UIContainerWidget = widget; UIActiveWidget = GameDisplay; initialize_current_state(0); } ////////////////////////////////////////////////////////////////////////////// void TitleScreenState::draw_title_screen(void) { GtkWidget *widget = owner->UIActiveWidget; gtk_drawing_area_size ((GtkDrawingArea *)widget, TitleWidth, TitleHeight); gtk_widget_set_usize ((GtkWidget *)widget, TitleWidth, TitleHeight); GdkDrawable *drawable = widget->window; //GdkGC *gc; //gc = widget->style->fg_gc[owner->UIActiveWidget->state]; if (drawable != NULL) { gdk_draw_pixmap (drawable, DrawingDisplay.gc, TitlePixmap, 0, 0, 0, 0, -1, -1); } CurrentDisplayPixmap = TitlePixmap; return; } ////////////////////////////////////////////////////////////////////////////// void InGameState::draw_maze(void) { int SquareWidth, SquareHeight; int MazeWidth, MazeHeight; int MazePixelWidth, MazePixelHeight; SquareWidth = MapSquare::get_square_width(); SquareHeight = MapSquare::get_square_height(); MazeWidth = maze.get_width(); MazeHeight = maze.get_height(); MazePixelWidth = MazeWidth*SquareWidth; MazePixelHeight = MazeHeight*SquareHeight; gtk_drawing_area_size ((GtkDrawingArea *)owner->UIActiveWidget, MazePixelWidth, MazePixelHeight); gtk_widget_set_usize ((GtkWidget *)owner->UIActiveWidget, MazePixelWidth, MazePixelHeight); gtk_container_check_resize(GTK_CONTAINER(AppWindow)); GdkWindow *window; window = owner->UIActiveWidget->window; //GdkGC *gc; //gc = owner->UIActiveWidget->style->fg_gc[owner->UIActiveWidget->state]; if (MazePixmap != NULL) { gdk_pixmap_unref(MazePixmap); MazePixmap = NULL; } MazePixmap = gdk_pixmap_new (window, MazePixelWidth, MazePixelHeight, -1); /* int i, j; for (j = 0; j < MazePixelHeight; j += SquareHeight) { for(i = 0; i < MazePixelWidth; i += SquareWidth) { gdk_draw_pixmap (MazePixmap, DrawingDisplay.gc, FloorSprite.frame[0].pixmap, //MapSquare::FloorSprite.frame[0].pixmap, 0, 0, i, j, -1, -1); } } */ CurrentDisplayPixmap = MazePixmap; //gdk_draw_pixmap (window, DrawingDisplay.gc, MazePixmap, 0, 0, 0, 0, -1, -1); maze.set_ui_target(window, DrawingDisplay.gc, MazePixmap); return; } void InGameState::undraw_maze(void) { if (MazePixmap != NULL) { gdk_pixmap_unref(MazePixmap); MazePixmap = NULL; } } void InGameState::unref_ui_components(void) { } static gint ingame_timeout_callback(gpointer data) { InGameState *state = (InGameState *)(game_get_current_state()); state->timeout_callback(data); return TRUE; } void InGameState::initialize_timer(void) { if (paused == false) { return; } TimeoutHandlingInProgress = false; TimeoutHandlerID = gtk_timeout_add (InGameState::Timeout_Interval, ingame_timeout_callback, NULL); paused = false; return; } void InGameState::disable_timer(void) { if (paused == true) { return; } gtk_timeout_remove (TimeoutHandlerID); paused = true; return; } void InGameState::update_score_display(void) { char *value; for (int i = 0; i < NumberOfPlayers; i++) { value = g_strdup_printf(_("%d"), NumberOfWins[i]); gtk_label_set_text (GTK_LABEL(PlayerScoreLabel[i]), value); g_free(value); } value = g_strdup_printf(_("%d"), round); gtk_label_set_text (GTK_LABEL(RoundLabel), value); g_free(value); } void InGameState::notify_pause_status(void) { if (paused == true) { gnome_appbar_push(GNOME_APPBAR(StatusBar), _("Game is paused")); } else { ui_clear_status_message(); } } // This function is not a member of InGameState because member functions // can't be directly used as signal handler callbacks. static gint handle_match_status_keypress( GtkWidget *widget, GdkEventKey *event, gpointer data ) { InGameState *state = (InGameState *)data; state->match_status_keypress(event->keyval); ::handle_keypress(widget, event, data); return TRUE; } void handle_match_status_click_continue( GtkButton *button, gpointer game_state ) { InGameState *state = (InGameState *)game_state; state->match_status_continue(); } void InGameState::hide_match_status(void) { if (MatchStatusWindow != NULL) { gtk_widget_destroy (MatchStatusWindow); } MatchStatusWindow = NULL; } void InGameState::display_match_status(int winner) { if (MatchStatusWindow != NULL) { gtk_widget_show(MatchStatusWindow); return; } MatchStatusWindow = gtk_window_new(GTK_WINDOW_DIALOG); bool game_over; if ((winner >= 0) && (NumberOfWins[winner] == WinsPerMatch)) { game_over = true; gtk_window_set_title (GTK_WINDOW(MatchStatusWindow), _("Game Over")); } else { game_over = false; gtk_window_set_title (GTK_WINDOW(MatchStatusWindow), _("Match Status")); } int i; char *label_name = NULL; GtkWidget *label = NULL; GtkWidget *table = NULL; GtkWidget *button = NULL; GtkWidget *separator = NULL; table = gtk_table_new (2, 1+NumberOfPlayers+3, FALSE); gtk_table_set_row_spacings (GTK_TABLE(table), GNOME_PAD); gtk_table_set_col_spacings (GTK_TABLE(table), GNOME_PAD); gtk_container_border_width (GTK_CONTAINER (table), GNOME_PAD); gtk_widget_show(table); gtk_container_add (GTK_CONTAINER(MatchStatusWindow), table); label_name = g_strdup_printf(_("Round %d results"), round); label = gtk_label_new (label_name); g_free(label_name); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 2, 0, 1); gtk_widget_show(label); separator = gtk_hseparator_new(); gtk_widget_show(separator); gtk_table_attach_defaults (GTK_TABLE(table), separator, 0, 2, 1, 2); label = gtk_label_new(_("Player")); gtk_widget_show(label); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, 2, 3); label = gtk_label_new(_("Wins")); gtk_widget_show(label); gtk_table_attach_defaults (GTK_TABLE(table), label, 1, 2, 2, 3); for (i = 0; i < NumberOfPlayers; i++) { label_name = g_strdup_printf(_("%d"), i+1); label = gtk_label_new (label_name); g_free(label_name); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 1, 3+i, 4+i); gtk_widget_show(label); label_name = g_strdup_printf(_("%d"), NumberOfWins[i]); label = gtk_label_new (label_name); g_free(label_name); gtk_table_attach_defaults (GTK_TABLE(table), label, 1, 2, 3+i, 4+i); gtk_widget_show(label); } separator = gtk_hseparator_new(); gtk_widget_show(separator); gtk_table_attach_defaults (GTK_TABLE(table), separator, 0, 2, 3+i, 4+i); if (game_over == true) { label_name = g_strdup_printf (_("Player %d wins the match!"), winner+1); } else if (winner == STALEMATE) { label_name = g_strdup_printf (_("Stalemate")); } else { label_name = g_strdup_printf (_("Player %d wins this round"), winner+1); } gnome_appbar_set_status(GNOME_APPBAR(StatusBar), label_name); label = gtk_label_new (label_name); g_free(label_name); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 2, 4+i, 5+i); gtk_widget_show(label); if (false == preferences_is_continue_button_enabled()) { label_name = g_strdup_printf (_("press [%s] to continue"), preferences_get_continue_key_name()); label = gtk_label_new (label_name); g_free(label_name); gtk_table_attach_defaults (GTK_TABLE(table), label, 0, 2, 5+i, 6+i); gtk_widget_show(label); } else { button = gtk_button_new_with_label (_("Continue")); gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 5+i, 6+i); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (handle_match_status_click_continue), this); gtk_widget_show(button); } //gtk_signal_connect (GTK_OBJECT (MatchStatusWindow), "destroy", // GTK_SIGNAL_FUNC (gtk_widget_destroyed), // &MatchStatusWindow); //gtk_signal_connect (GTK_OBJECT (MatchStatusWindow), "destroy", // GTK_SIGNAL_FUNC (gtk_widget_hide_on_delete), NULL); //gtk_signal_connect (GTK_OBJECT (MatchStatusWindow), "delete", // GTK_SIGNAL_FUNC (gtk_widget_hide_on_delete), NULL); gtk_signal_connect (GTK_OBJECT (MatchStatusWindow), "key_press_event", GTK_SIGNAL_FUNC (handle_match_status_keypress), this); gtk_window_set_modal (GTK_WINDOW(MatchStatusWindow), true); gtk_widget_show (MatchStatusWindow); gtk_widget_grab_focus (MatchStatusWindow); } void InGameState::update_ui(void) { maze.update_ui(); } ////////////////////////////////////////////////////////////////////////////// /* gint repaint_floor (gpointer key, gpointer value, gpointer data) { MapSquare *square = (MapSquare *)value; gdk_draw_pixmap (canvas, DrawingDisplay.gc, MapSquare::FloorSprite.frame[0].pixmap, 0, 0, square->PixelLocation.x, square->PixelLocation.y, -1, -1); return FALSE; } gint repaint_entities (gpointer key, gpointer value, gpointer data) { GameMap *maze = (GameMap *)data; MapSquare *square = (MapSquare *)value; GSList *EntityList; int x = square->location.x; int y = square->location.y; EntityList = square->EntityList; for (; EntityList != NULL; EntityList = EntityList->next) { ((Entity *)(EntityList->data))->update_ui (canvas, DrawingDisplay.gc, false); } if (square->location.y < maze->height-1) { EntityList = maze->map[x][y+1].EntityList; for (; EntityList != NULL; EntityList = EntityList->next) { ((Entity *)(EntityList->data))->update_ui (canvas, DrawingDisplay.gc, true); } } return FALSE; } gint repaint_display (gpointer key, gpointer value, gpointer data) { MapSquare *square = (MapSquare *)value; gdk_draw_pixmap (DrawingDisplay.window, DrawingDisplay.gc, canvas, square->PixelLocation.x, square->PixelLocation.y, square->PixelLocation.x, square->PixelLocation.y, MapSquare::Square_Width, MapSquare::Square_Height); square->RepaintRequired = false; return FALSE; } */ void GameMap::update_ui(void) { repaint_offscreen(); repaint_display(); /* g_tree_traverse (SquaresToBeRepainted, ::repaint_floor, G_IN_ORDER, NULL); g_tree_traverse (SquaresToBeRepainted, ::repaint_entities,G_IN_ORDER, this); g_tree_traverse (SquaresToBeRepainted, ::repaint_display, G_IN_ORDER, NULL); */ //g_tree_destroy (SquaresToBeRepainted); //SquaresToBeRepainted = g_tree_new(compare_coordinates); } void GameMap::repaint_offscreen(void) { repaint_floor(); repaint_entities(); } void GameMap::repaint_floor(void) { int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (check_if_repaint_required(x, y) == true) { gdk_draw_pixmap (DisplayBuffer, DisplayContext, FloorSprite.frame[0].pixmap, //MapSquare::FloorSprite.frame[0].pixmap, 0, 0, map[x][y].PixelLocation.x, map[x][y].PixelLocation.y, -1, -1); } } } } void GameMap::repaint_entities(void) { int x, y; GSList *EntityList; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (check_if_repaint_required(x, y) == true) { EntityList = map[x][y].EntityList; for (; EntityList != NULL; EntityList = EntityList->next) { ((Entity *)(EntityList->data))->update_ui (DisplayBuffer, DisplayContext, false); } if (y < height-1) { EntityList = map[x][y+1].EntityList; for (; EntityList != NULL; EntityList = EntityList->next) { ((Entity *)(EntityList->data))->update_ui (DisplayBuffer, DisplayContext, true); } } } } } } void GameMap::repaint_display(void) { if (DisplayWindow == NULL) return; int x, y; int square_width = MapSquare::get_square_width(); int square_height = MapSquare::get_square_height(); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (check_if_repaint_required(x, y) == true) { gdk_draw_pixmap (DisplayWindow, DisplayContext, DisplayBuffer, map[x][y].PixelLocation.x, map[x][y].PixelLocation.y, map[x][y].PixelLocation.x, map[x][y].PixelLocation.y, square_width, square_height); set_repaint_required(false, x, y); } } } } ////////////////////////////////////////////////////////////////////////////// void GameOverState::draw_game_over_screen(int winner) { } void GameOverState::hide_game_over_screen(void) { if (GameOverWindow != NULL) { gtk_widget_destroy(GameOverWindow); } GameOverWindow = NULL; } //////////////////////////////////////////////////////////////////////////////