// $Id: albert.cc,v 1.5 2006/08/07 12:50:07 matthew Exp $ // Fish Supper // Copyright (C) 2006 Matthew Clarke // // 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. #include "albert.h" #include #include // ******************* // *** CONSTRUCTOR *** // ******************* FS::Albert::Albert() { width = ALBERT_WIDTH; height = ALBERT_HEIGHT; velocity = ALBERT_VELOCITY; sprite_rect.w = width; sprite_rect.h = height; erase_rect.w = width; erase_rect.h = height; image_section_rect.y = 0; image_section_rect.w = width; image_section_rect.h = height; for (int i = 0; i < NUM_COLL_BOXES; ++i) { coll_box_x_offsets[i] = COLL_BOX_X_OFFSETS[i]; coll_box_y_offsets[i] = COLL_BOX_Y_OFFSETS[i]; my_coll_boxes[i].w = COLL_BOX_WIDTHS[i]; my_coll_boxes[i].h = COLL_BOX_HEIGHTS[i]; } // for // FIXME: make these literals constants? bounding_box.w = width + 20; bounding_box.h = height + 20; } // FS::Albert::Albert() // ****************** // *** DESTRUCTOR *** // ****************** FS::Albert::~Albert() {} // ************************ // *** MEMBER FUNCTIONS *** // ************************ // ************************************************** void FS::Albert::reset() { my_orientation = NORTH; actions = 0; airborne = false; host_log = 0; splashed_zapped_out = false; left = false; next_jump_double = false; // start coords x = old_x = ALBERT_START_X; y = old_y = ALBERT_START_Y; sprite_rect.x = x; sprite_rect.y = y; erase_rect.x = old_x; erase_rect.y = old_y; dirty_rect.x = x; dirty_rect.y = y; dirty_rect.w = width; dirty_rect.h = height; current_frame = 0; // depends on what he's doing! current_strip = WALKING_N; } // FS::Albert::reset() // ************************************************** void FS::Albert::update(int t, KeyboardEvent * events, int n, PlayDisplay * pd, bool running) { old_x = x; old_y = y; if (test_action(FLOATING)) { switch (host_log->get_direction()) { case LEFT_TO_RIGHT: x += host_log->get_num_pixels_moved(); start_x += host_log->get_num_pixels_moved(); break; case RIGHT_TO_LEFT: x -= host_log->get_num_pixels_moved(); start_x -= host_log->get_num_pixels_moved(); break; } // switch } // if // No keyboard input allowed when in water... if ( !test_action(SPLASHING) && !test_action(ZAPPING) && !test_action(LEAVING_WITH_FISH) && !test_action(LEAVING_IN_A_HUFF) ) { process_keypress(t, events, n, running); } // if process_animation(t); calc_strip(); if (test_action(FLOATING)) { check_host_log(); } // if if (stars.is_active()) { stars.update(t, get_coll_box(), pd); } // if image_section_rect.x = current_frame * width; pd->request_erase(&erase_rect); pd->request_blit(current_strip, &image_section_rect, &sprite_rect); pd->request_update(dirty_rect); } // FS::Albert::update() // ************************************************** void FS::Albert::process_keypress(int t, KeyboardEvent * events, int n, bool running) { int i = 0; while (i < n) { switch (events[i]) { case UP_KEY_PRESSED: if (test_action(JUMPING) || !running) { break; } // if turn_on_action(WALKING); my_orientation = NORTH; start_time = t; start_y = y; break; case RIGHT_KEY_PRESSED: if (test_action(JUMPING) || !running) { break; } // if turn_on_action(WALKING); my_orientation = EAST; start_time = t; start_x = x; break; case DOWN_KEY_PRESSED: if (test_action(JUMPING) || !running) { break; } // if turn_on_action(WALKING); my_orientation = SOUTH; start_time = t; start_y = y; break; case LEFT_KEY_PRESSED: if (test_action(JUMPING) || !running) { break; } // if turn_on_action(WALKING); my_orientation = WEST; start_time = t; start_x = x; break; case JUMP_KEY_PRESSED: if (test_action(JUMPING) || !running) { break; } // if turn_on_action(JUMPING); start_time = t; start_x = x; start_y = y; break; case UP_KEY_RELEASED: if (my_orientation == NORTH) { turn_off_action(WALKING); } // if ... else break; case RIGHT_KEY_RELEASED: if (my_orientation == EAST) { turn_off_action(WALKING); } // if break; case DOWN_KEY_RELEASED: if (my_orientation == SOUTH) { turn_off_action(WALKING); } // if break; case LEFT_KEY_RELEASED: if (my_orientation == WEST) { turn_off_action(WALKING); } // if break; case NONE: case ESCAPE_PRESSED: case PAUSE_KEY_PRESSED: break; } // switch ++i; } // while } // FS::Albert::process_keypress() // ************************************************** void FS::Albert::process_animation(int t) { if ( test_action(LEAVING_WITH_FISH) || test_action(LEAVING_IN_A_HUFF) ) { current_frame = ((t - start_time) / ALBERT_DURATION) % WALKING_STRIP_NUM_FRAMES; x = (int) (start_x + ((t - start_time) * velocity)); if ( x >= SCREEN_WIDTH ) { left = true; } // if } else if (test_action(SPLASHING)) { current_frame = ((t - start_time) / ALBERT_DURATION); if (current_frame >= SPLASHING_STRIP_NUM_FRAMES) { splashed_zapped_out = true; } // if } else if (test_action(ZAPPING)) { current_frame = ((t - start_time) / ALBERT_DURATION); if (current_frame >= ZAPPING_STRIP_NUM_FRAMES) { splashed_zapped_out = true; } // if } else if (test_action(JUMPING)) { current_frame = ((t - start_time) / ALBERT_DURATION); if ( airborne = (current_frame >= AIRBORNE_START_FRAME && current_frame <= AIRBORNE_END_FRAME) ) { turn_off_action(FLOATING); if ( (next_jump_double) && (!stars.is_active()) ) { stars.activate(t, get_coll_box()); } // if float vel = ((next_jump_double) ? (2 * ALBERT_JUMPING_VELOCITY) : ALBERT_JUMPING_VELOCITY); switch (my_orientation) { case NORTH: y = (int) (start_y - ((t - (start_time + 500)) * /*ALBERT_JUMPING_VELOCITY*/vel)); break; case EAST: x = (int) (start_x + ((t - (start_time + 500)) * /*ALBERT_JUMPING_VELOCITY*/vel)); break; case SOUTH: y = (int) (start_y + ((t - (start_time + 500)) * /*ALBERT_JUMPING_VELOCITY*/vel)); break; case WEST: x = (int) (start_x - ((t - (start_time + 500)) * /*ALBERT_JUMPING_VELOCITY*/vel)); break; } // switch } else if (current_frame >= JUMPING_STRIP_NUM_FRAMES) { turn_off_action(JUMPING); current_frame = 0; start_time = t; start_x = x; start_y = y; } // This is to make sure that if Albert was already on a log before jumping, // he's allowed to stay on that log if he lands on it again straight afterwards. else if ( (current_frame > AIRBORNE_END_FRAME) && (!test_action(FLOATING)) && (host_log != 0) ) { turn_on_action(FLOATING); next_jump_double = false; if ( stars.is_active() && !stars.is_stopped() ) { stars.stop(t); // ? double jump will always be from a log... } // if } // if ... else } else if (test_action(WALKING)) { switch (my_orientation) { case NORTH: y = (int) (start_y - ((t - start_time) * velocity)); break; case EAST: x = (int) (start_x + ((t - start_time) * velocity)); break; case SOUTH: y = (int) (start_y + ((t - start_time) * velocity)); break; case WEST: x = (int) (start_x - ((t - start_time) * velocity)); break; } // switch // Walking strip is looped indefinitely so we need to use modulus // operator for 'wraparound'. current_frame = ((t - start_time) / ALBERT_DURATION) % WALKING_STRIP_NUM_FRAMES; } // if ... else calc_rects(); } // FS::Albert::process_animation() // ************************************************** void FS::Albert::calc_rects() { if (!test_action(LEAVING_IN_A_HUFF) && !test_action(LEAVING_WITH_FISH)) { // check bounds if (x < 0) { x = 0; } else if ( x > (SCREEN_WIDTH - ALBERT_WIDTH) ) { x = SCREEN_WIDTH - ALBERT_WIDTH; } // if ... else if (y < -ALBERT_Y_OFFSCREEN_TOLERANCE) { y = -ALBERT_Y_OFFSCREEN_TOLERANCE; } else if ( y > (SCREEN_HEIGHT - ALBERT_HEIGHT + ALBERT_Y_OFFSCREEN_TOLERANCE) ) { y = SCREEN_HEIGHT - ALBERT_HEIGHT + ALBERT_Y_OFFSCREEN_TOLERANCE; } // if ... else } // if sprite_rect.x = x; sprite_rect.y = y; erase_rect.x = old_x; erase_rect.y = old_y; // FIXME: tidy up this bug fix. int min_x, max_x; switch (my_orientation) { case NORTH: dirty_rect.x = x; dirty_rect.y = y; dirty_rect.w = width; dirty_rect.h = height + (old_y - y); break; case EAST: min_x = min(x, old_x); max_x = max(x, old_x); dirty_rect.x = min_x; dirty_rect.y = y; dirty_rect.w = width + (max_x - min_x); dirty_rect.h = height; break; case SOUTH: dirty_rect.x = x; dirty_rect.y = old_y; dirty_rect.w = width; dirty_rect.h = height + (y - old_y); break; case WEST: min_x = min(x, old_x); max_x = max(x, old_x); dirty_rect.x = min_x; dirty_rect.y = y; dirty_rect.w = width + (max_x - min_x); dirty_rect.h = height; break; } // switch // added this: if (dirty_rect.x < 0) { dirty_rect.w += dirty_rect.x; dirty_rect.x = 0; } else if (dirty_rect.x + dirty_rect.w >= SCREEN_WIDTH) { dirty_rect.w = SCREEN_WIDTH - dirty_rect.x; } // if ... else if (dirty_rect.y < 0) { dirty_rect.h += dirty_rect.y; dirty_rect.y = 0; } else if (dirty_rect.y + dirty_rect.h >= SCREEN_HEIGHT) { dirty_rect.h = SCREEN_HEIGHT - dirty_rect.y; } // if ... else } // FS::Albert::calc_rects() // ************************************************** void FS::Albert::calc_strip() { if (test_action(LEAVING_IN_A_HUFF)) { current_strip = WALKING_E; } else if (test_action(LEAVING_WITH_FISH)) { current_strip = WALKING_E_WITH_FISH; } else if (test_action(SPLASHING)) { switch (my_orientation) { case NORTH: current_strip = SPLASHING_N; break; case EAST: current_strip = SPLASHING_E; break; case SOUTH: current_strip = SPLASHING_S; break; case WEST: current_strip = SPLASHING_W; break; } // switch } else if (test_action(ZAPPING)) { current_strip = ZAPPING_NESW; } else if (test_action(JUMPING)) { switch (my_orientation) { case NORTH: current_strip = JUMPING_N; break; case EAST: current_strip = JUMPING_E; break; case SOUTH: current_strip = JUMPING_S; break; case WEST: current_strip = JUMPING_W; break; } // switch } else // must be walking { switch (my_orientation) { case NORTH: current_strip = WALKING_N; break; case EAST: current_strip = WALKING_E; break; case SOUTH: current_strip = WALKING_S; break; case WEST: current_strip = WALKING_W; break; } // switch } // if ... else } // FS::Albert::calc_strip() // ************************************************** void FS::Albert::check_host_log() { if ( !Collisions::contains(host_log->get_coll_box(), get_coll_box()) ) { host_log = 0; turn_off_action(FLOATING); } // if } // FS::Albert::check_host_log() // ************************************************** void FS::Albert::start_splash(int t) { turn_on_action(SPLASHING); start_time = t; start_x = x; start_y = y; } // FS::Albert::start_splash() // ************************************************** void FS::Albert::start_zap(int t) { turn_on_action(ZAPPING); start_time = t; start_x = x; start_y = y; } // FS::Albert::start_zap(int t) // ************************************************** int FS::Albert::is_in_water_or_being_zapped() const { return ( test_action(SPLASHING) || test_action(ZAPPING) ); } // FS::Albert::is_in_water_or_being_zapped() // ************************************************** void FS::Albert::start_leave_with_fish(int t) { turn_on_action(LEAVING_WITH_FISH); my_orientation = EAST; start_time = t; start_x = x; } // FS::Albert::start_leave_with_fish() // ************************************************** void FS::Albert::start_leave_in_a_huff(int t) { turn_on_action(LEAVING_IN_A_HUFF); my_orientation = EAST; start_time = t; start_x = ALBERT_START_X; y = ALBERT_START_Y; } // FS::Albert::start_leave_in_a_huff() // ************************************************** void FS::Albert::set_new_host_log(Log * l) { host_log = l; turn_on_action(FLOATING); } // FS::Albert::set_new_host_log() // ************************************************** const SDL_Rect & FS::Albert::get_coll_box() { my_coll_boxes[my_orientation].x = sprite_rect.x + coll_box_x_offsets[my_orientation]; my_coll_boxes[my_orientation].y = sprite_rect.y + coll_box_y_offsets[my_orientation]; return my_coll_boxes[my_orientation]; } // FS::Albert::get_coll_box() // ************************************************** const SDL_Rect & FS::Albert::get_bounding_box() { bounding_box.x = sprite_rect.x - 10; bounding_box.y = sprite_rect.y - 10; return bounding_box; } // FS::Albert::get_bounding_box() // ************************************************** // ************************************************** // ************************************************** // **************************************************