-
Notifications
You must be signed in to change notification settings - Fork 0
/
dudemeyer.cp
708 lines (623 loc) · 27.7 KB
/
dudemeyer.cp
1
/****************************************************************************************//* DUDEMEYER.CP *//****************************************************************************************//* (c) 1995 by Magnet Interactive Studios, inc. All rights reserved. *//****************************************************************************************//* Revision History: *//* v5.6 5/5/95 Icebreaker Golden Master version. By Andrew Looney. *//* v6.1 8/21/95 Began making changes for Icebreaker Two. Fixed ice bug. *//****************************************************************************************//***************************** WHAT THIS SOFTWARE DOES ********************************** This class manages the appearance and functionality of the dudemeyer. ("Dudemeyer" is a generic term for the playing piece that you control; in this case, it's the character in the center of the screen that moves around on a scrollable landscape.) The dudemeyer will have 8 different appearances, depending on the direction in which it is facing, so there will be 8 different artwork elements to manage in order to show the dudemeyer. Additionally, depending on how the dudemeyer is shaped, it may be necessary to have different collision detection parameters for each view of the dudemeyer, so the global variables for this class include 8 pairs of collision detection numbers as well.*****************************************************************************************//***** includes (make sure CPlusSwiHack.h is the last one) *****/#include "graphics.h"#include "stdio.h"#include "stdlib.h"#include "mem.h"#include "types.h"#include "hardware.h"#include "event.h"#include "strings.h"#include "access.h"#include "UMemory.h"#include "Form3DO.h"#include "Init3DO.h"#include "Parse3DO.h"#include "Utils3DO.h"#include "audio.h"#include "music.h"/***** Magnet includes *****/#include "icebreaker.h"#include "animation.h"#include "solids.h"#include "dudemeyer.h"#include "sounds.h"#include "deadlist.h"#include "levels.h"#include "seeker.h"/***** special c++ include (this must be last) *****/#include "CPlusSwiHack.h"/***** global variables *****/extern int32 g_total_pyramids;extern int32 g_dead;extern int32 level;/***** global class instantiations *****/extern solids population;extern dead_list morgue;extern seeker enemies;/**************************** dudemeyer::LoadArtwork ********************************** This function is intended for use only during the first initialization of theprogram. It loads a single copy of each artwork element that will be needed by thisclass, and stores pointers to these artwork elements in variables available to the class. Multiple copies of these artwork elements can then be created (and destroyed) simply by creating other pointers and setting them equal to the pointers initialized in this function. The artwork will remain in memory until the function ShutdownForExit() is called. The artwork files used by this function are provided via symbols defined in the overall application's header file. This function returns TRUE if the art was loaded successful, and FALSE if one or more art files could not be properly loaded.*****************************************************************************************/bool dudemeyer::LoadArtwork (void){ int32 i; if (!( angel.LoadArtwork (DUDEMEYER_ANGEL))) return(FALSE); if (!( pitfall_death.LoadArtwork (FELL_INTO_PIT_ANIM))) return(FALSE); if (!( lava_death.LoadArtwork (DEATH_BY_LAVA_ANIM))) return(FALSE); if (!( slime_death.LoadArtwork (DEATH_BY_SLIME_ANIM))) return(FALSE); if (!( got_shot_death.LoadArtwork (SHOT_BY_FIREBALL_ANIM))) return(FALSE); dudemeyer_views[NORTH] = LoadCel(DUDEMEYER_NORTH,MEMTYPE_CEL); dudemeyer_views[SOUTH] = LoadCel(DUDEMEYER_SOUTH,MEMTYPE_CEL); dudemeyer_views[EAST] = LoadCel (DUDEMEYER_EAST,MEMTYPE_CEL); dudemeyer_views[WEST] = LoadCel (DUDEMEYER_WEST,MEMTYPE_CEL); dudemeyer_views[NORTHEAST] = LoadCel (DUDEMEYER_NE,MEMTYPE_CEL); dudemeyer_views[NORTHWEST] = LoadCel (DUDEMEYER_NW,MEMTYPE_CEL); dudemeyer_views[SOUTHEAST] = LoadCel (DUDEMEYER_SE,MEMTYPE_CEL); dudemeyer_views[SOUTHWEST] = LoadCel (DUDEMEYER_SW,MEMTYPE_CEL); if (!( shooting_sources[EAST].LoadArtwork (DUDESHOOTS_EAST))) return(FALSE); if (!( shooting_sources[WEST].LoadArtwork (DUDESHOOTS_WEST))) return(FALSE); if (!( shooting_sources[NORTH].LoadArtwork (DUDESHOOTS_NORTH))) return(FALSE); if (!( shooting_sources[SOUTH].LoadArtwork (DUDESHOOTS_SOUTH))) return(FALSE); if (!(shooting_sources[NORTHEAST].LoadArtwork (DUDESHOOTS_NE))) return(FALSE); if (!(shooting_sources[NORTHWEST].LoadArtwork (DUDESHOOTS_NW))) return(FALSE); if (!(shooting_sources[SOUTHEAST].LoadArtwork (DUDESHOOTS_SE))) return(FALSE); if (!(shooting_sources[SOUTHWEST].LoadArtwork (DUDESHOOTS_SW))) return(FALSE); if (!( dudemeyer_deaths[EAST].LoadArtwork (DUDEDEATH_EAST))) return(FALSE); if (!( dudemeyer_deaths[WEST].LoadArtwork (DUDEDEATH_WEST))) return(FALSE); if (!( dudemeyer_deaths[NORTH].LoadArtwork (DUDEDEATH_NORTH))) return(FALSE); if (!( dudemeyer_deaths[SOUTH].LoadArtwork (DUDEDEATH_SOUTH))) return(FALSE); if (!(dudemeyer_deaths[NORTHEAST].LoadArtwork (DUDEDEATH_NE))) return(FALSE); if (!(dudemeyer_deaths[NORTHWEST].LoadArtwork (DUDEDEATH_NW))) return(FALSE); if (!(dudemeyer_deaths[SOUTHEAST].LoadArtwork (DUDEDEATH_SE))) return(FALSE); if (!(dudemeyer_deaths[SOUTHWEST].LoadArtwork (DUDEDEATH_SW))) return(FALSE); for (i = 0; i < 8; i++) { dudemeyer_shooting[i].InitializeAnim(&shooting_sources[i], STANDARD_FRAME_RATE); dudemeyer_shooting[i].Restart(); if (dudemeyer_views[i] == NULL) { printf("dudemeyer::LoadArtwork: Couldn't open dudemeyer artwork.\n"); return(FALSE); } CenterCelOnScreen(dudemeyer_shooting[i].current_frame_ccb); CenterCelOnScreen(dudemeyer_views[i]); } return(TRUE);}/************************ dudemeyer::InitializeDudemeyer ****************************** This function handles all setup and initialization of variables that are used by this class. It is intended to be used repeatedly, at the start of each round of the game.*****************************************************************************************/void dudemeyer::InitializeDudemeyer (void){ int32 i; for (i = 0; i < 8; i++) { CenterCelOnScreen(dudemeyer_views[i]); dudemeyer_shooting[i].Restart(); CenterCelOnScreen(dudemeyer_shooting[i].current_frame_ccb); } direction = EAST; old_direction = direction; col_detect_x[NORTH] = 5; col_detect_y[NORTH] = 4; col_detect_x[SOUTH] = 5; col_detect_y[SOUTH] = 3; col_detect_x[EAST] = 7; col_detect_y[EAST] = 3; col_detect_x[WEST] = 7; col_detect_y[WEST] = 3; col_detect_x[NORTHEAST] = 7; col_detect_y[NORTHEAST] = 4; col_detect_x[NORTHWEST] = 7; col_detect_y[NORTHWEST] = 4; col_detect_x[SOUTHEAST] = 7; col_detect_y[SOUTHEAST] = 3; col_detect_x[SOUTHWEST] = 7; col_detect_y[SOUTHWEST] = 3; dudemeyer_cel = dudemeyer_views[direction]; population.AddToList (dudemeyer_cel, DUDEMEYER, col_detect_x[direction], col_detect_y[direction]); dudemeyer_object = population.FindPointerIntoList (dudemeyer_cel); vert_speed = ICEBREAKER_VERT_SPEED; horz_speed = ICEBREAKER_HORZ_SPEED; ice_delay_x = 0; ice_delay_y = 0; old_ice_direction = NO_DIRECTION; ice_movement_state = STATIONARY; visual_state = NORMAL_VIEW;}/*************************** dudemeyer::MoveDudemeyer ********************************* This function shifts the dudemeyer a given distance in either or both directions, as specified by the values of x_change and y_change. These parameters can have either positive or negative values depending on which direction you wish to move the dudemeyer. This function also makes sure that the dudemeyer's position on the solids list is still correct. We also advance the frame of the dudemeyer's animation.*****************************************************************************************/void dudemeyer:: MoveDudemeyer (int32 x_change, int32 y_change){ dudemeyer_cel = dudemeyer_views[direction]; dudemeyer_cel->ccb_XPos += x_change; dudemeyer_cel->ccb_YPos += y_change; population.FixPositionOnList(dudemeyer_object);}/************************** dudemeyer::ChangeDirection ******************************** When the user changes the direction in which he (or she) wishes for the dudemeyer to move, it becomes necessary to also replace the picture of the dudemeyer with the one that shows it moving in the new direction. To figure out if this process is needed, we keep track of the direction we were moving during the last pass.*****************************************************************************************/bool dudemeyer::ChangeDirection (void){ if (old_direction != direction) { dudemeyer_cel = dudemeyer_views[direction]; population.RemoveFromList(dudemeyer_object); dudemeyer_object->cel = dudemeyer_cel; dudemeyer_object->col_detect_x = col_detect_x[direction]; dudemeyer_object->col_detect_y = col_detect_y[direction]; dudemeyer_object->next = (solid_object *) NULL; dudemeyer_object->previous = (solid_object *) NULL; population.InsertAtProperPointInList (dudemeyer_object); old_direction = direction; return(TRUE); } return(FALSE);}/***************************** dudemeyer::UpdateView *********************************** When the dudemeyer fires a shot, it is desireable to switch the look of the dudemeyerfrom a normal view to one that indicates the action it has done. The shooting view isan anim that lasts several frames; we change the view to the shooting anim and switchmodes, from normal to shooting, staying in shooting mode until we've finished managingthe frames of the shooting anim, at which point we go back to the normal view and thenormal mode. This function is called just before drawing the solids list to the screen, and thecompanion function, RestoreView, is called immediately after drawing the solids. Thisis done to avoid needing to keep the current cel of the look of the dudemeyer accurateat all times. We keep it normal at all times other than right before presenting the view,and then go back to normal again after presenting the view. This function may soon be expanded to handle different views for accelerating anddeccelerating.*****************************************************************************************/void dudemeyer::UpdateView (int32 new_mode){ if (old_direction != direction) visual_state = NORMAL_VIEW; if ((new_mode == NORMAL_VIEW) && (visual_state == SHOOTING_VIEW)) { dudemeyer_object->cel = dudemeyer_shooting[direction].current_frame_ccb; dudemeyer_shooting[direction].AdvanceFrame(); if (dudemeyer_shooting[direction].AnimComplete()) visual_state = NORMAL_VIEW; } if (new_mode == SHOOTING_VIEW) { dudemeyer_shooting[direction].Restart(); dudemeyer_object->cel = dudemeyer_shooting[direction].current_frame_ccb; dudemeyer_shooting[direction].AdvanceFrame(); visual_state = SHOOTING_VIEW; } if (((new_mode == BRAKING_VIEW) && (visual_state == SHOOTING_VIEW)) || ((new_mode == ACCELERATING_VIEW) && (visual_state == SHOOTING_VIEW))) { dudemeyer_object->cel = dudemeyer_shooting[direction].current_frame_ccb; dudemeyer_shooting[direction].AdvanceFrame(); if (dudemeyer_shooting[direction].AnimComplete()) visual_state = NORMAL_VIEW; }}/**************************** dudemeyer::RestoreView *********************************** After the solids are displayed (including the display of any special frames),we switch back to the normal dudemeyer frame.*****************************************************************************************/void dudemeyer::RestoreView (){ dudemeyer_object->cel = dudemeyer_views[direction];}/**************************** dudemeyer::Obstructed *********************************** Although this is a boolean function, there are really 4 cases that can result from a call to this routine. 1.) There is nothing in the path of the dudemeyer, in which case we return FALSE. 2.) There is an object in the path of the dudemeyer that the dudemeyer can destroy simply by touching it, in which case we carry out the destruction of that object and then, since it is no longer an obstruction, we return FALSE. 3.) There is an object that the dudemeyer cannot destroy by ramming but which is also not harmful to dudemeyer, in which case it is blocked and we return TRUE. 4.) There is an object in the path of the dudemeyer which is fatal, in which case we carry out our own destruction. In this final case, we may or may not actually resolve our death; this depends on the value of the deal_with_death parameter.*****************************************************************************************/bool dudemeyer::Obstructed (bool deal_with_death){ solid_object *obstruction; int32 i,j,k; obstruction = population.DetectCollision(dudemeyer_object,FALSE); if ((obstruction == (solid_object *) NULL) || (obstruction->object_type == DEATH_SCENE)) return(FALSE); if ((obstruction->object_type >= YELLOW_SEEKER) && (obstruction->object_type <= ACTIVE_CHAMELEON)) { i = enemies.GetSeekerHealth(obstruction, j, k); if ((i == MATERIALIZING_1) || (i == MATERIALIZING_2)) return(FALSE); } if (obstruction->object_type == RAINBOW_PYRAMID) { population.EliminateAnimatedObject(obstruction); population.ResolveRainbowPyramid(obstruction); population.ChangeArt(obstruction->cel, (char) obstruction->object_type); } if ((obstruction->object_type == BLUE_PYRAMID)) { PlaySoundEffect(SHATTER_SOUND); morgue.CreateDeathScene (&population.blue_death, STANDARD_FRAME_RATE, obstruction->cel->ccb_XPos,obstruction->cel->ccb_YPos, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y,0); population.EliminateObject(obstruction); g_total_pyramids--; return(FALSE); } if ((obstruction->object_type == MIRROR_PYRAMID)) { PlaySoundEffect(SHATTER_SOUND); morgue.CreateDeathScene (&population.mirror_death, STANDARD_FRAME_RATE, obstruction->cel->ccb_XPos,obstruction->cel->ccb_YPos, PYRAMID_COL_DETECT_X, PYRAMID_COL_DETECT_Y,0); population.EliminateObject(obstruction); g_total_pyramids--; return(FALSE); } if ((obstruction->object_type == RED_PYRAMID) || (obstruction->object_type == SLIMY_PYRAMID) || (obstruction->object_type == YELLOW_SEEKER) || (obstruction->object_type == YELLOW_PYRAMID) || (obstruction->object_type == LTBLUE_SEEKER) || (obstruction->object_type == LTBLUE_PYRAMID) || (obstruction->object_type == PINK_SEEKER) || (obstruction->object_type == PINK_PYRAMID) || (obstruction->object_type == DORMANT_CHAMELEON) || (obstruction->object_type == ACTIVE_CHAMELEON) || (obstruction->object_type == WAKING_CHAMELEON) || (obstruction->object_type == DORMANT_BUMMER) || (obstruction->object_type == ACTIVE_BUMMER) || (obstruction->object_type == WAKING_BUMMER) || (obstruction->object_type == DORMANT_REDCOAT) || (obstruction->object_type == ACTIVE_REDCOAT) || (obstruction->object_type == WAKING_REDCOAT) || (obstruction->object_type == ZOMBIE) || (obstruction->object_type == LURKER) || (obstruction->object_type == LURKER_PYRAMID) || (obstruction->object_type == MEANY) || (obstruction->object_type == NASTY) || (obstruction->object_type == GRUMPY) || (obstruction->object_type == JUGGERNAUT) || (obstruction->object_type == PSYCHO) || (obstruction->object_type == BIRTH_SCENE) || (obstruction->object_type == LIME_SEEKER) || (obstruction->object_type == LIME_PYRAMID)) { if (deal_with_death) { PlaySoundEffect(DEATH_SOUND); g_dead = CAUGHT_BY_SEEKER; } return(FALSE); } return(TRUE);}/****************************** dudemeyer::Vanish ************************************* This function is used to make the dudemeyer slowly fade out of existence and is intended as a cheap way of showing the destruction of the dudemeyer easily no matterwhich way it's facing (rather than doing 8 different destruction animations). The function messes around with the cel's CCB flags to set the transparency to various levels. It is called iteratively, with values decreasing from 100 to 75 to 50 to 25 to 0. At 0, the dudemeyer becomes invisible, which is accomplished by simply removing it from the solids list. This function is slated for demolition, pending the completion of finished game art.*****************************************************************************************/void dudemeyer::Vanish(int percentage){ uint32 new_pixc; dudemeyer_cel->ccb_Flags &= ~CCB_POVER_MASK; dudemeyer_cel->ccb_Flags |= PMODE_ONE; new_pixc = 0x500; if (percentage == 100) new_pixc = 0x1F00; if (percentage == 75) new_pixc = 0x0991; if (percentage == 50) new_pixc = 0x581; if (percentage == 25) new_pixc = 0x89D1; dudemeyer_cel->ccb_PIXC = (new_pixc << 16) | (dudemeyer_cel->ccb_PIXC & 0xFFFF); if (percentage == 0) population.EliminateObject(dudemeyer_object);}/************************* dudemeyer::IceMovementAdjustments *************************** This function is used to alter the player's movement values so that they seem to skidand slide around on icy surfaces. This consists of 3 main effects: Sluggish starts,sliding stops, and skidding turns. This function is state driven. These are the states that can occur: OFF_THE_ICE: This is the initial state. If we are in this state, it means that the dudemeyer has just moved onto an icy tile. STATIONARY: We are on ice, but we aren't moving. We go into ACCELERATING from here as soon as the player tries to move. ACCELERATING: In this state, the player is starting to move but hasn't yet gotten up to full speed. In this state, we gradually allow more of the normal movement amount to be applied to the dudemeyer during each pass. From here, we go into FULL_THROTTLE, unless the player turns before reaching full speed, in which case we go into SKIDDING. Or, if the player stops moving before reaching FULL_THROTTLE, we drop into DECCELERATING. FULL_THROTTLE: After staying in ACCELERATING for a given number of passes (as determined by the slipperyness factor defined in the symobls HORZ_SLIPPERYNESS & VERT_SLIPPERYNESS) the player moves into this state and movement will be normal until either the player stops moving (in which case we drop into DECCELERATING and gradually slide to a stop) or else they attempt to turn (in which case we go into SKIDDING, and they make a wide, sweeping turn). DECCELERATING: In this state, the player keeps moving in the direction they were going when they stopped trying to move. The length of time it takes to glide to a stop is determined partly by the slipperyness of the ice and partly by the state they were in when they let up on the gas (FULL_THROTTLE takes the full slipperyness factor, ACCELERATING takes somewhat less, depending on how much accleration they had acheived.) SKIDDING: SKIDDING works kind of like a combination between ACCELERATING and DECCELERATING. The movement continues along the old line of direction just as it does while in DECCELERATING; however, at the same time, they also begin to move slowly in the new direction.*****************************************************************************************/void dudemeyer::IceMovementAdjustments(int32 &x_change, int32 &y_change, uint32 action){bool moved;int32 x_adjustment, y_adjustment;int32 x_skid, y_skid; /*************************************************************************************/ // Figure out if the player is trying to move. /*************************************************************************************/ if ((action & ControlDown) || (action & ControlUp) || (action & ControlLeft) || (action & ControlRight)) moved = TRUE; else moved = FALSE; /*************************************************************************************/ // Adjust the state we are in according the current state and the move attempt. /*************************************************************************************/ if (old_ice_direction == NO_DIRECTION) old_ice_direction = direction; if (((old_ice_direction != direction) && (ice_movement_state == FULL_THROTTLE))) { ice_delay_x = HORZ_SLIPPERYNESS; ice_delay_y = VERT_SLIPPERYNESS; ice_movement_state = SKIDDING; PlaySoundEffect(SKID_SOUND); } if ((old_ice_direction != direction) && (ice_movement_state == DECCELERATING)) { ice_delay_x = HORZ_SLIPPERYNESS - (ice_delay_x - ((horz_speed >> 16) - HORZ_SLIPPERYNESS)); ice_delay_y = VERT_SLIPPERYNESS - (ice_delay_y - ((vert_speed >> 16) - VERT_SLIPPERYNESS)); ice_movement_state = SKIDDING; } if ((old_ice_direction != direction) && (ice_movement_state == ACCELERATING)) { ice_movement_state = SKIDDING; } if (ice_movement_state == OFF_THE_ICE) ice_movement_state = FULL_THROTTLE; if ((ice_movement_state == DECCELERATING) && (moved)) { ice_delay_x = ice_delay_x + (horz_speed >> 16); ice_delay_y = ice_delay_y + (vert_speed >> 16); ice_movement_state = ACCELERATING; } if ((ice_movement_state == ACCELERATING) && (!(moved))) { ice_delay_x = HORZ_SLIPPERYNESS - (ice_delay_x - ((horz_speed >> 16) - HORZ_SLIPPERYNESS)); ice_delay_y = VERT_SLIPPERYNESS - (ice_delay_y - ((vert_speed >> 16) - VERT_SLIPPERYNESS)); ice_movement_state = DECCELERATING; } if ((ice_movement_state == STATIONARY) && (moved)) { old_ice_direction = direction; ice_movement_state = ACCELERATING; ice_delay_x = 0; ice_delay_y = 0; } if ((ice_movement_state == FULL_THROTTLE) && (!(moved))) { ice_movement_state = DECCELERATING; ice_delay_x = (horz_speed >> 16) - HORZ_SLIPPERYNESS; ice_delay_y = (vert_speed >> 16) - VERT_SLIPPERYNESS; } /*************************************************************************************/ // Now adjust the amount of our movement based on the state we are in. // If the player is ACCELERATING, make it sluggish. /*************************************************************************************/ if (ice_movement_state == ACCELERATING) { x_adjustment = ice_delay_x; y_adjustment = ice_delay_y; if (x_adjustment > (horz_speed >> 16)) x_adjustment = (horz_speed >> 16); if (y_adjustment > (vert_speed >> 16)) y_adjustment = (vert_speed >> 16); if (x_change > 0) x_change -= horz_speed - (x_adjustment << 16); if (x_change < 0) x_change += horz_speed - (x_adjustment << 16); if (y_change > 0) y_change -= vert_speed - (y_adjustment << 16); if (y_change < 0) y_change += vert_speed - (y_adjustment << 16); ice_delay_x++; ice_delay_y++; if ((ice_delay_x >= HORZ_SLIPPERYNESS) && (ice_delay_y >= VERT_SLIPPERYNESS)) ice_movement_state = FULL_THROTTLE; return; } /*************************************************************************************/ // If the player is DECCELERATING, it takes a while to slow down and come to a stop. /*************************************************************************************/ if (ice_movement_state == DECCELERATING) { if ((direction == NORTH) || (direction == NORTHEAST) || (direction == NORTHWEST)) y_change = vert_speed; if ((direction == SOUTH) || (direction == SOUTHEAST) || (direction == SOUTHWEST)) y_change = -(vert_speed); if ((direction == WEST) || (direction == SOUTHWEST) || (direction == NORTHWEST)) x_change = horz_speed; if ((direction == EAST) || (direction == NORTHEAST) || (direction == SOUTHEAST)) x_change = -(horz_speed); x_adjustment = ice_delay_x; if (x_adjustment < 0) x_adjustment = 0; y_adjustment = ice_delay_y; if (y_adjustment < 0) y_adjustment = 0; /*** the following lines changed from Icebreaker 5.6 after bug found during port **/ if (x_change < 0) { x_change += (x_adjustment << 16); if (x_change > 0) x_change = 0; } else if (x_change > 0) { x_change -= (x_adjustment << 16); if (x_change < 0) x_change = 0; } if (y_change < 0) { y_change += (y_adjustment << 16); if (y_change > 0) y_change = 0; } else if (y_change > 0) { y_change -= (y_adjustment << 16); if (y_change < 0) y_change = 0; } /********************* we now resume normal unchanged code ************************/ ice_delay_x++; ice_delay_y++; if ((x_change == 0) && (y_change == 0)) { old_ice_direction = direction; ice_movement_state = STATIONARY; } return; } /*************************************************************************************/ // If the player is SKIDDING, they will keep moving in the old direction for awhile. /*************************************************************************************/ if (ice_movement_state == SKIDDING) { /* first, find out what the old direction's movement amount is. */ x_skid = 0; y_skid = 0; if ((old_ice_direction == NORTH) || (old_ice_direction == NORTHEAST) || (old_ice_direction == NORTHWEST)) y_skid = (vert_speed) >> 16; if ((old_ice_direction == SOUTH) || (old_ice_direction == SOUTHEAST) || (old_ice_direction == SOUTHWEST)) y_skid = -((vert_speed) >> 16); if ((old_ice_direction == WEST) || (old_ice_direction == SOUTHWEST) || (old_ice_direction == NORTHWEST)) x_skid = (horz_speed) >> 16; if ((old_ice_direction == EAST) || (old_ice_direction == NORTHEAST) || (old_ice_direction == SOUTHEAST)) x_skid = -((horz_speed) >> 16); x_adjustment = x_change >> 16; y_adjustment = y_change >> 16; x_skid = (x_skid * ice_delay_x) / HORZ_SLIPPERYNESS; y_skid = (y_skid * ice_delay_y) / VERT_SLIPPERYNESS; x_adjustment = (x_adjustment * (HORZ_SLIPPERYNESS-ice_delay_x)) / HORZ_SLIPPERYNESS; y_adjustment = (y_adjustment * (VERT_SLIPPERYNESS-ice_delay_y)) / VERT_SLIPPERYNESS; if ((ABS(old_ice_direction - direction)) == 4) { x_change = x_skid << 16; y_change = y_skid << 16; } else { x_change = (x_skid + x_adjustment) << 16; y_change = (y_skid + y_adjustment) << 16; } if (ice_delay_x) ice_delay_x--; if (ice_delay_y) ice_delay_y--; if ((ice_delay_x <= 0) && (ice_delay_y <= 0)) { old_ice_direction = direction; if (moved) ice_movement_state = FULL_THROTTLE; else ice_movement_state = STATIONARY; if ((ABS(old_ice_direction - direction)) == 4) ice_movement_state = STATIONARY; } }}/************************* dudemeyer::ShutdownForExit ********************************* This function deallocates memory that was reserved for storage of artwork elementsthat are used repeatedly over a sequence of many games. This function should be calledwhen (but only when) the program is about to be shutdown for good.*****************************************************************************************/void dudemeyer::ShutdownForExit (void){ int32 i; for (i = 0; i < 8; i++) { UnloadCel(dudemeyer_views[i]); dudemeyer_shooting[i].ShutdownForRestart(); shooting_sources[i].ShutdownForExit(); dudemeyer_deaths[i].ShutdownForExit(); } angel.ShutdownForExit(); pitfall_death.ShutdownForExit(); lava_death.ShutdownForExit(); slime_death.ShutdownForExit(); got_shot_death.ShutdownForExit();}/************************************** EOF *********************************************/