/* Jinete - a GUI library * Copyright (c) 2003, 2004, 2005, 2007, David A. Capello * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of the Jinete nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "jinete.h" /* GUI */ void init_gui(void); void shutdown_gui(void); bool update_gui(void); void draw_gui(); float get_speed(void); float get_reaction_pos(void); bool get_back_to_center(); /* Game */ void play_game(void); /**********************************************************************/ /* Main routine */ int main(int argc, char *argv[]) { /* Allegro stuff */ allegro_init(); if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 320, 200, 0, 0) < 0) { if (set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0) < 0) { allegro_message("%s\n", allegro_error); return 1; } } install_timer(); install_keyboard(); install_mouse(); rgb_map = jmalloc(sizeof(RGB_MAP)); color_map = jmalloc(sizeof(COLOR_MAP)); create_rgb_table(rgb_map, default_palette, NULL); create_trans_table(color_map, default_palette, 128, 128, 128, NULL); init_gui(); play_game(); shutdown_gui(); jfree(rgb_map); jfree(color_map); return 0; } END_OF_MAIN(); /**********************************************************************/ /* GUI handle */ static JWidget window, manager, entry, check; static bool my_manager_hook(JWidget widget, JMessage msg); void init_gui(void) { JWidget box1, box2, label, button; /* Jinete initialization */ manager = jmanager_new(); ji_set_standard_theme(); /* hook manager behavior */ jwidget_add_hook(manager, JI_WIDGET, my_manager_hook, NULL); /* create main window */ window = jwindow_new("Game Manager"); box1 = jbox_new(JI_VERTICAL); box2 = jbox_new(JI_HORIZONTAL); label = jlabel_new("Speed:"); entry = jentry_new(8, "4"); check = jcheck_new("AI/Center after hit"); button = jbutton_new("&Game Over"); jwidget_expansive(box2, TRUE); jwidget_expansive(entry, TRUE); jwidget_add_child(window, box1); jwidget_add_childs(box1, box2, check, button, NULL); jwidget_add_childs(box2, label, entry, NULL); jwindow_open(window); } void shutdown_gui(void) { jwidget_free(window); jmanager_free(manager); manager = NULL; } bool update_gui(void) { return !jmanager_poll(manager, TRUE); } void draw_gui() { jwidget_dirty(manager); jwidget_flush_redraw(manager); jmanager_dispatch_draw_messages(); } float get_speed(void) { float speed = strtod(jwidget_get_text(entry), NULL); return speed; } float get_reaction_pos(void) { return window->rc->x1-2; } bool get_back_to_center() { return jwidget_is_selected(check); } static bool my_manager_hook(JWidget widget, JMessage msg) { switch (msg->type) { case JM_CHAR: case JM_KEYPRESSED: /* don't use UP & DOWN keys for focus movement */ if (msg->key.scancode == KEY_UP || msg->key.scancode == KEY_DOWN) { /* returning TRUE means that we use that keys (we don't use that keys here, but the game use them) */ return TRUE; } break; case JM_DRAW: /* draw nothing (this avoid the default behavior: paint with the desktop color of the current manager's theme) */ return TRUE; } return FALSE; } /**********************************************************************/ /* Game handle */ #define BS 8 /* ball size */ #define PS 40 /* player size */ static float ball_x, ball_y; static float ball_dx, ball_dy; static int p_y1, p_y2; static int count = 0; static void count_inc(void) { count++; } END_OF_STATIC_FUNCTION(count_inc); static void update_game(void); static void draw_game(BITMAP *bmp); static bool move_ball(float *x, float *y, float *dx, float *dy); static void calc_ball_dest(float *y); void play_game(void) { bool gameover = FALSE; bool trans_mode = FALSE; BITMAP *bmp, *bmp2; /* create a temporary bitmap to make double-buffered technique */ bmp = create_bitmap(SCREEN_W, SCREEN_H); bmp2 = create_bitmap(SCREEN_W, SCREEN_H); /* set Jinete output screen bitmap */ ji_set_screen(bmp); show_mouse(NULL); /* init game state */ ball_x = SCREEN_W / 2; ball_y = SCREEN_H / 2; ball_dx = cos(AL_PI/4); ball_dy = sin(AL_PI/4); p_y1 = p_y2 = SCREEN_H / 2 - PS / 2; LOCK_VARIABLE(count); LOCK_FUNCTION(count_inc); install_int_ex(count_inc, BPS_TO_TIMER(60)); while (!gameover) { while (count > 0 && !gameover) { update_game(); gameover = update_gui(); count--; } /* use transparent bitmap */ if (jwidget_pick(manager, mouse_x, mouse_y) == manager) { if (!trans_mode) { trans_mode = TRUE; ji_set_screen(bmp2); show_mouse(NULL); } } else if (trans_mode) { trans_mode = FALSE; ji_set_screen(bmp); show_mouse(NULL); } /* draw game state */ draw_game(bmp); /* draw GUI */ if (trans_mode) clear(bmp2); draw_gui(); /* blit to screen (with the mouse on it) */ show_mouse(ji_screen); freeze_mouse_flag = TRUE; if (trans_mode) draw_trans_sprite (bmp, bmp2, 0, 0); blit(bmp, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); freeze_mouse_flag = FALSE; show_mouse(NULL); } ji_set_screen(screen); destroy_bitmap(bmp); destroy_bitmap(bmp2); } static void update_game(void) { float y, angle; /* move ball */ if (!move_ball(&ball_x, &ball_y, &ball_dx, &ball_dy)) { /* some player loses */ ball_x = SCREEN_W / 2; ball_y = SCREEN_H / 2; ball_dx = cos(AL_PI/4); ball_dy = sin(AL_PI/4); } /* collision ball<->player */ if (ball_dx < 0) { if (ball_x >= 2 && ball_y+BS/2 >= p_y1-PS/2 && ball_x <= 12 && ball_y-BS/2 <= p_y1-PS/2+PS-1) { angle = -AL_PI/4 + AL_PI/2 * (ball_y-(p_y1-PS/2))/PS; ball_dx = cos(angle); ball_dy = sin(angle); } } else if (ball_dx > 0) { if (ball_x >= SCREEN_W-1-12 && ball_y+BS/2 >= p_y2-PS/2 && ball_x <= SCREEN_W-1-2 && ball_y-BS/2 <= p_y2-PS/2+PS-1) { angle = -AL_PI*3/4 - AL_PI/2 * (ball_y-(p_y2-PS/2))/PS; ball_dx = cos(angle); ball_dy = sin(angle); } } /* player */ if (key[KEY_UP]) p_y1 -= 4; if (key[KEY_DOWN]) p_y1 += 4; /* IA */ if (ball_dx > 0 && ball_x > get_reaction_pos()) calc_ball_dest(&y); else if (get_back_to_center()) y = SCREEN_H/2; else y = p_y2; if (p_y2 > y) { p_y2 -= 4; if (p_y2 < y) p_y2 = y; } else if (p_y2 < y) { p_y2 += 4; if (p_y2 > y) p_y2 = y; } /* limit players movement */ p_y1 = MID(PS/2, p_y1, SCREEN_H-1-PS/2); p_y2 = MID(PS/2, p_y2, SCREEN_H-1-PS/2); } static void draw_game(BITMAP *bmp) { float x = get_reaction_pos(); /* clear screen */ clear(bmp); /* reaction position */ vline(bmp, x, 0, SCREEN_H-1, makecol(255, 255, 255)); textout(bmp, font, "AI reaction position", x+2, 0, makecol(255, 255, 255)); /* draw ball */ rectfill(bmp, ball_x-BS/2, ball_y-BS/2, ball_x-BS/2+BS-1, ball_y-BS/2+BS-1, makecol(255, 255, 255)); /* draw left & right players */ rectfill(bmp, 2, p_y1-PS/2, 12, p_y1-PS/2+PS-1, makecol(255, 255, 255)); rectfill(bmp, SCREEN_W-1-12, p_y2-PS/2, SCREEN_W-1-2, p_y2-PS/2+PS-1, makecol(255, 255, 255)); } static bool move_ball(float *x, float *y, float *dx, float *dy) { float speed = get_speed(); /* ball movement */ *x += (*dx) * speed; *y += (*dy) * speed; /* bouncing with walls */ if (*dy < 0 && (*y)-BS/2 < 0) *dy = -(*dy); else if (*dy > 0 && (*y)+BS/2 > SCREEN_H-1) *dy = -(*dy); /* ball goes out of screen */ if (*x < 0 || *x > SCREEN_W-1) return FALSE; else return TRUE; } static void calc_ball_dest(float *y) { float speed = get_speed(); float x = ball_x; float dx = ball_dx; float dy = ball_dy; *y = ball_y; if (speed >= 1) while (move_ball(&x, y, &dx, &dy)); }