/****************************************************\ Tom Heilman / Section BA / CSE 142 / Homework #4 tomheil@u.washington.edu \****************************************************/ #include "gp142.h" #include #include #include /* Logical constants */ #define TRUE 1 #define FALSE 0 /* For GP142 */ #define FILL 0 /* Signifies filling a shape solid with color */ /* Directions */ #define RIGHT 1 #define LEFT 0 /* Menu buttons: */ #define BUTTON_HT 26 /* Height of buttons (in pixels) */ #define BUTTON_WIDTH 110 /* Width of buttons (in pixels) */ #define NUM_BUTTONS 2 /* Number of buttons per menu */ /* Menu location coordinates */ #define MENU_TOP -150 #define MENU1_LEFT (- BUTTON_WIDTH - 15) #define MENU2_LEFT 15 /* Mouse clicks: */ #define BUTTON_CLICK 1 /* Mouse click in some menu button */ #define OTHER_CLICK 0 /* Mouse click elsewhere */ /* Important coordinates of objects in the drawing */ #define HORIZON (- 2 * (GP142_YMAX / 10)) #define MAX_STAR_RADIUS 4 #define NUM_STARS 6 #define SN_X 110 /* Center of Space Needle disk: x coord. */ #define SN_Y (HORIZON + 30) /* Center of Space Needle disk: y coord. */ /* "Energy Morph" ability animation values */ #define ENERGY_ATK_ANIMATIONS 3 /* The # of energy beams shot per use */ #define ENERGY_ATK_TAILS 5 /* The number of tails per beam */ /* Duration of "Energy Shield": «« 20=short < 40=average < 60=long »» */ #define E_SHIELD_ANIMATIONS 40 /* Duration of "Dual Subwoofers": «« 40=short < 70=average < 100=long »» */ #define SUBWOOFER_ANIMATIONS 70 /* Base number of laser strikes per "Laser Blast" attack */ #define LASER_STRIKES 25 /*************************************************************************\ FUNCTION PROTOTYPES \*************************************************************************/ /* Initialization */ /* Initializes the spaceship parameters */ void init_ship(int *ship_x, int *ship_y); /* Initializes location of stars */ void init_star(int star_x[], int star_y[]); /* Drawing objects */ /* Draw buttons */ void draw_buttons(int spotlight_x, int spotlight_y); /* Draw the background, including the ship at coordinates ship_x and *\ \* ship_y, the stars, and the flames */ void draw_landscape(int ship_x, int ship_y, const int star_x[], const int star_y[], const int star_radius[], const int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]); /* Draws the Space Needle */ void draw_SpaceNeedle(void); /* Draw stars given their elements */ void draw_stars(const int star_x[], const int star_y[], const int star_radius[], const int star_color[]); /* Draws flames on Space Needle given peak x,y array coordinates and *\ \* the held constant reference peak x.y point arrays */ void draw_flames(int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]); /* Draws the spaceship from center coordinates */ void draw_ship(int ship_x, int ship_y); /* Draws the hero from its center x,y coordinates */ void draw_hero(int hero_x, int hero_y); /* Draws the enemy from its center x,y coordinates */ void draw_enemy(int enemy_x, int enemy_y); /* Update values (for some animations) */ /* Make stars blink */ void blink_star(int star_radius[], int star_color[]); /* Update ship coordinates ship_x, ship_y for one tick */ void move_ship(int *ship_x, int *ship_y); /* Updates the menu spotlight's current location and direction */ void move_spotlight(int *spotlight_x, int *spotlight_direction); /* Animates flame peaks given peak x,y array coordinates and *\ \* the held constant reference peak x.y point arrays */ void move_flames(int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]); /* Classification of input */ /* Return kind of mouse click (in a button, etc.) */ int classify_mouse_click(int mouse_x, int mouse_y); /* Find which button was clicked at location x, y. */ int check_button(int x, int y); /* Special event animations */ /* "Energy Shield" animation given character x,y coordinates and b/g info */ void energy_shield( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]); /* "Energy Morph" animation given character x,y coordinates and b/g info */ void energy_morph( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]); /* "Laser Blast" animation given character x,y coordinates and b/g info */ void laser_blast( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]); /* "Subwoofer" animation given character x,y coordinates and b/g info */ void subwoofer_atk( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]); /* Miscellaneous */ /* Initializes random number generator. */ void initialize_random_numbers(); /* Display error message if internal error is detected. */ void something_is_wrong (void); /*************************************************************************\ MAIN \*************************************************************************/ /*-----------------------------------------------------------------------*\ The main program function consists of important variables that are continuously used and updated. It is run by an event loop which processes GP142 events until valid input is detected or the user quits the program. Variables being constantly updated along with the continual redrawing of the GP142 window screen creates animation. \*-----------------------------------------------------------------------*/ int main(void) { /* Creation of variables and initialization */ /* Event handling and buttons: */ int quit; /* = "user has selected quit" */ int event; /* the most recent GP142 event */ int mouse_x, mouse_y; /* x and y coordinates of latest mouse event*/ int click_kind; /* kind of mouse click (button, etc.) */ int buttonNum; /* number of the menu button clicked */ char key_pressed; /* last keyboard character from key event */ /* Information about the spaceship */ int ship_x, ship_y; /* screen x and y coordinates */ /* Information on the stars */ int star_x[NUM_STARS], star_y[NUM_STARS]; /* x,y coordinates */ int star_radius[NUM_STARS]; /* radius of each star */ int star_color[NUM_STARS]; /* color of each star */ /* Hero information */ int hero_x, hero_y; /* x,y coordinates of hero's center point */ /* Enemy information */ int enemy_x, enemy_y; /* x,y coordinates of enemy's center point */ /* Information on flame peaks located on broken Space Needle *\ |* (the changing current peaks and static reference peaks). *| |* The reference peak values are coordinates for the flames based *| \* upon the location of the Space Needle (where the fire is at) */ int peak_x[8]; int peak_y[8]; int peak_ref_x[] = {SN_X - 32, SN_X - 23, SN_X - 16, SN_X - 7, SN_X, SN_X + 6, SN_X + 15, SN_X + 22}; int peak_ref_y[] = {SN_Y + 94, SN_Y + 87, SN_Y + 97, SN_Y + 95, SN_Y + 89, SN_Y + 92, SN_Y + 90, SN_Y + 93}; /* Information for the menu spotlight */ int spotlight_x, spotlight_y; /* x,y coordinates of spotlight */ int spotlight_direction; /* Gives current direction of spotlight */ /* Initialize random number generator */ initialize_random_numbers(); /* Initialize graphics package, clear the window, */ /* turn logging off, and start animation. */ GP142_open(); GP142_logging(LOG_OFF); GP142_clear(); GP142_animate(ANI_RUN); /* Set initial location of the ship */ init_ship(&ship_x, &ship_y); /* Set initial location of the stars */ init_star(star_x, star_y); blink_star(star_radius, star_color); /* Set initial conditions for hero */ hero_x = 185; hero_y = -110; /* Set initial conditions for enemy */ enemy_x = -hero_x; enemy_y = hero_y; /* Set initial menu spotlight location */ spotlight_x = MENU1_LEFT - 10; spotlight_y = MENU_TOP + 5; spotlight_direction = RIGHT; /* Load initial flame peak locations */ move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); /* Draw initial landscape, buttons, and traffic */ draw_landscape( ship_x,ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_hero(hero_x, hero_y); draw_enemy(enemy_x, enemy_y); draw_buttons(spotlight_x, spotlight_y); /* Main program loop *\ /* Continuously animates while awaiting input. If valid input is *\ |* detected, it is processed before returning control to this loop. *| \* This process continues until the user quits the program. */ quit = FALSE; while (!quit) { /* get next event */ event = GP142_await_event(&mouse_x, &mouse_y, &key_pressed); /* perform appropriate action depending on kind of event */ switch (event) { case GP142_QUIT: /* Quit selected */ quit = TRUE; break; case GP142_MOUSE: /* Mouse click - determine nature and process */ click_kind = classify_mouse_click(mouse_x, mouse_y); if (click_kind == BUTTON_CLICK) { buttonNum = check_button(mouse_x, mouse_y); switch(buttonNum) { case 0: /* Default if known error detected and processed */ break; case 1: /* "Laser Blast" attack */ laser_blast( hero_x, hero_y, enemy_x, enemy_y, &ship_x, &ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); break; case 2: /* "Subwoofer" attack */ subwoofer_atk( hero_x, hero_y, enemy_x, enemy_y, &ship_x, &ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); break; case 3: /* "Energy Morph" attack */ energy_morph( hero_x, hero_y, enemy_x, enemy_y, &ship_x, &ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); break; case 4: /* "Energy Shield" ability */ energy_shield( hero_x, hero_y, enemy_x, enemy_y, &ship_x, &ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); break; default: /* Unknown error detected - animation halts */ GP142_animate(ANI_HALT); something_is_wrong(); break; } } break; case GP142_PERIODIC: /* Timer event - updates for animation */ move_ship(&ship_x, &ship_y); blink_star(star_radius, star_color); move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); move_spotlight( &spotlight_x, &spotlight_direction); break; default: /* Unknown event - continue loop */ break; } /* End of event switch */ /* Redraw everything */ draw_landscape( ship_x, ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_hero(hero_x, hero_y); draw_enemy(enemy_x, enemy_y); draw_buttons(spotlight_x, spotlight_y); } /* End main event loop */ /* Shut down and exit procedures upon quitting program */ GP142_close(); return 0; } /*************************************************************************\ INITIALIZATION PROCEDURES \*************************************************************************/ /* Initializes the moon parameters */ void init_ship(int *ship_x, int *ship_y) { *ship_x = -GP142_XMAX - 25; *ship_y = GP142_YMAX - 35; return; } /* Initialize each star's location */ void init_star(int star_x[], int star_y[]) { int star_num; /* Counter for current star number in array */ /* Assigns random location to stars (within the sky region) */ for (star_num = 0; star_num < NUM_STARS; star_num++) { star_x[star_num] = GP142_XMAX - (rand() % 601); star_y[star_num] = GP142_YMAX - (rand() % 101); } return; } /*************************************************************************\ DRAWING OBJECTS (BACKGROUND, CHARACTERS, ETC...) \*************************************************************************/ /* TO DRAW ALL ELEMENTS OF MAIN LANDSCAPE */ /* Draws all of the main background elements */ void draw_landscape(int ship_x, int ship_y, const int star_x[], const int star_y[], const int star_radius[], const int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]) { int text_offset = -GP142_XMAX + 15; /* horizontal offset of text */ int text_size = 12; /* size of text font */ /* Draw the sky */ GP142_rectangleXY( BLACK, -GP142_XMAX, -GP142_YMAX, GP142_XMAX, GP142_YMAX, FILL); /* Draw the ship */ draw_ship(ship_x, ship_y); /* Draw stars */ draw_stars(star_x, star_y, star_radius, star_color); /* Draw mountains */ GP142_triangleXY( BROWN, -GP142_XMAX, HORIZON, GP142_XMAX, HORIZON, GP142_XMAX / 4, (2 * GP142_YMAX)/3, FILL); GP142_triangleXY( DUSTY_PLUM, -( 5 * GP142_XMAX/4), HORIZON, (GP142_XMAX)/3 , HORIZON, -(3 * GP142_XMAX)/4, (2 * GP142_YMAX)/3 , FILL); GP142_triangleXY( FOREST_GREEN, -GP142_XMAX / 3 , HORIZON, GP142_XMAX, HORIZON, GP142_XMAX, (2 * GP142_YMAX)/3 , FILL); /* Draw ground */ GP142_rectangleXY( SEA_GREEN, -GP142_XMAX, -GP142_YMAX, GP142_XMAX, HORIZON, FILL); /* Draw Space Needle */ draw_SpaceNeedle(); /* Draws flames */ draw_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); return; } /* Drawing landscape completed */ /* TO DRAW ELEMENTS SEPARATELY */ /* Draw stars given their elements */ void draw_stars(const int star_x[], const int star_y[], const int star_radius[], const int star_color[]) { int star_num; /* Counter for current star number in array loop */ /* Runs through array and draws all stars desired by NUM_STARS */ for (star_num = 0; star_num <= NUM_STARS; star_num++) { GP142_triangleXY( star_color[star_num], star_x[star_num], star_y[star_num] + star_radius[star_num], star_x[star_num] + (int)(star_radius[star_num] * 0.87), star_y[star_num] - (int)(star_radius[star_num] / 2.0), star_x[star_num] - (int)(star_radius[star_num] * 0.87), star_y[star_num] - (int)(star_radius[star_num] / 2.0), FILL); GP142_triangleXY( star_color[star_num], star_x[star_num], star_y[star_num] - star_radius[star_num], star_x[star_num] - (int)(star_radius[star_num] * 0.87), star_y[star_num] + (int)(star_radius[star_num] / 2.0), star_x[star_num] + (int)(star_radius[star_num] * 0.87), star_y[star_num] + (int)(star_radius[star_num] / 2.0), FILL); } return; } /* Draws the spaceship from center coordinates */ void draw_ship(int ship_x, int ship_y) { GP142_lineXY( CHALK, ship_x, ship_y + 12, ship_x, ship_y - 12, 2); GP142_ovalXY( TURQUOISE, ship_x - 15, ship_y + 6, ship_x + 15, ship_y - 6, FILL); return; } /* Draws the broken Space Needle into the background */ void draw_SpaceNeedle(void) { int x = -115; /* central x coordinate to base shapes off of */ int y = HORIZON + 195; /* central y coordinate to base shapes off of */ /* Legs (those still standing) */ GP142_lineXY( LT_GRAY, x, y, x + 10, y - 225, 10); GP142_lineXY( LT_GRAY, x - 12, y, x - 40, y - 210, 10); GP142_lineXY( LT_GRAY, x + 12, y, x + 35, y - 200, 10); GP142_lineXY( LT_GRAY, x - 15, y - 60, x + 15, y - 60, 8); GP142_lineXY( LT_GRAY, x + 5, y - 135, x - 25, y - 126, 8); GP142_lineXY( LT_GRAY, x + 5, y - 135, x + 20, y - 125, 8); GP142_rectangleXY( LT_GRAY, x - 16, y, x + 15, y + 20, FILL); /* Legs (connected to broken off disk) */ GP142_lineXY( LT_GRAY, SN_X, SN_Y, SN_X - 70, SN_Y, 10); GP142_lineXY( LT_GRAY, SN_X, SN_Y + 22, SN_X - 70, SN_Y + 12, 10); GP142_lineXY( LT_GRAY, SN_X, SN_Y - 22, SN_X - 70, SN_Y - 12, 10); GP142_rectangleXY( LT_GRAY, SN_X - 70, SN_Y - 15, SN_X - 90, SN_Y + 15, FILL); /* Oval disk area */ GP142_ovalXY( LT_GRAY, SN_X - 28, SN_Y - 75, SN_X + 28, SN_Y + 75, FILL); /* Needle */ GP142_lineXY( LT_GRAY, SN_X + 10, SN_Y, SN_X + 70, SN_Y, 4); /* Dirt covering buried portion of disk */ GP142_rectangleXY( SEA_GREEN, SN_X - 30, SN_Y - 80, SN_X + 30, SN_Y - 60, FILL); return; } /* Draws flames on Space Needle given peak x,y array coordinates and *\ \* the held constant reference peak x.y point arrays */ void draw_flames(int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]) { int flame_number; /* Counter for current flame in array */ int flames_x = SN_X - 15; /* x coordinate for flame location basis */ int flames_y = SN_Y + 60; /* y coordinate for flame location basis */ /* Goes through array to draw flames in back */ for(flame_number = 0; flame_number < 7; flame_number++) { GP142_triangleXY( ORANGE, flames_x - 5, flames_y - (rand() % 5), flames_x + 7, flames_y - (rand() % 5), peak_x[flame_number] + 2, peak_y[flame_number] + 9 + (rand() % 7), FILL); GP142_triangleXY( YELLOW, flames_x - 1, flames_y - (rand() % 6) - 1, flames_x + 4, flames_y - (rand() % 6) - 1, peak_x[flame_number] + 4, peak_y[flame_number] + 5 - (rand() % 5), FILL); flames_x = flames_x + 5; } /* Sets basis coordinates in the forground and draws nearer flames */ flames_x = SN_X - 22; flames_y = SN_Y + 50; move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); for(flame_number = 0; flame_number < 8; flame_number++) { GP142_triangleXY( ORANGE, flames_x, flames_y - (rand() % 8), flames_x + 7, flames_y - (rand() % 8), peak_x[flame_number], peak_y[flame_number], FILL); GP142_triangleXY( YELLOW, flames_x + 2, flames_y - (rand() % 9) - 1, flames_x + 5, flames_y - (rand() % 9) - 1, peak_x[flame_number], peak_y[flame_number] - 4 - (rand() % 5), FILL); flames_x = flames_x + 5; } return; } /* Draws the hero from its center x,y coordinates */ void draw_hero(int hero_x, int hero_y) { /* Body */ GP142_rectangleXY( MED_GRAY, hero_x - 25, hero_y - 35, hero_x + 25, hero_y + 35, FILL); /* Arm */ GP142_rectangleXY( MED_GRAY, hero_x, hero_y + 18, hero_x - 40, hero_y + 2, FILL); /* Leg */ GP142_rectangleXY( MED_GRAY, hero_x - 10, hero_y - 35, hero_x + 10, hero_y - 85, FILL); /* Head */ GP142_rectangleXY( MED_GRAY, hero_x - 12, hero_y + 35, hero_x + 12, hero_y + 63, FILL); /* Eye slit */ GP142_rectangleXY( FOREST_GREEN, hero_x + 2, hero_y + 55, hero_x - 12, hero_y + 50, FILL); /* Hand */ GP142_circleXY( LT_GRAY, hero_x - 45, hero_y + 10, 10); /* Foot */ GP142_ovalXY( LT_GRAY, hero_x - 24, hero_y - 95, hero_x + 16, hero_y - 80, FILL); /* Thruster backpack */ GP142_rectangleXY( LT_GRAY, hero_x + 15, hero_y + 30, hero_x + 40, hero_y - 14, FILL); /* Exhaust pipe */ GP142_lineXY( LT_GRAY, hero_x + 30, hero_y, hero_x + 32, hero_y - 20, 8); return; } /* Draws the enemy from its center x,y coordinates */ void draw_enemy(int enemy_x, int enemy_y) { /* Head */ GP142_triangleXY( OLIVE, enemy_x + 13, enemy_y + 67, enemy_x + 13, enemy_y + 10, enemy_x - 17, enemy_y + 54, FILL); /* Body */ GP142_rectangleXY( OLIVE, enemy_x - 25, enemy_y - 35, enemy_x + 25, enemy_y + 35, FILL); /* Hand */ GP142_circleXY( GOLD, enemy_x + 20, enemy_y, 10); /* Leg */ GP142_rectangleXY( OLIVE, enemy_x - 10, enemy_y - 35, enemy_x + 10, enemy_y - 85, FILL); /* Eye slit */ GP142_rectangleXY( RED, enemy_x - 2, enemy_y + 54, enemy_x + 13, enemy_y + 50, FILL); /* Foot */ GP142_ovalXY( GOLD, enemy_x + 24, enemy_y - 80, enemy_x - 16, enemy_y - 95, FILL); /* Cannon (first piece) */ GP142_rectangleXY( BLACK, enemy_x + 20, enemy_y + 8, enemy_x + 55, enemy_y - 8, FILL); /* Cannon (second piece) */ GP142_rectangleXY( BLACK, enemy_x + 55, enemy_y + 5, enemy_x + 75, enemy_y - 5, FILL); /* Thruster backpack */ GP142_rectangleXY( GOLD, enemy_x - 15, enemy_y + 30, enemy_x - 40, enemy_y - 14, FILL); /* Exhaust pipe */ GP142_lineXY( GOLD, enemy_x - 30, enemy_y, enemy_x - 32, enemy_y - 20, 8); return; } /*************************************************************************\ MENU, BUTTONS, AND MOUSE CLICKS \*************************************************************************/ /* Draws the buttons and the animated menu spotlight */ void draw_buttons(int spotlight_x, int spotlight_y) { int i; /* Index counter for drawing menus */ int text_offset; /* Text indention - set later */ int font_size = 12; /* size of button text */ /* Draw menu spotlight */ GP142_rectangleXY( BLACK, spotlight_x, spotlight_y, spotlight_x + 130, spotlight_y - (NUM_BUTTONS * BUTTON_HT) - 10, FILL); /* Left Menu */ /* draw rectangles for each left menu button */ for(i = 0; i < NUM_BUTTONS; i++) { GP142_rectangleXY( SEA_GREEN, MENU1_LEFT, MENU_TOP - i * BUTTON_HT, MENU1_LEFT + BUTTON_WIDTH, MENU_TOP - (i + 1) * BUTTON_HT, 1); } /* display left menu button text */ text_offset = MENU1_LEFT+9; i = MENU_TOP - (BUTTON_HT/2) - (font_size/2) - 2; GP142_printfXY( SEA_GREEN, text_offset, i, font_size, "Laser Blast Attack"); i -= BUTTON_HT; GP142_printfXY( SEA_GREEN, text_offset, i, font_size, "Dual Subwoofers"); /* Right Menu */ /* draw rectangles for each right menu button */ for(i = 0; i < NUM_BUTTONS; i++) { GP142_rectangleXY( SEA_GREEN, MENU2_LEFT, MENU_TOP - i * BUTTON_HT, MENU2_LEFT + BUTTON_WIDTH, MENU_TOP - (i + 1) * BUTTON_HT, 1); } /* display right menu button text */ text_offset = MENU2_LEFT + 9; i = MENU_TOP - (BUTTON_HT/2) - (font_size/2) - 2; GP142_printfXY( SEA_GREEN, text_offset, i, font_size, "Morph into Energy"); i -= BUTTON_HT; GP142_printfXY( SEA_GREEN, text_offset, i, font_size, "Energy Shield"); return; } /* Classify mouse click at (mouse_x,mouse_y) and return kind */ int classify_mouse_click(int mouse_x, int mouse_y) { if (((mouse_x > MENU1_LEFT) || (mouse_x > MENU2_LEFT)) && ((mouse_x < MENU1_LEFT + BUTTON_WIDTH) || (mouse_x < MENU2_LEFT + BUTTON_WIDTH)) && (mouse_y < MENU_TOP) && (mouse_y > (MENU_TOP - NUM_BUTTONS * BUTTON_HT))) return BUTTON_CLICK; else return OTHER_CLICK; } /* Find and return what button was clicked */ int check_button(int x, int y) { int buttonNum; /* number of selected button */ /* Complain if x coordinate couldn't be inside a button */ if ((x < MENU1_LEFT) || (x > MENU2_LEFT + BUTTON_WIDTH) || (x > MENU1_LEFT + BUTTON_WIDTH) && (x < MENU2_LEFT)) { something_is_wrong(); return 0; } /* Convert y coordinate to button number from top. */ if (x <= 0) buttonNum = (MENU_TOP - y)/BUTTON_HT + 1; if (x > 0) buttonNum = (MENU_TOP - y)/BUTTON_HT + 1 + NUM_BUTTONS; return buttonNum; } /*************************************************************************\ GENERAL ANIMATION AND BACKGROUND ALTERATIONS \*************************************************************************/ /* Make the stars blink */ void blink_star(int star_radius[], int star_color[]) { int star_num; /* Star number in the array during the loop */ for(star_num = 0; star_num <= NUM_STARS; star_num++) { star_radius[star_num] = rand() % MAX_STAR_RADIUS + 1; star_color[star_num] = rand() % MAX_COLORS; } return; } /* Update ship coordinates ship_x and ship_y */ void move_ship(int *ship_x, int *ship_y) { /* Moves the ship right across the sky while hovering up and down */ *ship_x = *ship_x + 2 + (rand() % 2); *ship_y = *ship_y + (rand() % 5) - 2; if (*ship_x > GP142_XMAX + 25) init_ship(ship_x, ship_y); return; } /* Moves the spotlight along the menus */ void move_spotlight(int *spotlight_x, int *spotlight_direction) { /* Changes direction if necessary */ if (*spotlight_x >= MENU2_LEFT + BUTTON_WIDTH - 115) *spotlight_direction = LEFT; if (*spotlight_x <= MENU1_LEFT - 15) *spotlight_direction = RIGHT; /* Moves spotlight along current direction */ if (*spotlight_direction == RIGHT) *spotlight_x = *spotlight_x + 5; if (*spotlight_direction == LEFT) *spotlight_x = *spotlight_x - 5; return; } /* Animates flame peaks given peak x,y array coordinates and *\ \* the held constant reference peak x.y point arrays */ void move_flames(int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]) { int flame_number; /* Counter for current flame in array */ /* Changes randomly how high the flames each flicker */ for (flame_number = 0; flame_number < 8; flame_number++) { peak_x[flame_number] = peak_ref_x[flame_number] + (rand() % 5); peak_y[flame_number] = peak_ref_y[flame_number] + (rand() % 11); } return; } /*************************************************************************\ SPECIAL EVENT ANIMATIONS \*************************************************************************/ /* "Energy Morph" animation given character x,y coordinates and b/g info */ void energy_morph( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]) { int a; char b; /* Values to hold event input */ int animation_go; /* Switch for GP142's animation event wait */ int animation; /* Counter for current animation number loop is on */ int energy_radius; /* The radius of the leading energy circle */ int tail; /* Counter for current tail in array */ int energy_trail_x[ENERGY_ATK_TAILS + 1]; /* x for tail location */ int energy_trail_y[ENERGY_ATK_TAILS + 1]; /* y for tail location */ int hero_energy = hero_y + 24; /* Current energy in container */ /* Animates initial energy blasts attacking enemy */ for (animation = 1; animation <= ENERGY_ATK_ANIMATIONS; animation++) { /* Resets values for next animation */ energy_trail_x[0] = hero_x; energy_trail_x[ENERGY_ATK_TAILS] = -GP142_XMAX; /* Removes proper amount from the energy container */ hero_energy = hero_energy - 48 / ENERGY_ATK_ANIMATIONS; /* Begin animation */ while (energy_trail_x[ENERGY_ATK_TAILS] >= -GP142_XMAX) { animation_go = GP142_await_event(&a, &a, &b); switch (animation_go) { /* Updates for animation */ case GP142_PERIODIC: energy_trail_x[0] = energy_trail_x[0] - 17; energy_radius = (rand() % 6) + 27; for (tail = 1; tail <= ENERGY_ATK_TAILS; tail++) { energy_trail_x[tail] = energy_trail_x[tail - 1] + ((rand() % 10) + 16); } move_ship(ship_x, ship_y); blink_star(star_radius, star_color); move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); break; default: break; } /* Draws background */ draw_landscape( *ship_x, *ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_enemy(enemy_x, enemy_y); /* Draws the container and the energy left in it */ GP142_ovalXY( MAGENTA, hero_x - 21, hero_y - 28, hero_x + 21, hero_y + 28, 4); GP142_ovalXY( CYAN, hero_x - 18, hero_y - 24, hero_x + 17, hero_energy, FILL); /* Draws the lead energy circle */ GP142_circleXY( CYAN, energy_trail_x[0], hero_y, energy_radius); /* When the blast hits the enemy, animates the hit effect */ if (enemy_x - energy_trail_x[0] >= 0) { GP142_lineXY( CYAN, enemy_x + 15 + (rand() % 40), enemy_y + 65 + (rand() % 25), enemy_x - 15 - (rand() % 40), enemy_y - 65 - (rand() % 25), (rand() % 4) + 3); GP142_lineXY( CYAN, enemy_x - 15 - (rand() % 40), enemy_y + 65 + (rand() % 25), enemy_x + 15 + (rand() % 40), enemy_y - 65 - (rand() % 25), (rand() % 4) + 3); } /* Draws tails behind lead energy circle */ for (tail = 1; tail <= ENERGY_ATK_TAILS; tail++) { if (energy_trail_x[tail] < hero_x) GP142_circleXY( CYAN, energy_trail_x[tail], hero_y, energy_radius - ((rand() % 8) + 4)); } } /* End this animation */ } /* End of all animations of this type */ /* Animates energy blasts returning to re-form character */ for (animation = 1; animation <= ENERGY_ATK_ANIMATIONS; animation++) { /* Resets values for new animation */ energy_trail_y[0] = GP142_YMAX; energy_trail_y[ENERGY_ATK_TAILS] = hero_y; /* Begin animation */ while (energy_trail_y[ENERGY_ATK_TAILS] >= hero_y) { animation_go = GP142_await_event(&a, &a, &b); switch (animation_go) { /* Updates for animation */ case GP142_PERIODIC: energy_trail_y[0] = energy_trail_y[0] - 17; energy_radius = (rand() % 6) + 27; for (tail = 1; tail <= ENERGY_ATK_TAILS; tail++) { energy_trail_y[tail] = energy_trail_y[tail - 1] + ((rand() % 10) + 16); } move_ship(ship_x, ship_y); blink_star(star_radius, star_color); move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); break; default: break; } /* Draws background */ draw_landscape( *ship_x, *ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_enemy(enemy_x, enemy_y); /* Draws container and left-over energy */ GP142_ovalXY( MAGENTA, hero_x - 21, hero_y - 28, hero_x + 21, hero_y + 28, 4); GP142_ovalXY( CYAN, hero_x - 18, hero_y - 24, hero_x + 17, hero_energy, FILL); /* Draws lead energy circle (stops when hits the container) */ if (energy_trail_y[0] > hero_y) GP142_circleXY( CYAN, hero_x, energy_trail_y[0], energy_radius); /* Draws tails behind lead energy circle*/ for (tail = 1; tail <= ENERGY_ATK_TAILS; tail++) { if (energy_trail_y[tail] > hero_y) GP142_circleXY( CYAN, hero_x, energy_trail_y[tail], energy_radius - ((rand() % 8) + 4)); } } /* End this animation */ /* Fills up the energy container by the proper amount */ hero_energy = hero_energy + 48 / ENERGY_ATK_ANIMATIONS; } /* End all animations (finished) */ return; } /* "Energy Shield" animation given character x,y coordinates and b/g info */ void energy_shield( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]) { int a; char b; /* Values to hold event input */ int animation_go; /* Switch for GP142's animation event wait */ int animations; /* Counter for current animation number loop is on */ /* Animates based on time length desired in E_SHIELD_ANIMATIONS */ for (animations = 0; animations <= E_SHIELD_ANIMATIONS; animations++) { animation_go = GP142_await_event(&a, &a, &b); switch (animation_go) { /* Updates for animation */ case GP142_PERIODIC: move_ship(ship_x, ship_y); blink_star(star_radius, star_color); move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); break; default: break; } /* Draws the background */ draw_landscape( *ship_x, *ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_hero(hero_x, hero_y); draw_enemy(enemy_x, enemy_y); /* Draws the changing shield */ GP142_ovalXY( rand() % MAX_COLORS, hero_x - 65, hero_y - 110, hero_x + 55, hero_y + 85, (rand() % 8) + 4); } return; } /* "Laser Blast" animation given character x,y coordinates and b/g info */ void laser_blast( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]) { int a; char b; /* Values to hold event input */ int animation_go; /* Switch for GP142's animation event wait */ int animations; /* Counter for current animation number loop is on */ int hits = LASER_STRIKES + (rand() % 11); /* # of laser strikes */ int beam[4] = {enemy_x + 75, enemy_y, enemy_x + 75, enemy_y}; /* Beam beginning x,y and ending x,y coordinates */ /* Animates the incident beam until it makes contact */ while (beam[2] <= hero_x - 16) { animation_go = GP142_await_event(&a, &a, &b); switch (animation_go) { /* Updates for animation */ case GP142_PERIODIC: beam[0] = beam[2] + 4; beam[2] = beam[2] + 12; beam[1] = beam[3]; beam[3] = beam[3] + (rand() % 9) - 4; move_ship(ship_x, ship_y); blink_star(star_radius, star_color); move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); break; default: break; } /* Draws the background */ draw_landscape( *ship_x, *ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_hero(hero_x, hero_y); draw_enemy(enemy_x, enemy_y); /* Draws the laser beam */ GP142_lineXY( ICE_BLUE, beam[0], beam[1], beam[2], beam[3], 14); GP142_lineXY( PINK, beam[0] - 4, beam[1], beam[2] + 4, beam[3], 1); } /* Animation over - beam has hit target */ /* Animates the laser strikes (after beam has hit) */ for (animations = 0; animations <= hits; animations++) { animation_go = GP142_await_event(&a, &a, &b); switch (animation_go) { /* Updates for animation */ case GP142_PERIODIC: beam[0] = hero_x - 40 + (rand() % 95); beam[1] = hero_y - 100 + (rand() % 200); move_ship(ship_x, ship_y); blink_star(star_radius, star_color); move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); break; default: break; } /* Draws the background */ draw_landscape( *ship_x, *ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_hero(hero_x, hero_y); draw_enemy(enemy_x, enemy_y); /* Draws laser impacts */ GP142_lineXY( YELLOW, beam[0], beam[1], beam[2], beam[3], (rand() % 4) + 3); GP142_lineXY( DUSTY_PLUM, beam[0], beam[1], beam[2], beam[3], 1); } /* Animation complete */ return; } /* "Subwoofer" animation given character x,y coordinates and b/g info */ void subwoofer_atk( int hero_x, int hero_y, int enemy_x, int enemy_y, int *ship_x, int *ship_y, const int star_x[], const int star_y[], int star_radius[], int star_color[], int peak_x[], int peak_y[], const int peak_ref_x[], const int peak_ref_y[]) { int a; char b; /* Values to hold event input */ int animation_go; /* Switch for GP142's animation event wait */ int animations; /* Counter for current animation number loop is on */ int sub_radius_mod; /* Modify subwoofer radius (creates beats) */ int sub_enclosure_x = enemy_x + 15; /* Enclosure's x coordinate */ int sub_enclosure_y = enemy_y - 40; /* Enclosure's y coordinate */ int hero_shake_x; /* Changes hero's x location (for shake effect) */ int hero_shake_y; /* Changes hero's y location (for shake effect) */ /* Animates based on time length desired in SUBWOOFER_ANIMATIONS */ for (animations = 0; animations <= SUBWOOFER_ANIMATIONS; animations++) { animation_go = GP142_await_event(&a, &a, &b); switch (animation_go) { /* Updates for animation */ case GP142_PERIODIC: sub_radius_mod = rand() % 5; hero_shake_x = hero_x + 5 - (rand() % 11); hero_shake_y = hero_y + 2 - (rand() % 5); move_ship(ship_x, ship_y); blink_star(star_radius, star_color); move_flames(peak_x, peak_y, peak_ref_x, peak_ref_y); break; default: break; } /* Draws background with hero shaking */ draw_landscape( *ship_x, *ship_y, star_x, star_y, star_radius, star_color, peak_x, peak_y, peak_ref_x, peak_ref_y); draw_hero(hero_shake_x, hero_shake_y); /* Draws the subwoofer enclosure */ GP142_rectangleXY( OLIVE, sub_enclosure_x - 61, sub_enclosure_y - 35, sub_enclosure_x + 61, sub_enclosure_y + 35, FILL); GP142_rectangleXY( GOLD, sub_enclosure_x - 58, sub_enclosure_y - 32, sub_enclosure_x + 58, sub_enclosure_y + 32, 1); /* Draws the subwoofers */ GP142_circleXY( BLACK, sub_enclosure_x - 28, sub_enclosure_y, 19 + sub_radius_mod); GP142_circleXY( MED_GRAY, sub_enclosure_x - 28, sub_enclosure_y, 4 + sub_radius_mod); GP142_circleXY( BLACK, sub_enclosure_x + 28, sub_enclosure_y, 19 + sub_radius_mod); GP142_circleXY( MED_GRAY, sub_enclosure_x + 28, sub_enclosure_y, 4 + sub_radius_mod); } return; } /*************************************************************************\ MISCELLANEOUS \*************************************************************************/ /* Initialize random number generator */ void initialize_random_numbers() { time_t t; /* current time */ srand (time(&t)); return; } /* Display error message if internal error is detected. */ void something_is_wrong (void) { GP142_printfXY (RED, 0, 0, 16, "Program error!"); return; } /******************************\ END OF MAIN PROGRAM CODE \******************************/