2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
2006-03-20 17:12:09 +00:00
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 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* Routines for EndGame , EndLevel , etc .
*
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# if !defined(_MSC_VER) && !defined(macintosh)
# include <unistd.h>
# endif
# include <time.h>
# ifdef OGL
# include "ogl_init.h"
# endif
# include "inferno.h"
# include "game.h"
# include "player.h"
# include "key.h"
# include "object.h"
# include "physics.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# 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 "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 "multi.h"
# include "playsave.h"
# include "ctype.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"
# include "gamepal.h"
# include "controls.h"
# include "credits.h"
# include "gamemine.h"
# ifdef EDITOR
# include "editor/editor.h"
# endif
# include "strutil.h"
# include "rle.h"
2014-07-03 01:47:29 +00:00
# include "byteutil.h"
2011-05-22 17:54:47 +00:00
# include "segment.h"
# include "gameseg.h"
2013-12-08 23:37:40 +00:00
# include "fmtcheck.h"
2006-03-20 17:12:09 +00:00
2014-10-12 23:05:46 +00:00
# include "compiler-range_for.h"
# include "highest_valid.h"
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# include "custom.h"
# define GLITZ_BACKGROUND Menu_pcx_name
2013-11-10 03:31:22 +00:00
2013-03-03 01:03:33 +00:00
static int AdvanceLevel ( int secret_flag ) ;
# elif defined(DXX_BUILD_DESCENT_II)
# include "movie.h"
# define GLITZ_BACKGROUND STARS_BACKGROUND
2006-08-30 18:12:04 +00:00
2013-09-22 22:26:27 +00:00
static void StartNewLevelSecret ( int level_num , int page_in_textures ) ;
static void InitPlayerPosition ( int random_flag ) ;
static void DoEndGame ( void ) ;
2013-11-10 03:31:22 +00:00
static void filter_objects_from_level ( ) ;
2013-09-22 22:26:27 +00:00
static void AdvanceLevel ( int secret_flag ) ;
2013-03-03 01:03:33 +00:00
# endif
2013-09-22 22:26:27 +00:00
static void StartLevel ( int random_flag ) ;
static void copy_defaults_to_robot_all ( void ) ;
2006-03-20 17:12:09 +00:00
//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 ] ;
// Global variables describing the player
2014-09-20 23:47:27 +00:00
unsigned N_players = 1 ; // Number of players ( >1 means a net game, eh?)
2014-09-21 22:10:12 +00:00
playernum_t Player_num ; // The player number who is on the console.
2014-08-08 03:02:59 +00:00
array < player , MAX_PLAYERS + DXX_PLAYER_HEADER_ADD_EXTRA_PLAYERS > Players ; // Misc player info
# if defined(DXX_BUILD_DESCENT_II)
2013-11-10 03:31:22 +00:00
int First_secret_visit = 1 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
obj_position Player_init [ MAX_PLAYERS ] ;
// Global variables telling what sort of game we have
int NumNetPlayerPositions = - 1 ;
int Do_appearance_effect = 0 ;
//--------------------------------------------------------------------
2013-10-27 22:00:14 +00:00
static void verify_console_object ( )
2006-03-20 17:12:09 +00:00
{
2014-09-27 22:57:15 +00:00
Assert ( Player_num < Players . size ( ) ) ;
2013-12-26 22:21:16 +00:00
Assert ( Players [ Player_num ] . objnum ! = object_none ) ;
2006-03-20 17:12:09 +00:00
ConsoleObject = & Objects [ Players [ Player_num ] . objnum ] ;
Assert ( ConsoleObject - > type = = OBJ_PLAYER ) ;
2013-11-10 03:31:22 +00:00
Assert ( get_player_id ( ConsoleObject ) = = Player_num ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static int count_number_of_robots ( )
2006-03-20 17:12:09 +00:00
{
int robot_count ;
robot_count = 0 ;
2014-10-12 23:05:46 +00:00
range_for ( auto i , highest_valid ( Objects ) )
{
2006-03-20 17:12:09 +00:00
if ( Objects [ i ] . type = = OBJ_ROBOT )
robot_count + + ;
}
return robot_count ;
}
2013-10-27 22:00:14 +00:00
static int count_number_of_hostages ( )
2006-03-20 17:12:09 +00:00
{
int count ;
count = 0 ;
2014-10-12 23:05:46 +00:00
range_for ( auto i , highest_valid ( Objects ) )
{
2006-03-20 17:12:09 +00:00
if ( Objects [ i ] . type = = OBJ_HOSTAGE )
count + + ;
}
return count ;
}
//added 10/12/95: delete buddy bot if coop game. Probably doesn't really belong here. -MT
2013-11-10 03:31:22 +00:00
static void gameseq_init_network_players ( )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
int k , j ;
2006-03-20 17:12:09 +00:00
// Initialize network player start locations and object numbers
ConsoleObject = & Objects [ 0 ] ;
k = 0 ;
j = 0 ;
2014-10-12 23:05:46 +00:00
range_for ( auto i , highest_valid ( Objects ) )
{
2014-11-26 03:39:21 +00:00
const auto o = vobjptridx ( i ) ;
if ( ( o - > type = = OBJ_PLAYER ) | | ( o - > type = = OBJ_GHOST ) | | ( o - > type = = OBJ_COOP ) )
2006-03-20 17:12:09 +00:00
{
2014-11-26 03:39:21 +00:00
if ( ( ! ( Game_mode & GM_MULTI_COOP ) & & ( ( o - > type = = OBJ_PLAYER ) | | ( o - > type = = OBJ_GHOST ) ) ) | |
( ( Game_mode & GM_MULTI_COOP ) & & ( ( j = = 0 ) | | ( o - > type = = OBJ_COOP ) ) ) )
2006-03-20 17:12:09 +00:00
{
2014-11-26 03:39:21 +00:00
o - > type = OBJ_PLAYER ;
Player_init [ k ] . pos = o - > pos ;
Player_init [ k ] . orient = o - > orient ;
Player_init [ k ] . segnum = o - > segnum ;
2006-03-20 17:12:09 +00:00
Players [ k ] . objnum = i ;
2014-11-26 03:39:21 +00:00
set_player_id ( o , k ) ;
2006-03-20 17:12:09 +00:00
k + + ;
}
else
2014-11-26 03:39:21 +00:00
obj_delete ( o ) ;
2006-03-20 17:12:09 +00:00
j + + ;
}
2014-11-26 03:39:21 +00:00
if ( ( o - > type = = OBJ_ROBOT ) & & robot_is_companion ( & Robot_info [ get_robot_id ( o ) ] ) & & ( Game_mode & GM_MULTI ) )
obj_delete ( o ) ; //kill the buddy in netgames
2006-03-20 17:12:09 +00:00
}
NumNetPlayerPositions = k ;
}
void gameseq_remove_unused_players ( )
{
int i ;
// 'Remove' the unused players
if ( Game_mode & GM_MULTI )
{
for ( i = 0 ; i < NumNetPlayerPositions ; i + + )
{
if ( ( ! Players [ i ] . connected ) | | ( i > = N_players ) )
{
multi_make_player_ghost ( i ) ;
}
}
}
else
{ // 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
2012-04-15 13:32:48 +00:00
void init_player_stats_game ( ubyte pnum )
2006-03-20 17:12:09 +00:00
{
2012-04-15 13:32:48 +00:00
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 ;
2013-12-26 22:21:16 +00:00
Players [ pnum ] . killer_objnum = object_none ;
2012-04-15 13:32:48 +00:00
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 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2012-04-15 13:32:48 +00:00
if ( pnum = = Player_num )
First_secret_visit = 1 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void init_ammo_and_energy ( void )
2006-03-20 17:12:09 +00:00
{
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; i<MAX_SECONDARY_WEAPONS; i++)
// if (Players[Player_num].secondary_ammo[i] < Default_secondary_ammo_level[i])
// Players[Player_num].secondary_ammo[i] = Default_secondary_ammo_level[i];
if ( Players [ Player_num ] . secondary_ammo [ 0 ] < 2 + NDL - Difficulty_level )
Players [ Player_num ] . secondary_ammo [ 0 ] = 2 + NDL - Difficulty_level ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
extern ubyte Last_afterburner_state ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
// Setup player for new level (After completion of previous level)
void init_player_stats_level ( int secret_flag )
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
secret_flag = 0 ;
# endif
2006-03-20 17:12:09 +00:00
// int i;
Players [ Player_num ] . last_score = Players [ Player_num ] . score ;
Players [ Player_num ] . level = Current_level_num ;
if ( ! Network_rejoined ) {
Players [ Player_num ] . time_level = 0 ;
Players [ Player_num ] . hours_level = 0 ;
}
2013-12-26 22:21:16 +00:00
Players [ Player_num ] . killer_objnum = object_none ;
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . num_kills_level = 0 ;
Players [ Player_num ] . num_robots_level = count_number_of_robots ( ) ;
Players [ Player_num ] . num_robots_total + = Players [ Player_num ] . num_robots_level ;
Players [ Player_num ] . hostages_level = count_number_of_hostages ( ) ;
Players [ Player_num ] . hostages_total + = Players [ Player_num ] . hostages_level ;
Players [ Player_num ] . hostages_on_board = 0 ;
if ( ! secret_flag ) {
init_ammo_and_energy ( ) ;
Players [ Player_num ] . flags & = ( ~ KEY_BLUE ) ;
Players [ Player_num ] . flags & = ( ~ KEY_RED ) ;
Players [ Player_num ] . flags & = ( ~ KEY_GOLD ) ;
2013-11-10 03:31:22 +00:00
Players [ Player_num ] . flags & = ~ ( PLAYER_FLAGS_INVULNERABLE | PLAYER_FLAGS_CLOAKED ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-11-10 03:31:22 +00:00
Players [ Player_num ] . flags & = ~ ( PLAYER_FLAGS_MAP_ALL ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . cloak_time = 0 ;
Players [ Player_num ] . invulnerable_time = 0 ;
if ( ( Game_mode & GM_MULTI ) & & ! ( Game_mode & GM_MULTI_COOP ) )
Players [ Player_num ] . flags | = ( KEY_BLUE | KEY_RED | KEY_GOLD ) ;
}
Player_is_dead = 0 ; // Added by RH
2011-01-18 19:02:04 +00:00
Dead_player_camera = NULL ;
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . homing_object_dist = - F1_0 ; // Added by RH
2010-09-03 21:49:39 +00:00
// properly init these cursed globals
2010-12-22 00:17:59 +00:00
Next_flare_fire_time = Last_laser_fired_time = Next_laser_fire_time = Next_missile_fire_time = GameTime64 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-11-26 22:46:48 +00:00
Controls . state . afterburner = 0 ;
2006-03-20 17:12:09 +00:00
Last_afterburner_state = 0 ;
digi_kill_sound_linked_to_object ( Players [ Player_num ] . objnum ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
init_gauges ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Missile_viewer = NULL ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
// Setup player for a brand-new ship
2012-04-15 13:32:48 +00:00
void init_player_stats_new_ship ( ubyte pnum )
2006-03-20 17:12:09 +00:00
{
2012-04-15 13:32:48 +00:00
int i ;
2006-03-20 17:12:09 +00:00
2012-04-15 13:32:48 +00:00
if ( pnum = = Player_num )
{
if ( Newdemo_state = = ND_STATE_RECORDING )
{
newdemo_record_laser_level ( Players [ Player_num ] . laser_level , 0 ) ;
newdemo_record_player_weapon ( 0 , 0 ) ;
newdemo_record_player_weapon ( 1 , 0 ) ;
}
Primary_weapon = 0 ;
Secondary_weapon = 0 ;
dead_player_end ( ) ; //player no longer dead
2012-04-15 23:13:29 +00:00
Player_is_dead = 0 ;
Player_exploded = 0 ;
Player_eggs_dropped = 0 ;
Dead_player_camera = 0 ;
2012-04-15 13:32:48 +00:00
Global_laser_firing_count = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-11-10 03:31:22 +00:00
for ( i = 0 ; i < MAX_PRIMARY_WEAPONS ; i + + )
Primary_last_was_super [ i ] = 0 ;
for ( i = 1 ; i < MAX_SECONDARY_WEAPONS ; i + + )
Secondary_last_was_super [ i ] = 0 ;
2012-04-15 13:32:48 +00:00
Afterburner_charge = 0 ;
2013-11-26 22:46:48 +00:00
Controls . state . afterburner = 0 ;
2012-04-15 13:32:48 +00:00
Last_afterburner_state = 0 ;
Missile_viewer = NULL ; //reset missile camera if out there
Missile_viewer_sig = - 1 ;
init_ai_for_ship ( ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2012-04-15 13:32:48 +00:00
Players [ pnum ] . energy = INITIAL_ENERGY ;
Players [ pnum ] . shields = StartingShields ;
Players [ pnum ] . laser_level = 0 ;
2013-12-26 22:21:16 +00:00
Players [ pnum ] . killer_objnum = object_none ;
2012-04-15 13:32:48 +00:00
Players [ pnum ] . hostages_on_board = 0 ;
2013-09-20 23:12:54 +00:00
Players [ pnum ] . vulcan_ammo = 0 ;
2012-04-15 13:32:48 +00:00
for ( i = 1 ; i < MAX_SECONDARY_WEAPONS ; i + + )
Players [ pnum ] . secondary_ammo [ i ] = 0 ;
Players [ pnum ] . secondary_ammo [ 0 ] = 2 + NDL - Difficulty_level ;
Players [ pnum ] . primary_weapon_flags = HAS_LASER_FLAG ;
Players [ pnum ] . secondary_weapon_flags = HAS_CONCUSSION_FLAG ;
2013-11-10 03:31:22 +00:00
Players [ pnum ] . flags & = ~ ( PLAYER_FLAGS_QUAD_LASERS | PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-11-10 03:31:22 +00:00
Players [ pnum ] . flags & = ~ ( PLAYER_FLAGS_AFTERBURNER | PLAYER_FLAGS_MAP_ALL | PLAYER_FLAGS_CONVERTER | PLAYER_FLAGS_AMMO_RACK | PLAYER_FLAGS_HEADLIGHT | PLAYER_FLAGS_HEADLIGHT_ON | PLAYER_FLAGS_FLAG ) ;
2013-03-03 01:03:33 +00:00
# endif
2012-04-15 13:32:48 +00:00
Players [ pnum ] . cloak_time = 0 ;
Players [ pnum ] . invulnerable_time = 0 ;
Players [ pnum ] . homing_object_dist = - F1_0 ; // Added by RH
digi_kill_sound_linked_to_object ( Players [ pnum ] . objnum ) ;
2006-03-20 17:12:09 +00:00
}
# ifdef EDITOR
//reset stuff so game is semi-normal when playing from editor
void editor_reset_stuff_on_level ( )
{
gameseq_init_network_players ( ) ;
init_player_stats_level ( 0 ) ;
Viewer = ConsoleObject ;
ConsoleObject = Viewer = & Objects [ Players [ Player_num ] . objnum ] ;
2013-11-10 03:31:22 +00:00
set_player_id ( ConsoleObject , Player_num ) ;
2006-03-20 17:12:09 +00:00
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 ( ) ;
2012-04-15 13:32:48 +00:00
init_player_stats_new_ship ( Player_num ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
init_controlcen_for_level ( ) ;
automap_clear_visited ( ) ;
init_stuck_objects ( ) ;
init_thief_for_level ( ) ;
Slide_segs_computed = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2012-03-19 05:49:19 +00:00
if ( ! Game_wind )
2013-12-01 05:21:47 +00:00
Game_wind = window_create ( & grd_curscreen - > sc_canvas , 0 , 0 , SWIDTH , SHEIGHT , game_handler , unused_window_userdata ) ;
2006-03-20 17:12:09 +00:00
}
# endif
//do whatever needs to be done when a player dies in multiplayer
2013-10-27 22:00:14 +00:00
static void DoGameOver ( )
2006-03-20 17:12:09 +00:00
{
if ( PLAYING_BUILTIN_MISSION )
scores_maybe_add_player ( 0 ) ;
2010-01-27 04:30:31 +00:00
if ( Game_wind )
window_close ( Game_wind ) ; // Exit out of game loop
2006-03-20 17:12:09 +00:00
}
//update various information about the player
void update_player_stats ( )
{
2013-02-21 00:20:26 +00:00
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 + + ;
}
2006-03-20 17:12:09 +00:00
2013-02-21 00:20:26 +00:00
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 + + ;
}
2006-03-20 17:12:09 +00:00
}
//go through this level and start any eclip sounds
2013-10-27 22:00:14 +00:00
static void set_sound_sources ( )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
int sidenum ;
2006-03-20 17:12:09 +00:00
digi_init_sounds ( ) ; //clear old sounds
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Dont_start_sound_objects = 1 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-10-12 23:10:05 +00:00
range_for ( auto segnum , highest_valid ( Segments ) )
{
auto seg = & Segments [ segnum ] ;
2006-03-20 17:12:09 +00:00
for ( sidenum = 0 ; sidenum < MAX_SIDES_PER_SEGMENT ; sidenum + + ) {
int tm , ec , sn ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( ( tm = seg - > sides [ sidenum ] . tmap_num2 ) ! = 0 )
if ( ( ec = TmapInfo [ tm & 0x3fff ] . eclip_num ) ! = - 1 )
# elif defined(DXX_BUILD_DESCENT_II)
2014-09-02 22:15:07 +00:00
auto wid = WALL_IS_DOORWAY ( seg , sidenum ) ;
if ( wid & WID_RENDER_FLAG )
2006-03-20 17:12:09 +00:00
if ( ( ( ( tm = seg - > sides [ sidenum ] . tmap_num2 ) ! = 0 ) & & ( ( ec = TmapInfo [ tm & 0x3fff ] . eclip_num ) ! = - 1 ) ) | | ( ( ec = TmapInfo [ seg - > sides [ sidenum ] . tmap_num ] . eclip_num ) ! = - 1 ) )
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( ( sn = Effects [ ec ] . sound_num ) ! = - 1 ) {
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-11-20 03:00:36 +00:00
auto csegnum = seg - > children [ sidenum ] ;
2006-03-20 17:12:09 +00:00
//check for sound on other side of wall. Don't add on
//both walls if sound travels through wall. If sound
//does travel through wall, add sound for lower-numbered
//segment.
if ( IS_CHILD ( csegnum ) & & csegnum < segnum ) {
2014-09-02 22:15:07 +00:00
if ( wid & ( WID_FLY_FLAG | WID_RENDPAST_FLAG ) ) {
2014-10-02 03:02:34 +00:00
auto csegp = & Segments [ seg - > children [ sidenum ] ] ;
2014-09-06 04:06:18 +00:00
auto csidenum = find_connect_side ( seg , csegp ) ;
2006-03-20 17:12:09 +00:00
if ( csegp - > sides [ csidenum ] . tmap_num2 = = seg - > sides [ sidenum ] . tmap_num2 )
continue ; //skip this one
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-10-30 03:32:27 +00:00
const auto pnt = compute_center_point_on_side ( seg , sidenum ) ;
2014-10-26 21:33:50 +00:00
digi_link_sound_to_pos ( sn , segnum , sidenum , pnt , 1 , F1_0 / 2 ) ;
2006-03-20 17:12:09 +00:00
}
}
2014-10-12 23:10:05 +00:00
}
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Dont_start_sound_objects = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
//fix flash_dist=i2f(1);
fix flash_dist = fl2f ( .9 ) ;
//create flash for player appearance
2014-10-02 03:02:34 +00:00
void create_player_appearance_effect ( const vobjptridx_t player_obj )
2006-03-20 17:12:09 +00:00
{
2014-11-02 03:43:57 +00:00
const auto pos = ( player_obj = = Viewer )
? vm_vec_scale_add ( player_obj - > pos , player_obj - > orient . fvec , fixmul ( player_obj - > size , flash_dist ) )
: player_obj - > pos ;
2006-03-20 17:12:09 +00:00
2014-10-02 03:02:34 +00:00
const objptridx_t effect_obj = object_create_explosion ( player_obj - > segnum , pos , player_obj - > size , VCLIP_PLAYER_APPEARANCE ) ;
2006-03-20 17:12:09 +00:00
if ( effect_obj ) {
effect_obj - > orient = player_obj - > orient ;
if ( Vclip [ VCLIP_PLAYER_APPEARANCE ] . sound_num > - 1 )
2013-12-24 04:53:59 +00:00
digi_link_sound_to_object ( Vclip [ VCLIP_PLAYER_APPEARANCE ] . sound_num , effect_obj , 0 , F1_0 ) ;
2006-03-20 17:12:09 +00:00
}
}
//
// New Game sequencing functions
//
2013-11-10 03:31:22 +00:00
//get level filename. level numbers start at 1. Secret levels are -1,-2,-3
2014-07-23 02:27:22 +00:00
static const d_fname & get_level_file ( int level_num )
2013-11-10 03:31:22 +00:00
{
if ( level_num < 0 ) //secret level
return Secret_level_names [ - level_num - 1 ] ;
else //normal level
return Level_names [ level_num - 1 ] ;
}
2011-05-22 17:54:47 +00:00
// routine to calculate the checksum of the segments.
2013-10-27 22:00:14 +00:00
static void do_checksum_calc ( ubyte * b , int len , unsigned int * s1 , unsigned int * s2 )
2009-03-20 12:10:38 +00:00
{
while ( len - - ) {
* s1 + = * b + + ;
if ( * s1 > = 255 ) * s1 - = 255 ;
* s2 + = * s1 ;
}
}
2013-10-27 22:00:14 +00:00
static ushort netmisc_calc_checksum ( )
2009-03-20 12:10:38 +00:00
{
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 + + ) {
2014-09-06 22:36:58 +00:00
do_checksum_calc ( ( unsigned char * ) & ( Segments [ i ] . sides [ j ] . get_type ( ) ) , 1 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
s = INTEL_SHORT ( Segments [ i ] . sides [ j ] . wall_num ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & s , 2 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
s = INTEL_SHORT ( Segments [ i ] . sides [ j ] . tmap_num ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & s , 2 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
s = INTEL_SHORT ( Segments [ i ] . sides [ j ] . tmap_num2 ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & s , 2 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
for ( k = 0 ; k < 4 ; k + + ) {
t = INTEL_INT ( ( ( int ) Segments [ i ] . sides [ j ] . uvls [ k ] . u ) ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & t , 4 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
t = INTEL_INT ( ( ( int ) Segments [ i ] . sides [ j ] . uvls [ k ] . v ) ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & t , 4 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
t = INTEL_INT ( ( ( int ) Segments [ i ] . sides [ j ] . uvls [ k ] . l ) ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & t , 4 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
}
for ( k = 0 ; k < 2 ; k + + ) {
t = INTEL_INT ( ( ( int ) Segments [ i ] . sides [ j ] . normals [ k ] . x ) ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & t , 4 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
t = INTEL_INT ( ( ( int ) Segments [ i ] . sides [ j ] . normals [ k ] . y ) ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & t , 4 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
t = INTEL_INT ( ( ( int ) Segments [ i ] . sides [ j ] . normals [ k ] . z ) ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & t , 4 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
}
}
for ( j = 0 ; j < MAX_SIDES_PER_SEGMENT ; j + + ) {
s = INTEL_SHORT ( Segments [ i ] . children [ j ] ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & s , 2 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
}
for ( j = 0 ; j < MAX_VERTICES_PER_SEGMENT ; j + + ) {
s = INTEL_SHORT ( Segments [ i ] . verts [ j ] ) ;
2011-05-22 17:54:47 +00:00
do_checksum_calc ( ( ubyte * ) & s , 2 , & sum1 , & sum2 ) ;
2009-03-20 12:10:38 +00:00
}
2013-11-10 03:31:22 +00:00
s = INTEL_SHORT ( Segments [ i ] . objects ) ;
do_checksum_calc ( ( ubyte * ) & s , 2 , & sum1 , & sum2 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
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 ) ;
# endif
2009-03-20 12:10:38 +00:00
}
sum2 % = 255 ;
return ( ( sum1 < < 8 ) + sum2 ) ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2009-11-15 08:22:08 +00:00
// load just the hxm file
void load_level_robots ( int level_num )
{
Assert ( level_num < = Last_level & & level_num > = Last_secret_level & & level_num ! = 0 ) ;
2014-07-23 02:27:22 +00:00
const d_fname & level_name = get_level_file ( level_num ) ;
2009-11-15 08:22:08 +00:00
if ( Robot_replacements_loaded ) {
free_polygon_models ( ) ;
2013-04-06 21:24:40 +00:00
load_mission_ham ( ) ;
2009-11-15 08:22:08 +00:00
Robot_replacements_loaded = 0 ;
}
load_robot_replacements ( level_name ) ;
}
2013-03-03 01:03:33 +00:00
# endif
2009-11-15 08:22:08 +00:00
2006-03-20 17:12:09 +00:00
//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 )
{
player save_player ;
2010-06-14 08:13:16 +00:00
save_player = Players [ Player_num ] ;
2006-03-20 17:12:09 +00:00
Assert ( level_num < = Last_level & & level_num > = Last_secret_level & & level_num ! = 0 ) ;
2014-07-23 02:27:22 +00:00
const d_fname & level_name = get_level_file ( level_num ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( ! load_level ( level_name ) )
Current_level_num = level_num ;
gr_use_palette_table ( " palette.256 " ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
gr_set_current_canvas ( NULL ) ;
gr_clear_canvas ( BM_XRGB ( 0 , 0 , 0 ) ) ; //so palette switching is less obvious
2013-11-10 03:31:22 +00:00
int load_ret = load_level ( level_name ) ; //actually load the data from disk!
2006-03-20 17:12:09 +00:00
if ( load_ret )
2014-07-23 02:27:22 +00:00
Error ( " Couldn't load level file <%s>, error = %d " , static_cast < const char * > ( level_name ) , load_ret ) ;
2006-03-20 17:12:09 +00:00
Current_level_num = level_num ;
load_palette ( Current_level_palette , 1 , 1 ) ; //don't change screen
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2008-03-20 23:23:46 +00:00
show_boxed_message ( TXT_LOADING , 0 ) ;
2010-06-27 11:28:26 +00:00
# ifdef RELEASE
timer_delay ( F1_0 ) ;
# endif
2008-03-20 23:23:46 +00:00
2006-03-20 17:12:09 +00:00
load_endlevel_data ( level_num ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
load_custom_data ( level_name ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( EMULATING_D1 )
load_d1_bitmap_replacements ( ) ;
else
load_bitmap_replacements ( level_name ) ;
2009-11-15 08:22:08 +00:00
load_level_robots ( level_num ) ;
2006-03-20 17:12:09 +00:00
if ( page_in_textures )
piggy_load_level_data ( ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2011-05-22 17:54:47 +00:00
my_segments_checksum = netmisc_calc_checksum ( ) ;
2006-03-20 17:12:09 +00:00
reset_network_objects ( ) ;
Players [ Player_num ] = save_player ;
set_sound_sources ( ) ;
2010-08-01 17:42:38 +00:00
songs_play_level_song ( Current_level_num , 0 ) ;
2006-03-20 17:12:09 +00:00
gr_palette_load ( gr_palette ) ; //actually load the palette
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( page_in_textures )
piggy_load_level_data ( ) ;
# endif
2006-03-20 17:12:09 +00:00
}
//sets up Player_num & ConsoleObject
void InitPlayerObject ( )
{
2014-09-21 22:10:12 +00:00
Assert ( Player_num < MAX_PLAYERS ) ;
2006-03-20 17:12:09 +00:00
if ( Player_num ! = 0 ) {
Players [ 0 ] = Players [ Player_num ] ;
Player_num = 0 ;
}
2013-12-29 04:28:07 +00:00
Players [ Player_num ] . objnum = object_first ;
2006-03-20 17:12:09 +00:00
ConsoleObject = & Objects [ Players [ Player_num ] . objnum ] ;
ConsoleObject - > type = OBJ_PLAYER ;
2013-11-10 03:31:22 +00:00
set_player_id ( ConsoleObject , Player_num ) ;
2006-03-20 17:12:09 +00:00
ConsoleObject - > control_type = CT_FLYING ;
ConsoleObject - > movement_type = MT_PHYSICS ;
}
//starts a new game on the given level
void StartNewGame ( int start_level )
{
2010-07-19 17:07:12 +00:00
state_quick_item = - 1 ; // for first blind save, pick slot to save in
2010-02-25 03:08:10 +00:00
2006-03-20 17:12:09 +00:00
Game_mode = GM_NORMAL ;
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
Next_level_num = 0 ;
InitPlayerObject ( ) ; //make sure player's object set up
2012-04-15 13:32:48 +00:00
init_player_stats_game ( Player_num ) ; //clear all stats
2006-03-20 17:12:09 +00:00
N_players = 1 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( start_level < 0 )
StartNewLevelSecret ( start_level , 0 ) ;
else
2013-03-03 01:03:33 +00:00
# endif
2013-03-23 20:50:35 +00:00
StartNewLevel ( start_level ) ;
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . starting_level = start_level ; // Mark where they started
game_disable_cheats ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
init_seismic_disturbances ( ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
// -----------------------------------------------------------------------------
// 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 ] ;
2013-11-10 03:31:22 +00:00
# define N_GLITZITEMS 9
2006-03-20 17:12:09 +00:00
char m_str [ N_GLITZITEMS ] [ 30 ] ;
2013-11-10 03:31:22 +00:00
newmenu_item m [ N_GLITZITEMS ] ;
2006-03-20 17:12:09 +00:00
int i , c ;
char title [ 128 ] ;
int is_last_level ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
gr_palette_load ( gr_palette ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
int mine_level ;
// Compute level player is on, deal with secret levels (negative numbers)
mine_level = Players [ Player_num ] . level ;
if ( mine_level < 0 )
mine_level * = - ( Last_level / N_secret_levels ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
level_points = Players [ Player_num ] . score - Players [ Player_num ] . last_score ;
2011-02-14 21:27:07 +00:00
if ( ! cheats . enabled ) {
2006-03-20 17:12:09 +00:00
if ( Difficulty_level > 1 ) {
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
skill_points = level_points * ( Difficulty_level - 1 ) / 2 ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
skill_points = level_points * ( Difficulty_level ) / 4 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
skill_points - = skill_points % 100 ;
} else
skill_points = 0 ;
2013-11-10 03:31:22 +00:00
hostage_points = Players [ Player_num ] . hostages_on_board * 500 * ( Difficulty_level + 1 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
shield_points = f2i ( Players [ Player_num ] . shields ) * 10 * ( Difficulty_level + 1 ) ;
energy_points = f2i ( Players [ Player_num ] . energy ) * 5 * ( Difficulty_level + 1 ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
shield_points = f2i ( Players [ Player_num ] . shields ) * 5 * mine_level ;
energy_points = f2i ( Players [ Player_num ] . energy ) * 2 * mine_level ;
shield_points - = shield_points % 50 ;
energy_points - = energy_points % 50 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
} else {
skill_points = 0 ;
shield_points = 0 ;
energy_points = 0 ;
hostage_points = 0 ;
}
all_hostage_text [ 0 ] = 0 ;
endgame_text [ 0 ] = 0 ;
2011-02-14 21:27:07 +00:00
if ( ! cheats . enabled & & ( Players [ Player_num ] . hostages_on_board = = Players [ Player_num ] . hostages_level ) ) {
2006-03-20 17:12:09 +00:00
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 ;
2011-02-14 21:27:07 +00:00
if ( ! cheats . enabled & & ! ( Game_mode & GM_MULTI ) & & ( Players [ Player_num ] . lives ) & & ( Current_level_num = = Last_level ) ) { //player has finished the game!
2006-03-20 17:12:09 +00:00
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 ; i < c ; i + + ) {
2012-11-24 20:57:15 +00:00
nm_set_item_text ( & m [ i ] , m_str [ i ] ) ;
2006-03-20 17:12:09 +00:00
}
if ( Current_level_num < 0 )
sprintf ( title , " %s%s %d %s \n %s %s " , is_last_level ? " \n \n \n " : " \n " , TXT_SECRET_LEVEL , - Current_level_num , TXT_COMPLETE , Current_level_name , TXT_DESTROYED ) ;
else
sprintf ( title , " %s%s %d %s \n %s %s " , is_last_level ? " \n \n \n " : " \n " , TXT_LEVEL , Current_level_num , TXT_COMPLETE , Current_level_name , TXT_DESTROYED ) ;
Assert ( c < = N_GLITZITEMS ) ;
if ( network & & ( Game_mode & GM_NETWORK ) )
2013-12-04 22:45:33 +00:00
newmenu_do2 ( NULL , title , c , m , multi_endlevel_poll1 , unused_newmenu_userdata , 0 , GLITZ_BACKGROUND ) ;
2006-03-20 17:12:09 +00:00
else
// NOTE LINK TO ABOVE!!!
2013-12-04 22:45:33 +00:00
newmenu_do2 ( NULL , title , c , m , unused_newmenu_subfunction , unused_newmenu_userdata , 0 , GLITZ_BACKGROUND ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------------------------------
//called when the player is starting a level (new game or new ship)
2013-10-27 22:00:14 +00:00
static void StartSecretLevel ( )
2006-03-20 17:12:09 +00:00
{
Assert ( ! Player_is_dead ) ;
InitPlayerPosition ( 0 ) ;
verify_console_object ( ) ;
ConsoleObject - > control_type = CT_FLYING ;
ConsoleObject - > movement_type = MT_PHYSICS ;
// -- WHY? -- disable_matcens();
clear_transient_objects ( 0 ) ; //0 means leave proximity bombs
// create_player_appearance_effect(ConsoleObject);
Do_appearance_effect = 1 ;
ai_reset_all_paths ( ) ;
// -- NO? -- reset_time();
reset_rear_view ( ) ;
Auto_fire_fusion_cannon_time = 0 ;
Fusion_charge = 0 ;
}
// Returns true if secret level has been destroyed.
int p_secret_level_destroyed ( void )
{
if ( First_secret_visit ) {
return 0 ; // Never been there, can't have been destroyed.
} else {
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( SECRETC_FILENAME , 0 ) )
2006-03-20 17:12:09 +00:00
{
return 0 ;
} else {
return 1 ;
}
}
}
// -----------------------------------------------------------------------------------------------------
2010-07-27 11:41:43 +00:00
# define TXT_SECRET_RETURN "Returning to level %i", Entered_from_level
# define TXT_SECRET_ADVANCE "Base level destroyed.\nAdvancing to level %i", Entered_from_level+1
2013-03-03 01:03:33 +00:00
# endif
2010-07-27 11:41:43 +00:00
2014-10-04 21:47:13 +00:00
static int draw_endlevel_background ( newmenu * , const d_event & event , grs_bitmap * background )
2006-03-20 17:12:09 +00:00
{
2014-10-04 21:47:13 +00:00
switch ( event . type )
2010-07-27 11:41:43 +00:00
{
case EVENT_WINDOW_DRAW :
gr_set_current_canvas ( NULL ) ;
show_fullscr ( background ) ;
break ;
default :
break ;
}
return 0 ;
}
2013-12-08 23:37:40 +00:00
static void do_screen_message ( const char * msg ) __attribute_nonnull ( ) ;
static void do_screen_message ( const char * msg )
2010-07-27 11:41:43 +00:00
{
grs_bitmap background ;
if ( Game_mode & GM_MULTI )
return ;
gr_init_bitmap_data ( & background ) ;
2013-11-10 03:31:22 +00:00
if ( pcx_read_bitmap ( GLITZ_BACKGROUND , & background , BM_LINEAR , gr_palette ) ! = PCX_ERROR_NONE )
2010-07-27 11:41:43 +00:00
return ;
2013-02-21 00:20:26 +00:00
2010-07-27 11:41:43 +00:00
gr_palette_load ( gr_palette ) ;
2013-12-04 04:20:55 +00:00
newmenu_item nm_message_items [ 1 ] ;
nm_set_item_menu ( & nm_message_items [ 0 ] , TXT_OK ) ;
2014-07-14 02:40:42 +00:00
newmenu_do ( NULL , msg , 1 , nm_message_items , draw_endlevel_background , static_cast < grs_bitmap * > ( & background ) ) ;
2010-07-27 11:41:43 +00:00
gr_free_bitmap_data ( & background ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-08 23:37:40 +00:00
static void do_screen_message_fmt ( const char * fmt , . . . ) __attribute_format_printf ( 1 , 2 ) ;
static void do_screen_message_fmt ( const char * fmt , . . . )
{
va_list arglist ;
char msg [ 1024 ] ;
va_start ( arglist , fmt ) ;
vsnprintf ( msg , sizeof ( msg ) , fmt , arglist ) ;
va_end ( arglist ) ;
do_screen_message ( msg ) ;
}
# define do_screen_message(F,...) dxx_call_printf_checked(do_screen_message_fmt,do_screen_message,(),F,##__VA_ARGS__)
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------------------------------
// called when the player is starting a new level for normal game mode and restore state
// Need to deal with whether this is the first time coming to this level or not. If not the
// first time, instead of initializing various things, need to do a game restore for all the
// robots, powerups, walls, doors, etc.
2013-09-22 22:26:27 +00:00
static void StartNewLevelSecret ( int level_num , int page_in_textures )
2006-03-20 17:12:09 +00:00
{
ThisLevelTime = 0 ;
2007-04-01 02:14:38 +00:00
last_drawn_cockpit = - 1 ;
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_PAUSED )
Newdemo_state = ND_STATE_RECORDING ;
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING ) {
newdemo_set_new_level ( level_num ) ;
2008-10-16 17:27:02 +00:00
newdemo_record_start_frame ( FrameTime ) ;
2006-03-20 17:12:09 +00:00
} else if ( Newdemo_state ! = ND_STATE_PLAYBACK ) {
set_screen_mode ( SCREEN_MENU ) ;
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
if ( First_secret_visit ) {
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_EXIT ) ;
2006-03-20 17:12:09 +00:00
} else {
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( SECRETC_FILENAME , 0 ) )
2006-03-20 17:12:09 +00:00
{
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_EXIT ) ;
2006-03-20 17:12:09 +00:00
} else {
2010-07-27 11:41:43 +00:00
do_screen_message ( " Secret level already destroyed. \n Advancing to level %i. " , Current_level_num + 1 ) ;
2006-03-20 17:12:09 +00:00
}
}
}
LoadLevel ( level_num , page_in_textures ) ;
2011-09-26 23:31:19 +00:00
Assert ( Current_level_num = = level_num ) ; // make sure level set right
2006-03-20 17:12:09 +00:00
2011-09-26 23:31:19 +00:00
gameseq_init_network_players ( ) ; // Initialize the Players array for this level
2006-03-20 17:12:09 +00:00
HUD_clear_messages ( ) ;
automap_clear_visited ( ) ;
Viewer = & Objects [ Players [ Player_num ] . objnum ] ;
gameseq_remove_unused_players ( ) ;
Game_suspended = 0 ;
Control_center_destroyed = 0 ;
init_cockpit ( ) ;
reset_palette_add ( ) ;
if ( First_secret_visit | | ( Newdemo_state = = ND_STATE_PLAYBACK ) ) {
init_robots_for_level ( ) ;
init_ai_objects ( ) ;
init_smega_detonates ( ) ;
init_morphs ( ) ;
init_all_matcens ( ) ;
reset_special_effects ( ) ;
StartSecretLevel ( ) ;
} else {
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( SECRETC_FILENAME , 0 ) )
2006-03-20 17:12:09 +00:00
{
int pw_save , sw_save ;
pw_save = Primary_weapon ;
sw_save = Secondary_weapon ;
2013-12-10 17:13:32 +00:00
state_restore_all ( 1 , 1 , SECRETC_FILENAME , 0 ) ;
2006-03-20 17:12:09 +00:00
Primary_weapon = pw_save ;
Secondary_weapon = sw_save ;
reset_special_effects ( ) ;
StartSecretLevel ( ) ;
// -- No: This is only for returning to base level: set_pos_from_return_segment();
} else {
2010-07-27 11:41:43 +00:00
do_screen_message ( " Secret level already destroyed. \n Advancing to level %i. " , Current_level_num + 1 ) ;
2006-03-20 17:12:09 +00:00
return ;
}
}
if ( First_secret_visit ) {
copy_defaults_to_robot_all ( ) ;
}
init_controlcen_for_level ( ) ;
2011-09-26 23:31:19 +00:00
// Say player can use FLASH cheat to mark path to exit.
2006-03-20 17:12:09 +00:00
Last_level_path_created = - 1 ;
First_secret_visit = 0 ;
}
int Entered_from_level ;
// ---------------------------------------------------------------------------------------------------------------
// Called from switch.c when player is on a secret level and hits exit to return to base level.
void ExitSecretLevel ( void )
{
if ( Newdemo_state = = ND_STATE_PLAYBACK )
return ;
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 0 ) ;
2006-03-20 17:12:09 +00:00
if ( ! Control_center_destroyed ) {
2011-02-09 11:58:32 +00:00
state_save_all ( 2 , SECRETC_FILENAME , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( SECRETB_FILENAME , 0 ) )
2006-03-20 17:12:09 +00:00
{
int pw_save , sw_save ;
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_RETURN ) ;
2006-03-20 17:12:09 +00:00
pw_save = Primary_weapon ;
sw_save = Secondary_weapon ;
2013-12-10 17:13:32 +00:00
state_restore_all ( 1 , 1 , SECRETB_FILENAME , 0 ) ;
2006-03-20 17:12:09 +00:00
Primary_weapon = pw_save ;
Secondary_weapon = sw_save ;
} else {
// File doesn't exist, so can't return to base level. Advance to next one.
if ( Entered_from_level = = Last_level )
DoEndGame ( ) ;
else {
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_ADVANCE ) ;
2013-03-23 20:50:35 +00:00
StartNewLevel ( Entered_from_level + 1 ) ;
2006-03-20 17:12:09 +00:00
}
}
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 1 ) ;
2010-07-04 13:12:08 +00:00
reset_time ( ) ;
2006-03-20 17:12:09 +00:00
}
// ---------------------------------------------------------------------------------------------------------------
// Set invulnerable_time and cloak_time in player struct to preserve amount of time left to
// be invulnerable or cloaked.
2010-12-22 00:17:59 +00:00
void do_cloak_invul_secret_stuff ( fix64 old_gametime )
2006-03-20 17:12:09 +00:00
{
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_INVULNERABLE ) {
2010-12-22 00:17:59 +00:00
fix64 time_used ;
2006-03-20 17:12:09 +00:00
time_used = old_gametime - Players [ Player_num ] . invulnerable_time ;
2010-12-22 00:17:59 +00:00
Players [ Player_num ] . invulnerable_time = GameTime64 - time_used ;
2006-03-20 17:12:09 +00:00
}
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_CLOAKED ) {
fix time_used ;
time_used = old_gametime - Players [ Player_num ] . cloak_time ;
2010-12-22 00:17:59 +00:00
Players [ Player_num ] . cloak_time = GameTime64 - time_used ;
2006-03-20 17:12:09 +00:00
}
}
// ---------------------------------------------------------------------------------------------------------------
// Called from switch.c when player passes through secret exit. That means he was on a non-secret level and he
// is passing to the secret level.
// Do a savegame.
void EnterSecretLevel ( void )
{
2011-09-26 23:31:19 +00:00
int i ;
2006-03-20 17:12:09 +00:00
Assert ( ! ( Game_mode & GM_MULTI ) ) ;
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 0 ) ;
2010-09-17 11:09:57 +00:00
digi_play_sample ( SOUND_SECRET_EXIT , F1_0 ) ; // after above call which stops all sounds
2006-03-20 17:12:09 +00:00
Entered_from_level = Current_level_num ;
if ( Control_center_destroyed )
DoEndLevelScoreGlitz ( 0 ) ;
if ( Newdemo_state ! = ND_STATE_PLAYBACK )
2011-02-09 11:58:32 +00:00
state_save_all ( 1 , NULL , 0 ) ; // Not between levels (ie, save all), IS a secret level, NO filename override
2006-03-20 17:12:09 +00:00
// Find secret level number to go to, stuff in Next_level_num.
for ( i = 0 ; i < - Last_secret_level ; i + + )
if ( Secret_level_table [ i ] = = Current_level_num ) {
Next_level_num = - ( i + 1 ) ;
break ;
} else if ( Secret_level_table [ i ] > Current_level_num ) { // Allows multiple exits in same group.
Next_level_num = - i ;
break ;
}
if ( ! ( i < - Last_secret_level ) ) //didn't find level, so must be last
Next_level_num = Last_secret_level ;
2007-04-14 20:44:09 +00:00
// NMN 04/09/07 Do a REAL start level routine if we are playing a D1 level so we have
// briefings
if ( EMULATING_D1 )
{
set_screen_mode ( SCREEN_MENU ) ;
2010-07-27 11:41:43 +00:00
do_screen_message ( " Alternate Exit Found! \n \n Proceeding to Secret Level! " ) ;
2013-03-23 20:50:35 +00:00
StartNewLevel ( Next_level_num ) ;
2007-04-14 20:44:09 +00:00
} else {
StartNewLevelSecret ( Next_level_num , 1 ) ;
}
// END NMN
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
// do_cloak_invul_stuff();
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 1 ) ;
2010-07-04 13:12:08 +00:00
reset_time ( ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//called when the player has finished a level
void PlayerFinishedLevel ( int secret_flag )
{
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 0 ) ;
2006-03-20 17:12:09 +00:00
//credit the player for hostages
Players [ Player_num ] . hostages_rescued_total + = Players [ Player_num ] . hostages_on_board ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
int rval ;
int was_multi = 0 ;
if ( ! ( Game_mode & GM_MULTI ) & & ( secret_flag ) ) {
newmenu_item m [ 1 ] ;
nm_set_item_text ( & m [ 0 ] , " " ) ; //TXT_SECRET_EXIT;
2013-12-04 22:45:33 +00:00
newmenu_do2 ( NULL , TXT_SECRET_EXIT , 1 , m , unused_newmenu_subfunction , unused_newmenu_userdata , 0 , Menu_pcx_name ) ;
2013-03-03 01:03:33 +00:00
}
// -- mk mk mk -- used to be here -- mk mk mk --
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
}
last_drawn_cockpit = - 1 ;
if ( Current_level_num = = Last_level ) {
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
{ // Note link to above else!
rval = AdvanceLevel ( secret_flag ) ; //now go on to the next one (if one)
DoEndLevelScoreGlitz ( 0 ) ; //give bonuses
}
} else {
if ( Game_mode & GM_MULTI )
multi_endlevel_score ( ) ;
else
DoEndLevelScoreGlitz ( 0 ) ; //give bonuses
rval = AdvanceLevel ( secret_flag ) ; //now go on to the next one (if one)
}
if ( ! was_multi & & rval ) {
if ( PLAYING_BUILTIN_MISSION )
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 ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
2013-11-10 03:31:22 +00:00
Assert ( ! secret_flag ) ;
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_NETWORK )
2009-11-24 09:48:53 +00:00
Players [ Player_num ] . connected = CONNECT_WAITING ; // Finished but did not die
2006-03-20 17:12:09 +00:00
2007-04-01 02:14:38 +00:00
last_drawn_cockpit = - 1 ;
2006-03-20 17:12:09 +00:00
AdvanceLevel ( secret_flag ) ; //now go on to the next one (if one)
2013-03-03 01:03:33 +00:00
# endif
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 1 ) ;
2010-07-04 13:12:08 +00:00
reset_time ( ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
static 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 ( ) ;
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 ) ;
}
}
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
if ( Game_mode & GM_MULTI )
{
multi_do_death ( Players [ Player_num ] . objnum ) ;
}
else
{ //Note link to above else!
Players [ Player_num ] . lives - - ;
if ( Players [ Player_num ] . lives = = 0 )
{
DoGameOver ( ) ;
return ;
}
}
if ( Control_center_destroyed ) {
//clear out stuff so no bonus
Players [ Player_num ] . hostages_on_board = 0 ;
Players [ Player_num ] . energy = 0 ;
Players [ Player_num ] . shields = 0 ;
Players [ Player_num ] . connected = CONNECT_DIED_IN_MINE ;
do_screen_message ( TXT_DIED_IN_MINE ) ; // Give them some indication of what happened
int rval ;
if ( Current_level_num = = Last_level ) {
if ( ( Game_mode & GM_MULTI ) & & ! ( Game_mode & GM_MULTI_COOP ) )
{
multi_endlevel_score ( ) ;
rval = AdvanceLevel ( 0 ) ; //if finished, go on to next level
}
else
{ // 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 {
if ( Game_mode & GM_MULTI )
multi_endlevel_score ( ) ;
else
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 ) {
if ( PLAYING_BUILTIN_MISSION )
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 ( ) ;
}
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
# define MOVIE_REQUIRED 1
# define ENDMOVIE "end"
//called when the player has finished the last level
2013-09-22 22:26:27 +00:00
static void DoEndGame ( void )
2006-03-20 17:12:09 +00:00
{
if ( ( Newdemo_state = = ND_STATE_RECORDING ) | | ( Newdemo_state = = ND_STATE_PAUSED ) )
newdemo_stop_recording ( ) ;
set_screen_mode ( SCREEN_MENU ) ;
gr_set_current_canvas ( NULL ) ;
key_flush ( ) ;
if ( PLAYING_BUILTIN_MISSION & & ! ( Game_mode & GM_MULTI ) )
{ //only built-in mission, & not multi
int played = MOVIE_NOT_PLAYED ; //default is not played
2013-10-27 21:01:04 +00:00
played = PlayMovie ( ENDMOVIE " .tex " , ENDMOVIE , MOVIE_REQUIRED ) ;
2010-03-25 23:37:19 +00:00
if ( ! played )
{
do_end_briefing_screens ( Ending_text_filename ) ;
2006-03-20 17:12:09 +00:00
}
2010-03-25 23:37:19 +00:00
}
else if ( ! ( Game_mode & GM_MULTI ) ) //not multi
{
2006-03-20 17:12:09 +00:00
char tname [ FILENAME_LEN ] ;
2010-03-25 23:37:19 +00:00
do_end_briefing_screens ( Ending_text_filename ) ;
2006-03-20 17:12:09 +00:00
//try doing special credits
2014-08-16 03:59:14 +00:00
snprintf ( tname , sizeof ( tname ) , " %s.ctb " , Current_mission_filename ) ;
2006-03-20 17:12:09 +00:00
credits_show ( tname ) ;
}
key_flush ( ) ;
if ( Game_mode & GM_MULTI )
multi_endlevel_score ( ) ;
else
// NOTE LINK TO ABOVE
DoEndLevelScoreGlitz ( 0 ) ;
if ( PLAYING_BUILTIN_MISSION & & ! ( ( Game_mode & GM_MULTI ) & & ! ( Game_mode & GM_MULTI_COOP ) ) ) {
gr_set_current_canvas ( NULL ) ;
gr_clear_canvas ( BM_XRGB ( 0 , 0 , 0 ) ) ;
2007-06-11 15:54:09 +00:00
load_palette ( D2_DEFAULT_PALETTE , 0 , 1 ) ;
2006-03-20 17:12:09 +00:00
scores_maybe_add_player ( 0 ) ;
}
2010-01-27 04:30:31 +00:00
if ( Game_wind )
window_close ( Game_wind ) ; // Exit out of game loop
2006-03-20 17:12:09 +00:00
}
//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.
2013-09-22 22:26:27 +00:00
static void AdvanceLevel ( int secret_flag )
2006-03-20 17:12:09 +00:00
{
Assert ( ! secret_flag ) ;
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
if ( Current_level_num ! = Last_level ) {
if ( Game_mode & GM_MULTI )
2010-06-14 08:13:16 +00:00
multi_endlevel_score ( ) ;
2006-03-20 17:12:09 +00:00
else
// NOTE LINK TO ABOVE!!!
DoEndLevelScoreGlitz ( 0 ) ; //give bonuses
}
Control_center_destroyed = 0 ;
# ifdef EDITOR
if ( Current_level_num = = 0 )
2010-03-21 00:54:56 +00:00
{
2012-04-17 07:05:43 +00:00
window_close ( Game_wind ) ; //not a real level
2010-03-21 00:54:56 +00:00
}
2006-03-20 17:12:09 +00:00
# endif
if ( Game_mode & GM_MULTI ) {
2013-11-10 03:31:22 +00:00
int result ;
2006-03-20 17:12:09 +00:00
result = multi_endlevel ( & secret_flag ) ; // Wait for other players to reach this point
if ( result ) // failed to sync
{
if ( Current_level_num = = Last_level ) //player has finished the game!
2010-01-27 04:30:31 +00:00
if ( Game_wind )
window_close ( Game_wind ) ; // Exit out of game loop
2010-03-21 00:54:56 +00:00
2010-01-27 04:30:31 +00:00
return ;
2006-03-20 17:12:09 +00:00
}
}
if ( Current_level_num = = Last_level ) { //player has finished the game!
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
DoEndGame ( ) ;
} else {
2007-04-14 20:44:09 +00:00
//NMN 04/08/07 If we are in a secret level and playing a D1
// level, then use Entered_from_level # instead
2010-06-14 08:13:16 +00:00
if ( Current_level_num < 0 & & EMULATING_D1 )
2007-04-14 20:44:09 +00:00
{
Next_level_num = Entered_from_level + 1 ; //assume go to next normal level
2013-11-10 03:31:22 +00:00
} else {
2007-04-14 20:44:09 +00:00
Next_level_num = Current_level_num + 1 ; //assume go to next normal level
}
// END NMN
2006-03-20 17:12:09 +00:00
2013-03-23 20:50:35 +00:00
StartNewLevel ( Next_level_num ) ;
2006-03-20 17:12:09 +00:00
}
}
void DoPlayerDead ( )
{
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 0 ) ;
2006-03-20 17:12:09 +00:00
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 * playerobj = & Objects [ Players [ Player_num ] . objnum ] ;
//nm_messagebox( "You're Dead!", 1, "Continue", "Not a real game, though." );
2012-04-16 06:42:34 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 1 ) ;
2006-03-20 17:12:09 +00:00
load_level ( " gamesave.lvl " ) ;
2012-04-15 13:32:48 +00:00
init_player_stats_new_ship ( Player_num ) ;
2006-03-20 17:12:09 +00:00
playerobj - > flags & = ~ OF_SHOULD_BE_DEAD ;
StartLevel ( 0 ) ;
return ;
}
# endif
if ( Game_mode & GM_MULTI )
{
multi_do_death ( Players [ Player_num ] . objnum ) ;
}
else
{ //Note link to above else!
Players [ Player_num ] . lives - - ;
if ( Players [ Player_num ] . lives = = 0 )
2010-06-14 08:13:16 +00:00
{
2006-03-20 17:12:09 +00:00
DoGameOver ( ) ;
return ;
}
}
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
if ( Control_center_destroyed ) {
//clear out stuff so no bonus
Players [ Player_num ] . hostages_on_board = 0 ;
Players [ Player_num ] . energy = 0 ;
Players [ Player_num ] . shields = 0 ;
2009-11-24 09:48:53 +00:00
Players [ Player_num ] . connected = CONNECT_DIED_IN_MINE ;
2006-03-20 17:12:09 +00:00
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_DIED_IN_MINE ) ; // Give them some indication of what happened
2006-03-20 17:12:09 +00:00
if ( Current_level_num < 0 ) {
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( SECRETB_FILENAME , 0 ) )
2006-03-20 17:12:09 +00:00
{
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_RETURN ) ;
2013-12-10 17:13:32 +00:00
state_restore_all ( 1 , 2 , SECRETB_FILENAME , 0 ) ; // 2 means you died
2006-03-20 17:12:09 +00:00
set_pos_from_return_segment ( ) ;
Players [ Player_num ] . lives - - ; // re-lose the life, Players[Player_num].lives got written over in restore.
} else {
2008-11-26 01:19:26 +00:00
if ( Entered_from_level = = Last_level )
DoEndGame ( ) ;
else {
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_ADVANCE ) ;
2013-03-23 20:50:35 +00:00
StartNewLevel ( Entered_from_level + 1 ) ;
2012-04-15 13:32:48 +00:00
init_player_stats_new_ship ( Player_num ) ; // New, MK, 05/29/96!, fix bug with dying in secret level, advance to next level, keep powerups!
2008-11-26 01:19:26 +00:00
}
2006-03-20 17:12:09 +00:00
}
} else {
AdvanceLevel ( 0 ) ; //if finished, go on to next level
2012-04-15 13:32:48 +00:00
init_player_stats_new_ship ( Player_num ) ;
2007-04-01 02:14:38 +00:00
last_drawn_cockpit = - 1 ;
2006-03-20 17:12:09 +00:00
}
} else if ( Current_level_num < 0 ) {
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( SECRETB_FILENAME , 0 ) )
2006-03-20 17:12:09 +00:00
{
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_RETURN ) ;
2006-03-20 17:12:09 +00:00
if ( ! Control_center_destroyed )
2011-02-09 11:58:32 +00:00
state_save_all ( 2 , SECRETC_FILENAME , 0 ) ;
2013-12-10 17:13:32 +00:00
state_restore_all ( 1 , 2 , SECRETB_FILENAME , 0 ) ;
2006-03-20 17:12:09 +00:00
set_pos_from_return_segment ( ) ;
Players [ Player_num ] . lives - - ; // re-lose the life, Players[Player_num].lives got written over in restore.
} else {
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_DIED_IN_MINE ) ; // Give them some indication of what happened
2008-11-26 01:19:26 +00:00
if ( Entered_from_level = = Last_level )
DoEndGame ( ) ;
else {
2010-07-27 11:41:43 +00:00
do_screen_message ( TXT_SECRET_ADVANCE ) ;
2013-03-23 20:50:35 +00:00
StartNewLevel ( Entered_from_level + 1 ) ;
2012-04-15 13:32:48 +00:00
init_player_stats_new_ship ( Player_num ) ; // New, MK, 05/29/96!, fix bug with dying in secret level, advance to next level, keep powerups!
2008-11-26 01:19:26 +00:00
}
2006-03-20 17:12:09 +00:00
}
} else {
2012-04-15 13:32:48 +00:00
init_player_stats_new_ship ( Player_num ) ;
2006-03-20 17:12:09 +00:00
StartLevel ( 1 ) ;
}
digi_sync_sounds ( ) ;
2010-06-27 11:28:26 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 1 ) ;
2010-07-04 13:12:08 +00:00
reset_time ( ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//called when the player is starting a new level for normal game mode and restore state
// secret_flag set if came from a secret level
void StartNewLevelSub ( int level_num , int page_in_textures , int secret_flag )
{
if ( ! ( Game_mode & GM_MULTI ) ) {
2007-04-01 02:14:38 +00:00
last_drawn_cockpit = - 1 ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
secret_flag = 0 ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
BigWindowSwitch = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_PAUSED )
Newdemo_state = ND_STATE_RECORDING ;
if ( Newdemo_state = = ND_STATE_RECORDING ) {
newdemo_set_new_level ( level_num ) ;
2008-10-16 17:27:02 +00:00
newdemo_record_start_frame ( FrameTime ) ;
2006-03-20 17:12:09 +00:00
}
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
Viewer = & Objects [ Players [ Player_num ] . objnum ] ;
Assert ( N_players < = NumNetPlayerPositions ) ;
//If this assert fails, there's not enough start positions
if ( Game_mode & GM_NETWORK )
{
2009-04-09 07:41:30 +00:00
if ( multi_level_sync ( ) ) // After calling this, Player_num is set
2010-06-29 21:14:30 +00:00
{
songs_play_song ( SONG_TITLE , 1 ) ; // level song already plays but we fail to start level...
2006-03-20 17:12:09 +00:00
return ;
2010-06-29 21:14:30 +00:00
}
2006-03-20 17:12:09 +00:00
}
HUD_clear_messages ( ) ;
automap_clear_visited ( ) ;
init_player_stats_level ( secret_flag ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
gr_use_palette_table ( " palette.256 " ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2007-05-10 08:53:35 +00:00
load_palette ( Current_level_palette , 0 , 1 ) ;
2013-03-03 01:03:33 +00:00
# endif
2007-05-10 08:53:35 +00:00
gr_palette_load ( gr_palette ) ;
2006-03-20 17:12:09 +00:00
if ( ( Game_mode & GM_MULTI_COOP ) & & Network_rejoined )
{
int i ;
for ( i = 0 ; i < N_players ; i + + )
Players [ i ] . flags | = Netgame . player_flags [ i ] ;
}
if ( Game_mode & GM_MULTI )
{
multi_prep_level ( ) ; // Removes robots from level if necessary
}
gameseq_remove_unused_players ( ) ;
Game_suspended = 0 ;
Control_center_destroyed = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
set_screen_mode ( SCREEN_GAME ) ;
2013-03-03 01:03:33 +00:00
# endif
2007-04-04 17:18:17 +00:00
2006-03-20 17:12:09 +00:00
init_cockpit ( ) ;
init_robots_for_level ( ) ;
init_ai_objects ( ) ;
init_morphs ( ) ;
init_all_matcens ( ) ;
reset_palette_add ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-11-10 03:31:22 +00:00
init_smega_detonates ( ) ;
2006-03-20 17:12:09 +00:00
init_thief_for_level ( ) ;
init_stuck_objects ( ) ;
if ( ! ( Game_mode & GM_MULTI ) )
filter_objects_from_level ( ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2011-02-14 21:27:07 +00:00
if ( ! ( Game_mode & GM_MULTI ) & & ! cheats . enabled )
2006-03-20 17:12:09 +00:00
set_highest_level ( Current_level_num ) ;
else
read_player_file ( ) ; //get window sizes
reset_special_effects ( ) ;
# ifdef OGL
gr_remap_mono_fonts ( ) ;
ogl_cache_level_textures ( ) ;
# endif
if ( Network_rejoined = = 1 )
{
Network_rejoined = 0 ;
StartLevel ( 1 ) ;
}
else
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 ;
2010-06-14 08:13:16 +00:00
2010-02-05 02:31:36 +00:00
// Initialise for palette_restore()
// Also takes care of nm_draw_background() possibly being called
if ( ! ( ( Game_mode & GM_MULTI ) & & ( Newdemo_state ! = ND_STATE_PLAYBACK ) ) )
full_palette_save ( ) ;
2010-06-14 08:13:16 +00:00
2010-02-08 05:34:43 +00:00
if ( ! Game_wind )
game ( ) ;
2006-03-20 17:12:09 +00:00
}
2014-11-26 04:02:08 +00:00
void ( bash_to_shield ) ( const vobjptr_t i )
2006-03-20 17:12:09 +00:00
{
2014-11-26 04:02:08 +00:00
enum powerup_type_t type = ( enum powerup_type_t ) get_powerup_id ( i ) ;
2006-03-20 17:12:09 +00:00
PowerupsInMine [ type ] = MaxPowerupsAllowed [ type ] = 0 ;
2014-11-26 04:02:08 +00:00
set_powerup_id ( i , POW_SHIELD_BOOST ) ;
i - > rtype . vclip_info . vclip_num = Powerup_info [ get_powerup_id ( i ) ] . vclip_num ;
i - > rtype . vclip_info . frametime = Vclip [ i - > rtype . vclip_info . vclip_num ] . frame_time ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-09-22 22:26:27 +00:00
static void filter_objects_from_level ( )
2006-03-20 17:12:09 +00:00
{
2014-10-12 23:05:46 +00:00
range_for ( auto i , highest_valid ( Objects ) )
2006-03-20 17:12:09 +00:00
{
2014-11-26 04:02:08 +00:00
const auto objp = vobjptridx ( i ) ;
if ( objp - > type = = OBJ_POWERUP )
if ( objp - > id = = POW_FLAG_RED | | objp - > id = = POW_FLAG_BLUE )
bash_to_shield ( objp ) ;
2006-03-20 17:12:09 +00:00
}
}
2012-11-11 22:12:51 +00:00
struct intro_movie_t {
2006-03-20 17:12:09 +00:00
int level_num ;
2012-11-11 22:12:51 +00:00
char movie_name [ 4 ] ;
} ;
static const intro_movie_t intro_movie [ ] = {
{ 1 , " pla " } ,
2006-03-20 17:12:09 +00:00
{ 5 , " plb " } ,
{ 9 , " plc " } ,
{ 13 , " pld " } ,
{ 17 , " ple " } ,
{ 21 , " plf " } ,
{ 24 , " plg " } } ;
# define NUM_INTRO_MOVIES (sizeof(intro_movie) / sizeof(*intro_movie))
2013-10-27 22:00:14 +00:00
static void ShowLevelIntro ( int level_num )
2006-03-20 17:12:09 +00:00
{
//if shareware, show a briefing?
if ( ! ( Game_mode & GM_MULTI ) ) {
int i ;
2013-01-06 21:03:57 +00:00
palette_array_t save_pal ;
2006-03-20 17:12:09 +00:00
2013-01-06 21:11:53 +00:00
save_pal = gr_palette ;
2006-03-20 17:12:09 +00:00
if ( PLAYING_BUILTIN_MISSION ) {
if ( is_SHAREWARE | | is_MAC_SHARE )
{
if ( level_num = = 1 )
2010-03-25 23:37:19 +00:00
do_briefing_screens ( Briefing_text_filename , 1 ) ;
2006-03-20 17:12:09 +00:00
}
else if ( is_D2_OEM )
{
if ( level_num = = 1 & & ! intro_played )
2010-03-25 23:37:19 +00:00
do_briefing_screens ( Briefing_text_filename , 1 ) ;
2006-03-20 17:12:09 +00:00
}
else // full version
{
for ( i = 0 ; i < NUM_INTRO_MOVIES ; i + + )
{
if ( intro_movie [ i ] . level_num = = level_num )
{
Screen_mode = - 1 ;
2013-10-27 21:01:04 +00:00
PlayMovie ( NULL , intro_movie [ i ] . movie_name , MOVIE_REQUIRED ) ;
2006-03-20 17:12:09 +00:00
break ;
}
}
2010-03-25 23:37:19 +00:00
do_briefing_screens ( Briefing_text_filename , level_num ) ;
2006-03-20 17:12:09 +00:00
}
}
2010-03-25 23:37:19 +00:00
else //not the built-in mission (maybe d1, too). check for add-on briefing
{
do_briefing_screens ( Briefing_text_filename , level_num ) ;
2006-03-20 17:12:09 +00:00
}
2013-01-06 21:11:53 +00:00
gr_palette = save_pal ;
2006-03-20 17:12:09 +00:00
}
}
// ---------------------------------------------------------------------------
// If starting a level which appears in the Secret_level_table, then set First_secret_visit.
// Reason: On this level, if player goes to a secret level, he will be going to a different
// secret level than he's ever been to before.
// Sets the global First_secret_visit if necessary. Otherwise leaves it unchanged.
2013-10-27 22:00:14 +00:00
static void maybe_set_first_secret_visit ( int level_num )
2006-03-20 17:12:09 +00:00
{
int i ;
for ( i = 0 ; i < N_secret_levels ; i + + ) {
if ( Secret_level_table [ i ] = = level_num ) {
First_secret_visit = 1 ;
}
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//called when the player is starting a new level for normal game model
// secret_flag if came from a secret level
2013-03-23 20:50:35 +00:00
void StartNewLevel ( int level_num )
2006-03-20 17:12:09 +00:00
{
2010-03-27 03:24:14 +00:00
hide_menus ( ) ;
2010-06-14 08:13:16 +00:00
2010-12-22 00:17:59 +00:00
GameTime64 = 0 ;
2006-03-20 17:12:09 +00:00
ThisLevelTime = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( ! ( Game_mode & GM_MULTI ) ) {
do_briefing_screens ( Briefing_text_filename , level_num ) ;
}
# elif defined(DXX_BUILD_DESCENT_II)
2013-03-23 20:50:35 +00:00
if ( level_num > 0 ) {
2006-03-20 17:12:09 +00:00
maybe_set_first_secret_visit ( level_num ) ;
}
ShowLevelIntro ( level_num ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2013-03-23 20:50:35 +00:00
StartNewLevelSub ( level_num , 1 , 0 ) ;
2006-03-20 17:12:09 +00:00
}
//initialize the player object position & orientation (at start of game, or new ship)
2013-09-22 22:26:27 +00:00
static void InitPlayerPosition ( int random_flag )
2006-03-20 17:12:09 +00:00
{
int NewPlayer = 0 ;
if ( ! ( ( Game_mode & GM_MULTI ) & & ! ( Game_mode & GM_MULTI_COOP ) ) ) // If not deathmatch
NewPlayer = Player_num ;
else if ( random_flag = = 1 )
{
2014-09-20 23:47:27 +00:00
int i ;
uint_fast32_t trys = 0 ;
2006-03-20 17:12:09 +00:00
fix closest_dist = 0x7ffffff , dist ;
2011-02-02 22:51:34 +00:00
timer_update ( ) ;
d_srand ( ( fix ) timer_query ( ) ) ;
2006-03-20 17:12:09 +00:00
do {
trys + + ;
NewPlayer = d_rand ( ) % NumNetPlayerPositions ;
closest_dist = 0x7fffffff ;
2010-06-14 08:13:16 +00:00
2006-03-20 17:12:09 +00:00
for ( i = 0 ; i < N_players ; i + + ) {
if ( ( i ! = Player_num ) & & ( Objects [ Players [ i ] . objnum ] . type = = OBJ_PLAYER ) ) {
2014-10-22 02:46:03 +00:00
dist = find_connected_distance ( Objects [ Players [ i ] . objnum ] . pos , Objects [ Players [ i ] . objnum ] . segnum , Player_init [ NewPlayer ] . pos , Player_init [ NewPlayer ] . segnum , 15 , WID_FLY_FLAG ) ; // Used to be 5, search up to 15 segments
2006-03-20 17:12:09 +00:00
if ( ( dist < closest_dist ) & & ( dist > = 0 ) ) {
closest_dist = dist ;
}
}
}
2012-04-15 13:32:48 +00:00
} while ( ( closest_dist < i2f ( 15 * 20 ) ) & & ( trys < MAX_PLAYERS * 2 ) ) ;
2006-03-20 17:12:09 +00:00
}
else {
2011-02-02 22:51:34 +00:00
// If deathmatch and not random, positions were already determined by sync packet
reset_player_object ( ) ;
reset_cruise ( ) ;
return ;
2006-03-20 17:12:09 +00:00
}
Assert ( NewPlayer > = 0 ) ;
Assert ( NewPlayer < NumNetPlayerPositions ) ;
ConsoleObject - > pos = Player_init [ NewPlayer ] . pos ;
ConsoleObject - > orient = Player_init [ NewPlayer ] . orient ;
2013-02-21 00:20:26 +00:00
obj_relink ( ConsoleObject - Objects , Player_init [ NewPlayer ] . segnum ) ;
2006-03-20 17:12:09 +00:00
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?
2014-10-02 03:02:34 +00:00
void copy_defaults_to_robot ( const vobjptr_t objp )
2006-03-20 17:12:09 +00:00
{
robot_info * robptr ;
int objid ;
Assert ( objp - > type = = OBJ_ROBOT ) ;
2013-11-10 03:31:22 +00:00
objid = get_robot_id ( objp ) ;
2006-03-20 17:12:09 +00:00
Assert ( objid < N_robot_types ) ;
robptr = & Robot_info [ objid ] ;
// Boost shield for Thief and Buddy based on level.
objp - > shields = robptr - > strength ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-11-03 22:27:28 +00:00
if ( ( robot_is_thief ( robptr ) ) | | ( robot_is_companion ( robptr ) ) ) {
2006-03-20 17:12:09 +00:00
objp - > shields = ( objp - > shields * ( abs ( Current_level_num ) + 7 ) ) / 8 ;
2013-11-03 22:27:28 +00:00
if ( robot_is_companion ( robptr ) ) {
2006-03-20 17:12:09 +00:00
// Now, scale guide-bot hits by skill level
switch ( Difficulty_level ) {
case 0 : objp - > shields = i2f ( 20000 ) ; break ; // Trainee, basically unkillable
case 1 : objp - > shields * = 3 ; break ; // Rookie, pretty dang hard
case 2 : objp - > shields * = 2 ; break ; // Hotshot, a bit tough
default : break ;
}
}
} else if ( robptr - > boss_flag ) // MK, 01/16/95, make boss shields lower on lower diff levels.
objp - > shields = objp - > shields / ( NDL + 3 ) * ( Difficulty_level + 4 ) ;
// Additional wimpification of bosses at Trainee
if ( ( robptr - > boss_flag ) & & ( Difficulty_level = = 0 ) )
objp - > shields / = 2 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
// -----------------------------------------------------------------------------------------------------
// 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.
2013-11-10 03:31:22 +00:00
static void copy_defaults_to_robot_all ( void )
2006-03-20 17:12:09 +00:00
{
2014-10-12 23:05:46 +00:00
range_for ( auto i , highest_valid ( Objects ) )
2006-03-20 17:12:09 +00:00
if ( Objects [ i ] . type = = OBJ_ROBOT )
copy_defaults_to_robot ( & Objects [ i ] ) ;
}
// -----------------------------------------------------------------------------------------------------
//called when the player is starting a level (new game or new ship)
2013-09-22 22:26:27 +00:00
static void StartLevel ( int random_flag )
2006-03-20 17:12:09 +00:00
{
Assert ( ! Player_is_dead ) ;
InitPlayerPosition ( random_flag ) ;
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 ( ) ;
2009-03-20 12:10:38 +00:00
multi_do_protocol_frame ( 1 , 1 ) ;
2012-05-24 10:46:35 +00:00
}
else // in Singleplayer, after we died ...
{
disable_matcens ( ) ; // ... disable matcens and ...
clear_transient_objects ( 0 ) ; // ... clear all transient objects.
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2012-05-24 10:46:35 +00:00
clear_stuck_objects ( ) ; // and stuck ones.
2013-03-03 01:03:33 +00:00
# endif
2012-05-24 10:46:35 +00:00
}
2006-03-20 17:12:09 +00:00
ai_reset_all_paths ( ) ;
ai_init_boss_for_ship ( ) ;
reset_rear_view ( ) ;
Auto_fire_fusion_cannon_time = 0 ;
Fusion_charge = 0 ;
}