-
Notifications
You must be signed in to change notification settings - Fork 0
/
levelstat.cp
2448 lines (2176 loc) · 80.5 KB
/
levelstat.cp
1
/****************************************************************************************//* LEVELSTAT.CP *//****************************************************************************************//* (c) 1995 by Magnet Interactive Studios, inc. All rights reserved. *//****************************************************************************************//* Revision History: *//* 3/22/95 File first created, based on Icebreaker.cp version 4.5. *//****************************************************************************************//***************************** WHAT THIS SOFTWARE DOES ********************************** This file ingests all of the Icebreaker level spec files and generates a list ofstatistics about usage of different types of seekers, tiles, and musical tracks.*****************************************************************************************//***** regular includes *****/#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"#include "Kernel.h"#include "task.h" /* includes needed to spawn other threads *//***** Magnet includes *****/#include "icebreaker.h"#include "animation.h"#include "landscape.h"#include "solids.h"#include "seeker.h"#include "dudemeyer.h"#include "sounds.h"#include "weapon.h"#include "deadlist.h"#include "levels.h"#include "FontHandler.h"#include "nvram.h"#include "userif.h"#include "PlayMusic.h"#include "memcheck.h"/***** special c++ include (this must be last) *****/#include "CPlusSwiHack.h"/***** global variables used globally *****/ScreenContext g_screen;ScoreContext *g_scon;int32 g_total_pyramids;int32 g_dead;int32 g_file_buffer[MAX_FILE_BYTES/4];char g_level_filename[80];bool g_art_usage[TOTAL_ART_ELEMENTS];int32 level_lookup_table [ROWS_IN_LANDSCAPE] [COLUMNS_IN_LANDSCAPE];bool check_for_ice;int32 level;int32 demo_level;int16 g_skill_level;int16 demo_skill_level;CCB *black_background;CCB *text_cel_ptr[MAX_TEXT_CELS];unsigned int text_cel_num[MAX_TEXT_CELS];C_FontHandler *cFontHandlerPtr;Item vbl;int32 supress_repeats;status_file_format stat_file;int32 operating_mode;bool faded;int32 music_state;bool sound_on;bool standard_musical_selections;random_level *random_level_spec;/***** global variables used locally *****/CCB *lost_arrow;bool game_paused;int32 original_pyramids;bool random_changes;uint32 action;bool on_slippery_ice;int32 bogged_down_in_swamp;char *black_box_index;int32 random_seed;int32 total_games;int32 new_dudemeyer_view;int32 current_canned_demo;int32 lives,lives_per_level;int32 dudemeyer_row, dudemeyer_column;int32 memory_needs[151];int32 big_usage_table[151];int32 easy_seekers[151], medium_seekers[151], hard_seekers[151], insane_seekers[151];bool pac_mid;/***** global class instantiations used globally *****/landscape pavement;solids population;seeker enemies;dead_list morgue;dudemeyer icebreaker;weapon fireball;/***** global variables used for accessing the 3DO system clock *****/Item timer_item;Item timer_request_item;IOInfo timer_request_info;IOReq *timer_ior;struct timeval current_time;/***** Background Music globals *****/unsigned long tracks; /* bits are set to turn individual music tracks on/off */Player ctx;typedef struct level_stat_node{ int32 level_number; level_stat_node *next;};level_stat_node *overall_usage[TOTAL_ART_ELEMENTS];level_stat_node *music_usage[TOTAL_TRACKS];/*********************************** RegulateSpeed ************************************ This function is called during each pass through the VideoHandler and serves to slowdown the game on levels where it would otherwise go too fast.*****************************************************************************************/void RegulateSpeed(int32 speed_limit){static struct timeval old_time; do { WaitVBL (vbl, 1); DoIO(timer_request_item,&timer_request_info); } while ((old_time.tv_sec == current_time.tv_sec) && (old_time.tv_usec + speed_limit > current_time.tv_usec)); old_time.tv_sec = current_time.tv_sec; old_time.tv_usec = current_time.tv_usec;}/****************************** HasThisMuchTimePassedYet ****************************** This function provides an easy way of knowing when a given amount of time has goneby. The first call should pass a TRUE value in for start_timing_now, to set the clock,and after that, any number of subsequent calls with a FALSE value and a time value canbe made, with this routine telling you if that much time has passed.*****************************************************************************************/bool HasThisMuchTimePassedYet(int32 time_in_seconds, bool start_timing_now){static struct timeval old_time; DoIO(timer_request_item,&timer_request_info); if (start_timing_now) { old_time.tv_sec = current_time.tv_sec; old_time.tv_usec = current_time.tv_usec; } if (old_time.tv_sec + time_in_seconds < current_time.tv_sec) return(TRUE); return(FALSE);}/*********************************** RandomNumber ************************************* This function returns a random number within the range of the upper and lower boundsspecified.*****************************************************************************************/int32 RandomNumber (int32 lower_bounds, int32 upper_bounds){ int32 result; result = rand() % (upper_bounds - lower_bounds + 1); result += lower_bounds; return(result);}/******************************* GravitateTowardsPoint ******************************** In some applications, it may be useful to tweak the CCB values so that a cel moves slightly towards a given point. For example, an object might be moving randomly and yet still wish to gravitate towards the center of the screen. This function alters the CCB values of a cel so that it will move towards the x and y coordinate provided.*****************************************************************************************/bool GravitateTowardsPoint(CCB *target, int32 speed, int32 desired_x, int32 desired_y){ int32 i, center_x, center_y; for (i = 0; i < speed; i++) { center_x = FIND_CENTER_X(target); center_y = FIND_CENTER_Y(target); if ((center_x == desired_x) && (center_y == desired_y)) return(TRUE); if (center_x > desired_x) target->ccb_XPos -= 1 << 16; if (center_x < desired_x) target->ccb_XPos += 1 << 16; if (center_y > desired_y) target->ccb_YPos -= 1 << 16; if (center_y < desired_y) target->ccb_YPos += 1 << 16; } return(FALSE);}/********************************** ObjectVisible ************************************* This function examines the size and x and y coordinates of the supplied CCB and determines if any of the given cel will be visible on the screen. If so, it returns TRUE. This is a generally useful function because drawing an object to the screen takes a fair amount of time, so if there's a possibility that your cel won't even be visible, it's worth checking before investing the time needed to draw it into the screen buffer.*****************************************************************************************/bool ObjectVisible (CCB *target){ if ((target->ccb_XPos + (target->ccb_Width << 16) >= 0) && (target->ccb_XPos <= (SCREEN_WIDTH << 16)) && (target->ccb_YPos + (target->ccb_Height << 16) >= 0) && (target->ccb_YPos <= (SCREEN_HEIGHT << 16))) return(TRUE); return(FALSE);}/*********************************** PointVisible ************************************* This function examines the supplied x and y coordinates and determines if they arewithin the boundaries of the screen. If so, it returns TRUE. Note that the coordinatesare plain numbers, not 16.16 numbers.*****************************************************************************************/bool PointVisible (int32 x, int32 y){ if ((x >= 0) && (x <= SCREEN_WIDTH) && (y >= 0) && (y <= SCREEN_HEIGHT)) return(TRUE); return(FALSE);}/************************************ LoadArtwork ************************************* This function is intended for use only during the first initialization of theprogram. It loads up the master copies of all artwork that will be needed during the game.*****************************************************************************************/bool LoadArtwork(void){ if (!(icebreaker.LoadArtwork())) return(FALSE); if (!(fireball.LoadArtwork())) return(FALSE); lost_arrow = (CCB *) NULL; return(TRUE);}/********************************** InitSystemClock *********************************** This function is somewhat misnamed... it doesn't actually initialize the system'sclock, it just sets up a communication path that allows us to read the system clock.*****************************************************************************************/bool InitSystemClock(){ timer_item = OpenNamedDevice("timer",0); if (timer_item < 0) { printf("InitSystemClock: OpenNamedDevice call failed!\n"); return(FALSE); } timer_request_item = CreateIOReq(0,0,timer_item,0); if (timer_request_item < 0) { printf("InitSystemClock: CreateIOReq call failed!\n"); return(FALSE); } timer_ior = (IOReq *) LookupItem(timer_request_item); timer_request_info.ioi_Send.iob_Buffer = 0; timer_request_info.ioi_Send.iob_Len = 0; timer_request_info.ioi_Offset = 0; timer_request_info.ioi_Flags = 0; timer_request_info.ioi_Command = CMD_READ; timer_request_info.ioi_Unit = TIMER_UNIT_USEC; timer_request_info.ioi_Recv.iob_Buffer = ¤t_time; timer_request_info.ioi_Recv.iob_Len = sizeof(struct timeval); if (DoIO(timer_request_item,&timer_request_info) < 0) { printf("InitSystemClock: DoIO call failed!\n"); return(FALSE); } if (timer_ior->io_Error) { printf("InitSystemClock: result of %ld returned by DoIO.\n",timer_ior->io_Error); return(FALSE); } return(TRUE);}/******************************** ShutdownSystemClock ********************************* This function is somewhat misnamed... it doesn't actually turn off the system'sclock, it just shuts down the communication link to the system clock that was createdby InitSystemClock.*****************************************************************************************/void ShutdownSystemClock(){ DeleteIOReq(timer_request_item); CloseItem(timer_item);}/*********************************** Init3D0System ************************************ This function makes a series of calls that perform important 3DO initialization tasks. Who knows what they do exactly... the point is, you'll never get anywhere if you don't do this stuff.*****************************************************************************************/bool Init3D0System (void){ OpenGraphics(&g_screen,2); if (OpenMathFolio() < 0) { printf ("Init3D0System: Couldn't open math folio\n"); return (FALSE); } InitEventUtility (1, 0, TRUE); if (!InitSystemClock()) { printf ("Init3D0System: Couldn't initialize system clock\n"); return (FALSE); } srand(ReadHardwareRandomNumber()); return (TRUE);}/********************************** BootIcebreaker ************************************ This function handles all one-time setup and initialization functions for the game. This includes initializing the 3DO system, loading up the artwork, and reading in the sounds. Since these activities take a fair amount of time, we also display title screens to keep the players happy (or at least keep them from getting angry) while they're waiting.*****************************************************************************************/bool BootIcebreaker(void){ bool success; int32 i; ControlPadEventData data; success = TRUE; if (!(Init3D0System())) success = FALSE; /***** Before doing anything, display the 3DO logo, because we have to *****/ black_background = LoadCel(BACKGROUND_IMAGE,MEMTYPE_CEL); if (black_background == NULL) { printf("Yikes! Couldn't load the black background.\n"); return(FALSE); } DisplaySplashScreen(THREEDO_LOGO); WaitVBL (vbl, 200); pavement.BootLandscape(); population.BootSolids(); enemies.BootSeekers(); /***** Set up structures for text display handling *****/ // Allocate memory for the FontHandler class cFontHandlerPtr = new(C_FontHandler); for (i = 0; i < MAX_TEXT_CELS; i++) { text_cel_ptr[i] = new(CCB); memset(text_cel_ptr[i], 0, sizeof(CCB)); text_cel_num[i] = cFontHandlerPtr->CreateCelFromFont(FONTFILENAME); if (text_cel_num[i] < 1) { printf("BootIcebreaker: CreateCelFromFont() failed.\n"); success = FALSE; } } /***** this provides a secret way of getting more than one life. *****/ for (i = 0; i < 5; i++) { GetControlPad (1,FALSE,&data); if ((data.cped_ButtonBits & ControlLeftShift) && (data.cped_ButtonBits & ControlRightShift)) { lives_per_level = 3; DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen], LoadIcebreakerTextIntoCel(EXTRA_LIVES_TEXT, -1, 210)); printf("Extra Lives Enabled.\n"); WaitVBL (vbl, 100); break; } } /***** While the graphics are loading, display the Magnet logo *****/ printf("Loading artwork...\n"); DisplaySplashScreen(MAGNET_LOGO); if (!(LoadArtwork())) success = FALSE; if (success == FALSE) { printf("BootIcebreaker: initialization failed!\n\n"); return(success); } /***** Now, while the audio stuff is loading, display the Icebreaker logo *****/ printf("Loading sounds...\n"); DisplaySplashScreen(ICEBREAKER_SPLASH); /***** Also, display the version number at this time *****/ for( int x = 0; x < MAXPROGRAMNUM; x++) { SoundfxNeeded[x] = FALSE; } SoundfxNeeded[PING_SOUND] = TRUE; SoundfxNeeded[FALLING_SOUND] = TRUE; if (!(InitAudio())) success = FALSE; if (success == FALSE) printf("BootIcebreaker: initialization failed!\n\n"); return(success);}/******************************* InitializeIcebreaker ********************************* This function handles all setup and initialization of variables that are used by the game. It is intended to be used repeatedly, at the start of each round of the game.*****************************************************************************************/void InitializeIcebreaker(int32 leveltoload, int16 difficulty){ check_for_ice = FALSE; morgue.InitializeMorgue(); LoadLevel(leveltoload); /* This function calls population.InitializeSolids() */ pavement.InitializeLandscape(); population.RegisterRocksWithLandscape(); population.CheckForPotentialPits(); enemies.InitializeSeekers (leveltoload,difficulty); icebreaker.InitializeDudemeyer(); fireball.InitializeWeapon(); original_pyramids = g_total_pyramids; g_screen.sc_curScreen = 0; supress_repeats = 0; on_slippery_ice = FALSE; bogged_down_in_swamp = 0; dudemeyer_row = -1; dudemeyer_column = -1; game_paused = FALSE; g_dead = NOT_DEAD; random_changes = TRUE; if ((leveltoload == LESSON_1_BLUE) || (leveltoload == LESSON_2_RED) || (leveltoload == LESSON_3_GREEN)) random_changes = FALSE; black_box_index = (char *) &g_file_buffer[0]; for( int x = 0; x < MAXPROGRAMNUM; x++) { SoundfxNeeded[x] = FALSE; } SoundfxNeeded[SHATTER_SOUND] = TRUE; SoundfxNeeded[ZAP_SOUND] = TRUE; SoundfxNeeded[SHOOT_SOUND] = TRUE; SoundfxNeeded[SPLAT_SOUND] = TRUE; SoundfxNeeded[PULVERIZE_SOUND] = TRUE; SoundfxNeeded[PING_SOUND] = TRUE; SoundfxNeeded[DEATH_SOUND] = TRUE; if ((g_art_usage[PA_TILE]) || (g_art_usage[PB_TILE]) || (g_art_usage[PC_TILE]) || (g_art_usage[PG_TILE]) || (g_art_usage[PH_TILE]) || (g_art_usage[PI_TILE]) || (g_art_usage[PJ_TILE]) || (g_art_usage[PL_TILE]) || (g_art_usage[PM_TILE]) || (g_art_usage[PD_TILE]) || (g_art_usage[PE_TILE]) || (g_art_usage[PF_TILE]) || (g_art_usage[P1_TILE]) || (g_art_usage[PK_TILE])) SoundfxNeeded[FALLING_SOUND] = TRUE; if ((g_art_usage[PURPLE_PYRAMID]) || (g_art_usage[RAINBOW_PYRAMID])) { SoundfxNeeded[PIT_RUMBLE_SOUND] = TRUE; SoundfxNeeded[FALLING_SOUND] = TRUE; } if ((g_art_usage[L1_TILE]) || (g_art_usage[LA_TILE]) || (g_art_usage[LB_TILE])) SoundfxNeeded[LAVA_SIZZLE_SOUND] = TRUE; if ((g_art_usage[S1_TILE]) || (g_art_usage[SA_TILE]) || (g_art_usage[SB_TILE])) SoundfxNeeded[DUDEMEYER_SLIME_SOUND] = TRUE; if ((g_art_usage[IA_TILE]) || (g_art_usage[IB_TILE]) || (g_art_usage[IC_TILE]) || (g_art_usage[ID_TILE])) SoundfxNeeded[SKID_SOUND] = TRUE; if (g_art_usage[CONCRETE_PYRAMID]) { SoundfxNeeded[CONCRETE_CRUMBLE_SOUND] = TRUE; SoundfxNeeded[CONCRETE_CHIP_SOUND] = TRUE; } if (g_art_usage[DORMANT_CHAMELEON]) { SoundfxNeeded[CHAM_ACTIVIATION_SOUND] = TRUE; SoundfxNeeded[LIME_DEATH_SOUND] = TRUE; } if (g_art_usage[YELLOW_SEEKER]) SoundfxNeeded[ERODE_SOUND] = TRUE; if (g_art_usage[LTBLUE_SEEKER]) SoundfxNeeded[LTBLUE_DEATH_SOUND] = TRUE; if (g_art_usage[PINK_SEEKER]) SoundfxNeeded[PINK_DEATH_SOUND] = TRUE; if (g_art_usage[LIME_SEEKER]) SoundfxNeeded[LIME_DEATH_SOUND] = TRUE; if (g_art_usage[ZOMBIE]) { SoundfxNeeded[ZOMBIE_BIRTH_SOUND] = TRUE; SoundfxNeeded[ZOMBIE_HIT_SOUND] = TRUE; SoundfxNeeded[ZOMBIE_DEATH_SOUND] = TRUE; } if (g_art_usage[LURKER]) SoundfxNeeded[LURKER_DEATH_SOUND] = TRUE; if (g_art_usage[MEANY]) SoundfxNeeded[ORANGE_HIT_SOUND] = TRUE; DynamicSampleLoader(SoundfxNeeded);}/********************************** ArtworkMissing ************************************* This function is called whenever a function that needs to load up a piece of artworkis unsuccessful in doing so. It prints a statement identifying the missing art element,and then aborts the program. This result should only occur during debug and test phases.*****************************************************************************************/void ArtworkMissing (int32 missing_element){ printf("\n\nIcebreaker must abort now because the "); printf("artwork element #%ld ",missing_element); printf(" artwork could not be loaded.\n"); Quit();}/************************************* AreWeLost *************************************** This function compares the location of an object to the location of the center tilein the playing area to see if the player (or a seeker) is completely out in the wasteland.If so, then this function returns the direction in which the playing area lies, relativeto where the object currently is.*****************************************************************************************/int32 AreWeLost(int32 our_x, int32 our_y, int32 home_x, int32 home_y, int32 modifier){ int32 perimeter_x; int32 perimeter_y; perimeter_x = (PERIMETER_DISTANCE_X * modifier) << 16; perimeter_y = (PERIMETER_DISTANCE_Y * modifier) << 16; if (((ABS(our_x - home_x)) > perimeter_x) || ((ABS(our_y - home_y)) > perimeter_y)) { if ((our_y < (home_y - perimeter_y)) && (our_x < (home_x - perimeter_x))) return(SOUTHEAST); if ((our_y > (home_y + perimeter_y)) && (our_x > (home_x + perimeter_x))) return(NORTHWEST); if ((our_y < (home_y - perimeter_y)) && (our_x > (home_x + perimeter_x))) return(SOUTHWEST); if ((our_y > (home_y + perimeter_y)) && (our_x < (home_x - perimeter_x))) return(NORTHEAST); if (our_y < (home_y - perimeter_y)) return(SOUTH); if (our_y > (home_y + perimeter_y)) return(NORTH); if (our_x < (home_x - perimeter_x)) return(EAST); if (our_x > (home_x + perimeter_x)) return(WEST); } return(NO_DIRECTION);}/********************************** FlightRecorder ************************************* This function is used for the creation of canned, self-running demos. It interprets theplayer's move during each pass through the game and stores a code for that move into alarge array which can be dumped out at the end of the game and saved for usage as acanned demo.*****************************************************************************************/void FlightRecorder(int32 x_change, int32 y_change, bool shot){ if (black_box_index > (((char *) &g_file_buffer[0]) + MAX_FILE_BYTES - 2)) return; if (black_box_index == (((char *) &g_file_buffer[0]) + MAX_FILE_BYTES - 2)) { printf("black box is full.\n"); *(black_box_index) = 'Z'; black_box_index++; return; } if (shot) { if ((x_change == 0) && (y_change > 0)) *(black_box_index) = 'A'; /* NORTH */ if ((x_change == 0) && (y_change < 0)) *(black_box_index) = 'B'; /* SOUTH */ if ((x_change > 0) && (y_change == 0)) *(black_box_index) = 'C'; /* WEST */ if ((x_change < 0) && (y_change == 0)) *(black_box_index) = 'D'; /* EAST */ if ((x_change > 0) && (y_change > 0)) *(black_box_index) = 'E'; /* NORTHWEST */ if ((x_change > 0) && (y_change < 0)) *(black_box_index) = 'F'; /* SOUTHWEST */ if ((x_change < 0) && (y_change > 0)) *(black_box_index) = 'G'; /* NORTHEAST */ if ((x_change < 0) && (y_change < 0)) *(black_box_index) = 'H'; /* SOUTHEAST */ if ((x_change == 0) && (y_change == 0)) *(black_box_index) = 'I'; /* NO MOVE */ } else { if ((x_change == 0) && (y_change > 0)) *(black_box_index) = '1'; /* NORTH */ if ((x_change == 0) && (y_change < 0)) *(black_box_index) = '2'; /* SOUTH */ if ((x_change > 0) && (y_change == 0)) *(black_box_index) = '3'; /* WEST */ if ((x_change < 0) && (y_change == 0)) *(black_box_index) = '4'; /* EAST */ if ((x_change > 0) && (y_change > 0)) *(black_box_index) = '5'; /* NORTHWEST */ if ((x_change > 0) && (y_change < 0)) *(black_box_index) = '6'; /* SOUTHWEST */ if ((x_change < 0) && (y_change > 0)) *(black_box_index) = '7'; /* NORTHEAST */ if ((x_change < 0) && (y_change < 0)) *(black_box_index) = '8'; /* SOUTHEAST */ if ((x_change == 0) && (y_change == 0)) *(black_box_index) = '0'; /* NO MOVE */ } black_box_index++;}/************************************ DumpBlackBox ************************************* This function is optionally called at the end of a game. It dumps out the movementcodes stored by the function FlightRecorder. Once printed to the debug window, thesecodes can be pasted into an ascii file and from there, they can be read back in viaReadActionsFile and used in the running of canned demo games. *****************************************************************************************/void DumpBlackBox(){ char *black_box_reader; int32 total_bytes; printf("\n\n"); total_bytes = 0; black_box_reader = (char *) &g_file_buffer[0]; while (black_box_reader < black_box_index) { printf("%c",*(black_box_reader)); black_box_reader++; total_bytes++; } printf("\n\ntotal bytes recorded: %ld\n",total_bytes);}/********************************** ReadActionsFile ************************************ This function is used to start up a canned, self-running demos. Given the existence ofa file containing codes for the player's movements during a game, this function readsthose codes in and stores them in a large array for use during the running of the demo.*****************************************************************************************/void ReadActionsFile(){ int32 bytes_read; char temp[20],*temp_ptr; char filename[80]; /* select a file to read. */ switch (current_canned_demo) { default: current_canned_demo = 0; case 0: strcpy (filename,"$boot/IceFiles/demos/pathways.actions"); break; case 1: strcpy (filename,"$boot/IceFiles/demos/basic_pits.actions"); break; case 2: strcpy (filename,"$boot/IceFiles/demos/dig_own_grave.actions"); break; case 3: strcpy (filename,"$boot/IceFiles/demos/woodstock.actions"); break; case 4: strcpy (filename,"$boot/IceFiles/demos/12_dudes.actions"); break; case 5: strcpy (filename,"$boot/IceFiles/demos/zombie_geyser.actions"); break; case 6: strcpy (filename,"$boot/IceFiles/demos/pool_of_fire.actions"); break; case 7: strcpy (filename,"$boot/IceFiles/demos/its_not_easy.actions"); break; case 8: strcpy (filename,"$boot/IceFiles/demos/Icy_rock_garden.actions"); break; case 9: strcpy (filename,"$boot/IceFiles/demos/stop_n_go.actions"); break; } /* read in the file. */ bytes_read = ReadFile(filename,MAX_FILE_BYTES,g_file_buffer,0); /* give up if we failed to read the file. */ if (bytes_read == -1) { printf("Bummer dude! Failure in attempt to open actions file!!!!!\n"); operating_mode = PICK_AND_PLAY_MODE; random_changes = TRUE; return; } /* peel off the first line, stick it into a temp string variable, convert it into */ /* a number, and set it aside for use as the seed for the random number generator. */ black_box_index = (char *) &g_file_buffer[0]; temp_ptr = black_box_index; while (*(black_box_index) != 13) black_box_index++; *(black_box_index) = 0; black_box_index++; strcpy(temp,temp_ptr); random_seed = atoi(temp); /* peel off the second line, stick it into a temp string variable, convert it into */ /* a number, and set it aside for use as the level number. */ temp_ptr = black_box_index; while (*(black_box_index) != 13) black_box_index++; *(black_box_index) = 0; black_box_index++; strcpy(temp,temp_ptr); demo_level = atoi(temp);}/********************************** InputRebuilder ************************************ The purpose of this function is cause the game to run in a canned demo mode by readinguser inputs out of a preset list of moves instead of taking live user input. In otherwords, in the normal case, a player will play the game, with their inputs being collectedby the function InputHandler and then passed along for processing to ResultsHandler.However, it is also possible to capture a player's moves using the function FlightRecorderand then supply those moves to ResultsHandler instead of fetching new ones from the user.In still other words, this function is kind of like a VCR that can play videotapes createdwith the function called FlightRecorder.*****************************************************************************************/void InputRebuilder(int32 &x_change, int32 &y_change){ ControlPadEventData data; bool initially_moving; if ((x_change == 0) && (y_change == 0)) initially_moving = FALSE; else initially_moving = TRUE; new_dudemeyer_view = NORMAL_VIEW; x_change = 0; y_change = 0; GetControlPad (1,FALSE,&data); if (data.cped_ButtonBits) { operating_mode = DEMO_MODE_ABORT; random_changes = TRUE; } switch(*(black_box_index)) { case '1': /* NORTH */ icebreaker.direction = NORTH; y_change = icebreaker.vert_speed; break; case '2': /* SOUTH */ icebreaker.direction = SOUTH; y_change = -(icebreaker.vert_speed); break; case '3': /* WEST */ icebreaker.direction = WEST; x_change = icebreaker.horz_speed; break; case '4': /* EAST */ icebreaker.direction = EAST; x_change = -(icebreaker.horz_speed); break; case '5': /* NORTHWEST */ icebreaker.direction = NORTHWEST; y_change = icebreaker.vert_speed; x_change = icebreaker.horz_speed; break; case '6': /* SOUTHWEST */ icebreaker.direction = SOUTHWEST; y_change = -(icebreaker.vert_speed); x_change = icebreaker.horz_speed; break; case '7': /* NORTHEAST */ icebreaker.direction = NORTHEAST; y_change = icebreaker.vert_speed; x_change = -(icebreaker.horz_speed); break; case '8': /* SOUTHEAST */ icebreaker.direction = SOUTHEAST; y_change = -(icebreaker.vert_speed); x_change = -(icebreaker.horz_speed); break; case '0': /* NO MOVE */ break; case 'A': /* NORTH and shoot */ icebreaker.direction = NORTH; y_change = icebreaker.vert_speed; if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'B': /* SOUTH and shoot */ icebreaker.direction = SOUTH; y_change = -(icebreaker.vert_speed); if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'C': /* WEST and shoot */ icebreaker.direction = WEST; x_change = icebreaker.horz_speed; if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'D': /* EAST and shoot */ icebreaker.direction = EAST; x_change = -(icebreaker.horz_speed); if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'E': /* NORTHWEST and shoot */ icebreaker.direction = NORTHWEST; y_change = icebreaker.vert_speed; x_change = icebreaker.horz_speed; if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'F': /* SOUTHWEST and shoot */ icebreaker.direction = SOUTHWEST; y_change = -(icebreaker.vert_speed); x_change = icebreaker.horz_speed; if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'G': /* NORTHEAST and shoot */ icebreaker.direction = NORTHEAST; y_change = icebreaker.vert_speed; x_change = -(icebreaker.horz_speed); if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'H': /* SOUTHEAST and shoot */ icebreaker.direction = SOUTHEAST; y_change = -(icebreaker.vert_speed); x_change = -(icebreaker.horz_speed); if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'I': /* NO MOVE but shoot */ if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; break; case 'Z': /* end of data */ operating_mode = DEMO_MODE_ABORT; random_changes = TRUE; break; } black_box_index++; if (new_dudemeyer_view == NORMAL_VIEW) { if ((x_change == 0) && (y_change == 0) && (initially_moving == TRUE)) new_dudemeyer_view = BRAKING_VIEW; if (((x_change != 0) || (y_change != 0)) && (initially_moving == FALSE)) new_dudemeyer_view = ACCELERATING_VIEW; }}/********************************** InputGenerator ************************************ The purpose of this function is to provide simulated user inputs, with the goal ofallowing Icebreaker to play itself when no human wishes to play it. This function iscalled instead of InputHandler, and it then does the best it can at generating user-likeinputs. It has the result of simulating the playing of this game by a rather dimwittedhuman.*****************************************************************************************/void InputGenerator(int32 &x_change, int32 &y_change){ static int32 duration; ControlPadEventData data; bool initially_moving; if ((x_change == 0) && (y_change == 0)) initially_moving = FALSE; else initially_moving = TRUE; new_dudemeyer_view = NORMAL_VIEW; x_change = 0; y_change = 0; GetControlPad (1,FALSE,&data); if (data.cped_ButtonBits) operating_mode = DEMO_MODE_ABORT; if ((duration < 0) || (duration > 8)) { duration = RandomNumber(3,8); icebreaker.direction = RandomNumber(NORTH,NORTHWEST); } duration--; switch(icebreaker.direction) { case NORTH: y_change = icebreaker.vert_speed; break; case SOUTH: y_change = -(icebreaker.vert_speed); break; case WEST: x_change = icebreaker.horz_speed; break; case EAST: x_change = -(icebreaker.horz_speed); break; case NORTHEAST: y_change = icebreaker.vert_speed; x_change = -(icebreaker.horz_speed); break; case NORTHWEST: y_change = icebreaker.vert_speed; x_change = icebreaker.horz_speed; break; case SOUTHEAST: y_change = -(icebreaker.vert_speed); x_change = -(icebreaker.horz_speed); break; case SOUTHWEST: y_change = -(icebreaker.vert_speed); x_change = icebreaker.horz_speed; break; } if (RandomNumber(1,8) == 1) if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW; if (new_dudemeyer_view == NORMAL_VIEW) { if ((x_change == 0) && (y_change == 0) && (initially_moving == TRUE)) new_dudemeyer_view = BRAKING_VIEW; if (((x_change != 0) || (y_change != 0)) && (initially_moving == FALSE)) new_dudemeyer_view = ACCELERATING_VIEW; }}/*********************************** InputHandler ************************************* This function reads the control pad to find out what the player wants to do. In general, though, it doesn't carry out much of these instructions; it just collects the information. The function ResultsHandler then figures out what the player managed to accomplish by his (or her) actions.*****************************************************************************************/void InputHandler(int32 &x_change, int32 &y_change){ ControlPadEventData data; bool initially_moving;#ifdef SCREEN_SHOTS_ENBALED char* screen_shot_filename = "Screen???"; static int32 screen_shot_counter = 0;#endif if ((x_change == 0) && (y_change == 0)) initially_moving = FALSE; else initially_moving = TRUE; new_dudemeyer_view = NORMAL_VIEW; action = 0; x_change = 0; y_change = 0; GetControlPad (1,FALSE,&data); action = data.cped_ButtonBits; if (supress_repeats) supress_repeats--; if (action & ControlStart) { if (!(supress_repeats)) { if (lost_arrow != (CCB *) NULL) { UnloadCel(lost_arrow); lost_arrow = (CCB *) NULL; } supress_repeats = 3; game_paused = !(game_paused); } } if (action & ControlUp) { y_change = icebreaker.vert_speed; icebreaker.direction = NORTH; } if (action & ControlDown) { y_change = -(icebreaker.vert_speed); icebreaker.direction = SOUTH; } if (action & ControlLeft) { x_change = icebreaker.horz_speed; icebreaker.direction = WEST; } if (action & ControlRight) { x_change = -(icebreaker.horz_speed); icebreaker.direction = EAST; } if ((action & ControlUp) && (action & ControlLeft)) icebreaker.direction = NORTHWEST; if ((action & ControlUp) && (action & ControlRight)) icebreaker.direction = NORTHEAST; if ((action & ControlDown) && (action & ControlLeft)) icebreaker.direction = SOUTHWEST; if ((action & ControlDown) && (action & ControlRight)) icebreaker.direction = SOUTHEAST; if ((game_paused) && (!(supress_repeats))) { if (action & ControlA) { supress_repeats = 3; sound_on = !(sound_on); if ((sound_on) && (music_state == MUSIC_MUTED)) { music_state = MUSIC_ON; START_THE_MUSIC; } } if (action & ControlB) { supress_repeats = 3; if (music_state == MUSIC_ON) { music_state = MUSIC_OFF; STOP_THE_MUSIC; } else { if (music_state == MUSIC_MUTED) sound_on = TRUE; music_state = MUSIC_ON; START_THE_MUSIC; } } if (action & ControlX) { operating_mode = GAME_ABORT; game_paused = FALSE; } } //if (game_paused) // icebreaker.direction = icebreaker.old_direction; if ((!(game_paused)) && (!(supress_repeats)) && ((action & ControlA) || (action & ControlB) || (action & ControlC))) { supress_repeats = 3; if (fireball.FireWeapon(icebreaker.direction)) new_dudemeyer_view = SHOOTING_VIEW;#ifdef FLIGHT_RECORDER_ON FlightRecorder(x_change, y_change, TRUE);#endif }#ifdef FLIGHT_RECORDER_ON else if (!(game_paused)) FlightRecorder(x_change, y_change, FALSE);#endif#ifdef SCREEN_SHOTS_ENBALED /* If the X button is pressed, save a shot of the screen */ if (action & ControlX) { sprintf (screen_shot_filename, "Screen%03d", screen_shot_counter++); printf ("\nsaving screen as image file '%s' ... ", screen_shot_filename); SaveImage(screen_shot_filename, g_screen.sc_Bitmaps[g_screen.sc_curScreen]->bm_Buffer); printf ("done "); }#endif if (new_dudemeyer_view == NORMAL_VIEW) { if ((x_change == 0) && (y_change == 0) && (initially_moving == TRUE)) new_dudemeyer_view = BRAKING_VIEW; if (((x_change != 0) || (y_change != 0)) && (initially_moving == FALSE)) new_dudemeyer_view = ACCELERATING_VIEW; }}/********************************** ResultsHandler ************************************ This function figures out what happened from one pass in the game to the next. In addition to attempting to carry out the player's actions, it also drives computerized actions (like the activities of the seekers) and follows through with game related events that require maintenance (like advancing the frame in death animations and seeing what happened when shots were fired).*****************************************************************************************/void ResultsHandler(int32 &x_change, int32 &y_change){ bool successfully_moved; int32 tile_type; CCB *tile; if (on_slippery_ice) icebreaker.IceMovementAdjustments(x_change,y_change,action); if (pavement.CheckForSwamp(FIND_CENTER_X (icebreaker.dudemeyer_cel), FIND_CENTER_Y (icebreaker.dudemeyer_cel), icebreaker.dudemeyer_object->col_detect_x + HAZARD_X_COL_DETECT_ADJUSTMENT, icebreaker.dudemeyer_object->col_detect_y + HAZARD_Y_COL_DETECT_ADJUSTMENT)) bogged_down_in_swamp = 6; if (bogged_down_in_swamp) { if ((x_change != 0) || (y_change != 0)) bogged_down_in_swamp--; if (x_change > 0) x_change -= 0x00022500; /* i.e. 2.25 */ else if (x_change < 0) x_change += 0x00022500; /* i.e. 2.25 */ if (y_change > 0) y_change -= 0x00015000; /* i.e. 1.5 */ else if (y_change < 0) y_change += 0x00015000; /* i.e. 1.5 */ } morgue.MaintainMorgue(); successfully_moved = icebreaker.ChangeDirection(); if ((x_change != 0) || (y_change != 0)) { successfully_moved = FALSE; while (!(successfully_moved)) { icebreaker.MoveDudemeyer(-(x_change),-(y_change)); population.MoveWorld(x_change,y_change); if (icebreaker.Obstructed(FALSE)) { /* undo the move, reduce the distance, and try again */ icebreaker.MoveDudemeyer(x_change,y_change); population.MoveWorld(-(x_change),-(y_change)); /* if the move amount has a fractional component, deal with it first. */ if (x_change & 0x0000FFFF) x_change = (x_change & 0xFFFF0000); else { if (x_change > 0) x_change -= 1 << 16; else if (x_change < 0) x_change += 1 << 16; } /* Now adjust the y value, again dealing first with any fractional amount. */ if (y_change & 0x0000FFFF) y_change = (y_change & 0xFFFF0000); else { if (y_change > 0) y_change -= 1 << 16; else if (y_change < 0) y_change += 1 << 16; } /* even though we haven't moved, it's as far as we can go */ if ((x_change == 0) && (y_change == 0)) successfully_moved = TRUE; if (icebreaker.ice_movement_state == SKIDDING) icebreaker.ice_movement_state = STATIONARY; } else { pavement.MoveWorld(x_change,y_change); pavement.MaintainWasteland(x_change,y_change); successfully_moved = TRUE; } } } fireball.MoveBullets(x_change,y_change); icebreaker.Obstructed(TRUE); if (g_dead) return; tile = (CCB *) NULL; if (pavement.CheckForDanger(FIND_CENTER_X (icebreaker.dudemeyer_cel), FIND_CENTER_Y (icebreaker.dudemeyer_cel), icebreaker.dudemeyer_object->col_detect_x + HAZARD_X_COL_DETECT_ADJUSTMENT + 2, icebreaker.dudemeyer_object->col_detect_y + HAZARD_Y_COL_DETECT_ADJUSTMENT + 1, dudemeyer_row,dudemeyer_column,tile_type,tile,TRUE,FALSE)) { if ((tile_type < FIRST_PITFORMATION) || (tile_type > LAST_PITFORMATION)) PullIntoHazard(tile,tile_type); } if (check_for_ice) { pavement.ExamineTile (FIND_CENTER_X (icebreaker.dudemeyer_cel), FIND_CENTER_Y (icebreaker.dudemeyer_cel), icebreaker.dudemeyer_object->col_detect_x + HAZARD_X_COL_DETECT_ADJUSTMENT, icebreaker.dudemeyer_object->col_detect_y + HAZARD_Y_COL_DETECT_ADJUSTMENT, tile_type); if ((tile_type == IA_TILE) || (tile_type == IB_TILE) || (tile_type == IC_TILE) || (tile_type == ID_TILE)) on_slippery_ice = TRUE; else if (tile_type != AMBIGUOUS) { on_slippery_ice = FALSE; icebreaker.ice_movement_state = OFF_THE_ICE; icebreaker.old_ice_direction = NO_DIRECTION; } } enemies.AnimateSeekers(x_change,y_change); population.EmptyTrash(); if (random_changes) { if (population.TransformSolid()) PlaySoundEffect(PING_SOUND); }}/*********************************** VideoHandler ************************************* This function takes care of alternating between the screen buffers and drawing everything the player gets to see from one twelfth of a second to the next. Notice that very few calls are made to get the game displayed; this is because almost everything is inserted into the big linked list of solid objects which is displayed by the function DisplaySolids (in the solids class).*****************************************************************************************/void VideoHandler(){ int32 the_way_home; RegulateSpeed(FRAME_RATE_12_PER_SECOND); /* Switch to the other screen */ g_screen.sc_curScreen = 1 - g_screen.sc_curScreen; /* Draw the background image (in this case, a solid black cel to clear the screen) */ DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen],black_background); if (g_dead == NOT_DEAD) icebreaker.UpdateView(new_dudemeyer_view); pavement.DisplayLandscape(((g_dead == NOT_DEAD) && (!(game_paused)))); fireball.DrawBullets(); population.DisplaySolids(); fireball.UndrawBullets(); if (g_dead == NOT_DEAD) icebreaker.RestoreView(); if (game_paused) { if (lost_arrow != (CCB *) NULL) DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen],lost_arrow); DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen], LoadIcebreakerTextIntoCel(PAUSED_P_OPTION, 25, 150)); DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen], LoadIcebreakerTextIntoCel(PAUSED_X_OPTION, 25, 165)); DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen], LoadIcebreakerTextIntoCel(PAUSED_A_OPTION, 25, 180)); DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen], LoadIcebreakerTextIntoCel(PAUSED_B_OPTION, 25, 195)); DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen], LoadIcebreakerTextIntoCel(PYRAMIDS_LEFT_TEXT, -1, 210)); } DisplayScreen(g_screen.sc_Screens[g_screen.sc_curScreen],0); /* if the user is totally out in the wasteland, load up a directional arrow to */ /* show the way back to the playing area. (We do this after we've drawn the */ /* screen once in paused mode to avoid the timing delay caused by loading data.) */ if (game_paused) { the_way_home = AreWeLost(icebreaker.dudemeyer_cel->ccb_XPos, icebreaker.dudemeyer_cel->ccb_YPos, pavement.center_tile->ccb_XPos, pavement.center_tile->ccb_YPos, 1); if (the_way_home != NO_DIRECTION) { switch(the_way_home) { case SOUTHWEST: lost_arrow = LoadCel(ARROW_SW, MEMTYPE_CEL); break; case SOUTHEAST: lost_arrow = LoadCel(ARROW_SE, MEMTYPE_CEL); break; case NORTHWEST: lost_arrow = LoadCel(ARROW_NW, MEMTYPE_CEL); break; case NORTHEAST: lost_arrow = LoadCel(ARROW_NE, MEMTYPE_CEL); break; case NORTH: lost_arrow = LoadCel(ARROW_N, MEMTYPE_CEL); break; case SOUTH: lost_arrow = LoadCel(ARROW_S, MEMTYPE_CEL); break; case WEST: lost_arrow = LoadCel(ARROW_W, MEMTYPE_CEL); break; case EAST: lost_arrow = LoadCel(ARROW_E, MEMTYPE_CEL); break; } if (lost_arrow == NULL) printf("Warning: unable to load lost arrow artwork.\n"); else { lost_arrow->ccb_XPos = 275 << 16; lost_arrow->ccb_YPos = 200 << 16; } } }}/********************************* PullIntoHazard ************************************ When the player goofs and gets close enough to a pit (or other tile-based hazard) tofall in, it becomes necessary to bridge the visual gap between the first frame of thefalling-into-a-pit animation (which depicts the dudemeyer falling into the pit from aposition directly over the center of the pit) and the actual current location of thedudemeyer (which can be at just about any point along any edge of the hazard in question).This routine takes care of that. It takes control away from the user and displays thedudemeyer in successive positions, growing gradually closer to the center of the hazard,until the dudemeyer is centered over the tile, at which point this routine calls forththe dudemeyer's death animation and exits. While the dudemeyer is being pulled into the hazard, we also change the directionin which it is facing. This makes it look like the dudemeyer has stumbled and gonespinning out of control on the way down into the hazard.*****************************************************************************************/void PullIntoHazard(CCB *tile, int32 tile_type){ int32 new_x, new_y; new_dudemeyer_view = NORMAL_VIEW; if ((tile_type == PA_TILE) || (tile_type == PB_TILE) || (tile_type == PC_TILE) || (tile_type == PD_TILE) || (tile_type == PE_TILE) || (tile_type == PF_TILE) || (tile_type == PG_TILE) || (tile_type == PH_TILE) || (tile_type == PI_TILE) || (tile_type == PJ_TILE) || (tile_type == PK_TILE) || (tile_type == P1_TILE) || (tile_type == PL_TILE) || (tile_type == PM_TILE)) g_dead = FELL_INTO_A_PIT; if ((tile_type == L1_TILE) || (tile_type == LA_TILE) || (tile_type == LB_TILE)) g_dead = CONSUMED_BY_LAVA; if ((tile_type == SA_TILE) || (tile_type == S1_TILE) || (tile_type == SB_TILE)) g_dead = DISSOLVED_IN_SLIME; if (icebreaker.direction == WEST) icebreaker.direction++; while (!(GravitateTowardsPoint(icebreaker.dudemeyer_cel, 5, FIND_CENTER_X(tile), FIND_CENTER_Y(tile)))) { new_x = icebreaker.dudemeyer_cel->ccb_XPos; new_y = icebreaker.dudemeyer_cel->ccb_YPos; if (icebreaker.direction != WEST) { icebreaker.direction++; if (icebreaker.direction == 8) icebreaker.direction = 0; icebreaker.ChangeDirection(); } icebreaker.dudemeyer_cel->ccb_XPos = new_x; icebreaker.dudemeyer_cel->ccb_YPos = new_y; population.FixPositionOnList(icebreaker.dudemeyer_object); enemies.AnimateSeekers(0,0); morgue.MaintainMorgue(); fireball.MoveBullets(0,0); VideoHandler(); } population.EliminateObject(icebreaker.dudemeyer_cel); if (g_dead == FELL_INTO_A_PIT) { PlaySoundEffect(FALLING_SOUND); morgue.CreateDeathScene (&icebreaker.pitfall_death, STANDARD_FRAME_RATE, tile->ccb_XPos,tile->ccb_YPos,0,0,0); } if (g_dead == CONSUMED_BY_LAVA) { PlaySoundEffect(LAVA_SIZZLE_SOUND); morgue.CreateDeathScene (&icebreaker.lava_death, STANDARD_FRAME_RATE, tile->ccb_XPos,tile->ccb_YPos,0,0,0); } if (g_dead == DISSOLVED_IN_SLIME) { PlaySoundEffect(LAVA_SIZZLE_SOUND); morgue.CreateDeathScene (&icebreaker.slime_death, STANDARD_FRAME_RATE, tile->ccb_XPos,tile->ccb_YPos,0,0,0); } PlaySoundEffect(DEATH_SOUND);}/*********************************** AngelFliesAway ************************************* Comments go here...*****************************************************************************************/void AngelFliesAway(){ anim_user angel; bool flying; flying = FALSE; angel.InitializeAnim(&icebreaker.angel, STANDARD_FRAME_RATE); angel.PositionAnim (icebreaker.dudemeyer_cel->ccb_XPos, icebreaker.dudemeyer_cel->ccb_YPos); population.AddToList(angel.current_frame_ccb,DEATH_SCENE,0,0); switch(icebreaker.direction) { case NORTH: angel.current_frame_ccb->ccb_XPos += ( 4 << 16); angel.current_frame_ccb->ccb_YPos -= (15 << 16); break; case SOUTH: angel.current_frame_ccb->ccb_XPos += (2 << 16); angel.current_frame_ccb->ccb_YPos -= (24 << 16); break; case EAST: angel.current_frame_ccb->ccb_XPos -= (12 << 16); angel.current_frame_ccb->ccb_YPos -= (22 << 16); break; case WEST: angel.current_frame_ccb->ccb_XPos += (18 << 16); angel.current_frame_ccb->ccb_YPos -= (22 << 16); break; case NORTHEAST: angel.current_frame_ccb->ccb_XPos -= (9 << 16); angel.current_frame_ccb->ccb_YPos -= (17 << 16); break; case NORTHWEST: angel.current_frame_ccb->ccb_XPos += (14 << 16); angel.current_frame_ccb->ccb_YPos -= (17 << 16); break; case SOUTHEAST: angel.current_frame_ccb->ccb_XPos -= (3 << 16); angel.current_frame_ccb->ccb_YPos -= (24 << 16); break; case SOUTHWEST: angel.current_frame_ccb->ccb_XPos += (7 << 16); angel.current_frame_ccb->ccb_YPos -= (24 << 16); break; } angel.Restart(); while (ObjectVisible(angel.current_frame_ccb)) { RegulateSpeed(FRAME_RATE_12_PER_SECOND); g_screen.sc_curScreen = 1 - g_screen.sc_curScreen; DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen],black_background); pavement.DisplayLandscape(FALSE); fireball.DrawBullets(); population.DisplaySolids(); fireball.UndrawBullets(); if (flying) { angel.current_frame_ccb->ccb_XPos -= (2 << 16); angel.current_frame_ccb->ccb_YPos -= (4 << 16); angel.DisplayFrame(); } else { if ((angel.current_frame_number >> 16) > 13) { flying = TRUE; population.EliminateObject(angel.current_frame_ccb); } } DisplayScreen(g_screen.sc_Screens[g_screen.sc_curScreen],0); angel.AdvanceFrame(); if (angel.AnimComplete()) { while(!((angel.current_frame_number >> 16) > 15)) angel.AdvanceFrame(); } } angel.ShutdownForRestart();}/************************************* GameOver *************************************** When a player either clears a level or gets killed, control switches to this subroutine. This function carries out many of the functions of InputHandler and ResultsHandler, but geared only to following through on the last few actions and ignoring the user's additional input. Basically, this function just keeps the scene going until the last few death animations are played out.*****************************************************************************************/void GameOver (bool end_quickly){ int i; bool loose_ends; CCB *results_message; int32 x_change, y_change; ControlPadEventData data; anim_user dudemeyer_expires; if (g_dead == CAUGHT_BY_SEEKER) { dudemeyer_expires.InitializeAnim(&icebreaker.dudemeyer_deaths[icebreaker.direction], STANDARD_FRAME_RATE); dudemeyer_expires.PositionAnim (icebreaker.dudemeyer_cel->ccb_XPos, icebreaker.dudemeyer_cel->ccb_YPos); dudemeyer_expires.Restart(); population.AddToList(dudemeyer_expires.current_frame_ccb,BIRTH_SCENE,0,0); } new_dudemeyer_view = NORMAL_VIEW; if (end_quickly) {// DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen], black_background);// DisplayScreen(g_screen.sc_Screens[g_screen.sc_curScreen],0); } fireball.StopBullets(); loose_ends = TRUE; while (loose_ends) { loose_ends = FALSE; if (enemies.StillMoving()) loose_ends = TRUE; if (enemies.CheckForSeekerHazardDeaths()) loose_ends = TRUE; if (morgue.MaintainMorgue()) loose_ends = TRUE; if ((g_dead == CAUGHT_BY_SEEKER) && (!(dudemeyer_expires.AnimComplete()))) { dudemeyer_expires.AdvanceFrame(); loose_ends = TRUE; } fireball.MoveBullets(0,0); if (!(end_quickly)) VideoHandler(); } if (g_dead == CAUGHT_BY_SEEKER) { population.EliminateObject(dudemeyer_expires.current_frame_ccb); dudemeyer_expires.ShutdownForRestart(); } if (end_quickly) return; /*************************************************************************************/ /* Nothing beyond this point will be executed if the caller wanted us to end quickly */ /*************************************************************************************/ /***** carry out the final stages of death. *****/ if (g_dead == CAUGHT_BY_SEEKER) { AngelFliesAway(); population.EliminateObject(icebreaker.dudemeyer_object); } if ((g_dead == DISSOLVED_IN_SLIME) || (g_dead == FELL_INTO_A_PIT) || (g_dead == CONSUMED_BY_LAVA)) WaitVBL (vbl, 120); /***** If the player has won or has run out of lives, display ending messages. *****/ lives--; if ((lives < 1) || (g_dead == NOT_DEAD)) { if (g_dead == NOT_DEAD) results_message = LoadCel(YOU_WIN, MEMTYPE_CEL); else results_message = LoadCel(GAME_OVER,MEMTYPE_CEL); if (results_message == NULL) printf("GameOver: Cannot load required artwork\n"); CenterCelOnScreen(results_message); DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen],results_message); DisplayScreen(g_screen.sc_Screens[g_screen.sc_curScreen],0); UnloadCel(results_message); WaitVBL (vbl, 100); return; } /***** If we didn't return, then we still have work to do and lives to do it with. ***/ enemies.ResetSeekers(); icebreaker.InitializeDudemeyer(); x_change = (178 << 16) - pavement.center_tile->ccb_XPos; y_change = (140 << 16) - pavement.center_tile->ccb_YPos; population.MoveWorld (x_change, y_change); icebreaker.MoveDudemeyer (-(x_change),-(y_change)); pavement.MoveWorld (x_change, y_change); pavement.MaintainWasteland (x_change, y_change); VideoHandler(); for (i = 0; i < 5; i++) GetControlPad (1,FALSE,&data); g_dead = NOT_DEAD;}/**************************** ShutdownAllLevelSpecificArtwork ************************** This function frees up all of the memory that was allocated to artwork elements whichotherwise would remain memory resident for use during the next playing of the last levelplayed. This function allows the caller to get access to as much memory as is possible,for times when it needs to load up a lot of meta level artwork.*****************************************************************************************/void ShutdownAllLevelSpecificArtwork(){ int32 i; for (i = 0; i < TOTAL_ART_ELEMENTS; i++) g_art_usage[i] = FALSE; enemies.ShutdownUnusedArtwork(); pavement.ShutdownUnusedArtwork(); population.ShutdownUnusedArtwork(); for( int x = 0; x < MAXPROGRAMNUM; x++) { SoundfxNeeded[x] = FALSE; } SoundfxNeeded[PING_SOUND] = TRUE; SoundfxNeeded[FALLING_SOUND] = TRUE; DynamicSampleLoader(SoundfxNeeded); ScavengeMem();}/******************************* ShutdownForRestart *********************************** This function is called after every game to give back to the system all of the memory that was dynamically allocated during the course of the game. This is done simply by making calls to all of the lower level ShutdownForRestart functions.*****************************************************************************************/void ShutdownForRestart(){ pavement.ShutdownForRestart();printf("r "); enemies.ShutdownForRestart();printf("d"); morgue.ShutdownForRestart();printf("u"); population.ShutdownForRestart();printf("d"); fireball.ShutdownForRestart();printf("e"); if (lost_arrow != (CCB *) NULL) { UnloadCel(lost_arrow); lost_arrow = (CCB *) NULL; } ScavengeMem();printf("! ");}/******************************** 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 ShutdownForExit(){ int32 i;printf("\nT"); for (i = 0; i < MAX_TEXT_CELS; i++) text_cel_ptr[i] = (CCB *) NULL;printf("h"); // For some reason, this next statement results in this error message: // FreeMemToMemList bad ptr:ffffc size=-84016632 // Thus, I'm commenting it out for now. // delete(cFontHandlerPtr);printf("a"); for (i = 0; i < MAX_TEXT_CELS; i++) delete(text_cel_ptr[i]);printf("n"); pavement.ShutdownForExit();printf("k"); population.ShutdownForExit();printf("s "); enemies.ShutdownForExit();printf("f"); icebreaker.ShutdownForExit();printf("o"); fireball.ShutdownForExit();printf("r "); UnloadCel(black_background);printf("p"); DeleteItem(vbl);}/************************************** Quit ****************************************** This function performs some 3DO shutdown functions and then exits.*****************************************************************************************/void Quit(){printf("l"); ShutdownSystemClock();printf("a"); if (!faded) FadeToBlack(&g_screen,40); faded = TRUE;printf("y"); ReleaseAudio();printf("i"); KillEventUtility();printf("ng Icebreaker!\n\n\n"); exit(0);}/************************************ PlayALevel *************************************** This workhorse function handles all aspects of the actual playing of an Icebreakerlevel.*****************************************************************************************/int32 PlayALevel(int32 whats_next){ int32 x_change, y_change; char level_name[40]; ControlPadEventData data; int i; if (level == ITS_TOTALLY_RANDOM) { random_level_spec = new(random_level); GenerateRandomLevel(); } switch (level) { case GOPHER_HOLES: i = (PITS_MOVIE); break; case YRAMIDSPAY_USTMAY_IEDAY: i = (PURPLE_MOVIE); break; case PINK_OR_SWIM: i = (PINK_MOVIE); break; case TIE_DIE: i = (RAINBOW_MOVIE); break; case ONE_MID_TWO_MID: i = (CYANIDE_MOVIE); break; case ICE_SCREAM: i = (ICE_MOVIE); break; case GUNNER_SABOT_LIMEY: i = (LIMEYS_MOVIE); break; case ENGLISH_COUNTRY_ROCK_GARDEN: i = (ROCKS_MOVIE); break; case PYRAMID_HENGE: i = (CONCRETE_MOVIE); break; case DOUBLE_DOUBLE_BOIL_AND_BUBBLE: i = (LAVA_MOVIE); break; case A_LEVEL_FOR_CHAMELEON: i = (CHAMELEON_MOVIE); break; case GREEN_SLIME: i = (SLIME_MOVIE); break; case PYRAMIDS_IN_A_STRANGE_LAND: i = (LURKERS_MOVIE); break; case SWAMPWALK: i = (SWAMP_MOVIE); break; case HARD_ROCK_ZOMBIE_PYRAMIDS: i = (ZOMBIE_MOVIE); break; case PATHWAYS_IN_THE_SAND: i = (MEANY_MOVIE); break; default: i = -1; break; } if (i != -1) { STOP_THE_MUSIC; PlayVideoStream(i); if (music_state == MUSIC_ON) START_MENU_MUSIC; } do { printf("Game #%ld: ",total_games); random_seed = ReadHardwareRandomNumber(); if ((operating_mode == PICK_AND_PLAY_MODE) && (whats_next == PLAY_THE_GAME)) PreGetReadyScreen(); if ((operating_mode == SELF_PLAY_MODE) || (operating_mode == CANNED_DEMO_MODE)) { DisplaySplashScreen(ICEBREAKER_SPLASH); if (operating_mode == SELF_PLAY_MODE) { g_skill_level = INSANE; if (level == ITS_TOTALLY_RANDOM) { g_skill_level = (short) RandomNumber(EASY,INSANE); GenerateRandomLevel(); } else { level++; if (level == ITS_TOTALLY_RANDOM) { random_level_spec = new(random_level); GenerateRandomLevel(); } } } if (operating_mode == CANNED_DEMO_MODE) { demo_skill_level = HARD; current_canned_demo++; ReadActionsFile(); } } srand(random_seed);#ifdef FLIGHT_RECORDER_ON g_skill_level = HARD;#endif if (operating_mode == CANNED_DEMO_MODE) { FetchLevelName (level_name, demo_level); printf("Level: %ld (%s). ",demo_level,level_name); InitializeIcebreaker(demo_level,demo_skill_level); } else { FetchLevelName (level_name, level); printf("Level: %ld (%s). ",level,level_name); InitializeIcebreaker(level,g_skill_level); switch (g_skill_level) { case EASY: printf("[E] "); break; case MEDIUM: printf("[M] "); break; case HARD: printf("[H] "); break; case INSANE: printf("[I] "); break; } }#ifdef FLIGHT_RECORDER_ON printf("\nRandom Seed: %ld\n",random_seed); printf(" Level: %ld\n",level);#endif STOP_THE_MUSIC; if (music_state == MUSIC_ON) START_THE_MUSIC; if ((operating_mode == PICK_AND_PLAY_MODE) && (whats_next == PLAY_THE_GAME)) { whats_next = GetReadyScreen(); if (whats_next != PLAY_THE_GAME) { GameOver(TRUE); STOP_THE_MUSIC; if (music_state == MUSIC_ON) START_MENU_MUSIC; ShutdownForRestart(); printf("\n"); if (level == ITS_TOTALLY_RANDOM) { delete (random_level_spec); level = 1; } return (whats_next); } }#ifdef FLIGHT_RECORDER_ON random_changes = FALSE;#endif if (operating_mode == CANNED_DEMO_MODE) { random_changes = FALSE; ReadActionsFile(); /* if we're in canned demo mode and someone pressed a button while we were */ /* loading up the game, abort immediately. */ GetControlPad (1,FALSE,&data); if (data.cped_ButtonBits) { operating_mode = DEMO_MODE_ABORT; GameOver(TRUE); } } if (operating_mode != DEMO_MODE_ABORT) { if (operating_mode == PICK_AND_PLAY_MODE) lives = lives_per_level; else lives = 1; if (!faded) FadeToBlack(&g_screen, 40); VideoHandler(); FadeFromBlack(&g_screen, 40); faded = FALSE; /* discard early user data (if any) */ for (i = 0; i < 10; i++) GetControlPad (1,FALSE,&data); /***** main program loop *****/ while (FOREVER) { switch (operating_mode) { case PICK_AND_PLAY_MODE: InputHandler (x_change,y_change); break; case SELF_PLAY_MODE: InputGenerator (x_change,y_change); break; case CANNED_DEMO_MODE: InputRebuilder (x_change,y_change); break; } // this call used only for testing --->>> Benchmark(); VideoHandler(); if (!(game_paused)) ResultsHandler(x_change,y_change); if ((operating_mode == DEMO_MODE_ABORT) || (operating_mode == GAME_ABORT)) { GameOver(TRUE); break; } if (enemies.seeker_list == (dude *) NULL) { GameOver(FALSE); break; } if (g_dead) { GameOver(FALSE); if (g_dead) break; } ScavengeMem(); } } /***** shutdown actions needed after every game *****/ ShutdownForRestart(); total_games++; STOP_THE_MUSIC; if (enemies.seeker_list == (dude *) NULL) { printf("Level cleared!\n"); if (lives_per_level == 1) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME,level, g_skill_level); } else printf ("Pyramids left: %ld.\n", g_total_pyramids);#ifdef FLIGHT_RECORDER_ON DumpBlackBox();#endif if (operating_mode == GAME_ABORT) operating_mode = PICK_AND_PLAY_MODE; if (operating_mode == PICK_AND_PLAY_MODE) whats_next = GameResultsScreen(); else { GetControlPad (1,FALSE,&data); if (data.cped_ButtonBits) operating_mode = DEMO_MODE_ABORT; } if (operating_mode == DEMO_MODE_ABORT) { if (music_state == MUSIC_ON) START_MENU_MUSIC; operating_mode = PICK_AND_PLAY_MODE; whats_next = GOTO_MAIN_MENU; } } while ((whats_next == PLAY_THE_GAME) || (whats_next == PLAY_AGAIN)); if (level == ITS_TOTALLY_RANDOM) { delete (random_level_spec); level = 1; } return (whats_next);}PrintElementName(int32 element){ switch(element) { case BLUE_PYRAMID: printf("BLUE_PYRAMID "); break; case RED_PYRAMID: printf("RED_PYRAMID "); break; case GREEN_PYRAMID: printf("GREEN_PYRAMID "); break; case PURPLE_PYRAMID: printf("PURPLE_PYRAMID "); break; case RAINBOW_PYRAMID: printf("RAINBOW_PYRAMID "); break; case CONCRETE_PYRAMID: printf("CONCRETE_PYRAMID "); break; case YELLOW_SEEKER: printf("YELLOW_SEEKER "); break; case LTBLUE_SEEKER: printf("LTBLUE_SEEKER "); break; case PINK_SEEKER: printf("PINK_SEEKER "); break; case LIME_SEEKER: printf("LIME_SEEKER "); break; case DORMANT_CHAMELEON: printf("CHAMELEON "); break; case WAKING_CHAMELEON: printf("CHAMELEON "); break; case ACTIVE_CHAMELEON: printf("CHAMELEON "); break; case ZOMBIE: printf("ZOMBIE "); break; case LURKER: printf("LURKER "); break; case MEANY: printf("MEANY "); break; case NASTY: printf("NASTY "); break; case GRUMPY: printf("GRUMPY "); break; case BOULDER0: printf("BOULDER0 "); break; case BOULDER1: printf("BOULDER1 "); break; case BOULDER2: printf("BOULDER2 "); break; case BOULDER3: printf("BOULDER3 "); break; case BOULDER4: printf("BOULDER4 "); break; case BOULDER5: printf("BOULDER5 "); break; case BOULDER6: printf("BOULDER6 "); break; case BOULDER7: printf("BOULDER7 "); break; case BOULDER8: printf("BOULDER8 "); break; case BOULDER9: printf("BOULDER9 "); break; case DA_TILE: printf("DA_TILE "); break; case DB_TILE: printf("DB_TILE "); break; case DC_TILE: printf("DC_TILE "); break; case DD_TILE: printf("DD_TILE "); break; case WA_TILE: printf("WA_TILE "); break; case GA_TILE: printf("GA_TILE "); break; case GB_TILE: printf("GB_TILE "); break; case GC_TILE: printf("GC_TILE "); break; case GD_TILE: printf("GD_TILE "); break; case GE_TILE: printf("GE_TILE "); break; case GF_TILE: printf("GF_TILE "); break; case GB2PA_TILE: printf("GB2PA_TILE "); break; case HA_TILE: printf("HA_TILE "); break; case HB_TILE: printf("HB_TILE "); break; case HC_TILE: printf("HC_TILE "); break; case HD_TILE: printf("HD_TILE "); break; case HD2PC_TILE: printf("HD2PC_TILE "); break; case IA_TILE: printf("IA_TILE "); break; case IA2PB_TILE: printf("IA2PB_TILE "); break; case IB2PG_TILE: printf("IB2PG_TILE "); break; case HA2PF_TILE: printf("HA2PF_TILE "); break; case GA2PE_TILE: printf("GA2PE_TILE "); break; case P1_TILE: printf("P1_TILE "); break; case L1_TILE: printf("L1_TILE "); break; case LA_TILE: printf("LA_TILE "); break; case LB_TILE: printf("LB_TILE "); break; case IB_TILE: printf("IB_TILE "); break; case PA_TILE: printf("PA_TILE "); break; case PB_TILE: printf("PB_TILE "); break; case PC_TILE: printf("PC_TILE "); break; case S1_TILE: printf("S1_TILE "); break; case SA_TILE: printf("SA_TILE "); break; case SB_TILE: printf("SB_TILE "); break; case HE_TILE: printf("HE_TILE "); break; case PG_TILE: printf("PG_TILE "); break; case WB_TILE: printf("WB_TILE "); break; case IC_TILE: printf("IC_TILE "); break; case PD_TILE: printf("PD_TILE "); break; case PE_TILE: printf("PE_TILE "); break; case PF_TILE: printf("PF_TILE "); break; case DD2PH_TILE: printf("DD2PH_TILE "); break; case DB2PI_TILE: printf("DB2PI_TILE "); break; case DA2PJ_TILE: printf("DA2PJ_TILE "); break; case VA2PK_TILE: printf("VA2PK_TILE "); break; case PI_TILE: printf("PI_TILE "); break; case PJ_TILE: printf("PJ_TILE "); break; case PK_TILE: printf("PK_TILE "); break; case PH_TILE: printf("PH_TILE "); break; case UA_TILE: printf("UA_TILE "); break; case UB_TILE: printf("UB_TILE "); break; case UC_TILE: printf("UC_TILE "); break; case UD_TILE: printf("UD_TILE "); break; case UE_TILE: printf("UE_TILE "); break; case VA_TILE: printf("VA_TILE "); break; case VB_TILE: printf("VB_TILE "); break; case BOULDERA: printf("BOULDERA "); break; case BOULDERD: printf("BOULDERD "); break; case ID_TILE: printf("ID_TILE "); break; case DC2PJ_TILE: printf("DC2PJ_TILE "); break; case IC2PB_TILE: printf("IC2PB_TILE "); break; case ID2PB_TILE: printf("ID2PB_TILE "); break; case GC2PA_TILE: printf("GC2PA_TILE "); break; case GD2PA_TILE: printf("GD2PA_TILE "); break; case GE2PA_TILE: printf("GE2PA_TILE "); break; case GF2PA_TILE: printf("GF2PA_TILE "); break; case DE_TILE: printf("DE_TILE "); break; case WC_TILE: printf("WC_TILE "); break; case WD_TILE: printf("WD_TILE "); break; case PL_TILE: printf("PL_TILE "); break; case PM_TILE: printf("PM_TILE "); break; case DE2PJ_TILE: printf("DE2PJ_TILE "); break; case HB2PC_TILE: printf("HB2PC_TILE "); break; case HC2PL_TILE: printf("HC2PL_TILE "); break; case HE2PC_TILE: printf("HE2PC_TILE "); break; case UA2P1_TILE: printf("UA2P1_TILE "); break; case UB2P1_TILE: printf("UB2P1_TILE "); break; case UC2PM_TILE: printf("UC2PM_TILE "); break; case UE2PM_TILE: printf("UE2PM_TILE "); break; case WB2PD_TILE: printf("WB2PD_TILE "); break; case WC2PD_TILE: printf("WC2PD_TILE "); break; case WD2PD_TILE: printf("WD2PD_TILE "); break; case WA2PD_TILE: printf("WA2PD_TILE "); break; case UD2P1_TILE: printf("UD2P1_TILE "); break; default: printf("artwork element #%ld ",element); }}#define GRASS_USAGE (0x00001)#define DESERT_USAGE (0x00002)#define ICE_USAGE (0x00004)#define SWAMP_USAGE (0x00008)#define LAVA_USAGE (0x00010)#define VOLC_USAGE (0x00020)#define H20_USAGE (0x00040)#define SLIME_USAGE (0x00080)#define SLIME_WASTE_USAGE (0x00100)#define SWAMP_WASTE_USAGE (0x00200)#define ICE_WASTE_USAGE (0x00400)#define LAVA_WASTE_USAGE (0x00800)#define YELLOW_USAGE (0x01000)#define PINK_USAGE (0x02000)#define CYAN_USAGE (0x04000)#define LIME_USAGE (0x08000)#define LURKER_USAGE (0x10000)#define ZOMBIE_USAGE (0x20000)#define MEANY_USAGE (0x40000)#define CHAM_USAGE (0x80000)void CountSeekers (int32 level) { int32 seeker_type, row, column, direction; int32 i,j,k; int32 bytes_read; char *input_index; int16 difficulty; easy_seekers[level] = 0; medium_seekers[level] = 0; hard_seekers[level] = 0; insane_seekers[level] = 0; bytes_read = ReadFile(g_level_filename,MAX_FILE_BYTES,g_file_buffer,0); if (bytes_read == -1) { printf("Bummer dude! Failure in attempt to open level parms file!!!!!\n"); return; } /* skip over the specs that don't relate to the seekers: */ input_index = (char *) &g_file_buffer[0]; for (i = 0; i < 35; i++) { while (*(input_index) != 13) input_index++; input_index++; } difficulty = 0; while (*(input_index) != 0xFF) { if (*(input_index) == '*') { while (*(input_index) != 13) input_index++; input_index++; difficulty++; if (difficulty > INSANE) break; } if (*(input_index) != '*') { input_index = ExtractSeekerData(input_index,seeker_type,row,column,direction); switch(difficulty) { case EASY: easy_seekers[level]++; break; case MEDIUM: medium_seekers[level]++; break; case HARD: hard_seekers[level]++; break; case INSANE: insane_seekers[level]++; break; } } }}/*************************************** main *************************************************************************************************************************************/int main(int argc, char** argv){ char level_name[40]; int32 i; level_stat_node *traversal, *vanguard, *new_node; int32 pre_total,post_total; int32 music_track; int32 first_level_for_stats, last_level_for_stats; if (argc != 3) { first_level_for_stats = 1; last_level_for_stats = 150; } else { first_level_for_stats = atoi(argv[1]); last_level_for_stats = atoi(argv[2]); if (first_level_for_stats < 1) first_level_for_stats = 1; if (last_level_for_stats > 150) last_level_for_stats = 150; printf("Creatings stats for levels %ld - %ld...\n",first_level_for_stats, last_level_for_stats); } vbl = GetVBLIOReq(); level = FIRST_LEVEL; total_games = 0; current_canned_demo = 0; music_state = MUSIC_ON; sound_on = TRUE; standard_musical_selections = TRUE; tracks = 0x3FFFF; operating_mode = PICK_AND_PLAY_MODE; g_skill_level = HARD; lives_per_level = 1; pac_mid = FALSE; if (!(BootIcebreaker())) exit(0); srand(ReadHardwareRandomNumber());#ifdef REBUILD_ANDYS_GRID for (i = 1; i <= 17; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, INSANE); for (i = 29; i <= 30; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, INSANE); for (i = 1; i <= 95; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, HARD); for (i = 97; i <= 123; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, HARD); for (i = 125; i <= 129; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, HARD); for (i = 133; i <= 139; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, HARD); for (i = 144; i <= 147; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, HARD); for (i = 140; i <= 150; i++) SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, i, MEDIUM); SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, 131, HARD); SetLevelFlagInStatusRecordFile(NVRAM_FILE_NAME, 141, HARD); exit(0);#endif for (i = 0; i < TOTAL_ART_ELEMENTS; i++) overall_usage[i] = (level_stat_node *) NULL; for (i = 0; i < TOTAL_TRACKS; i++) music_usage[i] = (level_stat_node *) NULL; level = last_level_for_stats; while(level >= first_level_for_stats) { big_usage_table[level] = 0; FetchLevelName (level_name, level); printf("Level: %ld (%s). ",level,level_name); ShutdownAllLevelSpecificArtwork(); pre_total = ReportMem(0, "Before initializing level"); InitializeIcebreaker(level,INSANE); post_total = ReportMem(0, "After initializing level"); VideoHandler(); if (faded) FadeFromBlack(&g_screen, 40); for (i = 0; i < TOTAL_ART_ELEMENTS; i++) { if (g_art_usage[i]) { new_node = new(level_stat_node); new_node->level_number = level; new_node->next = overall_usage[i]; overall_usage[i] = new_node; if ((i >= GA_TILE) && (i <= GF_TILE)) big_usage_table[level] |= GRASS_USAGE; if ((i >= DA_TILE) && (i <= DE_TILE)) big_usage_table[level] |= DESERT_USAGE; if ((i >= HA_TILE) && (i <= HE_TILE)) big_usage_table[level] |= VOLC_USAGE; if ((i >= UA_TILE) && (i <= UE_TILE)) big_usage_table[level] |= H20_USAGE; if ((i >= IA_TILE) && (i <= ID_TILE)) big_usage_table[level] |= ICE_USAGE; if ((i >= S1_TILE) && (i <= SB_TILE)) big_usage_table[level] |= SLIME_USAGE; if ((i >= WA_TILE) && (i <= WD_TILE)) big_usage_table[level] |= SWAMP_USAGE; if ((i >= L1_TILE) && (i <= LB_TILE)) big_usage_table[level] |= LAVA_USAGE; if (i == YELLOW_SEEKER) big_usage_table[level] |= YELLOW_USAGE; if (i == PINK_SEEKER) big_usage_table[level] |= PINK_USAGE; if (i == LTBLUE_SEEKER) big_usage_table[level] |= CYAN_USAGE; if (i == LIME_SEEKER) big_usage_table[level] |= LIME_USAGE; if (i == LURKER) big_usage_table[level] |= LURKER_USAGE; if (i == ZOMBIE) big_usage_table[level] |= ZOMBIE_USAGE; if (i == MEANY) big_usage_table[level] |= MEANY_USAGE; if (i == DORMANT_CHAMELEON) big_usage_table[level] |= CHAM_USAGE; } } if ((pavement.wasteland_descriptor >= IA_TILE) && (pavement.wasteland_descriptor <= ID_TILE)) big_usage_table[level] |= ICE_WASTE_USAGE; if ((pavement.wasteland_descriptor >= S1_TILE) && (pavement.wasteland_descriptor <= SB_TILE)) big_usage_table[level] |= SLIME_WASTE_USAGE; if ((pavement.wasteland_descriptor >= WA_TILE) && (pavement.wasteland_descriptor <= WD_TILE)) big_usage_table[level] |= SWAMP_WASTE_USAGE; if ((pavement.wasteland_descriptor >= L1_TILE) && (pavement.wasteland_descriptor <= LB_TILE)) big_usage_table[level] |= LAVA_WASTE_USAGE; switch (FetchMusicTrackFromFile()) { case QUACK: music_track = 0; break; case CHECK_THIS_OUT_TALK: music_track = 1; break; case MADONNA: music_track = 2; break; case SPACE_AGE: music_track = 3; break; case SOUND_OF_TALK: music_track = 4; break; case LOTS_OF_PERC: music_track = 5; break; case DRUNK_TRUMPET: music_track = 6; break; case MONKEY: music_track = 7; break; case THE_LONGER_ONE: music_track = 8; break; case MORE_QUACK: music_track = 9; break; case SEVENTIES2: music_track = 10; break; case SHAFT: music_track = 11; break; case HIT_ME: music_track = 12; break; case WATER_WORKS: music_track = 13; break; case FAST_HUNT: music_track = 14; break; case G_BOUNCE: music_track = 15; break; case SCHICK: music_track = 16; break; case BALI: music_track = 17; break; } new_node = new(level_stat_node); new_node->level_number = level; new_node->next = music_usage[music_track]; music_usage[music_track] = new_node; GameOver(TRUE); ShutdownForRestart(); printf("\n"); memory_needs[level] = post_total-pre_total; CountSeekers (level); level--; } for (i = BLUE_PYRAMID; i < BIRTH_SCENE; i++) { if ((i != PHANTOM_BOULDER) && (i != WAKING_CHAMELEON) && (i != ACTIVE_CHAMELEON) && (i != NASTY) && (i != GRUMPY)) { traversal = overall_usage[i]; PrintElementName(i); printf(":%c",9); while (traversal != (level_stat_node *) NULL) { printf("[%ld] ",traversal->level_number); traversal = traversal->next; } printf("\n"); } } for (i = 0; i < TOTAL_TRACKS - 1; i++) { { traversal = music_usage[i]; switch (i) { case 0: printf("QUACK"); break; case 1: printf("CHECK_THIS_OUT"); break; case 2: printf("MADONNA"); break; case 3: printf("SPACE_AGE"); break; case 4: printf("SOUND_OF_TALK"); break; case 5: printf("LOTS_OF_PERC"); break; case 6: printf("DRUNK_TRUMPET"); break; case 7: printf("MONKEY"); break; case 8: printf("THE_LONGER_ONE"); break; case 9: printf("MORE_QUACK"); break; case 10: printf("SEVENTIES2"); break; case 11: printf("SHAFT"); break; case 12: printf("HIT_ME"); break; case 13: printf("WATER_WORKS"); break; case 14: printf("FAST_HUNT"); break; case 15: printf("G_BOUNCE"); break; case 16: printf("SCHICK"); break; case 17: printf("BALI"); break; } printf(":%c",9); while (traversal != (level_stat_node *) NULL) { printf("[%ld] ",traversal->level_number); traversal = traversal->next; } printf("\n"); } } level = first_level_for_stats; while (level <= last_level_for_stats) { FetchLevelName (level_name, level); printf("Level: %ld [%ldK] (%s). ",level,memory_needs[level],level_name); if (big_usage_table[level] & GRASS_USAGE) printf("[Grass] "); if (big_usage_table[level] & DESERT_USAGE) printf("[Desert] "); if (big_usage_table[level] & ICE_USAGE) printf("[Ice] "); if (big_usage_table[level] & SWAMP_USAGE) printf("[Swamp] "); if (big_usage_table[level] & LAVA_USAGE) printf("[Lava] "); if (big_usage_table[level] & VOLC_USAGE) printf("[Volcanic] "); if (big_usage_table[level] & H20_USAGE) printf("[Underwater] "); if (big_usage_table[level] & SLIME_USAGE) printf("[Slime] "); if (big_usage_table[level] & SLIME_WASTE_USAGE) printf("[Slime wasteland] "); if (big_usage_table[level] & SWAMP_WASTE_USAGE) printf("[Swamp wasteland] "); if (big_usage_table[level] & ICE_WASTE_USAGE) printf("[Ice wasteland] "); if (big_usage_table[level] & LAVA_WASTE_USAGE) printf("[Lava wasteland] "); if (big_usage_table[level] & YELLOW_USAGE) printf("[Yellows] "); if (big_usage_table[level] & PINK_USAGE) printf("[Pinks] "); if (big_usage_table[level] & CYAN_USAGE) printf("[Cyanides] "); if (big_usage_table[level] & LIME_USAGE) printf("[Limeys] "); if (big_usage_table[level] & LURKER_USAGE) printf("[Lurkers] "); if (big_usage_table[level] & ZOMBIE_USAGE) printf("[Zombies] "); if (big_usage_table[level] & MEANY_USAGE) printf("[Meanies] "); if (big_usage_table[level] & CHAM_USAGE) printf("[Chameleons] "); printf("[%ld/%ld/%ld/%ld] ",easy_seekers[level],medium_seekers[level], hard_seekers[level],insane_seekers[level]); printf("\n"); level++; } for (i = 0; i < TOTAL_ART_ELEMENTS; i++) { { traversal = overall_usage[i]; while (traversal != (level_stat_node *) NULL) { vanguard = traversal->next; delete(traversal); traversal = vanguard; } } } for (i = 0; i < TOTAL_TRACKS; i++) { { traversal = music_usage[i]; while (traversal != (level_stat_node *) NULL) { vanguard = traversal->next; delete(traversal); traversal = vanguard; } } } /***** exiting the program *****/ ShutdownForExit(); Quit();}/************************************* End of File **************************************/