/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for EndGame, EndLevel, etc. * */ #include #include #include #include #include #include #ifdef OGL #include "ogl_init.h" #endif #include "inferno.h" #include "game.h" #include "key.h" #include "object.h" #include "physics.h" #include "dxxerror.h" #include "joy.h" #include "iff.h" #include "pcx.h" #include "timer.h" #include "render.h" #include "laser.h" #include "screens.h" #include "textures.h" #include "slew.h" #include "gauges.h" #include "texmap.h" #include "3d.h" #include "effects.h" #include "menu.h" #include "gameseg.h" #include "wall.h" #include "ai.h" #include "hostage.h" #include "fuelcen.h" #include "switch.h" #include "digi.h" #include "gamesave.h" #include "scores.h" #include "u_mem.h" #include "palette.h" #include "morph.h" #include "lighting.h" #include "newdemo.h" #include "titles.h" #include "collide.h" #include "weapon.h" #include "sounds.h" #include "args.h" #include "gameseq.h" #include "gamefont.h" #include "newmenu.h" #include "endlevel.h" #include "playsave.h" #include "ctype.h" #include "multi.h" #include "fireball.h" #include "kconfig.h" #include "config.h" #include "robot.h" #include "automap.h" #include "cntrlcen.h" #include "powerup.h" #include "text.h" #include "piggy.h" #include "texmerge.h" #include "paging.h" #include "mission.h" #include "state.h" #include "songs.h" #ifdef NETWORK #include "multi.h" #endif #include "strutil.h" #ifdef EDITOR #include "editor/editor.h" #endif #include "custom.h" #include "byteswap.h" #include "segment.h" #include "gameseg.h" void init_player_stats_new_ship(ubyte pnum); void copy_defaults_to_robot_all(void); int AdvanceLevel(int secret_flag); void StartLevel(int random); //Current_level_num starts at 1 for the first level //-1,-2,-3 are secret levels //0 means not a real level loaded int Current_level_num=0,Next_level_num; char Current_level_name[LEVEL_NAME_LEN]; // #ifndef SHAREWARE // int Last_level,Last_secret_level; // #endif // Global variables describing the player int N_players=1; // Number of players ( >1 means a net game, eh?) int Player_num=0; // The player number who is on the console. player Players[MAX_PLAYERS]; // Misc player info obj_position Player_init[MAX_PLAYERS]; // Global variables telling what sort of game we have int NumNetPlayerPositions = -1; extern fix ThisLevelTime; // Extern from game.c to fix a bug in the cockpit! extern int last_drawn_cockpit; extern int Last_level_path_created; void HUD_clear_messages(); // From hud.c void verify_console_object() { Assert( Player_num > -1 ); Assert( Players[Player_num].objnum > -1 ); ConsoleObject = &Objects[Players[Player_num].objnum]; Assert( ConsoleObject->id==Player_num ); } int count_number_of_robots() { int robot_count; int i; robot_count = 0; for (i=0;i<=Highest_object_index;i++) { if (Objects[i].type == OBJ_ROBOT) robot_count++; } return robot_count; } int count_number_of_hostages() { int count; int i; count = 0; for (i=0;i<=Highest_object_index;i++) { if (Objects[i].type == OBJ_HOSTAGE) count++; } return count; } void gameseq_init_network_players() { int i,k,j; // Initialize network player start locations and object numbers ConsoleObject = &Objects[0]; k = 0; j = 0; for (i=0;i<=Highest_object_index;i++) { if (( Objects[i].type==OBJ_PLAYER ) || (Objects[i].type == OBJ_GHOST) || (Objects[i].type == OBJ_COOP)) { #ifndef SHAREWARE if ( (!(Game_mode & GM_MULTI_COOP) && ((Objects[i].type == OBJ_PLAYER)||(Objects[i].type==OBJ_GHOST))) || ((Game_mode & GM_MULTI_COOP) && ((j == 0) || ( Objects[i].type==OBJ_COOP ))) ) { Objects[i].type=OBJ_PLAYER; #endif Player_init[k].pos = Objects[i].pos; Player_init[k].orient = Objects[i].orient; Player_init[k].segnum = Objects[i].segnum; Players[k].objnum = i; Objects[i].id = k; k++; #ifndef SHAREWARE } else obj_delete(i); j++; #endif } } NumNetPlayerPositions = k; } void gameseq_remove_unused_players() { int i; // 'Remove' the unused players #ifdef NETWORK if (Game_mode & GM_MULTI) { for (i=0; i < NumNetPlayerPositions; i++) { if ((!Players[i].connected) || (i >= N_players)) { multi_make_player_ghost(i); } } } else #endif { // Note link to above if!!! for (i=1; i < NumNetPlayerPositions; i++) { obj_delete(Players[i].objnum); } } } fix StartingShields=INITIAL_SHIELDS; // Setup player for new game void init_player_stats_game(ubyte pnum) { Players[pnum].score = 0; Players[pnum].last_score = 0; Players[pnum].lives = INITIAL_LIVES; Players[pnum].level = 1; Players[pnum].time_level = 0; Players[pnum].time_total = 0; Players[pnum].hours_level = 0; Players[pnum].hours_total = 0; Players[pnum].killer_objnum = -1; Players[pnum].net_killed_total = 0; Players[pnum].net_kills_total = 0; Players[pnum].num_kills_level = 0; Players[pnum].num_kills_total = 0; Players[pnum].num_robots_level = 0; Players[pnum].num_robots_total = 0; Players[pnum].KillGoalCount = 0; Players[pnum].hostages_rescued_total = 0; Players[pnum].hostages_level = 0; Players[pnum].hostages_total = 0; Players[pnum].laser_level = 0; Players[pnum].flags = 0; init_player_stats_new_ship(pnum); } void init_ammo_and_energy(void) { if (Players[Player_num].energy < INITIAL_ENERGY) Players[Player_num].energy = INITIAL_ENERGY; if (Players[Player_num].shields < StartingShields) Players[Player_num].shields = StartingShields; // for (i=0; iid=Player_num; ConsoleObject->control_type = CT_FLYING; ConsoleObject->movement_type = MT_PHYSICS; Game_suspended = 0; verify_console_object(); Control_center_destroyed = 0; if (Newdemo_state != ND_STATE_PLAYBACK) gameseq_remove_unused_players(); init_cockpit(); init_robots_for_level(); init_ai_objects(); init_morphs(); init_all_matcens(); init_player_stats_new_ship(Player_num); if (!Game_wind) Game_wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, game_handler, NULL); } #endif void reset_player_object(); //do whatever needs to be done when a player dies in multiplayer void DoGameOver() { #ifndef SHAREWARE if (PLAYING_BUILTIN_MISSION) #endif scores_maybe_add_player(0); if (Game_wind) window_close(Game_wind); // Exit out of game loop } //update various information about the player void update_player_stats() { Players[Player_num].time_level += FrameTime; //the never-ending march of time... if ( Players[Player_num].time_level > i2f(3600) ) { Players[Player_num].time_level -= i2f(3600); Players[Player_num].hours_level++; } Players[Player_num].time_total += FrameTime; //the never-ending march of time... if ( Players[Player_num].time_total > i2f(3600) ) { Players[Player_num].time_total -= i2f(3600); Players[Player_num].hours_total++; } } //go through this level and start any eclip sounds void set_sound_sources() { int segnum,sidenum; segment *seg; digi_init_sounds(); //clear old sounds for (seg=&Segments[0],segnum=0;segnum<=Highest_segment_index;seg++,segnum++) for (sidenum=0;sidenumsides[sidenum].tmap_num2) != 0) if ((ec=TmapInfo[tm&0x3fff].eclip_num)!=-1) if ((sn=Effects[ec].sound_num)!=-1) { vms_vector pnt; compute_center_point_on_side(&pnt,seg,sidenum); digi_link_sound_to_pos(sn,segnum,sidenum,&pnt,1, F1_0/2); } } } //fix flash_dist=i2f(1); fix flash_dist=fl2f(.9); //create flash for player appearance void create_player_appearance_effect(object *player_obj) { vms_vector pos; object *effect_obj; #ifndef NDEBUG { int objnum = player_obj-Objects; if ( (objnum < 0) || (objnum > Highest_object_index) ) Int3(); // See Rob, trying to track down weird network bug } #endif if (player_obj == Viewer) vm_vec_scale_add(&pos, &player_obj->pos, &player_obj->orient.fvec, fixmul(player_obj->size,flash_dist)); else pos = player_obj->pos; effect_obj = object_create_explosion(player_obj->segnum, &pos, player_obj->size, VCLIP_PLAYER_APPEARANCE ); if (effect_obj) { effect_obj->orient = player_obj->orient; if ( Vclip[VCLIP_PLAYER_APPEARANCE].sound_num > -1 ) digi_link_sound_to_object( Vclip[VCLIP_PLAYER_APPEARANCE].sound_num, effect_obj-Objects, 0, F1_0); } } // // New Game sequencing functions // extern int descent_critical_error; //get level filename. level numbers start at 1. Secret levels are -1,-2,-3 char *get_level_file(int level_num) { #ifdef SHAREWARE { static char t[13]; sprintf(t, "level%02d.sdl", level_num); return t; } #else if (level_num<0) //secret level return Secret_level_names[-level_num-1]; else //normal level return Level_names[level_num-1]; #endif } // routine to calculate the checksum of the segments. void do_checksum_calc(ubyte *b, int len, unsigned int *s1, unsigned int *s2) { while(len--) { *s1 += *b++; if (*s1 >= 255) *s1 -= 255; *s2 += *s1; } } ushort netmisc_calc_checksum() { int i, j, k; unsigned int sum1,sum2; short s; int t; sum1 = sum2 = 0; for (i = 0; i < Highest_segment_index + 1; i++) { for (j = 0; j < MAX_SIDES_PER_SEGMENT; j++) { do_checksum_calc((unsigned char *)&(Segments[i].sides[j].type), 1, &sum1, &sum2); do_checksum_calc(&(Segments[i].sides[j].pad), 1, &sum1, &sum2); s = INTEL_SHORT(Segments[i].sides[j].wall_num); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); s = INTEL_SHORT(Segments[i].sides[j].tmap_num); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); s = INTEL_SHORT(Segments[i].sides[j].tmap_num2); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); for (k = 0; k < 4; k++) { t = INTEL_INT(((int)Segments[i].sides[j].uvls[k].u)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].uvls[k].v)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].uvls[k].l)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); } for (k = 0; k < 2; k++) { t = INTEL_INT(((int)Segments[i].sides[j].normals[k].x)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].normals[k].y)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].normals[k].z)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); } } for (j = 0; j < MAX_SIDES_PER_SEGMENT; j++) { s = INTEL_SHORT(Segments[i].children[j]); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); } for (j = 0; j < MAX_VERTICES_PER_SEGMENT; j++) { s = INTEL_SHORT(Segments[i].verts[j]); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); } s = INTEL_SHORT(Segments[i].objects); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); do_checksum_calc((unsigned char *)&(Segments[i].special), 1, &sum1, &sum2); do_checksum_calc((unsigned char *)&(Segments[i].matcen_num), 1, &sum1, &sum2); s = INTEL_SHORT(Segments[i].value); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].static_light)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); s = INTEL_SHORT(0); // no matter if we need alignment on our platform, if we have editor we MUST consider this integer to get the same checksum as non-editor games calculate do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); } sum2 %= 255; return ((sum1<<8)+ sum2); } //load a level off disk. level numbers start at 1. Secret levels are -1,-2,-3 void LoadLevel(int level_num,int page_in_textures) { char *level_name; player save_player; save_player = Players[Player_num]; Assert(level_num <= Last_level && level_num >= Last_secret_level && level_num != 0); level_name = get_level_file(level_num); if (!load_level(level_name)) Current_level_num=level_num; gr_use_palette_table( "palette.256" ); show_boxed_message(TXT_LOADING, 0); #ifdef RELEASE timer_delay(F1_0); #endif #ifdef NETWORK my_segments_checksum = netmisc_calc_checksum(); #endif load_endlevel_data(level_num); load_custom_data(level_name); #ifdef NETWORK reset_network_objects(); #endif Players[Player_num] = save_player; set_sound_sources(); songs_play_level_song( Current_level_num, 0 ); gr_palette_load(gr_palette); //actually load the palette if ( page_in_textures ) piggy_load_level_data(); } //sets up Player_num & ConsoleObject void InitPlayerObject() { Assert(Player_num>=0 && Player_numtype = OBJ_PLAYER; ConsoleObject->id = Player_num; ConsoleObject->control_type = CT_FLYING; ConsoleObject->movement_type = MT_PHYSICS; } //starts a new game on the given level void StartNewGame(int start_level) { state_quick_item = -1; // for first blind save, pick slot to save in Game_mode = GM_NORMAL; Next_level_num = 0; InitPlayerObject(); //make sure player's object set up init_player_stats_game(Player_num); //clear all stats N_players = 1; StartNewLevel(start_level); Players[Player_num].starting_level = start_level; // Mark where they started game_disable_cheats(); } // ----------------------------------------------------------------------------- // Does the bonus scoring. // Call with dead_flag = 1 if player died, but deserves some portion of bonus (only skill points), anyway. void DoEndLevelScoreGlitz(int network) { int level_points, skill_points, energy_points, shield_points, hostage_points; int all_hostage_points; int endgame_points; char all_hostage_text[64]; char endgame_text[64]; #define N_GLITZITEMS 9 char m_str[N_GLITZITEMS][30]; newmenu_item m[9]; int i,c; char title[128]; int is_last_level; gr_palette_load( gr_palette ); level_points = Players[Player_num].score-Players[Player_num].last_score; if (!cheats.enabled) { if (Difficulty_level > 1) { skill_points = level_points*(Difficulty_level-1)/2; skill_points -= skill_points % 100; } else skill_points = 0; shield_points = f2i(Players[Player_num].shields) * 10 * (Difficulty_level+1); energy_points = f2i(Players[Player_num].energy) * 5 * (Difficulty_level+1); hostage_points = Players[Player_num].hostages_on_board * 500 * (Difficulty_level+1); } else { skill_points = 0; shield_points = 0; energy_points = 0; hostage_points = 0; } all_hostage_text[0] = 0; endgame_text[0] = 0; if (!cheats.enabled && (Players[Player_num].hostages_on_board == Players[Player_num].hostages_level)) { all_hostage_points = Players[Player_num].hostages_on_board * 1000 * (Difficulty_level+1); sprintf(all_hostage_text, "%s%i\n", TXT_FULL_RESCUE_BONUS, all_hostage_points); } else all_hostage_points = 0; if (!cheats.enabled && !(Game_mode & GM_MULTI) && (Players[Player_num].lives) && (Current_level_num == Last_level)) { //player has finished the game! endgame_points = Players[Player_num].lives * 10000; sprintf(endgame_text, "%s%i\n", TXT_SHIP_BONUS, endgame_points); is_last_level=1; } else endgame_points = is_last_level = 0; add_bonus_points_to_score(skill_points + energy_points + shield_points + hostage_points + all_hostage_points + endgame_points); c = 0; sprintf(m_str[c++], "%s%i", TXT_SHIELD_BONUS, shield_points); // Return at start to lower menu... sprintf(m_str[c++], "%s%i", TXT_ENERGY_BONUS, energy_points); sprintf(m_str[c++], "%s%i", TXT_HOSTAGE_BONUS, hostage_points); sprintf(m_str[c++], "%s%i", TXT_SKILL_BONUS, skill_points); sprintf(m_str[c++], "%s", all_hostage_text); if (!(Game_mode & GM_MULTI) && (Players[Player_num].lives) && (Current_level_num == Last_level)) sprintf(m_str[c++], "%s", endgame_text); sprintf(m_str[c++], "%s%i\n", TXT_TOTAL_BONUS, shield_points+energy_points+hostage_points+skill_points+all_hostage_points+endgame_points); sprintf(m_str[c++], "%s%i", TXT_TOTAL_SCORE, Players[Player_num].score); for (i=0; itype) { case EVENT_WINDOW_DRAW: gr_set_current_canvas(NULL); show_fullscr(background); break; default: break; } return 0; } static void do_screen_message(const char *fmt, ...) __attribute_format_printf(1, 2); static void do_screen_message(const char *fmt, ...) { va_list arglist; grs_bitmap background; char msg[1024]; if (Game_mode & GM_MULTI) return; gr_init_bitmap_data(&background); if (pcx_read_bitmap(Menu_pcx_name, &background, BM_LINEAR, gr_palette) != PCX_ERROR_NONE) return; gr_palette_load(gr_palette); va_start(arglist, fmt); vsprintf(msg, fmt, arglist); va_end(arglist); nm_messagebox1(NULL, (int (*)(newmenu *, d_event *, void *))draw_rock, &background, 1, TXT_OK, msg); gr_free_bitmap_data(&background); } //called when the player has finished a level void PlayerFinishedLevel(int secret_flag) { int rval; int was_multi = 0; if (Game_wind) window_set_visible(Game_wind, 0); //credit the player for hostages Players[Player_num].hostages_rescued_total += Players[Player_num].hostages_on_board; #ifndef SHAREWARE if (!(Game_mode & GM_MULTI) && (secret_flag)) { newmenu_item m[1]; m[0].type = NM_TYPE_TEXT; m[0].text = " "; //TXT_SECRET_EXIT; newmenu_do2(NULL, TXT_SECRET_EXIT, 1, m, NULL, NULL, 0, Menu_pcx_name); } #endif // -- mk mk mk -- used to be here -- mk mk mk -- #ifdef NETWORK if (Game_mode & GM_NETWORK) { if (secret_flag) Players[Player_num].connected = CONNECT_FOUND_SECRET; // Finished and went to secret level else Players[Player_num].connected = CONNECT_WAITING; // Finished but did not die } #endif last_drawn_cockpit = -1; if (Current_level_num == Last_level) { #ifdef NETWORK if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) { was_multi = 1; multi_endlevel_score(); rval = AdvanceLevel(secret_flag); //now go on to the next one (if one) } else #endif { // Note link to above else! rval = AdvanceLevel(secret_flag); //now go on to the next one (if one) DoEndLevelScoreGlitz(0); //give bonuses } } else { #ifdef NETWORK if (Game_mode & GM_MULTI) multi_endlevel_score(); else #endif // Note link!! DoEndLevelScoreGlitz(0); //give bonuses rval = AdvanceLevel(secret_flag); //now go on to the next one (if one) } if (!was_multi && rval) { #ifndef SHAREWARE if (PLAYING_BUILTIN_MISSION) #endif scores_maybe_add_player(0); if (Game_wind) window_close(Game_wind); // Exit out of game loop } else if (rval && Game_wind) window_close(Game_wind); if (Game_wind) window_set_visible(Game_wind, 1); reset_time(); } //from which level each do you get to each secret level // int Secret_level_table[MAX_SECRET_LEVELS_PER_MISSION]; //called to go to the next level (if there is one) //if secret_flag is true, advance to secret level, else next normal one // Return true if game over. int AdvanceLevel(int secret_flag) { Control_center_destroyed = 0; #ifdef EDITOR if (Current_level_num == 0) { return 1; //not a real level } #endif key_flush(); #ifdef NETWORK if (Game_mode & GM_MULTI) { int result; result = multi_endlevel(&secret_flag); // Wait for other players to reach this point if (result) // failed to sync { return (Current_level_num == Last_level); } } #endif key_flush(); if (Current_level_num == Last_level) { //player has finished the game! if ((Newdemo_state == ND_STATE_RECORDING) || (Newdemo_state == ND_STATE_PAUSED)) newdemo_stop_recording(); do_end_briefing_screens(Ending_text_filename); return 1; } else { Next_level_num = Current_level_num+1; //assume go to next normal level if (secret_flag) { //go to secret level instead int i; for (i=0;i<-Last_secret_level;i++) if (Secret_level_table[i]==Current_level_num) { Next_level_num = -(i+1); break; } Assert(i<-Last_secret_level); //couldn't find which secret level } if (Current_level_num < 0) { //on secret level, where to go? Assert(!secret_flag); //shouldn't be going to secret level Assert(Current_level_num<=-1 && Current_level_num>=Last_secret_level); Next_level_num = Secret_level_table[(-Current_level_num)-1]+1; } StartNewLevel(Next_level_num); } key_flush(); return 0; } //called when the player has died void DoPlayerDead() { if (Game_wind) window_set_visible(Game_wind, 0); reset_palette_add(); gr_palette_load (gr_palette); dead_player_end(); //terminate death sequence (if playing) #ifdef EDITOR if (Game_mode == GM_EDITOR) { //test mine, not real level object * player = &Objects[Players[Player_num].objnum]; //nm_messagebox( "You're Dead!", 1, "Continue", "Not a real game, though." ); if (Game_wind) window_set_visible(Game_wind, 1); load_level("gamesave.lvl"); init_player_stats_new_ship(Player_num); player->flags &= ~OF_SHOULD_BE_DEAD; StartLevel(0); return; } #endif #ifdef NETWORK if ( Game_mode&GM_MULTI ) { multi_do_death(Players[Player_num].objnum); } else #endif { //Note link to above else! Players[Player_num].lives--; if (Players[Player_num].lives == 0) { DoGameOver(); return; } } if ( Control_center_destroyed ) { int rval; //clear out stuff so no bonus Players[Player_num].hostages_on_board = 0; Players[Player_num].energy = 0; Players[Player_num].shields = 0; #ifdef NETWORK Players[Player_num].connected = CONNECT_DIED_IN_MINE; #endif do_screen_message(TXT_DIED_IN_MINE); // Give them some indication of what happened if (Current_level_num == Last_level) { #ifdef NETWORK if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) { multi_endlevel_score(); rval = AdvanceLevel(0); //if finished, go on to next level } else #endif { // Note link to above else! rval = AdvanceLevel(0); //if finished, go on to next level DoEndLevelScoreGlitz(0); } init_player_stats_new_ship(Player_num); last_drawn_cockpit = -1; } else { #ifdef NETWORK if (Game_mode & GM_MULTI) multi_endlevel_score(); else #endif DoEndLevelScoreGlitz(0); // Note above link! rval = AdvanceLevel(0); //if finished, go on to next level init_player_stats_new_ship(Player_num); last_drawn_cockpit = -1; } if (rval) { #ifndef SHAREWARE if (PLAYING_BUILTIN_MISSION) #endif scores_maybe_add_player(0); if (Game_wind) window_close(Game_wind); // Exit out of game loop } } else { init_player_stats_new_ship(Player_num); StartLevel(1); } if (Game_wind) window_set_visible(Game_wind, 1); reset_time(); } //called when the player is starting a new level for normal game mode and restore state void StartNewLevelSub(int level_num, int page_in_textures, int secret_flag) { /* * This flag is present for compatibility with D2X. Set it to zero * so the optimizer deletes all reference to it. */ secret_flag = 0; if (!(Game_mode & GM_MULTI)) { last_drawn_cockpit = -1; } if (Newdemo_state == ND_STATE_PAUSED) Newdemo_state = ND_STATE_RECORDING; if (Newdemo_state == ND_STATE_RECORDING) { newdemo_set_new_level(level_num); newdemo_record_start_frame(FrameTime ); } LoadLevel(level_num, page_in_textures); Assert(Current_level_num == level_num); //make sure level set right gameseq_init_network_players(); // Initialize the Players array for // this level #ifdef NETWORK if (Game_mode & GM_NETWORK) { if(multi_level_sync()) // After calling this, Player_num is set { songs_play_song( SONG_TITLE, 1 ); // level song already plays but we fail to start level... return; } } #endif HUD_clear_messages(); automap_clear_visited(); init_player_stats_level(secret_flag); gr_use_palette_table( "palette.256" ); gr_palette_load(gr_palette); #ifndef SHAREWARE #ifdef NETWORK if ((Game_mode & GM_MULTI_COOP) && Network_rejoined) { int i; for (i = 0; i < N_players; i++) Players[i].flags |= Netgame.player_flags[i]; } #endif #endif Viewer = &Objects[Players[Player_num].objnum]; #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_prep_level(); // Removes robots from level if necessary } #endif gameseq_remove_unused_players(); Game_suspended = 0; Control_center_destroyed = 0; init_cockpit(); init_robots_for_level(); init_ai_objects(); init_morphs(); init_all_matcens(); reset_palette_add(); if (!(Game_mode & GM_MULTI) && !cheats.enabled) set_highest_level(Current_level_num); reset_special_effects(); #ifdef OGL ogl_cache_level_textures(); #endif #ifdef NETWORK if (Network_rejoined == 1) { Network_rejoined = 0; StartLevel(1); } else #endif StartLevel(0); // Note link to above if! copy_defaults_to_robot_all(); init_controlcen_for_level(); // Say player can use FLASH cheat to mark path to exit. Last_level_path_created = -1; // Initialise for palette_restore() if (!((Game_mode & GM_MULTI) && (Newdemo_state != ND_STATE_PLAYBACK))) palette_save(); if (!Game_wind) game(); } #ifdef NETWORK extern char PowerupsInMine[MAX_POWERUP_TYPES], MaxPowerupsAllowed[MAX_POWERUP_TYPES]; #endif void bash_to_shield (int i,const char *s) { #ifdef NETWORK int type=Objects[i].id; #endif #ifdef NETWORK PowerupsInMine[type]=MaxPowerupsAllowed[type]=0; #endif Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } //called when the player is starting a new level for normal game model void StartNewLevel(int level_num) { hide_menus(); GameTime64 = 0; ThisLevelTime=0; if (!(Game_mode & GM_MULTI)) { do_briefing_screens(Briefing_text_filename, level_num); } StartNewLevelSub(level_num, 1, 0 ); } //initialize the player object position & orientation (at start of game, or new ship) void InitPlayerPosition(int random) { int NewPlayer=0; if (! ((Game_mode & GM_MULTI) && !(Game_mode&GM_MULTI_COOP)) ) // If not deathmatch NewPlayer = Player_num; else if (random == 1) { int i, trys=0; fix closest_dist = 0x7ffffff, dist; timer_update(); d_srand((fix)timer_query()); do { trys++; NewPlayer = d_rand() % NumNetPlayerPositions; closest_dist = 0x7fffffff; for (i=0; i= 0) ) { closest_dist = dist; } } } } while ( (closest_dist= 0); Assert(NewPlayer < NumNetPlayerPositions); ConsoleObject->pos = Player_init[NewPlayer].pos; ConsoleObject->orient = Player_init[NewPlayer].orient; obj_relink(ConsoleObject-Objects,Player_init[NewPlayer].segnum); reset_player_object(); reset_cruise(); } // ----------------------------------------------------------------------------------------------------- // Initialize default parameters for one robot, copying from Robot_info to *objp. // What about setting size!? Where does that come from? void copy_defaults_to_robot(object *objp) { robot_info *robptr; int objid; Assert(objp->type == OBJ_ROBOT); objid = objp->id; Assert(objid < N_robot_types); robptr = &Robot_info[objid]; objp->shields = robptr->strength; } // ----------------------------------------------------------------------------------------------------- // Copy all values from the robot info structure to all instances of robots. // This allows us to change bitmaps.tbl and have these changes manifested in existing robots. // This function should be called at level load time. void copy_defaults_to_robot_all(void) { int i; for (i=0; i<=Highest_object_index; i++) if (Objects[i].type == OBJ_ROBOT) copy_defaults_to_robot(&Objects[i]); } int Do_appearance_effect=0; // ----------------------------------------------------------------------------------------------------- //called when the player is starting a level (new game or new ship) void StartLevel(int random) { Assert(!Player_is_dead); InitPlayerPosition(random); verify_console_object(); ConsoleObject->control_type = CT_FLYING; ConsoleObject->movement_type = MT_PHYSICS; // create_player_appearance_effect(ConsoleObject); Do_appearance_effect = 1; if (Game_mode & GM_MULTI) { if (Game_mode & GM_MULTI_COOP) multi_send_score(); multi_send_reappear(); multi_do_protocol_frame(1, 1); } else // in Singleplayer, after we died ... { disable_matcens(); // ... disable matcens and ... clear_transient_objects(0); // ... clear all transient objects. } ai_reset_all_paths(); ai_init_boss_for_ship(); reset_rear_view(); Auto_fire_fusion_cannon_time = 0; Fusion_charge = 0; if (!(Game_mode & GM_MULTI)) // stuff for Singleplayer only { } }