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 .
*/
/*
*
2007-12-29 14:18:49 +00:00
* Multiplayer code for network play .
2006-03-20 17:12:09 +00:00
*
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <ctype.h>
# include "u_mem.h"
# include "strutil.h"
# include "game.h"
# include "multi.h"
2013-12-16 23:44:34 +00:00
# include "multiinternal.h"
2006-03-20 17:12:09 +00:00
# include "object.h"
# include "laser.h"
# include "fuelcen.h"
# include "scores.h"
# include "gauges.h"
2013-12-26 04:18:28 +00:00
# include "gameseg.h"
2006-03-20 17:12:09 +00:00
# include "collide.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "fireball.h"
# include "newmenu.h"
2008-04-06 20:23:28 +00:00
# include "console.h"
2006-03-20 17:12:09 +00:00
# include "wall.h"
# include "cntrlcen.h"
2013-03-03 01:03:33 +00:00
# include "powerup.h"
2006-03-20 17:12:09 +00:00
# include "polyobj.h"
# include "bm.h"
# include "endlevel.h"
# include "key.h"
# include "playsave.h"
# include "timer.h"
# include "digi.h"
# include "sounds.h"
# include "kconfig.h"
# include "newdemo.h"
# include "text.h"
# include "kmatrix.h"
# include "multibot.h"
# include "gameseq.h"
# include "physics.h"
# include "config.h"
# include "ai.h"
# include "switch.h"
# include "textures.h"
2014-07-03 01:47:29 +00:00
# include "byteutil.h"
2006-03-20 17:12:09 +00:00
# include "sounds.h"
# include "args.h"
# include "effects.h"
2006-10-02 13:29:04 +00:00
# include "iff.h"
2011-02-09 11:58:32 +00:00
# include "state.h"
2012-06-10 09:26:29 +00:00
# include "automap.h"
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
# include "net_udp.h"
# endif
2006-03-20 17:12:09 +00:00
2014-08-16 18:16:59 +00:00
# include "partial_range.h"
2013-09-22 22:26:27 +00:00
static void multi_reset_object_texture ( object * objp ) ;
static void multi_add_lifetime_killed ( ) ;
static void multi_send_heartbeat ( ) ;
2014-09-21 22:10:12 +00:00
static void multi_powcap_adjust_remote_cap ( const playernum_t pnum ) ;
2013-09-22 22:26:27 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-08-16 18:16:59 +00:00
static std : : size_t find_goal_texture ( ubyte t ) ;
static tmap_info & find_required_goal_texture ( ubyte t ) ;
2014-09-21 22:10:12 +00:00
static void multi_do_capture_bonus ( const playernum_t pnum , const ubyte * buf ) ;
static void multi_do_orb_bonus ( const playernum_t pnum , const ubyte * buf ) ;
2013-12-29 04:28:07 +00:00
static void multi_send_drop_flag ( objnum_t objnum , int seed ) ;
2013-09-22 22:26:27 +00:00
# endif
static void multi_send_ranking ( ) ;
2014-09-21 22:10:12 +00:00
static void multi_new_bounty_target ( playernum_t pnum ) ;
2013-09-22 22:26:27 +00:00
static void multi_save_game ( ubyte slot , uint id , char * desc ) ;
static void multi_restore_game ( ubyte slot , uint id ) ;
static void multi_send_gmode_update ( ) ;
2013-12-16 22:28:15 +00:00
static void multi_send_quit ( ) ;
2014-09-21 22:10:21 +00:00
static void multi_process_data ( playernum_t pnum , const ubyte * dat , uint_fast32_t type ) ;
2006-03-20 17:12:09 +00:00
2013-08-11 19:59:20 +00:00
static inline void vm_angvec_zero ( vms_angvec * v )
{
( v ) - > p = ( v ) - > b = ( v ) - > h = 0 ;
}
2006-03-20 17:12:09 +00:00
//
// Global variables
//
2009-04-09 07:41:30 +00:00
int multi_protocol = 0 ; // set and determinate used protocol
2012-04-27 00:09:48 +00:00
int imulti_new_game = 0 ; // to prep stuff for level only when starting new game
2009-04-09 07:41:30 +00:00
2006-03-20 17:12:09 +00:00
//do we draw the kill list on the HUD?
int Show_kill_list = 1 ;
int Show_reticle_name = 1 ;
fix Show_kill_list_timer = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 23:03:40 +00:00
int PhallicLimit = 0 ;
int PhallicMan = - 1 ;
int SoundHacked = 0 ;
digi_sound ReversedSound ;
2006-03-20 17:12:09 +00:00
char Multi_is_guided = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2011-05-25 13:25:13 +00:00
int Bounty_target = 0 ;
2011-05-15 09:59:12 +00:00
2006-03-20 17:12:09 +00:00
2013-12-13 21:47:46 +00:00
msgsend_state_t multi_sending_message [ MAX_PLAYERS ] ;
2006-03-20 17:12:09 +00:00
int multi_defining_message = 0 ;
int multi_message_index = 0 ;
2013-03-30 19:41:33 +00:00
ubyte multibuf [ MAX_MULTI_MESSAGE_LEN + 4 ] ; // This is where multiplayer message are built
2006-03-20 17:12:09 +00:00
2013-07-20 17:09:08 +00:00
static short remote_to_local [ MAX_PLAYERS ] [ MAX_OBJECTS ] ; // Remote object number for each local object
static short local_to_remote [ MAX_OBJECTS ] ;
2006-03-20 17:12:09 +00:00
sbyte object_owner [ MAX_OBJECTS ] ; // Who created each object in my universe, -1 = loaded at start
2013-12-29 04:28:07 +00:00
objnum_t Net_create_objnums [ MAX_NET_CREATE_OBJECTS ] ; // For tracking object creation that will be sent to remote
2006-03-20 17:12:09 +00:00
int Net_create_loc = 0 ; // pointer into previous array
2009-03-20 12:10:38 +00:00
int Network_status = 0 ;
2006-03-20 17:12:09 +00:00
char Network_message [ MAX_MESSAGE_LEN ] ;
int Network_message_reciever = - 1 ;
2012-04-15 13:32:48 +00:00
int sorted_kills [ MAX_PLAYERS ] ;
2014-07-04 03:54:18 +00:00
array < array < short , MAX_PLAYERS > , MAX_PLAYERS > kill_matrix ;
2006-03-20 17:12:09 +00:00
int multi_goto_secret = 0 ;
short team_kills [ 2 ] ;
int multi_quit_game = 0 ;
2013-06-08 22:24:17 +00:00
const char GMNames [ MULTI_GAME_TYPE_COUNT ] [ MULTI_GAME_NAME_LENGTH ] = {
" Anarchy " ,
" Team Anarchy " ,
" Robo Anarchy " ,
" Cooperative " ,
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
" Unknown " ,
" Unknown " ,
" Unknown " ,
# elif defined(DXX_BUILD_DESCENT_II)
2013-06-08 22:24:17 +00:00
" Capture the Flag " ,
" Hoard " ,
" Team Hoard " ,
2013-03-03 01:03:33 +00:00
# endif
2013-06-08 22:24:17 +00:00
" Bounty "
} ;
const char GMNamesShrt [ MULTI_GAME_TYPE_COUNT ] [ 8 ] = {
" ANRCHY " ,
" TEAM " ,
" ROBO " ,
" COOP " ,
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
" UNKNOWN " ,
" UNKNOWN " ,
" UNKNOWN " ,
# elif defined(DXX_BUILD_DESCENT_II)
2013-06-08 22:24:17 +00:00
" FLAG " ,
" HOARD " ,
" TMHOARD " ,
2013-03-03 01:03:33 +00:00
# endif
2013-06-08 22:24:17 +00:00
" BOUNTY "
} ;
2006-03-20 17:12:09 +00:00
2009-11-24 09:48:53 +00:00
// For rejoin object syncing (used here and all protocols - globally)
2009-03-20 12:10:38 +00:00
2009-04-09 07:41:30 +00:00
int Network_send_objects = 0 ; // Are we in the process of sending objects to a player?
2009-11-24 09:48:53 +00:00
int Network_send_object_mode = 0 ; // What type of objects are we sending, static or dynamic?
2009-04-09 07:41:30 +00:00
int Network_send_objnum = - 1 ; // What object are we sending next?
2009-03-20 12:10:38 +00:00
int Network_rejoined = 0 ; // Did WE rejoin this game?
2009-11-24 09:48:53 +00:00
int Network_sending_extras = 0 ;
2010-11-22 21:44:03 +00:00
int VerifyPlayerJoined = - 1 ; // Player (num) to enter game before any ingame/extra stuff is being sent
2009-11-24 09:48:53 +00:00
int Player_joining_extras = - 1 ; // This is so we know who to send 'latecomer' packets to.
int Network_player_added = 0 ; // Is this a new player or a returning player?
2009-03-20 12:10:38 +00:00
ushort my_segments_checksum = 0 ;
2006-03-20 17:12:09 +00:00
netgame_info Netgame ;
2012-04-15 13:32:48 +00:00
bitmap_index multi_player_textures [ MAX_PLAYERS ] [ N_PLAYER_SHIP_TEXTURES ] ;
2006-03-20 17:12:09 +00:00
2009-11-24 09:48:53 +00:00
// Globals for protocol-bound Refuse-functions
char RefuseThisPlayer = 0 , WaitForRefuseAnswer = 0 , RefuseTeam , RefusePlayerName [ 12 ] ;
2010-12-10 23:18:17 +00:00
fix64 RefuseTimeLimit = 0 ;
2009-11-24 09:48:53 +00:00
2013-06-09 21:28:55 +00:00
static const int message_length [ ] = {
# define define_message_length(NAME,SIZE) (SIZE),
2013-12-17 22:05:44 +00:00
for_each_multiplayer_command ( define_message_length )
2006-03-20 17:12:09 +00:00
} ;
2014-07-12 03:30:35 +00:00
array < uint8_t , MAX_POWERUP_TYPES > PowerupsInMine , MaxPowerupsAllowed ;
2006-03-20 17:12:09 +00:00
2013-11-28 02:08:54 +00:00
const char RankStrings [ 10 ] [ 14 ] = { " (unpatched) " , " Cadet " , " Ensign " , " Lieutenant " , " Lt.Commander " ,
2009-04-09 07:41:30 +00:00
" Commander " , " Captain " , " Vice Admiral " , " Admiral " , " Demigod " } ;
2013-11-28 02:09:30 +00:00
const char multi_allow_powerup_text [ MULTI_ALLOW_POWERUP_MAX ] [ MULTI_ALLOW_POWERUP_TEXT_LENGTH ] =
2013-06-22 02:26:08 +00:00
{
# define define_netflag_string(NAME,STR) STR,
for_each_netflag_value ( define_netflag_string )
} ;
2009-03-20 12:10:38 +00:00
2009-04-09 07:41:30 +00:00
int GetMyNetRanking ( )
{
int rank , eff ;
if ( PlayerCfg . NetlifeKills + PlayerCfg . NetlifeKilled = = 0 )
return ( 1 ) ;
rank = ( int ) ( ( ( float ) PlayerCfg . NetlifeKills / 3000.0 ) * 8.0 ) ;
eff = ( int ) ( ( float ) ( ( float ) PlayerCfg . NetlifeKills / ( ( float ) PlayerCfg . NetlifeKilled + ( float ) PlayerCfg . NetlifeKills ) ) * 100.0 ) ;
if ( rank > 8 )
rank = 8 ;
if ( eff < 0 )
eff = 0 ;
if ( eff < 60 )
rank - = ( ( 59 - eff ) / 10 ) ;
if ( rank < 0 )
rank = 0 ;
if ( rank > 8 )
rank = 8 ;
return ( rank + 1 ) ;
}
2009-11-24 09:48:53 +00:00
void ClipRank ( ubyte * rank )
{
// This function insures no crashes when dealing with D2 1.0
if ( * rank > 9 )
* rank = 0 ;
}
2006-03-20 17:12:09 +00:00
//
// Functions that replace what used to be macros
//
2013-12-29 04:28:07 +00:00
objnum_t objnum_remote_to_local ( int remote_objnum , int owner )
2006-03-20 17:12:09 +00:00
{
// Map a remote object number from owner to a local object number
if ( ( owner > = N_players ) | | ( owner < - 1 ) ) {
Int3 ( ) ; // Illegal!
return ( remote_objnum ) ;
}
if ( owner = = - 1 )
return ( remote_objnum ) ;
if ( ( remote_objnum < 0 ) | | ( remote_objnum > = MAX_OBJECTS ) )
2013-12-29 04:28:07 +00:00
return ( object_none ) ;
2006-03-20 17:12:09 +00:00
2013-12-29 04:28:07 +00:00
objnum_t result = remote_to_local [ owner ] [ remote_objnum ] ;
2006-03-20 17:12:09 +00:00
return ( result ) ;
}
2014-09-13 23:45:13 +00:00
owned_remote_objnum objnum_local_to_remote ( objnum_t local_objnum )
2006-03-20 17:12:09 +00:00
{
// Map a local object number to a remote + owner
if ( ( local_objnum < 0 ) | | ( local_objnum > Highest_object_index ) ) {
2014-09-13 23:45:13 +00:00
return { - 1 , - 1 } ;
2006-03-20 17:12:09 +00:00
}
2014-09-13 23:45:13 +00:00
auto owner = object_owner [ local_objnum ] ;
if ( owner = = - 1 )
return { owner , local_objnum } ;
if ( owner > = N_players | | owner < - 1 )
throw std : : runtime_error ( " illegal object owner " ) ;
auto result = local_to_remote [ local_objnum ] ;
2006-03-20 17:12:09 +00:00
if ( result < 0 )
2014-09-13 23:45:13 +00:00
throw std : : runtime_error ( " illegal object remote number " ) ; // See Rob, object has no remote number!
return { owner , result } ;
}
2006-03-20 17:12:09 +00:00
2014-09-13 23:45:13 +00:00
short objnum_local_to_remote ( objnum_t local_objnum , sbyte * owner )
{
auto r = objnum_local_to_remote ( local_objnum ) ;
* owner = r . owner ;
return r . objnum ;
2006-03-20 17:12:09 +00:00
}
void
map_objnum_local_to_remote ( int local_objnum , int remote_objnum , int owner )
{
// Add a mapping from a network remote object number to a local one
Assert ( local_objnum > - 1 ) ;
Assert ( local_objnum < MAX_OBJECTS ) ;
Assert ( remote_objnum > - 1 ) ;
Assert ( remote_objnum < MAX_OBJECTS ) ;
Assert ( owner > - 1 ) ;
Assert ( owner ! = Player_num ) ;
object_owner [ local_objnum ] = owner ;
remote_to_local [ owner ] [ remote_objnum ] = local_objnum ;
local_to_remote [ local_objnum ] = remote_objnum ;
return ;
}
2013-12-29 04:28:07 +00:00
void map_objnum_local_to_local ( objnum_t local_objnum )
2006-03-20 17:12:09 +00:00
{
// Add a mapping for our locally created objects
Assert ( local_objnum > - 1 ) ;
Assert ( local_objnum < MAX_OBJECTS ) ;
object_owner [ local_objnum ] = Player_num ;
remote_to_local [ Player_num ] [ local_objnum ] = local_objnum ;
local_to_remote [ local_objnum ] = local_objnum ;
return ;
}
void reset_network_objects ( )
{
memset ( local_to_remote , - 1 , MAX_OBJECTS * sizeof ( short ) ) ;
2012-04-15 13:32:48 +00:00
memset ( remote_to_local , - 1 , MAX_PLAYERS * MAX_OBJECTS * sizeof ( short ) ) ;
2006-03-20 17:12:09 +00:00
memset ( object_owner , - 1 , MAX_OBJECTS ) ;
}
2013-12-29 04:28:07 +00:00
int multi_objnum_is_past ( objnum_t objnum )
2009-04-09 07:41:30 +00:00
{
switch ( multi_protocol )
{
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
return net_udp_objnum_is_past ( objnum ) ;
2009-04-09 07:41:30 +00:00
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
2009-11-24 09:48:53 +00:00
Error ( " Protocol handling missing in multi_objnum_is_past \n " ) ;
2009-04-09 07:41:30 +00:00
break ;
}
}
2006-03-20 17:12:09 +00:00
//
// Part 1 : functions whose main purpose in life is to divert the flow
2007-12-29 14:18:49 +00:00
// of execution to either network specific code based
2006-03-20 17:12:09 +00:00
// on the curretn Game_mode value.
//
2012-05-14 17:20:18 +00:00
// Show a score list to end of net players
void multi_endlevel_score ( void )
2006-03-20 17:12:09 +00:00
{
2012-05-14 17:20:18 +00:00
int i , old_connect = 0 , game_wind_visible = 0 ;
2006-03-20 17:12:09 +00:00
2012-05-14 17:20:18 +00:00
// If there still is a Game_wind and it's suspended (usually both shoudl be the case), bring it up again so host can still take actions of the game
if ( Game_wind )
{
if ( ! window_is_visible ( Game_wind ) )
{
game_wind_visible = 1 ;
window_set_visible ( Game_wind , 1 ) ;
}
}
2009-02-08 12:49:27 +00:00
// Save connect state and change to new connect state
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_NETWORK )
{
2009-02-08 12:49:27 +00:00
old_connect = Players [ Player_num ] . connected ;
2009-11-24 09:48:53 +00:00
if ( Players [ Player_num ] . connected ! = CONNECT_DIED_IN_MINE )
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . connected = CONNECT_END_MENU ;
Network_status = NETSTAT_ENDLEVEL ;
}
// Do the actual screen we wish to show
2011-09-13 23:15:32 +00:00
kmatrix_view ( Game_mode & GM_NETWORK ) ;
2006-03-20 17:12:09 +00:00
2009-02-08 12:49:27 +00:00
// Restore connect state
if ( Game_mode & GM_NETWORK )
{
Players [ Player_num ] . connected = old_connect ;
}
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_MULTI_COOP )
{
2012-04-18 09:28:23 +00:00
for ( i = 0 ; i < Netgame . max_numplayers ; i + + )
2006-03-20 17:12:09 +00:00
// Reset keys
Players [ i ] . flags & = ~ ( PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY ) ;
}
2009-11-24 09:48:53 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2012-04-18 09:28:23 +00:00
for ( i = 0 ; i < Netgame . max_numplayers ; i + + )
2006-03-20 17:12:09 +00:00
Players [ i ] . flags & = ~ ( PLAYER_FLAGS_FLAG ) ; // Clear capture flag
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-09-20 23:47:27 +00:00
range_for ( auto & i , Players )
i . KillGoalCount = 0 ;
2006-03-20 17:12:09 +00:00
2014-07-12 03:30:35 +00:00
MaxPowerupsAllowed = { } ;
PowerupsInMine = { } ;
2012-05-14 17:20:18 +00:00
// hide Game_wind again if we brought it up
if ( Game_wind & & game_wind_visible )
window_set_visible ( Game_wind , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
int get_team ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
if ( Netgame . team_vector & ( 1 < < pnum ) )
return 1 ;
else
return 0 ;
}
void
multi_new_game ( void )
{
// Reset variables for a new net game
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < MAX_PLAYERS ; i + + )
2012-04-15 13:32:48 +00:00
init_player_stats_game ( i ) ;
2012-04-15 01:05:28 +00:00
2014-07-04 03:54:18 +00:00
kill_matrix = { } ; // Clear kill matrix
2006-03-20 17:12:09 +00:00
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < MAX_PLAYERS ; i + + )
2006-03-20 17:12:09 +00:00
{
sorted_kills [ i ] = i ;
2010-11-28 00:02:05 +00:00
Players [ i ] . connected = CONNECT_DISCONNECTED ;
2006-03-20 17:12:09 +00:00
Players [ i ] . net_killed_total = 0 ;
Players [ i ] . net_kills_total = 0 ;
Players [ i ] . flags = 0 ;
Players [ i ] . KillGoalCount = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ i ] = msgsend_none ;
2006-03-20 17:12:09 +00:00
}
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < MAX_ROBOTS_CONTROLLED ; i + + )
2006-03-20 17:12:09 +00:00
{
robot_controlled [ i ] = - 1 ;
robot_agitation [ i ] = 0 ;
robot_fired [ i ] = 0 ;
}
2014-07-12 03:30:35 +00:00
MaxPowerupsAllowed = { } ;
PowerupsInMine = { } ;
2012-04-15 01:05:28 +00:00
2006-03-20 17:12:09 +00:00
team_kills [ 0 ] = team_kills [ 1 ] = 0 ;
2012-04-27 00:09:48 +00:00
imulti_new_game = 1 ;
2006-03-20 17:12:09 +00:00
multi_quit_game = 0 ;
Show_kill_list = 1 ;
game_disable_cheats ( ) ;
}
2014-09-21 22:10:12 +00:00
void multi_make_player_ghost ( const playernum_t playernum )
2006-03-20 17:12:09 +00:00
{
2014-09-21 22:10:12 +00:00
if ( playernum = = Player_num | | playernum > = MAX_PLAYERS )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // Non-terminal, see Rob
return ;
}
2014-08-16 23:18:17 +00:00
auto obj = vobjptridx ( Players [ playernum ] . objnum ) ;
2006-03-20 17:12:09 +00:00
obj - > type = OBJ_GHOST ;
obj - > render_type = RT_NONE ;
obj - > movement_type = MT_NONE ;
multi_reset_player_object ( obj ) ;
2013-08-11 16:13:04 +00:00
multi_strip_robots ( playernum ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_make_ghost_player ( const playernum_t playernum )
2006-03-20 17:12:09 +00:00
{
2012-04-15 13:32:48 +00:00
if ( ( playernum = = Player_num ) | | ( playernum > = MAX_PLAYERS ) )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // Non-terminal, see rob
return ;
}
2014-08-16 23:18:17 +00:00
auto obj = vobjptridx ( Players [ playernum ] . objnum ) ;
2006-03-20 17:12:09 +00:00
obj - > type = OBJ_PLAYER ;
obj - > movement_type = MT_PHYSICS ;
multi_reset_player_object ( obj ) ;
2012-04-15 13:32:48 +00:00
if ( playernum ! = Player_num )
init_player_stats_new_ship ( playernum ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
int multi_get_kill_list ( playernum_array_t & plist )
2006-03-20 17:12:09 +00:00
{
// Returns the number of active net players and their
// sorted order of kills
int i ;
int n = 0 ;
for ( i = 0 ; i < N_players ; i + + )
//if (Players[sorted_kills[i]].connected)
plist [ n + + ] = sorted_kills [ i ] ;
if ( n = = 0 )
Int3 ( ) ; // SEE ROB OR MATT
//memcpy(plist, sorted_kills, N_players*sizeof(int));
return ( n ) ;
}
void
multi_sort_kill_list ( void )
{
// Sort the kills list each time a new kill is added
2012-04-15 13:32:48 +00:00
int kills [ MAX_PLAYERS ] ;
2006-03-20 17:12:09 +00:00
int changed = 1 ;
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < MAX_PLAYERS ; i + + )
2006-03-20 17:12:09 +00:00
{
if ( Game_mode & GM_MULTI_COOP )
kills [ i ] = Players [ i ] . score ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
else
if ( Show_kill_list = = 2 )
{
if ( Players [ i ] . net_killed_total + Players [ i ] . net_kills_total = = 0 )
kills [ i ] = - 1 ; // always draw the ones without any ratio last
else
kills [ i ] = ( int ) ( ( float ) ( ( float ) Players [ i ] . net_kills_total / ( ( float ) Players [ i ] . net_killed_total + ( float ) Players [ i ] . net_kills_total ) ) * 100.0 ) ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
else
kills [ i ] = Players [ i ] . net_kills_total ;
}
while ( changed )
{
changed = 0 ;
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < N_players - 1 ; i + + )
2006-03-20 17:12:09 +00:00
{
if ( kills [ sorted_kills [ i ] ] < kills [ sorted_kills [ i + 1 ] ] )
{
changed = sorted_kills [ i ] ;
sorted_kills [ i ] = sorted_kills [ i + 1 ] ;
sorted_kills [ i + 1 ] = changed ;
changed = 1 ;
}
}
}
}
2012-11-11 00:14:30 +00:00
char Multi_killed_yourself = 0 ;
2006-03-20 17:12:09 +00:00
2014-09-21 22:10:12 +00:00
static const char * prepare_kill_name ( const playernum_t pnum , char ( & buf ) [ ( CALLSIGN_LEN * 2 ) + 4 ] )
2014-07-05 03:32:08 +00:00
{
if ( Game_mode & GM_TEAM )
{
2014-07-05 16:48:12 +00:00
snprintf ( buf , sizeof ( buf ) , " %s (%s) " , static_cast < const char * > ( Players [ pnum ] . callsign ) , static_cast < const char * > ( Netgame . team_name [ get_team ( pnum ) ] ) ) ;
2014-07-05 03:32:08 +00:00
return buf ;
}
else
2014-07-05 16:48:12 +00:00
return static_cast < const char * > ( Players [ pnum ] . callsign ) ;
2014-07-05 03:32:08 +00:00
}
2013-12-29 04:28:07 +00:00
static void multi_compute_kill ( objnum_t killer , objnum_t killed )
2006-03-20 17:12:09 +00:00
{
// Figure out the results of a network kills and add it to the
// appropriate player's tally.
2014-09-21 22:10:12 +00:00
playernum_t killed_pnum , killer_pnum ;
int killed_type ;
int killer_type ;
2006-03-20 17:12:09 +00:00
int TheGoal ;
// Both object numbers are localized already!
if ( ( killed < 0 ) | | ( killed > Highest_object_index ) | | ( killer < 0 ) | | ( killer > Highest_object_index ) )
{
Int3 ( ) ; // See Rob, illegal value passed to compute_kill;
return ;
}
killed_type = Objects [ killed ] . type ;
killer_type = Objects [ killer ] . type ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
int killer_id = Objects [ killer ] . id ;
# endif
2006-03-20 17:12:09 +00:00
if ( ( killed_type ! = OBJ_PLAYER ) & & ( killed_type ! = OBJ_GHOST ) )
{
Int3 ( ) ; // compute_kill passed non-player object!
return ;
}
2013-10-07 23:52:33 +00:00
killed_pnum = get_player_id ( & Objects [ killed ] ) ;
2006-03-20 17:12:09 +00:00
2014-09-21 22:10:12 +00:00
Assert ( killed_pnum < N_players ) ;
2006-03-20 17:12:09 +00:00
2014-07-05 03:32:08 +00:00
char killed_buf [ ( CALLSIGN_LEN * 2 ) + 4 ] ;
const char * killed_name = prepare_kill_name ( killed_pnum , killed_buf ) ;
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_death ( killed_pnum ) ;
digi_play_sample ( SOUND_HUD_KILL , F3_0 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Control_center_destroyed )
2009-11-24 09:48:53 +00:00
Players [ killed_pnum ] . connected = CONNECT_DIED_IN_MINE ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( killer_type = = OBJ_CNTRLCEN )
{
Players [ killed_pnum ] . net_killed_total + + ;
Players [ killed_pnum ] . net_kills_total - - ;
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_kill ( killed_pnum , - 1 ) ;
if ( killed_pnum = = Player_num )
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s. " , TXT_YOU_WERE , TXT_KILLED_BY_NONPLAY ) ;
2006-03-20 17:12:09 +00:00
multi_add_lifetime_killed ( ) ;
}
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s. " , killed_name , TXT_WAS , TXT_KILLED_BY_NONPLAY ) ;
2006-03-20 17:12:09 +00:00
return ;
}
else if ( ( killer_type ! = OBJ_PLAYER ) & & ( killer_type ! = OBJ_GHOST ) )
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( killer_id = = PMINE_ID & & killer_type ! = OBJ_ROBOT )
{
if ( killed_pnum = = Player_num )
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You were killed by a mine! " ) ;
2006-03-20 17:12:09 +00:00
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s was killed by a mine! " , killed_name ) ;
2006-03-20 17:12:09 +00:00
}
else
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
{
if ( killed_pnum = = Player_num )
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s. " , TXT_YOU_WERE , TXT_KILLED_BY_ROBOT ) ;
2006-03-20 17:12:09 +00:00
multi_add_lifetime_killed ( ) ;
}
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s. " , killed_name , TXT_WAS , TXT_KILLED_BY_ROBOT ) ;
2006-03-20 17:12:09 +00:00
}
Players [ killed_pnum ] . net_killed_total + + ;
return ;
}
2013-10-07 23:52:33 +00:00
killer_pnum = get_player_id ( & Objects [ killer ] ) ;
2006-03-20 17:12:09 +00:00
2014-07-05 03:32:08 +00:00
char killer_buf [ ( CALLSIGN_LEN * 2 ) + 4 ] ;
const char * killer_name = prepare_kill_name ( killer_pnum , killer_buf ) ;
2006-03-20 17:12:09 +00:00
// Beyond this point, it was definitely a player-player kill situation
2014-09-21 22:10:12 +00:00
if ( killer_pnum > = N_players )
2006-03-20 17:12:09 +00:00
Int3 ( ) ; // See rob, tracking down bug with kill HUD messages
2014-09-21 22:10:12 +00:00
if ( killed_pnum > = N_players )
2006-03-20 17:12:09 +00:00
Int3 ( ) ; // See rob, tracking down bug with kill HUD messages
if ( killer_pnum = = killed_pnum )
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
{
if ( Game_mode & GM_TEAM )
2013-03-03 01:03:33 +00:00
{
2006-03-20 17:12:09 +00:00
team_kills [ get_team ( killed_pnum ) ] - = 1 ;
2013-03-03 01:03:33 +00:00
}
2006-03-20 17:12:09 +00:00
Players [ killed_pnum ] . net_killed_total + = 1 ;
Players [ killed_pnum ] . net_kills_total - = 1 ;
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_kill ( killed_pnum , - 1 ) ;
}
kill_matrix [ killed_pnum ] [ killed_pnum ] + = 1 ; // # of suicides
if ( killer_pnum = = Player_num )
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s! " , TXT_YOU , TXT_KILLED , TXT_YOURSELF ) ;
2006-03-20 17:12:09 +00:00
multi_add_lifetime_killed ( ) ;
}
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , killed_name , TXT_SUICIDE ) ;
2013-02-21 00:20:26 +00:00
2011-01-19 01:19:17 +00:00
/* Bounty mode needs some lovin' */
2011-05-25 13:25:13 +00:00
if ( Game_mode & GM_BOUNTY & & killed_pnum = = Bounty_target & & multi_i_am_master ( ) )
2011-01-19 01:19:17 +00:00
{
2011-05-25 13:25:13 +00:00
/* Select a random number */
2012-11-18 18:21:50 +00:00
int n = d_rand ( ) % MAX_PLAYERS ;
2011-05-25 13:25:13 +00:00
/* Make sure they're valid: Don't check against kill flags,
* just in case everyone ' s dead ! */
2012-11-18 18:21:50 +00:00
while ( ! Players [ n ] . connected )
n = d_rand ( ) % MAX_PLAYERS ;
2011-05-25 13:25:13 +00:00
/* Select new target - it will be sent later when we're done with this function */
2012-11-18 18:21:50 +00:00
multi_new_bounty_target ( n ) ;
2011-01-19 01:19:17 +00:00
}
2006-03-20 17:12:09 +00:00
}
else
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
{
if ( Game_mode & GM_TEAM )
{
if ( get_team ( killed_pnum ) = = get_team ( killer_pnum ) )
2013-01-19 15:37:42 +00:00
{
2006-03-20 17:12:09 +00:00
team_kills [ get_team ( killed_pnum ) ] - = 1 ;
2013-01-19 15:37:42 +00:00
Players [ killer_pnum ] . net_kills_total - = 1 ;
}
2006-03-20 17:12:09 +00:00
else
2013-01-19 15:37:42 +00:00
{
2006-03-20 17:12:09 +00:00
team_kills [ get_team ( killer_pnum ) ] + = 1 ;
2013-01-19 15:37:42 +00:00
Players [ killer_pnum ] . net_kills_total + = 1 ;
Players [ killer_pnum ] . KillGoalCount + = 1 ;
}
2006-03-20 17:12:09 +00:00
}
2013-01-19 15:37:42 +00:00
else if ( Game_mode & GM_BOUNTY )
2011-01-19 01:19:17 +00:00
{
/* Did the target die? Did the target get a kill? */
if ( killed_pnum = = Bounty_target | | killer_pnum = = Bounty_target )
{
/* Increment kill counts */
Players [ killer_pnum ] . net_kills_total + + ;
Players [ killer_pnum ] . KillGoalCount + + ;
/* Record the kill in a demo */
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_kill ( killer_pnum , 1 ) ;
/* If the target died, the new one is set! */
if ( killed_pnum = = Bounty_target )
multi_new_bounty_target ( killer_pnum ) ;
}
}
else
{
Players [ killer_pnum ] . net_kills_total + = 1 ;
Players [ killer_pnum ] . KillGoalCount + = 1 ;
}
if ( Newdemo_state = = ND_STATE_RECORDING & & ! ( Game_mode & GM_BOUNTY ) )
2006-03-20 17:12:09 +00:00
newdemo_record_multi_kill ( killer_pnum , 1 ) ;
}
kill_matrix [ killer_pnum ] [ killed_pnum ] + = 1 ;
Players [ killed_pnum ] . net_killed_total + = 1 ;
if ( killer_pnum = = Player_num ) {
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s! " , TXT_YOU , TXT_KILLED , killed_name ) ;
2006-03-20 17:12:09 +00:00
multi_add_lifetime_kills ( ) ;
if ( ( Game_mode & GM_MULTI_COOP ) & & ( Players [ Player_num ] . score > = 1000 ) )
add_points_to_score ( - 1000 ) ;
}
else if ( killed_pnum = = Player_num )
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s! " , killer_name , TXT_KILLED , TXT_YOU ) ;
2006-03-20 17:12:09 +00:00
multi_add_lifetime_killed ( ) ;
}
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s! " , killer_name , TXT_KILLED , killed_name ) ;
2006-03-20 17:12:09 +00:00
}
TheGoal = Netgame . KillGoal * 5 ;
if ( Netgame . KillGoal > 0 )
{
if ( Players [ killer_pnum ] . KillGoalCount > = TheGoal )
{
if ( killer_pnum = = Player_num )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You reached the kill goal! " ) ;
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . shields = i2f ( 200 ) ;
}
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has reached the kill goal! " , static_cast < const char * > ( Players [ killer_pnum ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " The control center has been destroyed! " ) ;
2006-03-20 17:12:09 +00:00
net_destroy_controlcen ( obj_find_first_of_type ( OBJ_CNTRLCEN ) ) ;
}
}
multi_sort_kill_list ( ) ;
multi_show_player_list ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Players [ killed_pnum ] . flags & = ( ~ ( PLAYER_FLAGS_HEADLIGHT_ON ) ) ; // clear the killed guys flags/headlights
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2009-03-20 12:10:38 +00:00
void multi_do_protocol_frame ( int force , int listen )
{
2009-04-09 07:41:30 +00:00
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
net_udp_do_frame ( force , listen ) ;
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
Error ( " Protocol handling missing in multi_do_protocol_frame \n " ) ;
break ;
}
2009-03-20 12:10:38 +00:00
}
2010-01-29 03:36:44 +00:00
void multi_do_frame ( void )
2006-03-20 17:12:09 +00:00
{
static int lasttime = 0 ;
2011-05-25 13:25:13 +00:00
static fix64 last_update_time = 0 ;
2006-03-20 17:12:09 +00:00
int i ;
2008-06-11 21:18:50 +00:00
if ( ! ( Game_mode & GM_MULTI ) | | Newdemo_state = = ND_STATE_PLAYBACK )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ;
return ;
}
if ( ( Game_mode & GM_NETWORK ) & & Netgame . PlayTimeAllowed & & lasttime ! = f2i ( ThisLevelTime ) )
{
for ( i = 0 ; i < N_players ; i + + )
if ( Players [ i ] . connected )
{
if ( i = = Player_num )
{
multi_send_heartbeat ( ) ;
lasttime = f2i ( ThisLevelTime ) ;
}
break ;
}
}
2011-05-25 13:25:13 +00:00
// Send update about our game mode-specific variables every 2 secs (to keep in sync since delayed kills can invalidate these infos on Clients)
if ( multi_i_am_master ( ) & & timer_query ( ) > = last_update_time + ( F1_0 * 2 ) )
{
multi_send_gmode_update ( ) ;
last_update_time = timer_query ( ) ;
}
2006-03-20 17:12:09 +00:00
multi_send_message ( ) ; // Send any waiting messages
if ( Game_mode & GM_MULTI_ROBOTS )
{
multi_check_robot_timeout ( ) ;
}
2009-03-20 12:10:38 +00:00
multi_do_protocol_frame ( 0 , 1 ) ;
2006-03-20 17:12:09 +00:00
2010-01-29 03:36:44 +00:00
if ( multi_quit_game )
2006-03-20 17:12:09 +00:00
{
multi_quit_game = 0 ;
2010-01-27 04:30:31 +00:00
if ( Game_wind )
window_close ( Game_wind ) ;
2006-03-20 17:12:09 +00:00
}
}
2013-12-16 23:44:34 +00:00
void _multi_send_data ( const ubyte * buf , unsigned len , int priority )
2006-03-20 17:12:09 +00:00
{
2007-12-29 14:18:49 +00:00
if ( Game_mode & GM_NETWORK )
2009-04-09 07:41:30 +00:00
{
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
2013-03-30 19:41:33 +00:00
net_udp_send_data ( buf , len , priority ) ;
2009-04-09 07:41:30 +00:00
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
2011-05-25 13:25:13 +00:00
Error ( " Protocol handling missing in multi_send_data \n " ) ;
2009-04-09 07:41:30 +00:00
break ;
}
}
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void _multi_send_data_direct ( const ubyte * buf , unsigned len , const playernum_t pnum , int priority )
2011-05-25 13:25:13 +00:00
{
2014-09-21 22:10:12 +00:00
if ( pnum > = MAX_PLAYERS )
Error ( " multi_send_data_direct: Illegal player num: %u \n " , pnum ) ;
2011-05-25 13:25:13 +00:00
switch ( multi_protocol )
{
# ifdef USE_UDP
case MULTI_PROTO_UDP :
2013-03-03 01:03:33 +00:00
net_udp_send_mdata_direct ( multibuf , len , pnum , priority ) ;
2011-05-25 13:25:13 +00:00
break ;
# endif
default :
Error ( " Protocol handling missing in multi_send_data_direct \n " ) ;
break ;
}
}
2013-12-16 22:15:38 +00:00
template < multiplayer_command_t C >
2014-09-21 22:10:12 +00:00
static void multi_send_data_direct ( ubyte * buf , unsigned len , const playernum_t pnum , int priority )
2013-12-16 22:15:38 +00:00
{
buf [ 0 ] = C ;
unsigned expected = command_length < C > : : value ;
if ( len ! = expected )
Error ( " multi_send_data_direct: Packet type %i length: %i, expected: %i \n " , C , len , expected ) ;
_multi_send_data_direct ( buf , len , pnum , priority ) ;
}
2006-03-20 17:12:09 +00:00
void
multi_leave_game ( void )
{
if ( ! ( Game_mode & GM_MULTI ) )
return ;
if ( Game_mode & GM_NETWORK )
{
Net_create_loc = 0 ;
2009-11-24 09:48:53 +00:00
multi_send_position ( Players [ Player_num ] . objnum ) ;
2011-01-14 13:29:08 +00:00
multi_powcap_cap_objects ( ) ;
2011-01-14 14:13:29 +00:00
if ( ! Player_eggs_dropped )
{
drop_player_eggs ( ConsoleObject ) ;
Player_eggs_dropped = 1 ;
}
2013-12-16 22:59:31 +00:00
multi_send_player_deres ( deres_drop ) ;
2006-03-20 17:12:09 +00:00
}
2013-12-16 22:28:15 +00:00
multi_send_quit ( ) ;
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_NETWORK )
2009-04-09 07:41:30 +00:00
{
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
net_udp_leave_game ( ) ;
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
Error ( " Protocol handling missing in multi_leave_game \n " ) ;
break ;
}
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
plyr_save_stats ( ) ;
# endif
2006-03-20 17:12:09 +00:00
}
void
multi_show_player_list ( )
{
if ( ! ( Game_mode & GM_MULTI ) | | ( Game_mode & GM_MULTI_COOP ) )
return ;
if ( Show_kill_list )
return ;
Show_kill_list_timer = F1_0 * 5 ; // 5 second timer
Show_kill_list = 1 ;
}
int
multi_endlevel ( int * secret )
{
int result = 0 ;
2009-04-09 07:41:30 +00:00
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
result = net_udp_endlevel ( secret ) ;
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
Error ( " Protocol handling missing in multi_endlevel \n " ) ;
break ;
}
2006-03-20 17:12:09 +00:00
return ( result ) ;
}
2013-12-04 22:45:33 +00:00
int multi_endlevel_poll1 ( newmenu * menu , d_event * event , unused_newmenu_userdata_t * userdata )
2009-04-09 07:41:30 +00:00
{
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
2010-01-07 14:49:07 +00:00
return net_udp_kmatrix_poll1 ( menu , event , userdata ) ;
2009-04-09 07:41:30 +00:00
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
2009-11-24 09:48:53 +00:00
Error ( " Protocol handling missing in multi_endlevel_poll1 \n " ) ;
2009-04-09 07:41:30 +00:00
break ;
}
2010-01-07 14:49:07 +00:00
return 0 ; // kill warning
2009-04-09 07:41:30 +00:00
}
2013-12-04 22:45:33 +00:00
int multi_endlevel_poll2 ( newmenu * menu , d_event * event , unused_newmenu_userdata_t * userdata )
2009-04-09 07:41:30 +00:00
{
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
2010-01-07 14:49:07 +00:00
return net_udp_kmatrix_poll2 ( menu , event , userdata ) ;
2009-04-09 07:41:30 +00:00
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
2009-11-24 09:48:53 +00:00
Error ( " Protocol handling missing in multi_endlevel_poll2 \n " ) ;
2009-04-09 07:41:30 +00:00
break ;
}
2010-01-07 14:49:07 +00:00
return 0 ;
2009-04-09 07:41:30 +00:00
}
void multi_send_endlevel_packet ( )
{
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
net_udp_send_endlevel_packet ( ) ;
2009-04-09 07:41:30 +00:00
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
2009-11-24 09:48:53 +00:00
Error ( " Protocol handling missing in multi_send_endlevel_packet \n " ) ;
2009-04-09 07:41:30 +00:00
break ;
}
}
2006-03-20 17:12:09 +00:00
//
2007-12-29 14:18:49 +00:00
// Part 2 : functions that act on network messages and change the
2006-03-20 17:12:09 +00:00
// the state of the game in some way.
//
void
multi_define_macro ( int key )
{
if ( ! ( Game_mode & GM_MULTI ) )
return ;
key & = ( ~ KEY_SHIFTED ) ;
switch ( key )
{
2008-05-07 14:02:01 +00:00
case KEY_F9 :
multi_defining_message = 1 ; break ;
case KEY_F10 :
multi_defining_message = 2 ; break ;
case KEY_F11 :
multi_defining_message = 3 ; break ;
case KEY_F12 :
multi_defining_message = 4 ; break ;
default :
Int3 ( ) ;
2006-03-20 17:12:09 +00:00
}
if ( multi_defining_message ) {
2011-02-02 00:36:49 +00:00
key_toggle_repeat ( 1 ) ;
2006-03-20 17:12:09 +00:00
multi_message_index = 0 ;
Network_message [ multi_message_index ] = 0 ;
}
}
2013-12-03 22:54:27 +00:00
static void multi_message_feedback ( void )
2006-03-20 17:12:09 +00:00
{
char * colon ;
int found = 0 ;
int i ;
2013-12-03 22:54:27 +00:00
char feedback_result [ 200 ] ;
2006-03-20 17:12:09 +00:00
2011-04-11 15:47:16 +00:00
if ( ! ( ( ( colon = strstr ( Network_message , " : " ) ) = = NULL ) | | ( colon - Network_message < 1 ) | | ( colon - Network_message > CALLSIGN_LEN ) ) )
2006-03-20 17:12:09 +00:00
{
2014-07-05 03:32:08 +00:00
std : : size_t feedlen = snprintf ( feedback_result , sizeof ( feedback_result ) , " %s " , TXT_MESSAGE_SENT_TO ) ;
if ( ( Game_mode & GM_TEAM ) & & ( Network_message [ 0 ] = = ' 1 ' | | Network_message [ 0 ] = = ' 2 ' ) )
2006-03-20 17:12:09 +00:00
{
2014-07-05 16:48:12 +00:00
snprintf ( feedback_result + feedlen , sizeof ( feedback_result ) - feedlen , " %s '%s' " , TXT_TEAM , static_cast < const char * > ( Netgame . team_name [ Network_message [ 0 ] - ' 1 ' ] ) ) ;
2006-03-20 17:12:09 +00:00
found = 1 ;
}
if ( Game_mode & GM_TEAM )
{
for ( i = 0 ; i < N_players ; i + + )
{
2012-05-18 23:36:43 +00:00
if ( ! d_strnicmp ( Netgame . team_name [ i ] , Network_message , colon - Network_message ) )
2006-03-20 17:12:09 +00:00
{
2014-07-05 16:48:12 +00:00
const char * comma = found ? " , " : " " ;
2006-03-20 17:12:09 +00:00
found + + ;
2014-07-05 16:48:12 +00:00
const char * newline = ( ! ( found % 4 ) ) ? " \n " : " " ;
size_t l = strlen ( feedback_result ) ;
snprintf ( feedback_result + l , sizeof ( feedback_result ) - l , " %s%s%s '%s' " , comma , newline , TXT_TEAM , static_cast < const char * > ( Netgame . team_name [ i ] ) ) ;
2006-03-20 17:12:09 +00:00
}
}
}
for ( i = 0 ; i < N_players ; i + + )
{
2014-07-05 16:48:12 +00:00
if ( ( ! d_strnicmp ( static_cast < const char * > ( Players [ i ] . callsign ) , Network_message , colon - Network_message ) ) & & ( i ! = Player_num ) & & ( Players [ i ] . connected ) )
2006-03-20 17:12:09 +00:00
{
2014-07-05 03:32:08 +00:00
const char * comma = found ? " , " : " " ;
2006-03-20 17:12:09 +00:00
found + + ;
2014-07-05 03:32:08 +00:00
const char * newline = ( ! ( found % 4 ) ) ? " \n " : " " ;
size_t l = strlen ( feedback_result ) ;
2014-07-26 22:45:01 +00:00
snprintf ( feedback_result + l , sizeof ( feedback_result ) - l , " %s%s%s " , comma , newline , static_cast < const char * > ( Players [ i ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
}
}
if ( ! found )
strcat ( feedback_result , TXT_NOBODY ) ;
else
strcat ( feedback_result , " . " ) ;
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
Assert ( strlen ( feedback_result ) < 200 ) ;
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , feedback_result ) ;
2006-03-20 17:12:09 +00:00
}
}
void
multi_send_macro ( int key )
{
if ( ! ( Game_mode & GM_MULTI ) )
return ;
switch ( key )
{
2008-05-07 14:02:01 +00:00
case KEY_F9 :
key = 0 ; break ;
case KEY_F10 :
key = 1 ; break ;
case KEY_F11 :
key = 2 ; break ;
case KEY_F12 :
key = 3 ; break ;
default :
Int3 ( ) ;
2006-03-20 17:12:09 +00:00
}
2008-04-13 00:28:36 +00:00
if ( ! PlayerCfg . NetworkMessageMacro [ key ] [ 0 ] )
2006-03-20 17:12:09 +00:00
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , TXT_NO_MACRO ) ;
2006-03-20 17:12:09 +00:00
return ;
}
2008-04-13 00:28:36 +00:00
strcpy ( Network_message , PlayerCfg . NetworkMessageMacro [ key ] ) ;
2006-03-20 17:12:09 +00:00
Network_message_reciever = 100 ;
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s '%s' " , TXT_SENDING , Network_message ) ;
2006-03-20 17:12:09 +00:00
multi_message_feedback ( ) ;
}
void
multi_send_message_start ( )
{
if ( Game_mode & GM_MULTI ) {
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_typing ;
multi_send_msgsend_state ( msgsend_typing ) ;
2006-03-20 17:12:09 +00:00
multi_message_index = 0 ;
Network_message [ multi_message_index ] = 0 ;
2011-02-02 00:36:49 +00:00
key_toggle_repeat ( 1 ) ;
2006-03-20 17:12:09 +00:00
}
}
2014-07-19 22:42:50 +00:00
static void kick_player ( player & plr , netplayer_info & nplr )
{
switch ( multi_protocol )
{
# ifdef USE_UDP
case MULTI_PROTO_UDP :
net_udp_dump_player ( nplr . protocol . udp . addr , DUMP_KICKED ) ;
break ;
# endif
default :
Error ( " Protocol handling missing in multi_send_message_end \n " ) ;
break ;
}
HUD_init_message ( HM_MULTI , " Dumping %s... " , static_cast < const char * > ( plr . callsign ) ) ;
multi_message_index = 0 ;
multi_sending_message [ Player_num ] = msgsend_none ;
# if defined(DXX_BUILD_DESCENT_II)
multi_send_msgsend_state ( msgsend_none ) ;
# endif
}
2013-10-27 22:00:14 +00:00
static void multi_send_message_end ( )
2006-03-20 17:12:09 +00:00
{
char * mytempbuf ;
int i , t ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
multi_message_index = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
multi_send_msgsend_state ( msgsend_none ) ;
2013-03-03 01:03:33 +00:00
key_toggle_repeat ( 0 ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Network_message_reciever = 100 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2012-05-18 23:36:43 +00:00
if ( ! d_strnicmp ( Network_message , " /Handicap: " , 11 ) )
2006-03-20 17:12:09 +00:00
{
2011-04-11 15:47:16 +00:00
mytempbuf = & Network_message [ 11 ] ;
2006-03-20 17:12:09 +00:00
StartingShields = atol ( mytempbuf ) ;
if ( StartingShields < 10 )
StartingShields = 10 ;
if ( StartingShields > 100 )
{
2014-07-05 16:48:12 +00:00
snprintf ( Network_message , sizeof ( Network_message ) , " %s has tried to cheat! " , static_cast < const char * > ( Players [ Player_num ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
StartingShields = 100 ;
}
else
2014-07-05 16:48:12 +00:00
snprintf ( Network_message , sizeof ( Network_message ) , " %s handicap is now %d " , static_cast < const char * > ( Players [ Player_num ] . callsign ) , StartingShields ) ;
2006-03-20 17:12:09 +00:00
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " Telling others of your handicap of %d! " , StartingShields ) ;
2006-03-20 17:12:09 +00:00
StartingShields = i2f ( StartingShields ) ;
}
2012-05-18 23:36:43 +00:00
else if ( ! d_strnicmp ( Network_message , " /move: " , 7 ) )
2006-03-20 17:12:09 +00:00
{
if ( ( Game_mode & GM_NETWORK ) & & ( Game_mode & GM_TEAM ) )
{
2012-11-11 22:12:51 +00:00
unsigned name_index = 7 ;
2011-04-11 15:47:16 +00:00
if ( strlen ( Network_message ) > 7 )
2006-03-20 17:12:09 +00:00
while ( Network_message [ name_index ] = = ' ' )
name_index + + ;
2009-04-09 07:41:30 +00:00
if ( ! multi_i_am_master ( ) )
2006-03-20 17:12:09 +00:00
{
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " Only %s can move players! " , static_cast < const char * > ( Players [ multi_who_is_master ( ) ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
return ;
}
if ( strlen ( Network_message ) < = name_index )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You must specify a name to move " ) ;
2006-03-20 17:12:09 +00:00
return ;
}
for ( i = 0 ; i < N_players ; i + + )
2014-07-05 16:48:12 +00:00
if ( ( ! d_strnicmp ( static_cast < const char * > ( Players [ i ] . callsign ) , & Network_message [ name_index ] , strlen ( Network_message ) - name_index ) ) & & ( Players [ i ] . connected ) )
2006-03-20 17:12:09 +00:00
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:03:47 +00:00
if ( game_mode_capture_flag ( ) & & ( Players [ i ] . flags & PLAYER_FLAGS_FLAG ) )
2006-03-20 17:12:09 +00:00
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Can't move player because s/he has a flag! " ) ;
2006-03-20 17:12:09 +00:00
return ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( Netgame . team_vector & ( 1 < < i ) )
Netgame . team_vector & = ( ~ ( 1 < < i ) ) ;
else
Netgame . team_vector | = ( 1 < < i ) ;
for ( t = 0 ; t < N_players ; t + + )
if ( Players [ t ] . connected )
multi_reset_object_texture ( & Objects [ Players [ t ] . objnum ] ) ;
2011-05-25 13:25:13 +00:00
reset_cockpit ( ) ;
2006-03-20 17:12:09 +00:00
2011-09-13 23:15:32 +00:00
multi_send_gmode_update ( ) ;
2011-05-25 13:25:13 +00:00
2014-07-05 16:48:12 +00:00
snprintf ( Network_message , sizeof ( Network_message ) , " %s has changed teams! " , static_cast < const char * > ( Players [ i ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
if ( i = = Player_num )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You have changed teams! " ) ;
2006-03-20 17:12:09 +00:00
reset_cockpit ( ) ;
}
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " Moving %s to other team. " , static_cast < const char * > ( Players [ i ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
break ;
}
}
}
2012-05-18 23:36:43 +00:00
else if ( ! d_strnicmp ( Network_message , " /kick: " , 7 ) & & ( Game_mode & GM_NETWORK ) )
2006-03-20 17:12:09 +00:00
{
2012-11-11 22:12:51 +00:00
unsigned name_index = 7 ;
2011-04-11 15:47:16 +00:00
if ( strlen ( Network_message ) > 7 )
2006-03-20 17:12:09 +00:00
while ( Network_message [ name_index ] = = ' ' )
name_index + + ;
2009-04-09 07:41:30 +00:00
if ( ! multi_i_am_master ( ) )
2006-03-20 17:12:09 +00:00
{
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " Only %s can kick others out! " , static_cast < const char * > ( Players [ multi_who_is_master ( ) ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
multi_message_index = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-13 21:47:46 +00:00
multi_send_msgsend_state ( msgsend_none ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
return ;
}
if ( strlen ( Network_message ) < = name_index )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You must specify a name to kick " ) ;
2006-03-20 17:12:09 +00:00
multi_message_index = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-13 21:47:46 +00:00
multi_send_msgsend_state ( msgsend_none ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
return ;
}
if ( Network_message [ name_index ] = = ' # ' & & isdigit ( Network_message [ name_index + 1 ] ) ) {
2014-09-21 22:10:12 +00:00
playernum_array_t players ;
2006-03-20 17:12:09 +00:00
int listpos = Network_message [ name_index + 1 ] - ' 0 ' ;
if ( Show_kill_list = = 1 | | Show_kill_list = = 2 ) {
if ( listpos = = 0 | | listpos > = N_players ) {
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Invalid player number for kick. " ) ;
2006-03-20 17:12:09 +00:00
multi_message_index = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-13 21:47:46 +00:00
multi_send_msgsend_state ( msgsend_none ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
return ;
}
multi_get_kill_list ( players ) ;
i = players [ listpos ] ;
if ( ( i ! = Player_num ) & & ( Players [ i ] . connected ) )
2014-07-19 22:42:50 +00:00
{
kick_player ( Players [ i ] , Netgame . players [ i ] ) ;
return ;
}
2006-03-20 17:12:09 +00:00
}
2013-06-23 16:27:34 +00:00
else HUD_init_message_literal ( HM_MULTI , " You cannot use # kicking with in team display. " ) ;
2006-03-20 17:12:09 +00:00
multi_message_index = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-13 21:47:46 +00:00
multi_send_msgsend_state ( msgsend_none ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
return ;
}
for ( i = 0 ; i < N_players ; i + + )
2014-07-05 16:48:12 +00:00
if ( ( ! d_strnicmp ( static_cast < const char * > ( Players [ i ] . callsign ) , & Network_message [ name_index ] , strlen ( Network_message ) - name_index ) ) & & ( i ! = Player_num ) & & ( Players [ i ] . connected ) ) {
2014-07-19 22:42:50 +00:00
kick_player ( Players [ i ] , Netgame . players [ i ] ) ;
2006-03-20 17:12:09 +00:00
return ;
}
}
2008-12-12 15:53:13 +00:00
2012-05-18 23:36:43 +00:00
else if ( ! d_strnicmp ( Network_message , " /killreactor " , 12 ) & & ( Game_mode & GM_NETWORK ) & & ! Control_center_destroyed )
2008-12-12 15:53:13 +00:00
{
2009-04-09 07:41:30 +00:00
if ( ! multi_i_am_master ( ) )
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " Only %s can kill the reactor this way! " , static_cast < const char * > ( Players [ multi_who_is_master ( ) ] . callsign ) ) ;
2008-12-12 15:53:13 +00:00
else
{
2014-01-11 23:29:35 +00:00
net_destroy_controlcen ( object_none ) ;
2013-12-26 22:21:16 +00:00
multi_send_destroy_controlcen ( object_none , Player_num ) ;
2008-12-12 15:53:13 +00:00
}
2008-12-12 15:57:00 +00:00
multi_message_index = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-13 21:47:46 +00:00
multi_send_msgsend_state ( msgsend_none ) ;
2013-03-03 01:03:33 +00:00
# endif
2008-12-12 15:57:00 +00:00
return ;
2008-12-12 15:53:13 +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
else
2013-03-03 01:03:33 +00:00
# endif
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s '%s' " , TXT_SENDING , Network_message ) ;
2006-03-20 17:12:09 +00:00
multi_send_message ( ) ;
multi_message_feedback ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
Network_message_reciever = 100 ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
multi_message_index = 0 ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
multi_send_msgsend_state ( msgsend_none ) ;
2011-02-02 00:36:49 +00:00
key_toggle_repeat ( 0 ) ;
2013-03-03 01:03:33 +00:00
# endif
2008-05-07 14:11:30 +00:00
game_flush_inputs ( ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_define_macro_end ( )
2006-03-20 17:12:09 +00:00
{
Assert ( multi_defining_message > 0 ) ;
2008-04-13 00:28:36 +00:00
strcpy ( PlayerCfg . NetworkMessageMacro [ multi_defining_message - 1 ] , Network_message ) ;
2006-03-20 17:12:09 +00:00
write_player_file ( ) ;
multi_message_index = 0 ;
multi_defining_message = 0 ;
2011-02-02 00:36:49 +00:00
key_toggle_repeat ( 0 ) ;
2008-05-07 14:11:30 +00:00
game_flush_inputs ( ) ;
2006-03-20 17:12:09 +00:00
}
2014-08-06 02:10:49 +00:00
window_event_result multi_message_input_sub ( int key )
2006-03-20 17:12:09 +00:00
{
2008-05-07 14:02:01 +00:00
switch ( key )
{
case KEY_F8 :
case KEY_ESC :
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_none ;
multi_send_msgsend_state ( msgsend_none ) ;
2008-05-07 14:02:01 +00:00
multi_defining_message = 0 ;
2011-02-02 00:36:49 +00:00
key_toggle_repeat ( 0 ) ;
2008-05-07 14:02:01 +00:00
game_flush_inputs ( ) ;
2014-08-06 02:10:49 +00:00
return window_event_result : : handled ;
2008-05-07 14:02:01 +00:00
case KEY_LEFT :
case KEY_BACKSP :
case KEY_PAD4 :
if ( multi_message_index > 0 )
multi_message_index - - ;
Network_message [ multi_message_index ] = 0 ;
2014-08-06 02:10:49 +00:00
return window_event_result : : handled ;
2008-05-07 14:02:01 +00:00
case KEY_ENTER :
2011-04-11 15:47:16 +00:00
if ( multi_sending_message [ Player_num ] )
2008-05-07 14:02:01 +00:00
multi_send_message_end ( ) ;
else if ( multi_defining_message )
multi_define_macro_end ( ) ;
game_flush_inputs ( ) ;
2014-08-06 02:10:49 +00:00
return window_event_result : : handled ;
2008-05-07 14:02:01 +00:00
default :
2008-11-17 23:38:43 +00:00
{
int ascii = key_ascii ( ) ;
2012-06-17 23:23:32 +00:00
if ( ascii < 255 ) {
2006-03-20 17:12:09 +00:00
if ( multi_message_index < MAX_MESSAGE_LEN - 2 ) {
Network_message [ multi_message_index + + ] = ascii ;
Network_message [ multi_message_index ] = 0 ;
2011-04-11 15:47:16 +00:00
} else if ( multi_sending_message [ Player_num ] ) {
2006-03-20 17:12:09 +00:00
int i ;
char * ptext , * pcolon ;
ptext = NULL ;
Network_message [ multi_message_index + + ] = ascii ;
Network_message [ multi_message_index ] = 0 ;
for ( i = multi_message_index - 1 ; i > = 0 ; i - - ) {
if ( Network_message [ i ] = = 32 ) {
ptext = & Network_message [ i + 1 ] ;
Network_message [ i ] = 0 ;
break ;
}
}
multi_send_message_end ( ) ;
if ( ptext ) {
2013-12-13 21:47:46 +00:00
multi_sending_message [ Player_num ] = msgsend_typing ;
multi_send_msgsend_state ( msgsend_typing ) ;
2013-01-08 10:42:10 +00:00
pcolon = strstr ( Network_message , " : " ) ;
2006-03-20 17:12:09 +00:00
if ( pcolon )
strcpy ( pcolon + 1 , ptext ) ;
else
strcpy ( Network_message , ptext ) ;
multi_message_index = strlen ( Network_message ) ;
}
}
}
}
}
2014-08-06 02:10:49 +00:00
return window_event_result : : ignored ;
2006-03-20 17:12:09 +00:00
}
void
multi_send_message_dialog ( void )
{
newmenu_item m [ 1 ] ;
int choice ;
if ( ! ( Game_mode & GM_MULTI ) )
return ;
Network_message [ 0 ] = 0 ; // Get rid of old contents
2012-11-24 20:57:15 +00:00
nm_set_item_input ( & m [ 0 ] , MAX_MESSAGE_LEN - 1 , Network_message ) ;
2013-12-04 22:45:33 +00:00
choice = newmenu_do ( NULL , TXT_SEND_MESSAGE , 1 , m , unused_newmenu_subfunction , unused_newmenu_userdata ) ;
2006-03-20 17:12:09 +00:00
2013-12-03 23:21:36 +00:00
if ( ( choice > - 1 ) & & ( Network_message [ 0 ] ) ) {
2006-03-20 17:12:09 +00:00
Network_message_reciever = 100 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s '%s' " , TXT_SENDING , Network_message ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
multi_message_feedback ( ) ;
}
}
2014-07-16 02:35:14 +00:00
void multi_do_death ( int )
2006-03-20 17:12:09 +00:00
{
// Do any miscellaneous stuff for a new network player after death
if ( ! ( Game_mode & GM_MULTI_COOP ) )
{
Players [ Player_num ] . flags | = ( PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY ) ;
}
}
2014-09-21 22:10:12 +00:00
static void multi_do_fire ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
ubyte weapon ;
sbyte flags ;
2013-11-23 13:02:19 +00:00
vms_vector shot_orientation ;
2006-03-20 17:12:09 +00:00
// Act out the actual shooting
weapon = ( int ) buf [ 2 ] ;
2007-12-29 14:18:49 +00:00
2006-03-20 17:12:09 +00:00
flags = buf [ 4 ] ;
2013-08-09 15:21:03 +00:00
if ( buf [ 0 ] = = MULTI_FIRE_TRACK )
{
Network_laser_track = GET_INTEL_SHORT ( buf + 6 ) ;
Network_laser_track = objnum_remote_to_local ( Network_laser_track , buf [ 8 ] ) ;
}
2006-03-20 17:12:09 +00:00
2013-11-23 13:02:19 +00:00
shot_orientation . x = ( fix ) GET_INTEL_INT ( buf + 6 ) ;
shot_orientation . y = ( fix ) GET_INTEL_INT ( buf + 10 ) ;
shot_orientation . z = ( fix ) GET_INTEL_INT ( buf + 14 ) ;
2006-03-20 17:12:09 +00:00
Assert ( pnum < N_players ) ;
2013-08-11 15:17:01 +00:00
if ( Objects [ Players [ pnum ] . objnum ] . type = = OBJ_GHOST )
2006-03-20 17:12:09 +00:00
multi_make_ghost_player ( pnum ) ;
if ( weapon = = FLARE_ADJUST )
2013-12-12 21:48:34 +00:00
Laser_player_fire ( & Objects [ Players [ pnum ] . objnum ] , FLARE_ID , 6 , 1 , shot_orientation ) ;
2013-08-11 15:17:01 +00:00
else
if ( weapon > = MISSILE_ADJUST ) {
2013-12-29 04:28:07 +00:00
int weapon_gun , remote_objnum ;
2013-10-08 03:20:09 +00:00
enum weapon_type_t weapon_id = ( enum weapon_type_t ) Secondary_weapon_to_weapon_info [ weapon - MISSILE_ADJUST ] ;
2006-03-20 17:12:09 +00:00
weapon_gun = Secondary_weapon_to_gun_num [ weapon - MISSILE_ADJUST ] + ( flags & 1 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( weapon - MISSILE_ADJUST = = GUIDED_INDEX )
{
Multi_is_guided = 1 ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2013-12-29 04:28:07 +00:00
objnum_t objnum = Laser_player_fire ( & Objects [ Players [ pnum ] . objnum ] , weapon_id , weapon_gun , 1 , shot_orientation ) ;
2013-08-09 15:21:03 +00:00
if ( buf [ 0 ] = = MULTI_FIRE_BOMB )
{
remote_objnum = GET_INTEL_SHORT ( buf + 6 ) ;
map_objnum_local_to_remote ( objnum , remote_objnum , pnum ) ;
}
2006-03-20 17:12:09 +00:00
}
else {
fix save_charge = Fusion_charge ;
if ( weapon = = FUSION_INDEX ) {
Fusion_charge = flags < < 12 ;
}
if ( weapon = = LASER_ID ) {
if ( flags & LASER_QUAD )
2013-08-11 15:17:01 +00:00
Players [ pnum ] . flags | = PLAYER_FLAGS_QUAD_LASERS ;
2006-03-20 17:12:09 +00:00
else
2013-08-11 15:17:01 +00:00
Players [ pnum ] . flags & = ~ PLAYER_FLAGS_QUAD_LASERS ;
2006-03-20 17:12:09 +00:00
}
2013-11-23 13:02:19 +00:00
do_laser_firing ( Players [ pnum ] . objnum , weapon , ( int ) buf [ 3 ] , flags , ( int ) buf [ 5 ] , shot_orientation ) ;
2006-03-20 17:12:09 +00:00
if ( weapon = = FUSION_INDEX )
Fusion_charge = save_charge ;
}
}
void
2013-10-27 22:00:14 +00:00
static multi_do_message ( const ubyte * cbuf )
2006-03-20 17:12:09 +00:00
{
2013-03-30 19:41:33 +00:00
const char * buf = ( const char * ) cbuf ;
2012-11-11 22:12:51 +00:00
const char * colon ;
2013-03-03 01:03:33 +00:00
int loc = 2 ;
2006-03-20 17:12:09 +00:00
2011-04-11 15:47:16 +00:00
if ( ( ( colon = strstr ( buf + loc , " : " ) ) = = NULL ) | | ( colon - ( buf + loc ) < 1 ) | | ( colon - ( buf + loc ) > CALLSIGN_LEN ) )
2006-03-20 17:12:09 +00:00
{
2007-09-05 17:31:22 +00:00
int color = 0 ;
if ( Game_mode & GM_TEAM )
color = get_team ( ( int ) buf [ 1 ] ) ;
else
color = ( int ) buf [ 1 ] ;
2013-12-03 22:59:03 +00:00
char xrgb = BM_XRGB ( player_rgb [ color ] . r , player_rgb [ color ] . g , player_rgb [ color ] . b ) ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %c%c%s:%c%c %s " , CC_COLOR , xrgb , static_cast < const char * > ( Players [ ( int ) buf [ 1 ] ] . callsign ) , CC_COLOR , BM_XRGB ( 0 , 31 , 0 ) , buf + 2 ) ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ ( int ) buf [ 1 ] ] = msgsend_none ;
2006-03-20 17:12:09 +00:00
}
else
{
2014-07-05 16:48:12 +00:00
if ( ( ! d_strnicmp ( static_cast < const char * > ( Players [ Player_num ] . callsign ) , buf + loc , colon - ( buf + loc ) ) ) | |
2012-05-18 23:36:43 +00:00
( ( Game_mode & GM_TEAM ) & & ( ( get_team ( Player_num ) = = atoi ( buf + loc ) - 1 ) | | ! d_strnicmp ( Netgame . team_name [ get_team ( Player_num ) ] , buf + loc , colon - ( buf + loc ) ) ) ) )
2006-03-20 17:12:09 +00:00
{
2007-09-05 17:31:22 +00:00
int color = 0 ;
if ( Game_mode & GM_TEAM )
color = get_team ( ( int ) buf [ 1 ] ) ;
else
color = ( int ) buf [ 1 ] ;
2013-12-03 22:59:03 +00:00
char xrgb = BM_XRGB ( player_rgb [ color ] . r , player_rgb [ color ] . g , player_rgb [ color ] . b ) ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %c%c%s:%c%c %s " , CC_COLOR , xrgb , static_cast < const char * > ( Players [ ( int ) buf [ 1 ] ] . callsign ) , CC_COLOR , BM_XRGB ( 0 , 31 , 0 ) , colon + 2 ) ;
2013-12-13 21:47:46 +00:00
multi_sending_message [ ( int ) buf [ 1 ] ] = msgsend_none ;
2006-03-20 17:12:09 +00:00
}
}
}
2014-09-21 22:10:12 +00:00
static void multi_do_position ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
# ifdef WORDS_BIGENDIAN
shortpos sp ;
# endif
# ifndef WORDS_BIGENDIAN
2009-11-24 09:48:53 +00:00
extract_shortpos ( & Objects [ Players [ pnum ] . objnum ] , ( shortpos * ) ( buf + 2 ) , 0 ) ;
2006-03-20 17:12:09 +00:00
# else
2009-11-24 09:48:53 +00:00
memcpy ( ( ubyte * ) ( sp . bytemat ) , ( ubyte * ) ( buf + 2 ) , 9 ) ;
memcpy ( ( ubyte * ) & ( sp . xo ) , ( ubyte * ) ( buf + 11 ) , 14 ) ;
2006-03-20 17:12:09 +00:00
extract_shortpos ( & Objects [ Players [ pnum ] . objnum ] , & sp , 1 ) ;
# endif
if ( Objects [ Players [ pnum ] . objnum ] . movement_type = = MT_PHYSICS )
set_thrust_from_velocity ( & Objects [ Players [ pnum ] . objnum ] ) ;
}
2014-09-21 22:10:12 +00:00
static void multi_do_reappear ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
short objnum ;
2012-04-07 10:32:22 +00:00
objnum = GET_INTEL_SHORT ( buf + 2 ) ;
2006-03-20 17:12:09 +00:00
Assert ( objnum > = 0 ) ;
2013-10-07 23:52:33 +00:00
if ( pnum ! = get_player_id ( & Objects [ objnum ] ) )
2012-04-12 00:15:26 +00:00
return ;
2012-04-07 10:32:22 +00:00
2013-10-07 23:52:33 +00:00
multi_make_ghost_player ( get_player_id ( & Objects [ objnum ] ) ) ;
2006-03-20 17:12:09 +00:00
create_player_appearance_effect ( & Objects [ objnum ] ) ;
}
2014-09-21 22:10:12 +00:00
static void multi_do_player_deres ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
// Only call this for players, not robots. pnum is player number, not
// Object number.
int count ;
int i ;
char remote_created ;
# ifdef NDEBUG
if ( ( pnum < 0 ) | | ( pnum > = N_players ) )
return ;
# else
Assert ( pnum < N_players ) ;
# endif
// If we are in the process of sending objects to a new player, reset that process
if ( Network_send_objects )
{
Network_send_objnum = - 1 ;
}
// Stuff the Players structure to prepare for the explosion
2013-12-16 22:59:31 +00:00
count = 3 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# define GET_WEAPON_FLAGS(buf,count) buf[count++]
# elif defined(DXX_BUILD_DESCENT_II)
2013-08-11 15:17:28 +00:00
# define GET_WEAPON_FLAGS(buf,count) (count += sizeof(uint16_t), GET_INTEL_SHORT(buf + (count - sizeof(uint16_t))))
2013-03-03 01:03:33 +00:00
# endif
2013-08-11 15:17:28 +00:00
Players [ pnum ] . primary_weapon_flags = GET_WEAPON_FLAGS ( buf , count ) ;
Players [ pnum ] . secondary_weapon_flags = GET_WEAPON_FLAGS ( buf , count ) ;
2006-03-20 17:12:09 +00:00
Players [ pnum ] . laser_level = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ HOMING_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ CONCUSSION_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ SMART_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ MEGA_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ PROXIMITY_INDEX ] = buf [ count ] ; count + + ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Players [ pnum ] . secondary_ammo [ SMISSILE1_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ GUIDED_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ SMART_MINE_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ SMISSILE4_INDEX ] = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_ammo [ SMISSILE5_INDEX ] = buf [ count ] ; count + + ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2013-09-20 23:12:54 +00:00
Players [ pnum ] . vulcan_ammo = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
2006-03-20 17:12:09 +00:00
Players [ pnum ] . flags = GET_INTEL_INT ( buf + count ) ; count + = 4 ;
2011-01-14 13:29:08 +00:00
multi_powcap_adjust_remote_cap ( pnum ) ;
2006-03-20 17:12:09 +00:00
2014-08-16 23:18:17 +00:00
vobjptridx_t objp = vobjptridx ( Players [ pnum ] . objnum ) ;
2006-03-20 17:12:09 +00:00
// objp->phys_info.velocity = *(vms_vector *)(buf+16); // 12 bytes
// objp->pos = *(vms_vector *)(buf+28); // 12 bytes
remote_created = buf [ count + + ] ; // How many did the other guy create?
Net_create_loc = 0 ;
drop_player_eggs ( objp ) ;
// Create mapping from remote to local numbering system
// We now handle this situation gracefully, Int3 not required
// if (Net_create_loc != remote_created)
// Int3(); // Probably out of object array space, see Rob
for ( i = 0 ; i < remote_created ; i + + )
{
short s ;
s = GET_INTEL_SHORT ( buf + count ) ;
2013-03-03 01:03:33 +00:00
if ( ( i < Net_create_loc ) & & ( s > 0 ) & &
( Net_create_objnums [ i ] > 0 ) )
2006-03-20 17:12:09 +00:00
map_objnum_local_to_remote ( ( short ) Net_create_objnums [ i ] , s , pnum ) ;
count + = 2 ;
}
for ( i = remote_created ; i < Net_create_loc ; i + + ) {
Objects [ Net_create_objnums [ i ] ] . flags | = OF_SHOULD_BE_DEAD ;
}
2013-12-16 22:59:31 +00:00
if ( buf [ 2 ] = = deres_explode )
2006-03-20 17:12:09 +00:00
{
explode_badass_player ( objp ) ;
objp - > flags & = ~ OF_SHOULD_BE_DEAD ; //don't really kill player
multi_make_player_ghost ( pnum ) ;
}
else
{
create_player_appearance_effect ( objp ) ;
}
2013-08-11 16:23:37 +00:00
Players [ pnum ] . flags & = ~ ( PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:23:37 +00:00
Players [ pnum ] . flags & = ~ PLAYER_FLAGS_FLAG ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
Players [ pnum ] . cloak_time = 0 ;
2012-04-07 10:32:22 +00:00
2014-06-24 12:52:18 +00:00
multi_make_ghost_player ( get_player_id ( & Objects [ Players [ pnum ] . objnum ] ) ) ;
create_player_appearance_effect ( & Objects [ Players [ pnum ] . objnum ] ) ;
2006-03-20 17:12:09 +00:00
}
2011-05-25 13:25:13 +00:00
/*
* Process can compute a kill . If I am a Client this might be my own one ( see multi_send_kill ( ) ) but with more specific data so I can compute my kill correctly .
*/
2014-09-21 22:10:12 +00:00
static void multi_do_kill ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
int count = 1 ;
2011-05-25 13:25:13 +00:00
int type = ( int ) ( buf [ 0 ] ) ;
2011-09-13 23:15:32 +00:00
if ( multi_i_am_master ( ) & & type ! = MULTI_KILL_CLIENT )
return ;
if ( ! multi_i_am_master ( ) & & type ! = MULTI_KILL_HOST )
2011-05-25 13:25:13 +00:00
return ;
2006-03-20 17:12:09 +00:00
2014-07-16 02:35:26 +00:00
if ( pnum > = N_players )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // Invalid player number killed
return ;
}
2011-09-13 23:15:32 +00:00
// I am host, I know what's going on so take this packet, add game_mode related info which might be necessary for kill computation and send it to everyone so they can compute their kills correctly
if ( multi_i_am_master ( ) )
2011-05-25 13:25:13 +00:00
{
2011-09-13 23:15:32 +00:00
memcpy ( multibuf , buf , 5 ) ;
multibuf [ 5 ] = Netgame . team_vector ;
multibuf [ 6 ] = Bounty_target ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_KILL_HOST > ( multibuf , 7 , 2 ) ;
2011-05-25 13:25:13 +00:00
}
2013-12-29 04:28:07 +00:00
objnum_t killer , killed ;
2011-09-13 23:15:32 +00:00
killed = Players [ pnum ] . objnum ;
count + = 1 ;
killer = GET_INTEL_SHORT ( buf + count ) ;
if ( killer > 0 )
killer = objnum_remote_to_local ( killer , ( sbyte ) buf [ count + 2 ] ) ;
if ( ! multi_i_am_master ( ) )
{
Netgame . team_vector = buf [ 5 ] ;
Bounty_target = buf [ 6 ] ;
}
2011-05-25 13:25:13 +00:00
2011-09-13 23:15:32 +00:00
multi_compute_kill ( killer , killed ) ;
2006-03-20 17:12:09 +00:00
2011-09-13 23:15:32 +00:00
if ( Game_mode & GM_BOUNTY & & multi_i_am_master ( ) ) // update in case if needed... we could attach this to this packet but... meh...
multi_send_bounty ( ) ;
2006-03-20 17:12:09 +00:00
}
// Changed by MK on 10/20/94 to send NULL as object to net_destroy_controlcen if it got -1
// which means not a controlcen object, but contained in another object
2013-10-27 22:00:14 +00:00
static void multi_do_controlcen_destroy ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
sbyte who ;
2013-12-29 04:28:07 +00:00
objnum_t objnum = GET_INTEL_SHORT ( buf + 1 ) ;
2006-03-20 17:12:09 +00:00
who = buf [ 3 ] ;
if ( Control_center_destroyed ! = 1 )
{
if ( ( who < N_players ) & & ( who ! = Player_num ) ) {
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , static_cast < const char * > ( Players [ who ] . callsign ) , TXT_HAS_DEST_CONTROL ) ;
2006-03-20 17:12:09 +00:00
}
else if ( who = = Player_num )
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , TXT_YOU_DEST_CONTROL ) ;
2006-03-20 17:12:09 +00:00
else
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , TXT_CONTROL_DESTROYED ) ;
2006-03-20 17:12:09 +00:00
2013-12-26 22:21:16 +00:00
if ( objnum ! = object_none )
2013-12-12 21:48:34 +00:00
net_destroy_controlcen ( & Objects [ objnum ] ) ;
2006-03-20 17:12:09 +00:00
else
2014-01-11 23:29:35 +00:00
net_destroy_controlcen ( object_none ) ;
2006-03-20 17:12:09 +00:00
}
}
void
2013-10-27 22:00:14 +00:00
static multi_do_escape ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
int objnum ;
objnum = Players [ ( int ) buf [ 1 ] ] . objnum ;
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
digi_kill_sound_linked_to_object ( objnum ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( buf [ 2 ] = = 0 )
{
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , static_cast < const char * > ( Players [ ( int ) buf [ 1 ] ] . callsign ) , TXT_HAS_ESCAPED ) ;
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_NETWORK )
Players [ ( int ) buf [ 1 ] ] . connected = CONNECT_ESCAPE_TUNNEL ;
if ( ! multi_goto_secret )
multi_goto_secret = 2 ;
}
else if ( buf [ 2 ] = = 1 )
{
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , static_cast < const char * > ( Players [ ( int ) buf [ 1 ] ] . callsign ) , TXT_HAS_FOUND_SECRET ) ;
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_NETWORK )
Players [ ( int ) buf [ 1 ] ] . connected = CONNECT_FOUND_SECRET ;
if ( ! multi_goto_secret )
multi_goto_secret = 1 ;
}
create_player_appearance_effect ( & Objects [ objnum ] ) ;
multi_make_player_ghost ( buf [ 1 ] ) ;
}
void
2013-10-27 22:00:14 +00:00
static multi_do_remobj ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
short objnum ; // which object to remove
sbyte obj_owner ; // which remote list is it entered in
objnum = GET_INTEL_SHORT ( buf + 1 ) ;
obj_owner = buf [ 3 ] ;
Assert ( objnum > = 0 ) ;
if ( objnum < 1 )
return ;
2013-12-29 04:28:07 +00:00
objnum_t local_objnum = objnum_remote_to_local ( objnum , obj_owner ) ; // translate to local objnum
2006-03-20 17:12:09 +00:00
2013-12-29 04:28:07 +00:00
if ( local_objnum = = object_none )
2006-03-20 17:12:09 +00:00
{
return ;
}
if ( ( Objects [ local_objnum ] . type ! = OBJ_POWERUP ) & & ( Objects [ local_objnum ] . type ! = OBJ_HOSTAGE ) )
{
return ;
}
2009-04-09 07:41:30 +00:00
if ( Network_send_objects & & multi_objnum_is_past ( local_objnum ) )
2006-03-20 17:12:09 +00:00
{
Network_send_objnum = - 1 ;
}
if ( Objects [ local_objnum ] . type = = OBJ_POWERUP )
if ( Game_mode & GM_NETWORK )
{
2013-10-07 23:52:33 +00:00
if ( multi_powerup_is_4pack ( get_powerup_id ( & Objects [ local_objnum ] ) ) )
2011-01-14 13:29:08 +00:00
{
2014-07-12 03:26:58 +00:00
if ( PowerupsInMine [ Objects [ local_objnum ] . id - 1 ] < 4 )
2011-01-14 13:29:08 +00:00
PowerupsInMine [ Objects [ local_objnum ] . id - 1 ] = 0 ;
else
PowerupsInMine [ Objects [ local_objnum ] . id - 1 ] - = 4 ;
}
else
{
2013-10-07 23:52:33 +00:00
if ( PowerupsInMine [ get_powerup_id ( & Objects [ local_objnum ] ) ] > 0 )
PowerupsInMine [ get_powerup_id ( & Objects [ local_objnum ] ) ] - - ;
2011-01-14 13:29:08 +00:00
}
2006-03-20 17:12:09 +00:00
}
Objects [ local_objnum ] . flags | = OF_SHOULD_BE_DEAD ; // quick and painless
}
2014-09-21 22:10:12 +00:00
void multi_disconnect_player ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
2011-02-09 11:58:32 +00:00
int i , n = 0 ;
2006-03-20 17:12:09 +00:00
2011-02-09 11:58:32 +00:00
if ( ! ( Game_mode & GM_NETWORK ) )
2012-04-12 00:15:26 +00:00
return ;
2012-04-23 14:15:19 +00:00
if ( Players [ pnum ] . connected = = CONNECT_DISCONNECTED )
return ;
2012-04-12 00:15:26 +00:00
if ( Players [ pnum ] . connected = = CONNECT_PLAYING )
{
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , static_cast < const char * > ( Players [ pnum ] . callsign ) , TXT_HAS_LEFT_THE_GAME ) ;
2006-03-20 17:12:09 +00:00
2013-12-13 21:47:46 +00:00
multi_sending_message [ pnum ] = msgsend_none ;
2012-04-12 00:15:26 +00:00
if ( Network_status = = NETSTAT_PLAYING )
{
multi_make_player_ghost ( pnum ) ;
multi_strip_robots ( pnum ) ;
}
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_disconnect ( pnum ) ;
// Bounty target left - select a new one
if ( Game_mode & GM_BOUNTY & & pnum = = Bounty_target & & multi_i_am_master ( ) )
{
/* Select a random number */
2012-11-18 18:21:50 +00:00
int n = d_rand ( ) % MAX_PLAYERS ;
2012-04-12 00:15:26 +00:00
/* Make sure they're valid: Don't check against kill flags,
* just in case everyone ' s dead ! */
2012-11-18 18:21:50 +00:00
while ( ! Players [ n ] . connected )
n = d_rand ( ) % MAX_PLAYERS ;
2012-04-12 00:15:26 +00:00
/* Select new target */
2012-11-18 18:21:50 +00:00
multi_new_bounty_target ( n ) ;
2012-04-12 00:15:26 +00:00
/* Send this new data */
multi_send_bounty ( ) ;
}
}
2006-03-20 17:12:09 +00:00
2012-04-12 00:15:26 +00:00
Players [ pnum ] . connected = CONNECT_DISCONNECTED ;
Netgame . players [ pnum ] . connected = CONNECT_DISCONNECTED ;
2006-03-20 17:12:09 +00:00
2011-02-09 11:58:32 +00:00
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2011-02-09 11:58:32 +00:00
case MULTI_PROTO_UDP :
net_udp_disconnect_player ( pnum ) ;
break ;
2009-11-29 16:46:13 +00:00
# endif
2011-02-09 11:58:32 +00:00
default :
Error ( " Protocol handling missing in multi_disconnect_player \n " ) ;
break ;
}
2006-03-20 17:12:09 +00:00
2012-04-12 00:15:26 +00:00
if ( pnum = = multi_who_is_master ( ) ) // Host has left - Quit game!
{
if ( Network_status = = NETSTAT_PLAYING )
multi_leave_game ( ) ;
if ( Game_wind )
window_set_visible ( Game_wind , 0 ) ;
nm_messagebox ( NULL , 1 , TXT_OK , " Host left the game! " ) ;
if ( Game_wind )
window_set_visible ( Game_wind , 1 ) ;
multi_quit_game = 1 ;
game_leave_menus ( ) ;
multi_reset_stuff ( ) ;
return ;
}
2011-02-09 11:58:32 +00:00
for ( i = 0 ; i < N_players ; i + + )
if ( Players [ i ] . connected ) n + + ;
if ( n = = 1 )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You are the only person remaining in this netgame " ) ;
2011-02-09 11:58:32 +00:00
}
}
2006-03-20 17:12:09 +00:00
2011-02-09 11:58:32 +00:00
void
2013-10-27 22:00:14 +00:00
static multi_do_quit ( const ubyte * buf )
2011-02-09 11:58:32 +00:00
{
if ( ! ( Game_mode & GM_NETWORK ) )
return ;
multi_disconnect_player ( ( int ) buf [ 1 ] ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_cloak ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
Assert ( pnum < N_players ) ;
Players [ pnum ] . flags | = PLAYER_FLAGS_CLOAKED ;
2010-12-22 00:17:59 +00:00
Players [ pnum ] . cloak_time = GameTime64 ;
2006-03-20 17:12:09 +00:00
ai_do_cloak_stuff ( ) ;
2013-08-11 16:13:04 +00:00
multi_strip_robots ( pnum ) ;
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_cloak ( pnum ) ;
}
2014-09-21 22:10:12 +00:00
static void multi_do_decloak ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_decloak ( pnum ) ;
}
void
2013-10-27 22:00:14 +00:00
static multi_do_door_open ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
segnum_t segnum ;
2013-08-11 15:17:01 +00:00
ubyte side ;
2006-03-20 17:12:09 +00:00
segment * seg ;
wall * w ;
segnum = GET_INTEL_SHORT ( buf + 1 ) ;
side = buf [ 3 ] ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 15:17:01 +00:00
ubyte flag = buf [ 4 ] ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-09-20 23:47:27 +00:00
if ( segnum < 0 | | segnum > Highest_segment_index | | side > 5 )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ;
return ;
}
seg = & Segments [ segnum ] ;
2014-09-21 22:11:51 +00:00
if ( seg - > sides [ side ] . wall_num = = wall_none ) { //Opening door on illegal wall
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
return ;
}
w = & Walls [ seg - > sides [ side ] . wall_num ] ;
if ( w - > type = = WALL_BLASTABLE )
{
if ( ! ( w - > flags & WALL_BLASTED ) )
{
wall_destroy ( seg , side ) ;
}
return ;
}
else if ( w - > state ! = WALL_DOOR_OPENING )
{
wall_open_door ( seg , side ) ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:23:37 +00:00
w - > flags = flag ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_create_explosion ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
create_small_fireball_on_object ( & Objects [ Players [ pnum ] . objnum ] , F1_0 , 1 ) ;
}
void
2013-10-27 22:00:14 +00:00
static multi_do_controlcen_fire ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
vms_vector to_target ;
2013-08-11 15:17:01 +00:00
int gun_num ;
2013-12-29 04:28:07 +00:00
objnum_t objnum ;
2006-03-20 17:12:09 +00:00
int count = 1 ;
memcpy ( & to_target , buf + count , 12 ) ; count + = 12 ;
# ifdef WORDS_BIGENDIAN // swap the vector to_target
to_target . x = ( fix ) INTEL_INT ( ( int ) to_target . x ) ;
to_target . y = ( fix ) INTEL_INT ( ( int ) to_target . y ) ;
to_target . z = ( fix ) INTEL_INT ( ( int ) to_target . z ) ;
# endif
gun_num = buf [ count ] ; count + = 1 ;
objnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
2014-08-16 23:18:17 +00:00
auto objp = vobjptridx ( objnum ) ;
Laser_create_new_easy ( & to_target , & objp - > ctype . reactor_info . gun_pos [ gun_num ] , objp , CONTROLCEN_WEAPON_NUM , 1 ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_create_powerup ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
int count = 1 ;
vms_vector new_pos ;
char powerup_type ;
if ( Endlevel_sequence | | Control_center_destroyed )
return ;
2014-05-30 02:45:34 +00:00
count + + ;
2006-03-20 17:12:09 +00:00
powerup_type = buf [ count + + ] ;
2013-12-29 04:28:07 +00:00
segnum_t segnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
objnum_t objnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
2006-03-20 17:12:09 +00:00
if ( ( segnum < 0 ) | | ( segnum > Highest_segment_index ) ) {
Int3 ( ) ;
return ;
}
memcpy ( & new_pos , buf + count , sizeof ( vms_vector ) ) ; count + = sizeof ( vms_vector ) ;
# ifdef WORDS_BIGENDIAN
new_pos . x = ( fix ) SWAPINT ( ( int ) new_pos . x ) ;
new_pos . y = ( fix ) SWAPINT ( ( int ) new_pos . y ) ;
new_pos . z = ( fix ) SWAPINT ( ( int ) new_pos . z ) ;
# endif
Net_create_loc = 0 ;
2013-12-29 04:28:07 +00:00
objnum_t my_objnum = call_object_create_egg ( & Objects [ Players [ pnum ] . objnum ] , 1 , OBJ_POWERUP , powerup_type ) ;
2006-03-20 17:12:09 +00:00
2013-12-29 04:28:07 +00:00
if ( my_objnum = = object_none ) {
2006-03-20 17:12:09 +00:00
return ;
}
2009-04-09 07:41:30 +00:00
if ( Network_send_objects & & multi_objnum_is_past ( my_objnum ) )
2006-03-20 17:12:09 +00:00
{
Network_send_objnum = - 1 ;
}
Objects [ my_objnum ] . pos = new_pos ;
2014-09-28 21:11:04 +00:00
vm_vec_zero ( Objects [ my_objnum ] . mtype . phys_info . velocity ) ;
2006-03-20 17:12:09 +00:00
obj_relink ( my_objnum , segnum ) ;
map_objnum_local_to_remote ( my_objnum , objnum , pnum ) ;
object_create_explosion ( segnum , & new_pos , i2f ( 5 ) , VCLIP_POWERUP_DISAPPEARANCE ) ;
2011-01-14 13:29:08 +00:00
if ( Game_mode & GM_NETWORK )
{
if ( multi_powerup_is_4pack ( ( int ) powerup_type ) )
PowerupsInMine [ ( int ) ( powerup_type - 1 ) ] + = 4 ;
else
PowerupsInMine [ ( int ) powerup_type ] + + ;
}
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_play_sound ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-08-11 15:17:01 +00:00
int sound_num = buf [ 2 ] ;
fix volume = buf [ 3 ] < < 12 ;
2006-03-20 17:12:09 +00:00
if ( ! Players [ pnum ] . connected )
return ;
Assert ( Players [ pnum ] . objnum > = 0 ) ;
Assert ( Players [ pnum ] . objnum < = Highest_object_index ) ;
digi_link_sound_to_object ( sound_num , Players [ pnum ] . objnum , 0 , volume ) ;
}
2014-09-21 22:10:12 +00:00
static void multi_do_score ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2014-07-16 02:35:26 +00:00
if ( pnum > = N_players )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // Non-terminal, see rob
return ;
}
if ( Newdemo_state = = ND_STATE_RECORDING ) {
int score ;
score = GET_INTEL_INT ( buf + 2 ) ;
newdemo_record_multi_score ( pnum , score ) ;
}
Players [ pnum ] . score = GET_INTEL_INT ( buf + 2 ) ;
multi_sort_kill_list ( ) ;
}
2014-09-21 22:10:12 +00:00
static void multi_do_trigger ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-08-11 15:17:01 +00:00
int trigger = buf [ 2 ] ;
2014-07-16 02:35:26 +00:00
if ( pnum > = N_players | | pnum = = Player_num )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // Got trigger from illegal playernum
return ;
}
if ( ( trigger < 0 ) | | ( trigger > = Num_triggers ) )
{
Int3 ( ) ; // Illegal trigger number in multiplayer
return ;
}
check_trigger_sub ( trigger , pnum , 0 ) ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-09-21 22:10:12 +00:00
static void multi_do_effect_blowup ( const playernum_t pnum , const ubyte * buf )
2013-12-19 12:48:33 +00:00
{
2013-12-29 04:28:07 +00:00
int side ;
2013-12-19 12:48:33 +00:00
vms_vector hitpnt ;
object dummy ;
2014-07-16 02:35:26 +00:00
if ( pnum > = N_players | | pnum = = Player_num )
2013-12-19 12:48:33 +00:00
return ;
multi_do_protocol_frame ( 1 , 0 ) ; // force packets to be sent, ensuring this packet will be attached to following MULTI_TRIGGER
2013-12-29 04:28:07 +00:00
segnum_t segnum = GET_INTEL_SHORT ( buf + 2 ) ;
2013-12-19 12:48:33 +00:00
side = buf [ 4 ] ;
hitpnt . x = GET_INTEL_INT ( buf + 5 ) ;
hitpnt . y = GET_INTEL_INT ( buf + 9 ) ;
hitpnt . z = GET_INTEL_INT ( buf + 13 ) ;
//create a dummy object which will be the weapon that hits
//the monitor. the blowup code wants to know who the parent of the
//laser is, so create a laser whose parent is the player
dummy . ctype . laser_info . parent_type = OBJ_PLAYER ;
dummy . ctype . laser_info . parent_num = pnum ;
check_effect_blowup ( & ( Segments [ segnum ] ) , side , & hitpnt , & dummy , 0 , 1 ) ;
}
2014-09-21 22:10:12 +00:00
static void multi_do_drop_marker ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
int i ;
2013-08-11 15:17:01 +00:00
int mesnum = buf [ 2 ] ;
2006-03-20 17:12:09 +00:00
vms_vector position ;
if ( pnum = = Player_num ) // my marker? don't set it down cuz it might screw up the orientation
return ;
position . x = GET_INTEL_INT ( buf + 3 ) ;
position . y = GET_INTEL_INT ( buf + 7 ) ;
position . z = GET_INTEL_INT ( buf + 11 ) ;
for ( i = 0 ; i < 40 ; i + + )
MarkerMessage [ ( pnum * 2 ) + mesnum ] [ i ] = buf [ 15 + i ] ;
2013-12-26 22:21:16 +00:00
if ( MarkerObject [ ( pnum * 2 ) + mesnum ] ! = object_none & & Objects [ MarkerObject [ ( pnum * 2 ) + mesnum ] ] . type ! = OBJ_NONE & & MarkerObject [ ( pnum * 2 ) + mesnum ] ! = 0 )
2006-03-20 17:12:09 +00:00
obj_delete ( MarkerObject [ ( pnum * 2 ) + mesnum ] ) ;
2014-01-01 23:38:06 +00:00
MarkerObject [ ( pnum * 2 ) + mesnum ] = drop_marker_object ( & position , Objects [ Players [ pnum ] . objnum ] . segnum , & Objects [ Players [ pnum ] . objnum ] . orient , ( pnum * 2 ) + mesnum ) ;
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
2013-10-27 22:00:14 +00:00
static void multi_do_hostage_door_status ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
// Update hit point status of a door
int count = 1 ;
int wallnum ;
fix hps ;
wallnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
hps = GET_INTEL_INT ( buf + count ) ; count + = 4 ;
if ( ( wallnum < 0 ) | | ( wallnum > Num_walls ) | | ( hps < 0 ) | | ( Walls [ wallnum ] . type ! = WALL_BLASTABLE ) )
{
Int3 ( ) ; // Non-terminal, see Rob
return ;
}
if ( hps < Walls [ wallnum ] . hps )
wall_damage ( & Segments [ Walls [ wallnum ] . segnum ] , Walls [ wallnum ] . sidenum , Walls [ wallnum ] . hps - hps ) ;
}
void
multi_reset_stuff ( void )
{
// A generic, emergency function to solve problems that crop up
// when a player exits quick-out from the game because of a
2007-12-29 14:18:49 +00:00
// connection loss. Fixes several weird bugs!
2006-03-20 17:12:09 +00:00
dead_player_end ( ) ;
Players [ Player_num ] . homing_object_dist = - F1_0 ; // Turn off homing sound.
reset_rear_view ( ) ;
}
2014-08-16 23:18:17 +00:00
void multi_reset_player_object ( vobjptridx_t objp )
2006-03-20 17:12:09 +00:00
{
int i ;
//Init physics for a non-console player
2013-12-24 04:53:59 +00:00
Assert ( ( objp ) < = Highest_object_index ) ;
2006-03-20 17:12:09 +00:00
Assert ( ( objp - > type = = OBJ_PLAYER ) | | ( objp - > type = = OBJ_GHOST ) ) ;
2014-09-28 21:11:04 +00:00
vm_vec_zero ( objp - > mtype . phys_info . velocity ) ;
vm_vec_zero ( objp - > mtype . phys_info . thrust ) ;
vm_vec_zero ( objp - > mtype . phys_info . rotvel ) ;
vm_vec_zero ( objp - > mtype . phys_info . rotthrust ) ;
2013-12-26 02:47:34 +00:00
objp - > mtype . phys_info . turnroll = 0 ;
2006-03-20 17:12:09 +00:00
objp - > mtype . phys_info . mass = Player_ship - > mass ;
objp - > mtype . phys_info . drag = Player_ship - > drag ;
2011-02-09 11:58:32 +00:00
if ( objp - > type = = OBJ_PLAYER )
2012-05-21 15:06:50 +00:00
objp - > mtype . phys_info . flags | = PF_TURNROLL | PF_WIGGLE ;
2011-02-09 11:58:32 +00:00
else
objp - > mtype . phys_info . flags & = ~ ( PF_TURNROLL | PF_LEVELLING | PF_WIGGLE ) ;
2006-03-20 17:12:09 +00:00
//Init render info
objp - > render_type = RT_POLYOBJ ;
objp - > rtype . pobj_info . model_num = Player_ship - > model_num ; //what model is this?
objp - > rtype . pobj_info . subobj_flags = 0 ; //zero the flags
for ( i = 0 ; i < MAX_SUBMODELS ; i + + )
vm_angvec_zero ( & objp - > rtype . pobj_info . anim_angles [ i ] ) ;
//reset textures for this, if not player 0
multi_reset_object_texture ( objp ) ;
// Clear misc
objp - > flags = 0 ;
if ( objp - > type = = OBJ_GHOST )
objp - > render_type = RT_NONE ;
}
void multi_reset_object_texture ( object * objp )
{
int id , i ;
if ( Game_mode & GM_TEAM )
2013-10-07 23:52:33 +00:00
id = get_team ( get_player_id ( objp ) ) ;
2006-03-20 17:12:09 +00:00
else
2013-10-07 23:52:33 +00:00
id = get_player_id ( objp ) ;
2006-03-20 17:12:09 +00:00
if ( id = = 0 )
objp - > rtype . pobj_info . alt_textures = 0 ;
else {
2011-06-04 20:50:37 +00:00
if ( N_PLAYER_SHIP_TEXTURES < Polygon_models [ objp - > rtype . pobj_info . model_num ] . n_textures )
Error ( " Too many player ship textures! \n " ) ;
2006-03-20 17:12:09 +00:00
2012-03-28 10:26:24 +00:00
for ( i = 0 ; i < Polygon_models [ objp - > rtype . pobj_info . model_num ] . n_textures ; i + + )
2006-03-20 17:12:09 +00:00
multi_player_textures [ id - 1 ] [ i ] = ObjBitmaps [ ObjBitmapPtrs [ Polygon_models [ objp - > rtype . pobj_info . model_num ] . first_texture + i ] ] ;
multi_player_textures [ id - 1 ] [ 4 ] = ObjBitmaps [ ObjBitmapPtrs [ First_multi_bitmap_num + ( id - 1 ) * 2 ] ] ;
multi_player_textures [ id - 1 ] [ 5 ] = ObjBitmaps [ ObjBitmapPtrs [ First_multi_bitmap_num + ( id - 1 ) * 2 + 1 ] ] ;
objp - > rtype . pobj_info . alt_textures = id ;
}
}
2014-09-21 22:10:21 +00:00
void multi_process_bigdata ( const playernum_t pnum , const ubyte * buf , uint_fast32_t len )
2006-03-20 17:12:09 +00:00
{
// Takes a bunch of messages, check them for validity,
// and pass them to multi_process_data.
2014-09-21 22:10:21 +00:00
uint_fast32_t bytes_processed = 0 ;
2006-03-20 17:12:09 +00:00
while ( bytes_processed < len ) {
2014-09-21 22:10:21 +00:00
uint_fast32_t type = buf [ bytes_processed ] ;
2006-03-20 17:12:09 +00:00
2013-06-09 23:06:53 +00:00
if ( ( type > = sizeof ( message_length ) / sizeof ( message_length [ 0 ] ) ) )
2012-04-15 01:05:28 +00:00
{
2014-09-21 22:10:21 +00:00
con_printf ( CON_DEBUG , " multi_process_bigdata: Invalid packet type %lu! " , static_cast < unsigned long > ( type ) ) ;
2006-03-20 17:12:09 +00:00
return ;
}
2014-09-21 22:10:21 +00:00
uint_fast32_t sub_len = message_length [ type ] ;
2006-03-20 17:12:09 +00:00
Assert ( sub_len > 0 ) ;
if ( ( bytes_processed + sub_len ) > len ) {
2014-09-21 22:10:21 +00:00
con_printf ( CON_DEBUG , " multi_process_bigdata: packet type %u too short (%lu>%lu)! " , static_cast < unsigned > ( type ) , static_cast < unsigned long > ( bytes_processed + sub_len ) , static_cast < unsigned long > ( len ) ) ;
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
return ;
}
2014-09-21 22:10:21 +00:00
multi_process_data ( pnum , & buf [ bytes_processed ] , type ) ;
2006-03-20 17:12:09 +00:00
bytes_processed + = sub_len ;
}
}
//
// Part 2 : Functions that send communication messages to inform the other
// players of something we did.
//
2014-08-23 23:53:56 +00:00
void multi_send_fire ( int laser_gun , int laser_level , int laser_flags , int laser_fired , objnum_t laser_track , objptridx_t is_bomb_objnum )
2006-03-20 17:12:09 +00:00
{
2013-12-12 21:48:34 +00:00
object * ownship = & Objects [ Players [ Player_num ] . objnum ] ;
2013-12-09 13:05:24 +00:00
static fix64 last_fireup_time = 0 ;
2013-11-23 13:02:19 +00:00
2013-12-09 13:05:24 +00:00
// provoke positional update if possible (20 times per second max. matches vulcan, the fastest firing weapon)
if ( timer_query ( ) > = ( last_fireup_time + ( F1_0 / 20 ) ) )
{
multi_do_protocol_frame ( 1 , 0 ) ;
last_fireup_time = timer_query ( ) ;
}
2012-04-15 01:05:28 +00:00
2006-03-20 17:12:09 +00:00
multibuf [ 0 ] = ( char ) MULTI_FIRE ;
2013-12-26 22:21:16 +00:00
if ( is_bomb_objnum ! = object_none )
2013-08-09 15:21:03 +00:00
{
2014-08-23 23:53:56 +00:00
if ( is_proximity_bomb_or_smart_mine ( get_weapon_id ( is_bomb_objnum ) ) )
2013-08-09 15:21:03 +00:00
multibuf [ 0 ] = ( char ) MULTI_FIRE_BOMB ;
}
2013-12-26 22:21:16 +00:00
else if ( laser_track ! = object_none )
2013-08-09 15:21:03 +00:00
{
multibuf [ 0 ] = ( char ) MULTI_FIRE_TRACK ;
}
2006-03-20 17:12:09 +00:00
multibuf [ 1 ] = ( char ) Player_num ;
2011-09-15 08:45:48 +00:00
multibuf [ 2 ] = ( char ) laser_gun ;
multibuf [ 3 ] = ( char ) laser_level ;
multibuf [ 4 ] = ( char ) laser_flags ;
multibuf [ 5 ] = ( char ) laser_fired ;
2013-11-23 13:02:19 +00:00
PUT_INTEL_INT ( multibuf + 6 , ownship - > orient . fvec . x ) ;
PUT_INTEL_INT ( multibuf + 10 , ownship - > orient . fvec . y ) ;
PUT_INTEL_INT ( multibuf + 14 , ownship - > orient . fvec . z ) ;
2013-08-09 15:21:03 +00:00
/*
* If we fire a bomb , it ' s persistent . Let others know of it ' s objnum so host can track it ' s behaviour over clients ( host - authority functions , D2 chaff ability ) .
* If we fire a tracking projectile , we should others let know abotu what we track but we have to pay attention it ' s mapped correctly .
* If we fire something else , we make the packet as small as possible .
*/
if ( multibuf [ 0 ] = = MULTI_FIRE_BOMB )
{
map_objnum_local_to_local ( is_bomb_objnum ) ;
2013-11-23 13:02:19 +00:00
PUT_INTEL_SHORT ( multibuf + 18 , is_bomb_objnum ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_FIRE_BOMB > ( multibuf , 20 , 1 ) ;
2013-08-09 15:21:03 +00:00
}
else if ( multibuf [ 0 ] = = MULTI_FIRE_TRACK )
{
sbyte remote_owner ;
short remote_laser_track = - 1 ;
2006-03-20 17:12:09 +00:00
2013-12-29 04:28:07 +00:00
remote_laser_track = objnum_local_to_remote ( laser_track , & remote_owner ) ;
2013-11-23 13:02:19 +00:00
PUT_INTEL_SHORT ( multibuf + 18 , remote_laser_track ) ;
multibuf [ 20 ] = remote_owner ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_FIRE_TRACK > ( multibuf , 21 , 1 ) ;
2013-08-09 15:21:03 +00:00
}
else
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_FIRE > ( multibuf , 18 , 1 ) ;
2006-03-20 17:12:09 +00:00
}
2013-12-29 04:28:07 +00:00
void multi_send_destroy_controlcen ( objnum_t objnum , int player )
2006-03-20 17:12:09 +00:00
{
if ( player = = Player_num )
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , TXT_YOU_DEST_CONTROL ) ;
2006-03-20 17:12:09 +00:00
else if ( ( player > 0 ) & & ( player < N_players ) )
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , static_cast < const char * > ( Players [ player ] . callsign ) , TXT_HAS_DEST_CONTROL ) ;
2006-03-20 17:12:09 +00:00
else
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , TXT_CONTROL_DESTROYED ) ;
2006-03-20 17:12:09 +00:00
PUT_INTEL_SHORT ( multibuf + 1 , objnum ) ;
multibuf [ 3 ] = player ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_CONTROLCEN > ( multibuf , 4 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-29 20:52:17 +00:00
void multi_send_drop_marker ( int player , const vms_vector & position , char messagenum , const marker_message_text_t & text )
2006-03-20 17:12:09 +00:00
{
if ( player < N_players )
{
multibuf [ 1 ] = ( char ) player ;
multibuf [ 2 ] = messagenum ;
PUT_INTEL_INT ( multibuf + 3 , position . x ) ;
PUT_INTEL_INT ( multibuf + 7 , position . y ) ;
PUT_INTEL_INT ( multibuf + 11 , position . z ) ;
2013-12-28 18:56:34 +00:00
for ( unsigned i = 0 ; i < text . size ( ) ; i + + )
2006-03-20 17:12:09 +00:00
multibuf [ 15 + i ] = text [ i ] ;
2013-12-28 18:56:34 +00:00
multi_send_data < MULTI_MARKER > ( multibuf , 15 + text . size ( ) , 2 ) ;
2006-03-20 17:12:09 +00:00
}
}
2012-06-10 09:26:29 +00:00
void multi_send_markers ( )
{
// send marker positions/text to new player
int i ;
for ( i = 0 ; i < N_players ; i + + )
{
2013-12-29 04:28:07 +00:00
objnum_t mo ;
2013-12-29 21:59:50 +00:00
mo = MarkerObject [ ( i * 2 ) ] ;
if ( mo ! = object_none )
multi_send_drop_marker ( i , Objects [ mo ] . pos , 0 , MarkerMessage [ i * 2 ] ) ;
mo = MarkerObject [ ( i * 2 ) + 1 ] ;
if ( mo ! = object_none )
multi_send_drop_marker ( i , Objects [ mo ] . pos , 1 , MarkerMessage [ ( i * 2 ) + 1 ] ) ;
2012-06-10 09:26:29 +00:00
}
}
2013-03-03 01:03:33 +00:00
# endif
2012-06-10 09:26:29 +00:00
2006-03-20 17:12:09 +00:00
void
multi_send_endlevel_start ( int secret )
{
multibuf [ 1 ] = Player_num ;
multibuf [ 2 ] = ( char ) secret ;
if ( ( secret ) & & ! multi_goto_secret )
multi_goto_secret = 1 ;
else if ( ! multi_goto_secret )
multi_goto_secret = 2 ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_ENDLEVEL_START > ( multibuf , 3 , 2 ) ;
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_ESCAPE_TUNNEL ;
2009-04-09 07:41:30 +00:00
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
net_udp_send_endlevel_packet ( ) ;
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
Error ( " Protocol handling missing in multi_send_endlevel_start \n " ) ;
break ;
}
2006-03-20 17:12:09 +00:00
}
}
2013-12-16 22:59:31 +00:00
void multi_send_player_deres ( deres_type_t type )
2006-03-20 17:12:09 +00:00
{
int count = 0 ;
int i ;
if ( Network_send_objects )
{
Network_send_objnum = - 1 ;
}
2011-05-13 20:21:13 +00:00
multi_send_position ( Players [ Player_num ] . objnum ) ;
2013-12-16 23:44:34 +00:00
count + + ;
2006-03-20 17:12:09 +00:00
multibuf [ count + + ] = Player_num ;
2013-12-16 22:59:31 +00:00
multibuf [ count + + ] = type ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# define PUT_WEAPON_FLAGS(buf,count,value) (buf[count] = value, ++count)
# elif defined(DXX_BUILD_DESCENT_II)
2013-08-11 15:17:28 +00:00
# define PUT_WEAPON_FLAGS(buf,count,value) ((PUT_INTEL_SHORT(buf+count, value)), count+=sizeof(uint16_t))
2013-03-03 01:03:33 +00:00
# endif
2013-08-11 15:17:28 +00:00
PUT_WEAPON_FLAGS ( multibuf , count , Players [ Player_num ] . primary_weapon_flags ) ;
PUT_WEAPON_FLAGS ( multibuf , count , Players [ Player_num ] . secondary_weapon_flags ) ;
2006-03-20 17:12:09 +00:00
multibuf [ count + + ] = ( char ) Players [ Player_num ] . laser_level ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ HOMING_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ CONCUSSION_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ SMART_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ MEGA_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ PROXIMITY_INDEX ] ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ SMISSILE1_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ GUIDED_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ SMART_MINE_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ SMISSILE4_INDEX ] ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_ammo [ SMISSILE5_INDEX ] ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2013-09-20 23:12:54 +00:00
PUT_INTEL_SHORT ( multibuf + count , Players [ Player_num ] . vulcan_ammo ) ;
2006-03-20 17:12:09 +00:00
count + = 2 ;
PUT_INTEL_INT ( multibuf + count , Players [ Player_num ] . flags ) ;
count + = 4 ;
multibuf [ count + + ] = Net_create_loc ;
Assert ( Net_create_loc < = MAX_NET_CREATE_OBJECTS ) ;
memset ( multibuf + count , - 1 , MAX_NET_CREATE_OBJECTS * sizeof ( short ) ) ;
for ( i = 0 ; i < Net_create_loc ; i + + )
{
if ( Net_create_objnums [ i ] < = 0 ) {
Int3 ( ) ; // Illegal value in created egg object numbers
count + = 2 ;
continue ;
}
PUT_INTEL_SHORT ( multibuf + count , Net_create_objnums [ i ] ) ; count + = 2 ;
// We created these objs so our local number = the network number
2013-12-29 04:28:07 +00:00
map_objnum_local_to_local ( Net_create_objnums [ i ] ) ;
2006-03-20 17:12:09 +00:00
}
Net_create_loc = 0 ;
2013-12-16 22:59:31 +00:00
if ( count > message_length [ MULTI_PLAYER_DERES ] )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // See Rob
}
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_PLAYER_DERES > ( multibuf , command_length < MULTI_PLAYER_DERES > : : value , 2 ) ;
2006-03-20 17:12:09 +00:00
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_CLOAKED )
multi_send_decloak ( ) ;
2013-08-11 16:13:04 +00:00
multi_strip_robots ( Player_num ) ;
2006-03-20 17:12:09 +00:00
}
2011-01-14 13:29:08 +00:00
/*
* Powerup capping : Keep track of how many powerups are in level and kill these which would exceed initial limit .
2011-09-13 23:15:32 +00:00
* NOTE : code encapsuled by OLDPOWCAP define is original and buggy Descent2 code .
2011-01-14 13:29:08 +00:00
*/
// Count the initial amount of Powerups in the level
void multi_powcap_count_powerups_in_mine ( void )
{
int i ;
2014-07-12 03:30:35 +00:00
PowerupsInMine = { } ;
2011-01-14 13:29:08 +00:00
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
if ( Objects [ i ] . type = = OBJ_POWERUP )
{
2013-10-07 23:52:33 +00:00
if ( multi_powerup_is_4pack ( get_powerup_id ( & Objects [ i ] ) ) )
2011-01-14 13:29:08 +00:00
PowerupsInMine [ Objects [ i ] . id - 1 ] + = 4 ;
else
2013-10-07 23:52:33 +00:00
PowerupsInMine [ get_powerup_id ( & Objects [ i ] ) ] + + ;
2011-01-14 13:29:08 +00:00
}
}
}
2006-03-20 17:12:09 +00:00
2011-01-14 13:29:08 +00:00
// We want to drop something. Kill every Powerup which exceeds the level limit
void multi_powcap_cap_objects ( )
2006-03-20 17:12:09 +00:00
{
2013-03-03 01:03:33 +00:00
char type ;
2006-03-20 17:12:09 +00:00
int index ;
2013-12-14 01:53:45 +00:00
if ( ! ( Game_mode & GM_NETWORK ) | | ( Game_mode & GM_MULTI_COOP ) )
2006-03-20 17:12:09 +00:00
return ;
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2011-01-14 13:29:08 +00:00
Players [ Player_num ] . secondary_ammo [ PROXIMITY_INDEX ] + = Proximity_dropped ;
Proximity_dropped = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:23:37 +00:00
Players [ Player_num ] . secondary_ammo [ SMART_MINE_INDEX ] + = Smartmines_dropped ;
2011-01-14 13:29:08 +00:00
Smartmines_dropped = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2011-01-14 13:29:08 +00:00
2006-03-20 17:12:09 +00:00
for ( index = 0 ; index < MAX_PRIMARY_WEAPONS ; index + + )
{
type = Primary_weapon_to_powerup [ index ] ;
if ( PowerupsInMine [ ( int ) type ] > = MaxPowerupsAllowed [ ( int ) type ] )
2013-10-26 19:52:41 +00:00
if ( Players [ Player_num ] . primary_weapon_flags & HAS_PRIMARY_FLAG ( index ) )
2006-03-20 17:12:09 +00:00
{
2013-12-07 00:47:27 +00:00
con_printf ( CON_VERBOSE , " PIM=%d MPA=%d " , PowerupsInMine [ ( int ) type ] , MaxPowerupsAllowed [ ( int ) type ] ) ;
con_printf ( CON_VERBOSE , " Killing a primary cuz there's too many! (%d) " , type ) ;
2013-10-26 19:52:41 +00:00
Players [ Player_num ] . primary_weapon_flags & = ( ~ HAS_PRIMARY_FLAG ( index ) ) ;
2006-03-20 17:12:09 +00:00
}
}
// Don't do the adjustment stuff for Hoard mode
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . secondary_ammo [ 2 ] / = 4 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . secondary_ammo [ 7 ] / = 4 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
for ( index = 0 ; index < MAX_SECONDARY_WEAPONS ; index + + )
{
2013-08-11 16:03:47 +00:00
if ( game_mode_hoard ( ) & & index = = PROXIMITY_INDEX )
2006-03-20 17:12:09 +00:00
continue ;
type = Secondary_weapon_to_powerup [ index ] ;
if ( ( Players [ Player_num ] . secondary_ammo [ index ] + PowerupsInMine [ ( int ) type ] ) > MaxPowerupsAllowed [ ( int ) type ] )
{
if ( MaxPowerupsAllowed [ ( int ) type ] - PowerupsInMine [ ( int ) type ] < 0 )
Players [ Player_num ] . secondary_ammo [ index ] = 0 ;
else
Players [ Player_num ] . secondary_ammo [ index ] = ( MaxPowerupsAllowed [ ( int ) type ] - PowerupsInMine [ ( int ) type ] ) ;
2013-12-07 00:47:27 +00:00
con_printf ( CON_VERBOSE , " Hey! I killed secondary type %d because PIM=%d MPA=%d " , type , PowerupsInMine [ ( int ) type ] , MaxPowerupsAllowed [ ( int ) type ] ) ;
2006-03-20 17:12:09 +00:00
}
}
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . secondary_ammo [ 2 ] * = 4 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . secondary_ammo [ 7 ] * = 4 ;
if ( Players [ Player_num ] . laser_level > MAX_LASER_LEVEL )
if ( PowerupsInMine [ POW_SUPER_LASER ] + 1 > MaxPowerupsAllowed [ POW_SUPER_LASER ] )
Players [ Player_num ] . laser_level = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_QUAD_LASERS )
if ( PowerupsInMine [ POW_QUAD_FIRE ] + 1 > MaxPowerupsAllowed [ POW_QUAD_FIRE ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_QUAD_LASERS ) ;
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_CLOAKED )
if ( PowerupsInMine [ POW_CLOAK ] + 1 > MaxPowerupsAllowed [ POW_CLOAK ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_CLOAKED ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_MAP_ALL )
if ( PowerupsInMine [ POW_FULL_MAP ] + 1 > MaxPowerupsAllowed [ POW_FULL_MAP ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_MAP_ALL ) ;
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_AFTERBURNER )
if ( PowerupsInMine [ POW_AFTERBURNER ] + 1 > MaxPowerupsAllowed [ POW_AFTERBURNER ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_AFTERBURNER ) ;
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_AMMO_RACK )
if ( PowerupsInMine [ POW_AMMO_RACK ] + 1 > MaxPowerupsAllowed [ POW_AMMO_RACK ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_AMMO_RACK ) ;
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_CONVERTER )
if ( PowerupsInMine [ POW_CONVERTER ] + 1 > MaxPowerupsAllowed [ POW_CONVERTER ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_CONVERTER ) ;
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_HEADLIGHT )
if ( PowerupsInMine [ POW_HEADLIGHT ] + 1 > MaxPowerupsAllowed [ POW_HEADLIGHT ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_HEADLIGHT ) ;
2013-08-11 16:03:47 +00:00
if ( game_mode_capture_flag ( ) )
2006-03-20 17:12:09 +00:00
{
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_FLAG )
{
2013-03-03 01:03:33 +00:00
char flagtype ;
2006-03-20 17:12:09 +00:00
if ( get_team ( Player_num ) = = TEAM_RED )
flagtype = POW_FLAG_BLUE ;
else
flagtype = POW_FLAG_RED ;
if ( PowerupsInMine [ ( int ) flagtype ] + 1 > MaxPowerupsAllowed [ ( int ) flagtype ] )
Players [ Player_num ] . flags & = ( ~ PLAYER_FLAGS_FLAG ) ;
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2011-01-14 13:29:08 +00:00
// Adds players inventory to multi cap
2014-09-21 22:10:12 +00:00
static void multi_powcap_adjust_cap_for_player ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
char type ;
int index ;
2013-12-14 01:53:45 +00:00
if ( ! ( Game_mode & GM_NETWORK ) | | ( Game_mode & GM_MULTI_COOP ) )
2006-03-20 17:12:09 +00:00
return ;
for ( index = 0 ; index < MAX_PRIMARY_WEAPONS ; index + + )
{
type = Primary_weapon_to_powerup [ index ] ;
2013-10-26 19:52:41 +00:00
if ( Players [ pnum ] . primary_weapon_flags & HAS_PRIMARY_FLAG ( index ) )
2006-03-20 17:12:09 +00:00
MaxPowerupsAllowed [ ( int ) type ] + + ;
}
for ( index = 0 ; index < MAX_SECONDARY_WEAPONS ; index + + )
{
type = Secondary_weapon_to_powerup [ index ] ;
MaxPowerupsAllowed [ ( int ) type ] + = Players [ pnum ] . secondary_ammo [ index ] ;
}
if ( Players [ pnum ] . flags & PLAYER_FLAGS_QUAD_LASERS )
MaxPowerupsAllowed [ POW_QUAD_FIRE ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_CLOAKED )
MaxPowerupsAllowed [ POW_CLOAK ] + + ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:23:37 +00:00
if ( Players [ pnum ] . laser_level > MAX_LASER_LEVEL )
MaxPowerupsAllowed [ POW_SUPER_LASER ] + + ;
2006-03-20 17:12:09 +00:00
if ( Players [ pnum ] . flags & PLAYER_FLAGS_MAP_ALL )
MaxPowerupsAllowed [ POW_FULL_MAP ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_AFTERBURNER )
MaxPowerupsAllowed [ POW_AFTERBURNER ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_AMMO_RACK )
MaxPowerupsAllowed [ POW_AMMO_RACK ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_CONVERTER )
MaxPowerupsAllowed [ POW_CONVERTER ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_HEADLIGHT )
MaxPowerupsAllowed [ POW_HEADLIGHT ] + + ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_powcap_adjust_remote_cap ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
char type ;
int index ;
2013-12-14 01:53:45 +00:00
if ( ! ( Game_mode & GM_NETWORK ) | | ( Game_mode & GM_MULTI_COOP ) )
2006-03-20 17:12:09 +00:00
return ;
for ( index = 0 ; index < MAX_PRIMARY_WEAPONS ; index + + )
{
type = Primary_weapon_to_powerup [ index ] ;
2013-10-26 19:52:41 +00:00
if ( Players [ pnum ] . primary_weapon_flags & HAS_PRIMARY_FLAG ( index ) )
2006-03-20 17:12:09 +00:00
PowerupsInMine [ ( int ) type ] + + ;
}
for ( index = 0 ; index < MAX_SECONDARY_WEAPONS ; index + + )
{
type = Secondary_weapon_to_powerup [ index ] ;
2013-08-11 16:03:47 +00:00
if ( game_mode_hoard ( ) & & index = = 2 )
2006-03-20 17:12:09 +00:00
continue ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( index = = 2 ) // PROX? Those bastards...
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( index = = 2 | | index = = 7 ) // PROX or SMARTMINES? Those bastards...
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
PowerupsInMine [ ( int ) type ] + = ( Players [ pnum ] . secondary_ammo [ index ] / 4 ) ;
else
PowerupsInMine [ ( int ) type ] + = Players [ pnum ] . secondary_ammo [ index ] ;
}
if ( Players [ pnum ] . flags & PLAYER_FLAGS_QUAD_LASERS )
PowerupsInMine [ POW_QUAD_FIRE ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_CLOAKED )
PowerupsInMine [ POW_CLOAK ] + + ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:23:37 +00:00
if ( Players [ pnum ] . laser_level > MAX_LASER_LEVEL )
PowerupsInMine [ POW_SUPER_LASER ] + + ;
2006-03-20 17:12:09 +00:00
if ( Players [ pnum ] . flags & PLAYER_FLAGS_MAP_ALL )
PowerupsInMine [ POW_FULL_MAP ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_AFTERBURNER )
PowerupsInMine [ POW_AFTERBURNER ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_AMMO_RACK )
PowerupsInMine [ POW_AMMO_RACK ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_CONVERTER )
PowerupsInMine [ POW_CONVERTER ] + + ;
if ( Players [ pnum ] . flags & PLAYER_FLAGS_HEADLIGHT )
PowerupsInMine [ POW_HEADLIGHT ] + + ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
void
multi_send_message ( void )
{
int loc = 0 ;
if ( Network_message_reciever ! = - 1 )
{
2013-12-16 23:44:34 +00:00
loc + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ loc ] = ( char ) Player_num ; loc + = 1 ;
2013-03-30 19:41:33 +00:00
strncpy ( ( char * ) ( multibuf + loc ) , Network_message , MAX_MESSAGE_LEN ) ; loc + = MAX_MESSAGE_LEN ;
2006-03-20 17:12:09 +00:00
multibuf [ loc - 1 ] = ' \0 ' ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_MESSAGE > ( multibuf , loc , 0 ) ;
2006-03-20 17:12:09 +00:00
Network_message_reciever = - 1 ;
}
}
void
multi_send_reappear ( )
{
2009-11-24 09:48:53 +00:00
multi_send_position ( Players [ Player_num ] . objnum ) ;
2012-04-07 10:32:22 +00:00
multibuf [ 1 ] = ( char ) Player_num ;
PUT_INTEL_SHORT ( multibuf + 2 , Players [ Player_num ] . objnum ) ;
2006-03-20 17:12:09 +00:00
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_REAPPEAR > ( multibuf , 4 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
void
multi_send_position ( int objnum )
{
# ifdef WORDS_BIGENDIAN
shortpos sp ;
# endif
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + + ;
2009-11-24 09:48:53 +00:00
multibuf [ count + + ] = ( char ) Player_num ;
2006-03-20 17:12:09 +00:00
# ifndef WORDS_BIGENDIAN
2013-12-12 21:48:34 +00:00
create_shortpos ( ( shortpos * ) ( multibuf + count ) , & Objects [ objnum ] , 0 ) ;
2006-03-20 17:12:09 +00:00
count + = sizeof ( shortpos ) ;
# else
create_shortpos ( & sp , Objects + objnum , 1 ) ;
memcpy ( & ( multibuf [ count ] ) , ( ubyte * ) ( sp . bytemat ) , 9 ) ;
count + = 9 ;
memcpy ( & ( multibuf [ count ] ) , ( ubyte * ) & ( sp . xo ) , 14 ) ;
count + = 14 ;
# endif
2009-11-24 09:48:53 +00:00
// send twice while first has priority so the next one will be attached to the next bigdata packet
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_POSITION > ( multibuf , count , 2 ) ;
multi_send_data < MULTI_POSITION > ( multibuf , count , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2011-05-25 13:25:13 +00:00
/*
2011-09-13 23:15:32 +00:00
* I was killed . If I am host , send this info to everyone and compute kill . If I am just a Client I ' ll only send the kill but not compute it for me . I ( Client ) will wait for Host to send me my kill back together with updated game_mode related variables which are important for me to compute consistent kill .
2011-05-25 13:25:13 +00:00
*/
2014-08-16 23:18:17 +00:00
void multi_send_kill ( vobjptridx_t objnum )
2006-03-20 17:12:09 +00:00
{
// I died, tell the world.
int count = 0 ;
2014-07-05 22:21:47 +00:00
Assert ( get_player_id ( objnum ) = = Player_num ) ;
2013-12-29 04:28:07 +00:00
objnum_t killer_objnum = Players [ Player_num ] . killer_objnum ;
2011-05-25 13:25:13 +00:00
2011-09-13 23:15:32 +00:00
count + = 1 ;
multibuf [ count ] = Player_num ; count + = 1 ;
2006-03-20 17:12:09 +00:00
2013-12-26 22:21:16 +00:00
if ( killer_objnum ! = object_none )
2011-09-13 23:15:32 +00:00
{
short s = ( short ) objnum_local_to_remote ( killer_objnum , ( sbyte * ) & multibuf [ count + 2 ] ) ; // do it with variable since INTEL_SHORT won't work on return val from function.
PUT_INTEL_SHORT ( multibuf + count , s ) ;
}
else
{
PUT_INTEL_SHORT ( multibuf + count , - 1 ) ;
multibuf [ count + 2 ] = ( char ) - 1 ;
}
count + = 3 ;
// I am host - I know what's going on so attach game_mode related info which might be vital for correct kill computation
if ( multi_i_am_master ( ) )
{
multibuf [ count ] = Netgame . team_vector ; count + = 1 ;
multibuf [ count ] = Bounty_target ; count + = 1 ;
}
2006-03-20 17:12:09 +00:00
2011-09-13 23:15:32 +00:00
if ( multi_i_am_master ( ) )
{
2011-05-25 13:25:13 +00:00
multi_compute_kill ( killer_objnum , objnum ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_KILL_HOST > ( multibuf , count , 2 ) ;
2006-03-20 17:12:09 +00:00
}
else
2013-12-16 22:15:38 +00:00
multi_send_data_direct < MULTI_KILL_CLIENT > ( multibuf , count , multi_who_is_master ( ) , 2 ) ; // I am just a client so I'll only send my kill but not compute it, yet. I'll get response from host so I can compute it correctly
2006-03-20 17:12:09 +00:00
2013-08-11 16:13:04 +00:00
multi_strip_robots ( Player_num ) ;
2011-05-25 13:25:13 +00:00
2011-09-13 23:15:32 +00:00
if ( Game_mode & GM_BOUNTY & & multi_i_am_master ( ) ) // update in case if needed... we could attach this to this packet but... meh...
multi_send_bounty ( ) ;
2006-03-20 17:12:09 +00:00
}
2014-08-16 23:18:17 +00:00
void multi_send_remobj ( vobjptridx_t objnum )
2006-03-20 17:12:09 +00:00
{
// Tell the other guy to remove an object from his list
sbyte obj_owner ;
short remote_objnum ;
2014-07-05 22:21:47 +00:00
if ( objnum - > type = = OBJ_POWERUP & & ( Game_mode & GM_NETWORK ) )
2011-01-14 13:29:08 +00:00
{
2014-07-05 22:21:47 +00:00
if ( multi_powerup_is_4pack ( get_powerup_id ( objnum ) ) )
2011-01-14 13:29:08 +00:00
{
2014-07-12 03:26:58 +00:00
if ( PowerupsInMine [ objnum - > id - 1 ] < 4 )
2014-07-05 22:21:47 +00:00
PowerupsInMine [ objnum - > id - 1 ] = 0 ;
2011-01-14 13:29:08 +00:00
else
2014-07-05 22:21:47 +00:00
PowerupsInMine [ objnum - > id - 1 ] - = 4 ;
2011-01-14 13:29:08 +00:00
}
else
{
2014-07-05 22:21:47 +00:00
if ( PowerupsInMine [ get_powerup_id ( objnum ) ] > 0 )
PowerupsInMine [ get_powerup_id ( objnum ) ] - - ;
2011-01-14 13:29:08 +00:00
}
2006-03-20 17:12:09 +00:00
}
2013-12-29 04:28:07 +00:00
remote_objnum = objnum_local_to_remote ( objnum , & obj_owner ) ;
2006-03-20 17:12:09 +00:00
PUT_INTEL_SHORT ( multibuf + 1 , remote_objnum ) ; // Map to network objnums
multibuf [ 3 ] = obj_owner ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_REMOVE_OBJECT > ( multibuf , 4 , 2 ) ;
2006-03-20 17:12:09 +00:00
2009-04-09 07:41:30 +00:00
if ( Network_send_objects & & multi_objnum_is_past ( objnum ) )
2006-03-20 17:12:09 +00:00
{
Network_send_objnum = - 1 ;
}
}
void
2013-12-16 22:28:15 +00:00
multi_send_quit ( )
2006-03-20 17:12:09 +00:00
{
// I am quitting the game, tell the other guy the bad news.
multibuf [ 1 ] = Player_num ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_QUIT > ( multibuf , 2 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
void
multi_send_cloak ( void )
{
// Broadcast a change in our pflags (made to support cloaking)
multibuf [ 1 ] = ( char ) Player_num ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_CLOAK > ( multibuf , 2 , 2 ) ;
2006-03-20 17:12:09 +00:00
2013-08-11 16:13:04 +00:00
multi_strip_robots ( Player_num ) ;
2006-03-20 17:12:09 +00:00
}
void
multi_send_decloak ( void )
{
// Broadcast a change in our pflags (made to support cloaking)
multibuf [ 1 ] = ( char ) Player_num ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_DECLOAK > ( multibuf , 2 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-12-29 04:28:07 +00:00
void multi_send_door_open ( segnum_t segnum , int side , ubyte flag )
2006-03-20 17:12:09 +00:00
{
// When we open a door make sure everyone else opens that door
PUT_INTEL_SHORT ( multibuf + 1 , segnum ) ;
multibuf [ 3 ] = ( sbyte ) side ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
( void ) flag ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
multibuf [ 4 ] = flag ;
2013-03-03 01:03:33 +00:00
# endif
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_DOOR_OPEN > ( multibuf , DXX_MP_SIZE_DOOR_OPEN , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-09-21 22:10:12 +00:00
void multi_send_door_open_specific ( const playernum_t pnum , segnum_t segnum , int side , ubyte flag )
2006-03-20 17:12:09 +00:00
{
// For sending doors only to a specific person (usually when they're joining)
Assert ( Game_mode & GM_NETWORK ) ;
// Assert (pnum>-1 && pnum<N_players);
PUT_INTEL_SHORT ( multibuf + 1 , segnum ) ;
multibuf [ 3 ] = ( sbyte ) side ;
multibuf [ 4 ] = flag ;
2013-12-16 22:15:38 +00:00
multi_send_data_direct < MULTI_DOOR_OPEN > ( multibuf , DXX_MP_SIZE_DOOR_OPEN , pnum , 2 ) ;
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
//
// Part 3 : Functions that change or prepare the game for multiplayer use.
// Not including functions needed to syncronize or start the
// particular type of multiplayer game. Includes preparing the
// mines, player structures, etc.
2014-09-21 22:10:12 +00:00
void multi_send_create_explosion ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
// Send all data needed to create a remote explosion
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ count ] = ( sbyte ) pnum ; count + = 1 ;
// -----------
// Total size = 2
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_CREATE_EXPLOSION > ( multibuf , count , 0 ) ;
2006-03-20 17:12:09 +00:00
}
void
multi_send_controlcen_fire ( vms_vector * to_goal , int best_gun_num , int objnum )
{
# ifdef WORDS_BIGENDIAN
vms_vector swapped_vec ;
# endif
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2006-03-20 17:12:09 +00:00
# ifndef WORDS_BIGENDIAN
memcpy ( multibuf + count , to_goal , 12 ) ; count + = 12 ;
# else
swapped_vec . x = ( fix ) INTEL_INT ( ( int ) to_goal - > x ) ;
swapped_vec . y = ( fix ) INTEL_INT ( ( int ) to_goal - > y ) ;
swapped_vec . z = ( fix ) INTEL_INT ( ( int ) to_goal - > z ) ;
memcpy ( multibuf + count , & swapped_vec , 12 ) ; count + = 12 ;
# endif
multibuf [ count ] = ( char ) best_gun_num ; count + = 1 ;
PUT_INTEL_SHORT ( multibuf + count , objnum ) ; count + = 2 ;
// ------------
// Total = 16
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_CONTROLCEN_FIRE > ( multibuf , count , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2013-12-29 04:28:07 +00:00
void multi_send_create_powerup ( int powerup_type , segnum_t segnum , objnum_t objnum , vms_vector * pos )
2006-03-20 17:12:09 +00:00
{
// Create a powerup on a remote machine, used for remote
// placement of used powerups like missiles and cloaking
// powerups.
# ifdef WORDS_BIGENDIAN
vms_vector swapped_vec ;
# endif
int count = 0 ;
2009-11-24 09:48:53 +00:00
multi_send_position ( Players [ Player_num ] . objnum ) ;
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_NETWORK )
2011-01-14 13:29:08 +00:00
{
if ( multi_powerup_is_4pack ( powerup_type ) )
PowerupsInMine [ powerup_type - 1 ] + = 4 ;
else
PowerupsInMine [ powerup_type ] + + ;
}
2006-03-20 17:12:09 +00:00
2013-12-16 23:44:34 +00:00
count + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ count ] = Player_num ; count + = 1 ;
multibuf [ count ] = powerup_type ; count + = 1 ;
PUT_INTEL_SHORT ( multibuf + count , segnum ) ; count + = 2 ;
PUT_INTEL_SHORT ( multibuf + count , objnum ) ; count + = 2 ;
# ifndef WORDS_BIGENDIAN
memcpy ( multibuf + count , pos , sizeof ( vms_vector ) ) ; count + = sizeof ( vms_vector ) ;
# else
swapped_vec . x = ( fix ) INTEL_INT ( ( int ) pos - > x ) ;
swapped_vec . y = ( fix ) INTEL_INT ( ( int ) pos - > y ) ;
swapped_vec . z = ( fix ) INTEL_INT ( ( int ) pos - > z ) ;
memcpy ( multibuf + count , & swapped_vec , 12 ) ; count + = 12 ;
# endif
// -----------
// Total = 19
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_CREATE_POWERUP > ( multibuf , count , 2 ) ;
2006-03-20 17:12:09 +00:00
2009-04-09 07:41:30 +00:00
if ( Network_send_objects & & multi_objnum_is_past ( objnum ) )
2006-03-20 17:12:09 +00:00
{
Network_send_objnum = - 1 ;
}
map_objnum_local_to_local ( objnum ) ;
}
void
multi_send_play_sound ( int sound_num , fix volume )
{
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ count ] = Player_num ; count + = 1 ;
multibuf [ count ] = ( char ) sound_num ; count + = 1 ;
multibuf [ count ] = ( char ) ( volume > > 12 ) ; count + = 1 ;
// -----------
// Total = 4
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_PLAY_SOUND > ( multibuf , count , 0 ) ;
2006-03-20 17:12:09 +00:00
}
void
multi_send_score ( void )
{
// Send my current score to all other players so it will remain
// synced.
int count = 0 ;
if ( Game_mode & GM_MULTI_COOP ) {
multi_sort_kill_list ( ) ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ count ] = Player_num ; count + = 1 ;
PUT_INTEL_INT ( multibuf + count , Players [ Player_num ] . score ) ; count + = 4 ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_SCORE > ( multibuf , count , 0 ) ;
2006-03-20 17:12:09 +00:00
}
}
void
multi_send_trigger ( int triggernum )
{
2013-03-03 01:03:33 +00:00
// Send an event to trigger something in the mine
2006-03-20 17:12:09 +00:00
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ count ] = Player_num ; count + = 1 ;
multibuf [ count ] = ( ubyte ) triggernum ; count + = 1 ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_TRIGGER > ( multibuf , count , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-12-19 12:48:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
void
2013-12-29 04:28:07 +00:00
multi_send_effect_blowup ( segnum_t segnum , int side , vms_vector * pnt )
2013-12-19 12:48:33 +00:00
{
// We blew up something connected to a trigger. Send this blowup result to other players shortly before MULTI_TRIGGER.
// NOTE: The reason this is now a separate packet is to make sure trigger-connected switches/monitors are in sync with MULTI_TRIGGER.
// If a fire packet is late it might blow up a switch for some clients without the shooter actually registering this hit,
// not sending MULTI_TRIGGER and making puzzles or progress impossible.
int count = 0 ;
multi_do_protocol_frame ( 1 , 0 ) ; // force packets to be sent, ensuring this packet will be attached to following MULTI_TRIGGER
2013-12-16 23:44:34 +00:00
count + = 1 ;
2013-12-19 12:48:33 +00:00
multibuf [ count ] = Player_num ; count + = 1 ;
PUT_INTEL_SHORT ( multibuf + count , segnum ) ; count + = 2 ;
multibuf [ count ] = ( sbyte ) side ; count + = 1 ;
PUT_INTEL_INT ( multibuf + count , pnt - > x ) ; count + = 4 ;
PUT_INTEL_INT ( multibuf + count , pnt - > y ) ; count + = 4 ;
PUT_INTEL_INT ( multibuf + count , pnt - > z ) ; count + = 4 ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_EFFECT_BLOWUP > ( multibuf , count , 0 ) ;
2013-12-19 12:48:33 +00:00
}
# endif
2006-03-20 17:12:09 +00:00
void
multi_send_hostage_door_status ( int wallnum )
{
// Tell the other player what the hit point status of a hostage door
// should be
int count = 0 ;
Assert ( Walls [ wallnum ] . type = = WALL_BLASTABLE ) ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2006-03-20 17:12:09 +00:00
PUT_INTEL_SHORT ( multibuf + count , wallnum ) ; count + = 2 ;
PUT_INTEL_INT ( multibuf + count , Walls [ wallnum ] . hps ) ; count + = 4 ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_HOSTAGE_DOOR > ( multibuf , count , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2009-11-24 09:48:53 +00:00
void multi_consistency_error ( int reset )
{
static int count = 0 ;
if ( reset )
count = 0 ;
if ( + + count < 10 )
return ;
2010-11-09 10:53:19 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 0 ) ;
2009-11-24 09:48:53 +00:00
nm_messagebox ( NULL , 1 , TXT_OK , TXT_CONSISTENCY_ERROR ) ;
2010-11-09 10:53:19 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 1 ) ;
2009-11-24 09:48:53 +00:00
count = 0 ;
multi_quit_game = 1 ;
2010-01-31 07:45:26 +00:00
game_leave_menus ( ) ;
2009-11-24 09:48:53 +00:00
multi_reset_stuff ( ) ;
}
2006-03-20 17:12:09 +00:00
void multi_prep_level ( void )
{
2007-12-29 14:18:49 +00:00
// Do any special stuff to the level required for games
2006-03-20 17:12:09 +00:00
// before we begin playing in it.
// Player_num MUST be set before calling this procedure.
// This function must be called before checksuming the Object array,
// since the resulting checksum with depend on the value of Player_num
// at the time this is called.
2011-01-14 13:29:08 +00:00
int i ;
2006-03-20 17:12:09 +00:00
int cloak_count , inv_count ;
Assert ( Game_mode & GM_MULTI ) ;
Assert ( NumNetPlayerPositions > 0 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
PhallicLimit = 0 ;
PhallicMan = - 1 ;
Drop_afterburner_blob_flag = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2011-01-19 01:19:17 +00:00
Bounty_target = 0 ;
2011-05-19 00:34:14 +00:00
2009-11-24 09:48:53 +00:00
multi_consistency_error ( 1 ) ;
2006-03-20 17:12:09 +00:00
2012-04-15 13:32:48 +00:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
2011-04-11 15:47:16 +00:00
{
2013-12-13 21:47:46 +00:00
multi_sending_message [ i ] = msgsend_none ;
2012-04-27 00:09:48 +00:00
if ( imulti_new_game )
init_player_stats_new_ship ( i ) ;
2011-04-11 15:47:16 +00:00
}
2006-03-20 17:12:09 +00:00
for ( i = 0 ; i < NumNetPlayerPositions ; i + + )
{
if ( i ! = Player_num )
Objects [ Players [ i ] . objnum ] . control_type = CT_REMOTE ;
Objects [ Players [ i ] . objnum ] . movement_type = MT_PHYSICS ;
multi_reset_player_object ( & Objects [ Players [ i ] . objnum ] ) ;
2009-04-09 07:41:30 +00:00
Netgame . players [ i ] . LastPacketTime = 0 ;
2006-03-20 17:12:09 +00:00
}
for ( i = 0 ; i < MAX_ROBOTS_CONTROLLED ; i + + )
{
robot_controlled [ i ] = - 1 ;
robot_agitation [ i ] = 0 ;
robot_fired [ i ] = 0 ;
}
Viewer = ConsoleObject = & Objects [ Players [ Player_num ] . objnum ] ;
if ( ! ( Game_mode & GM_MULTI_COOP ) )
{
multi_delete_extra_objects ( ) ; // Removes monsters from level
}
2013-12-14 01:53:45 +00:00
if ( ( Game_mode & GM_NETWORK ) & & ! ( Game_mode & GM_MULTI_COOP ) )
2006-03-20 17:12:09 +00:00
{
2011-01-14 13:29:08 +00:00
multi_powcap_adjust_cap_for_player ( Player_num ) ;
multi_send_powcap_update ( ) ;
2006-03-20 17:12:09 +00:00
}
inv_count = 0 ;
cloak_count = 0 ;
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
if ( ( Objects [ i ] . type = = OBJ_HOSTAGE ) & & ! ( Game_mode & GM_MULTI_COOP ) )
{
2014-09-08 03:24:48 +00:00
auto objnum = obj_create ( OBJ_POWERUP , POW_SHIELD_BOOST , Objects [ i ] . segnum , & Objects [ i ] . pos , & vmd_identity_matrix , Powerup_info [ POW_SHIELD_BOOST ] . size , CT_POWERUP , MT_PHYSICS , RT_POWERUP ) ;
2006-03-20 17:12:09 +00:00
obj_delete ( i ) ;
2013-12-26 22:21:16 +00:00
if ( objnum ! = object_none )
2006-03-20 17:12:09 +00:00
{
2014-08-13 02:05:30 +00:00
objnum - > rtype . vclip_info . vclip_num = Powerup_info [ POW_SHIELD_BOOST ] . vclip_num ;
objnum - > rtype . vclip_info . frametime = Vclip [ objnum - > rtype . vclip_info . vclip_num ] . frame_time ;
objnum - > rtype . vclip_info . framenum = 0 ;
objnum - > mtype . phys_info . drag = 512 ; //1024;
objnum - > mtype . phys_info . mass = F1_0 ;
2014-09-28 21:11:04 +00:00
vm_vec_zero ( objnum - > mtype . phys_info . velocity ) ;
2006-03-20 17:12:09 +00:00
}
continue ;
}
if ( Objects [ i ] . type = = OBJ_POWERUP )
{
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_EXTRA_LIFE )
2006-03-20 17:12:09 +00:00
{
2011-01-14 13:29:08 +00:00
if ( ! ( Netgame . AllowedItems & NETFLAG_DOINVUL ) )
2006-03-20 17:12:09 +00:00
{
2013-10-07 23:52:33 +00:00
set_powerup_id ( & Objects [ i ] , POW_SHIELD_BOOST ) ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ get_powerup_id ( & Objects [ i ] ) ] . vclip_num ;
2006-03-20 17:12:09 +00:00
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
}
else
{
2013-10-07 23:52:33 +00:00
set_powerup_id ( & Objects [ i ] , POW_INVULNERABILITY ) ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ get_powerup_id ( & Objects [ i ] ) ] . vclip_num ;
2006-03-20 17:12:09 +00:00
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
}
}
if ( ! ( Game_mode & GM_MULTI_COOP ) )
2013-10-07 23:52:33 +00:00
if ( ( get_powerup_id ( & Objects [ i ] ) > = POW_KEY_BLUE ) & & ( get_powerup_id ( & Objects [ i ] ) < = POW_KEY_GOLD ) )
2006-03-20 17:12:09 +00:00
{
2013-10-07 23:52:33 +00:00
set_powerup_id ( & Objects [ i ] , POW_SHIELD_BOOST ) ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ get_powerup_id ( & Objects [ i ] ) ] . vclip_num ;
2006-03-20 17:12:09 +00:00
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
}
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_INVULNERABILITY ) {
2011-01-14 13:29:08 +00:00
if ( inv_count > = 3 | | ( ! ( Netgame . AllowedItems & NETFLAG_DOINVUL ) ) ) {
2013-10-07 23:52:33 +00:00
set_powerup_id ( & Objects [ i ] , POW_SHIELD_BOOST ) ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ get_powerup_id ( & Objects [ i ] ) ] . vclip_num ;
2006-03-20 17:12:09 +00:00
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
} else
inv_count + + ;
}
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_CLOAK ) {
2011-01-14 13:29:08 +00:00
if ( cloak_count > = 3 | | ( ! ( Netgame . AllowedItems & NETFLAG_DOCLOAK ) ) ) {
2013-10-07 23:52:33 +00:00
set_powerup_id ( & Objects [ i ] , POW_SHIELD_BOOST ) ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ get_powerup_id ( & Objects [ i ] ) ] . vclip_num ;
2006-03-20 17:12:09 +00:00
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
} else
cloak_count + + ;
}
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_FUSION_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOFUSION ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " fusion " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_MEGA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOMEGA ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " mega " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_SMARTBOMB_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOSMART ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " smartmissile " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_VULCAN_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOVULCAN ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " vulcan " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_PLASMA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPLASMA ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " plasma " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_PROXIMITY_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPROXIM ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " proximity " ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_VULCAN_AMMO & & ( ! ( Netgame . AllowedItems & NETFLAG_DOVULCAN ) ) )
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_VULCAN_AMMO & & ( ! ( Netgame . AllowedItems & NETFLAG_DOVULCAN ) & & ! ( Netgame . AllowedItems & NETFLAG_DOGAUSS ) ) )
2013-03-03 01:03:33 +00:00
# endif
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " vulcan ammo " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_SPREADFIRE_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOSPREAD ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " spread " ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_AFTERBURNER & & ! ( Netgame . AllowedItems & NETFLAG_DOAFTERBURNER ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " afterburner " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_PHOENIX_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPHOENIX ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " phoenix " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_HELIX_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOHELIX ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " helix " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_GAUSS_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOGAUSS ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " gauss " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_OMEGA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOOMEGA ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " omega " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_SUPER_LASER & & ! ( Netgame . AllowedItems & NETFLAG_DOSUPERLASER ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " superlaser " ) ;
// Special: Make all proximity bombs into shields if in
// hoard mode because we use the proximity slot in the
// player struct to signify how many orbs the player has.
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_PROXIMITY_WEAPON & & game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " proximity " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_SMART_MINE & & ! ( Netgame . AllowedItems & NETFLAG_DOSMARTMINE ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " smartmine " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_SMISSILE1_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOFLASH ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " flash " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_SMISSILE1_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOFLASH ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " flash " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_GUIDED_MISSILE_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOGUIDED ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " guided " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_GUIDED_MISSILE_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOGUIDED ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " guided " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_EARTHSHAKER_MISSILE & & ! ( Netgame . AllowedItems & NETFLAG_DOSHAKER ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " earth " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_MERCURY_MISSILE_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOMERCURY ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Mercury " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_MERCURY_MISSILE_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOMERCURY ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Mercury " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_CONVERTER & & ! ( Netgame . AllowedItems & NETFLAG_DOCONVERTER ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Converter " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_AMMO_RACK & & ! ( Netgame . AllowedItems & NETFLAG_DOAMMORACK ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Ammo rack " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_HEADLIGHT & & ! ( Netgame . AllowedItems & NETFLAG_DOHEADLIGHT ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Headlight " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_FLAG_BLUE & & ! game_mode_capture_flag ( ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " Blue flag " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_FLAG_RED & & ! game_mode_capture_flag ( ) )
2013-08-11 16:23:37 +00:00
bash_to_shield ( i , " Red flag " ) ;
2013-03-03 01:03:33 +00:00
# endif
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_LASER & & ! ( Netgame . AllowedItems & NETFLAG_DOLASER ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Laser powerup " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_HOMING_AMMO_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOHOMING ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Homing " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_HOMING_AMMO_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOHOMING ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Homing " ) ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( & Objects [ i ] ) = = POW_QUAD_FIRE & & ! ( Netgame . AllowedItems & NETFLAG_DOQUAD ) )
2006-03-20 17:12:09 +00:00
bash_to_shield ( i , " Quad Lasers " ) ;
}
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:03:47 +00:00
if ( game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
init_hoard_data ( ) ;
2013-08-11 16:03:47 +00:00
if ( game_mode_capture_flag ( ) | | game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
multi_apply_goal_textures ( ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
multi_sort_kill_list ( ) ;
multi_show_player_list ( ) ;
ConsoleObject - > control_type = CT_FLYING ;
reset_player_object ( ) ;
2012-04-27 00:09:48 +00:00
imulti_new_game = 0 ;
2006-03-20 17:12:09 +00:00
}
2009-04-09 07:41:30 +00:00
int multi_level_sync ( void )
{
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2009-11-24 09:48:53 +00:00
case MULTI_PROTO_UDP :
return net_udp_level_sync ( ) ;
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-04-09 07:41:30 +00:00
default :
2009-11-24 09:48:53 +00:00
Error ( " Protocol handling missing in multi_level_sync \n " ) ;
2009-04-09 07:41:30 +00:00
break ;
}
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-08-16 18:16:59 +00:00
static void apply_segment_goal_texture ( segment * seg , ubyte team_mask )
{
seg - > static_light = i2f ( 100 ) ; //make static light bright
std : : size_t tex = find_goal_texture ( game_mode_hoard ( ) ? TMI_GOAL_HOARD : team_mask ) ;
if ( tex < TmapInfo . size ( ) )
range_for ( auto & s , seg - > sides )
{
s . tmap_num = tex ;
range_for ( auto & uvl , s . uvls )
uvl . l = i2f ( 100 ) ; //max out
}
}
2006-03-20 17:12:09 +00:00
void multi_apply_goal_textures ( )
{
2014-08-16 18:16:59 +00:00
int i ;
2006-03-20 17:12:09 +00:00
segment * seg ;
for ( i = 0 ; i < = Highest_segment_index ; i + + )
{
seg = & Segments [ i ] ;
2014-08-16 18:16:59 +00:00
if ( seg - > special = = SEGMENT_IS_GOAL_BLUE )
2006-03-20 17:12:09 +00:00
{
2014-08-16 18:16:59 +00:00
apply_segment_goal_texture ( seg , TMI_GOAL_BLUE ) ;
2006-03-20 17:12:09 +00:00
}
2014-08-16 18:16:59 +00:00
else if ( seg - > special = = SEGMENT_IS_GOAL_RED )
2006-03-20 17:12:09 +00:00
{
// Make both textures the same if Hoard mode
2014-08-16 18:16:59 +00:00
apply_segment_goal_texture ( seg , TMI_GOAL_RED ) ;
2006-03-20 17:12:09 +00:00
}
}
}
2014-08-16 18:16:59 +00:00
std : : size_t find_goal_texture ( ubyte t )
{
auto r = partial_range ( TmapInfo , NumTextures ) ;
return std : : distance ( r . begin ( ) , std : : find_if ( r . begin ( ) , r . end ( ) , [ t ] ( const tmap_info & i ) { return ( i . flags & t ) ; } ) ) ;
}
2006-03-20 17:12:09 +00:00
2014-08-16 18:16:59 +00:00
tmap_info & find_required_goal_texture ( ubyte t )
{
std : : size_t r = find_goal_texture ( t ) ;
if ( r < TmapInfo . size ( ) )
return TmapInfo [ r ] ;
2006-03-20 17:12:09 +00:00
Int3 ( ) ; // Hey, there is no goal texture for this PIG!!!!
// Edit bitmaps.tbl and designate two textures to be RED and BLUE
// goal textures
2014-08-16 18:16:59 +00:00
throw std : : runtime_error ( " PIG missing goal texture " ) ;
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
2013-08-11 18:24:54 +00:00
static inline int object_allowed_in_anarchy ( const object * objp )
{
if ( ( objp - > type = = OBJ_NONE ) | |
( objp - > type = = OBJ_PLAYER ) | |
( objp - > type = = OBJ_POWERUP ) | |
( objp - > type = = OBJ_CNTRLCEN ) | |
( objp - > type = = OBJ_HOSTAGE ) )
return 1 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-10-07 23:52:33 +00:00
if ( objp - > type = = OBJ_WEAPON & & get_weapon_id ( objp ) = = PMINE_ID )
2013-08-11 18:24:54 +00:00
return 1 ;
2013-03-03 01:03:33 +00:00
# endif
2013-08-11 18:24:54 +00:00
return 0 ;
}
2006-03-20 17:12:09 +00:00
int multi_delete_extra_objects ( )
{
2013-12-29 04:28:07 +00:00
objnum_t i ;
2006-03-20 17:12:09 +00:00
int nnp = 0 ;
// Go through the object list and remove any objects not used in
// 'Anarchy!' games.
// This function also prints the total number of available multiplayer
// positions in this level, even though this should always be 8 or more!
for ( i = 0 ; i < = Highest_object_index ; i + + ) {
2013-12-12 21:48:34 +00:00
object * objp = & Objects [ i ] ;
2006-03-20 17:12:09 +00:00
if ( ( objp - > type = = OBJ_PLAYER ) | | ( objp - > type = = OBJ_GHOST ) )
nnp + + ;
else if ( ( objp - > type = = OBJ_ROBOT ) & & ( Game_mode & GM_MULTI_ROBOTS ) )
;
2013-08-11 18:24:54 +00:00
else if ( ! object_allowed_in_anarchy ( objp ) ) {
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
// Before deleting object, if it's a robot, drop it's special powerup, if any
if ( objp - > type = = OBJ_ROBOT )
if ( objp - > contains_count & & ( objp - > contains_type = = OBJ_POWERUP ) )
object_create_egg ( objp ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
obj_delete ( i ) ;
}
}
return nnp ;
}
2009-11-24 09:48:53 +00:00
// Returns 1 if player is Master/Host of this game
int multi_i_am_master ( void )
2009-04-09 07:41:30 +00:00
{
2011-09-13 23:15:32 +00:00
return ( Player_num = = 0 ) ;
2009-04-09 07:41:30 +00:00
}
2009-11-24 09:48:53 +00:00
// Returns the Player_num of Master/Host of this game
2014-09-21 22:10:12 +00:00
playernum_t multi_who_is_master ( )
2009-04-09 07:41:30 +00:00
{
2011-09-13 23:15:32 +00:00
return 0 ;
2009-04-09 07:41:30 +00:00
}
2006-03-20 17:12:09 +00:00
void change_playernum_to ( int new_Player_num )
{
2014-09-27 22:57:15 +00:00
if ( Player_num < Players . size ( ) )
2007-08-09 14:43:56 +00:00
{
2014-07-05 16:48:12 +00:00
Players [ new_Player_num ] . callsign = Players [ Player_num ] . callsign ;
2007-08-09 14:43:56 +00:00
}
2006-03-20 17:12:09 +00:00
Player_num = new_Player_num ;
}
2013-10-26 03:52:09 +00:00
# if defined(DXX_BUILD_DESCENT_I)
static
# endif
2006-03-20 17:12:09 +00:00
int multi_all_players_alive ( )
{
int i ;
for ( i = 0 ; i < N_players ; i + + )
{
2014-06-24 12:52:18 +00:00
if ( Players [ i ] . connected )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
}
return ( 1 ) ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-29 04:28:07 +00:00
void multi_send_drop_weapon ( objnum_t objnum , int seed )
2006-03-20 17:12:09 +00:00
{
object * objp ;
int count = 0 ;
int ammo_count ;
2009-11-24 09:48:53 +00:00
multi_send_position ( Players [ Player_num ] . objnum ) ;
2006-03-20 17:12:09 +00:00
objp = & Objects [ objnum ] ;
ammo_count = objp - > ctype . powerup_info . count ;
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( objp ) = = POW_OMEGA_WEAPON & & ammo_count = = F1_0 )
2006-03-20 17:12:09 +00:00
ammo_count = F1_0 - 1 ; //make fit in short
Assert ( ammo_count < F1_0 ) ; //make sure fits in short
2013-12-16 23:44:34 +00:00
count + + ;
2013-10-07 23:52:33 +00:00
multibuf [ count + + ] = ( char ) get_powerup_id ( objp ) ;
2006-03-20 17:12:09 +00:00
PUT_INTEL_SHORT ( multibuf + count , Player_num ) ; count + = 2 ;
PUT_INTEL_SHORT ( multibuf + count , objnum ) ; count + = 2 ;
PUT_INTEL_SHORT ( multibuf + count , ammo_count ) ; count + = 2 ;
PUT_INTEL_INT ( multibuf + count , seed ) ;
map_objnum_local_to_local ( objnum ) ;
if ( Game_mode & GM_NETWORK )
2011-01-14 13:29:08 +00:00
{
2013-10-07 23:52:33 +00:00
if ( multi_powerup_is_4pack ( get_powerup_id ( objp ) ) )
2011-01-14 13:29:08 +00:00
PowerupsInMine [ objp - > id - 1 ] + = 4 ;
else
2013-10-07 23:52:33 +00:00
PowerupsInMine [ get_powerup_id ( objp ) ] + + ;
2011-01-14 13:29:08 +00:00
}
2006-03-20 17:12:09 +00:00
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_DROP_WEAPON > ( multibuf , 12 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_drop_weapon ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
int ammo , remote_objnum , seed ;
2006-03-20 17:12:09 +00:00
object * objp ;
int powerup_id ;
powerup_id = ( int ) ( buf [ 1 ] ) ;
remote_objnum = GET_INTEL_SHORT ( buf + 4 ) ;
ammo = GET_INTEL_SHORT ( buf + 6 ) ;
seed = GET_INTEL_INT ( buf + 8 ) ;
objp = & Objects [ Players [ pnum ] . objnum ] ;
2013-12-29 04:28:07 +00:00
objnum_t objnum = spit_powerup ( objp , powerup_id , seed ) ;
2006-03-20 17:12:09 +00:00
map_objnum_local_to_remote ( objnum , remote_objnum , pnum ) ;
2013-12-26 22:21:16 +00:00
if ( objnum ! = object_none )
2006-03-20 17:12:09 +00:00
Objects [ objnum ] . ctype . powerup_info . count = ammo ;
if ( Game_mode & GM_NETWORK )
2011-01-14 13:29:08 +00:00
{
if ( multi_powerup_is_4pack ( powerup_id ) )
PowerupsInMine [ powerup_id - 1 ] + = 4 ;
else
PowerupsInMine [ powerup_id ] + + ;
}
2006-03-20 17:12:09 +00:00
}
void multi_send_guided_info ( object * miss , char done )
{
# ifdef WORDS_BIGENDIAN
shortpos sp ;
# endif
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + + ;
2006-03-20 17:12:09 +00:00
multibuf [ count + + ] = ( char ) Player_num ;
multibuf [ count + + ] = done ;
# ifndef WORDS_BIGENDIAN
create_shortpos ( ( shortpos * ) ( multibuf + count ) , miss , 0 ) ;
count + = sizeof ( shortpos ) ;
# else
create_shortpos ( & sp , miss , 1 ) ;
memcpy ( & ( multibuf [ count ] ) , ( ubyte * ) ( sp . bytemat ) , 9 ) ;
count + = 9 ;
memcpy ( & ( multibuf [ count ] ) , ( ubyte * ) & ( sp . xo ) , 14 ) ;
count + = 14 ;
# endif
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_GUIDED > ( multibuf , count , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_guided ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
int count = 3 ;
static int fun = 200 ;
# ifdef WORDS_BIGENDIAN
shortpos sp ;
# endif
if ( Guided_missile [ ( int ) pnum ] = = NULL )
{
if ( + + fun > = 50 )
{
fun = 0 ;
}
return ;
}
else if ( + + fun > = 50 )
{
fun = 0 ;
}
if ( buf [ 2 ] )
{
release_guided_missile ( pnum ) ;
return ;
}
if ( Guided_missile [ ( int ) pnum ] - Objects < 0 | | Guided_missile [ ( int ) pnum ] - Objects > Highest_object_index )
{
Int3 ( ) ; // Get Jason immediately!
return ;
}
# ifndef WORDS_BIGENDIAN
extract_shortpos ( Guided_missile [ ( int ) pnum ] , ( shortpos * ) ( buf + count ) , 0 ) ;
# else
memcpy ( ( ubyte * ) ( sp . bytemat ) , ( ubyte * ) ( buf + count ) , 9 ) ;
memcpy ( ( ubyte * ) & ( sp . xo ) , ( ubyte * ) ( buf + count + 9 ) , 14 ) ;
extract_shortpos ( Guided_missile [ ( int ) pnum ] , & sp , 1 ) ;
# endif
count + = sizeof ( shortpos ) ;
update_object_seg ( Guided_missile [ ( int ) pnum ] ) ;
}
void multi_send_stolen_items ( )
{
int i , count = 1 ;
for ( i = 0 ; i < MAX_STOLEN_ITEMS ; i + + )
{
multibuf [ i + 1 ] = Stolen_items [ i ] ;
count + + ; // So I like to break my stuff into smaller chunks, so what?
}
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_STOLEN_ITEMS > ( multibuf , count , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_stolen_items ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
int i ;
for ( i = 0 ; i < MAX_STOLEN_ITEMS ; i + + )
{
Stolen_items [ i ] = buf [ i + 1 ] ;
}
}
2014-09-21 22:10:12 +00:00
void multi_send_wall_status_specific ( const playernum_t pnum , int wallnum , ubyte type , ubyte flags , ubyte state )
2006-03-20 17:12:09 +00:00
{
// Send wall states a specific rejoining player
int count = 0 ;
Assert ( Game_mode & GM_NETWORK ) ;
//Assert (pnum>-1 && pnum<N_players);
2013-12-16 22:15:38 +00:00
count + + ;
2006-03-20 17:12:09 +00:00
PUT_INTEL_SHORT ( multibuf + count , wallnum ) ; count + = 2 ;
multibuf [ count ] = type ; count + + ;
multibuf [ count ] = flags ; count + + ;
multibuf [ count ] = state ; count + + ;
2013-12-16 22:15:38 +00:00
multi_send_data_direct < MULTI_WALL_STATUS > ( multibuf , count , pnum , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_wall_status ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
short wallnum ;
ubyte flag , type , state ;
wallnum = GET_INTEL_SHORT ( buf + 1 ) ;
type = buf [ 3 ] ;
flag = buf [ 4 ] ;
state = buf [ 5 ] ;
Assert ( wallnum > = 0 ) ;
Walls [ wallnum ] . type = type ;
Walls [ wallnum ] . flags = flag ;
//Assert(state <= 4);
Walls [ wallnum ] . state = state ;
if ( Walls [ wallnum ] . type = = WALL_OPEN )
{
digi_kill_sound_linked_to_segment ( Walls [ wallnum ] . segnum , Walls [ wallnum ] . sidenum , SOUND_FORCEFIELD_HUM ) ;
//digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM);
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
void multi_send_kill_goal_counts ( )
{
int i , count = 1 ;
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
{
* ( char * ) ( multibuf + count ) = ( char ) Players [ i ] . KillGoalCount ;
count + + ;
}
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_KILLGOALS > ( multibuf , count , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_kill_goal_counts ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
int i , count = 1 ;
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
{
Players [ i ] . KillGoalCount = * ( char * ) ( buf + count ) ;
count + + ;
}
}
void multi_send_heartbeat ( )
{
if ( ! Netgame . PlayTimeAllowed )
return ;
PUT_INTEL_INT ( multibuf + 1 , ThisLevelTime ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_HEARTBEAT > ( multibuf , 5 , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_heartbeat ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
fix num ;
num = GET_INTEL_INT ( buf + 1 ) ;
ThisLevelTime = num ;
}
void multi_check_for_killgoal_winner ( )
{
int i , best = 0 , bestnum = 0 ;
if ( Control_center_destroyed )
return ;
for ( i = 0 ; i < N_players ; i + + )
{
if ( Players [ i ] . KillGoalCount > best )
{
best = Players [ i ] . KillGoalCount ;
bestnum = i ;
}
}
if ( bestnum = = Player_num )
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " You have the best score at %d kills! " , best ) ;
2006-03-20 17:12:09 +00:00
//Players[Player_num].shields=i2f(200);
}
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has the best score with %d kills! " , static_cast < const char * > ( Players [ bestnum ] . callsign ) , best ) ;
2006-03-20 17:12:09 +00:00
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " The control center has been destroyed! " ) ;
2014-08-23 23:53:56 +00:00
net_destroy_controlcen ( obj_find_first_of_type ( OBJ_CNTRLCEN ) ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2010-12-22 00:17:59 +00:00
// Sync our seismic time with other players
void multi_send_seismic ( fix64 t1 , fix64 t2 )
2006-03-20 17:12:09 +00:00
{
int count = 1 ;
2011-09-13 23:15:32 +00:00
PUT_INTEL_INT ( multibuf + count , t1 ) ; count + = ( sizeof ( fix ) ) ;
PUT_INTEL_INT ( multibuf + count , t2 ) ; count + = ( sizeof ( fix ) ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_SEISMIC > ( multibuf , count , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_seismic ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2011-09-13 23:15:32 +00:00
fix duration = GET_INTEL_INT ( buf + 5 ) ;
Seismic_disturbance_start_time = GameTime64 ;
Seismic_disturbance_end_time = GameTime64 + duration ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_SEISMIC_DISTURBANCE_START , F1_0 ) ;
}
2014-09-21 22:10:12 +00:00
void multi_send_light_specific ( const playernum_t pnum , segnum_t segnum , ubyte val )
2006-03-20 17:12:09 +00:00
{
int count = 1 , i ;
Assert ( Game_mode & GM_NETWORK ) ;
// Assert (pnum>-1 && pnum<N_players);
PUT_INTEL_INT ( multibuf + count , segnum ) ; count + = ( sizeof ( int ) ) ;
* ( char * ) ( multibuf + count ) = val ; count + + ;
for ( i = 0 ; i < 6 ; i + + )
{
PUT_INTEL_SHORT ( multibuf + count , Segments [ segnum ] . sides [ i ] . tmap_num2 ) ; count + = 2 ;
}
2009-04-09 07:41:30 +00:00
2013-12-16 22:15:38 +00:00
multi_send_data_direct < MULTI_LIGHT > ( multibuf , count , pnum , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_light ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
int i ;
2006-03-20 17:12:09 +00:00
ubyte sides = * ( char * ) ( buf + 5 ) ;
2013-12-29 04:28:07 +00:00
segnum_t seg ;
2006-03-20 17:12:09 +00:00
seg = GET_INTEL_INT ( buf + 1 ) ;
for ( i = 0 ; i < 6 ; i + + )
{
if ( ( sides & ( 1 < < i ) ) )
{
subtract_light ( seg , i ) ;
Segments [ seg ] . sides [ i ] . tmap_num2 = GET_INTEL_SHORT ( buf + ( 6 + ( 2 * i ) ) ) ;
}
}
}
2014-09-21 22:10:12 +00:00
static void multi_do_flags ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
uint flags ;
flags = GET_INTEL_INT ( buf + 2 ) ;
if ( pnum ! = Player_num )
Players [ ( int ) pnum ] . flags = flags ;
}
2014-09-21 22:10:12 +00:00
void multi_send_flags ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
multibuf [ 1 ] = pnum ;
PUT_INTEL_INT ( multibuf + 2 , Players [ ( int ) pnum ] . flags ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_FLAGS > ( multibuf , 6 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_send_drop_blobs ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
multibuf [ 1 ] = pnum ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_DROP_BLOB > ( multibuf , 2 , 0 ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_drop_blob ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
drop_afterburner_blobs ( & Objects [ Players [ ( int ) pnum ] . objnum ] , 2 , i2f ( 5 ) / 2 , - 1 ) ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2011-01-14 13:29:08 +00:00
void multi_send_powcap_update ( )
2006-03-20 17:12:09 +00:00
{
2013-12-14 01:53:45 +00:00
if ( ! ( Game_mode & GM_NETWORK ) | | ( Game_mode & GM_MULTI_COOP ) )
return ;
2013-03-03 01:03:33 +00:00
for ( unsigned i = 0 ; i < MAX_POWERUP_TYPES ; i + + )
2006-03-20 17:12:09 +00:00
multibuf [ i + 1 ] = MaxPowerupsAllowed [ i ] ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_POWCAP_UPDATE > ( multibuf , MAX_POWERUP_TYPES + 1 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
2013-10-27 22:00:14 +00:00
static void multi_do_powcap_update ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-12-14 01:53:45 +00:00
if ( ! ( Game_mode & GM_NETWORK ) | | ( Game_mode & GM_MULTI_COOP ) )
return ;
2013-03-03 01:03:33 +00:00
for ( unsigned i = 0 ; i < MAX_POWERUP_TYPES ; i + + )
2006-03-20 17:12:09 +00:00
if ( buf [ i + 1 ] > MaxPowerupsAllowed [ i ] )
MaxPowerupsAllowed [ i ] = buf [ i + 1 ] ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
void multi_send_sound_function ( char whichfunc , char sound )
{
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + + ;
2006-03-20 17:12:09 +00:00
multibuf [ 1 ] = Player_num ; count + + ;
multibuf [ 2 ] = whichfunc ; count + + ;
# ifndef WORDS_BIGENDIAN
* ( uint * ) ( multibuf + count ) = sound ; count + + ;
# else
multibuf [ 3 ] = sound ; count + + ; // this would probably work on the PC as well. Jason?
# endif
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_SOUND_FUNCTION > ( multibuf , 4 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
# define AFTERBURNER_LOOP_START 20098
# define AFTERBURNER_LOOP_END 25776
2014-09-21 22:10:12 +00:00
static void multi_do_sound_function ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
// for afterburner
2014-05-30 02:45:34 +00:00
char whichfunc ;
2006-03-20 17:12:09 +00:00
int sound ;
2009-11-24 09:48:53 +00:00
if ( Players [ Player_num ] . connected ! = CONNECT_PLAYING )
2006-03-20 17:12:09 +00:00
return ;
whichfunc = buf [ 2 ] ;
sound = buf [ 3 ] ;
if ( whichfunc = = 0 )
digi_kill_sound_linked_to_object ( Players [ ( int ) pnum ] . objnum ) ;
else if ( whichfunc = = 3 )
digi_link_sound_to_object3 ( sound , Players [ ( int ) pnum ] . objnum , 1 , F1_0 , i2f ( 256 ) , AFTERBURNER_LOOP_START , AFTERBURNER_LOOP_END ) ;
}
2014-09-21 22:10:12 +00:00
void multi_send_capture_bonus ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
2013-08-11 16:03:47 +00:00
Assert ( game_mode_capture_flag ( ) ) ;
2006-03-20 17:12:09 +00:00
multibuf [ 1 ] = pnum ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_CAPTURE_BONUS > ( multibuf , 2 , 2 ) ;
2014-05-30 02:45:34 +00:00
multi_do_capture_bonus ( pnum , multibuf ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_send_orb_bonus ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
2013-08-11 16:03:47 +00:00
Assert ( game_mode_hoard ( ) ) ;
2006-03-20 17:12:09 +00:00
multibuf [ 1 ] = pnum ;
multibuf [ 2 ] = Players [ Player_num ] . secondary_ammo [ PROXIMITY_INDEX ] ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_ORB_BONUS > ( multibuf , 3 , 2 ) ;
2014-05-30 02:45:34 +00:00
multi_do_orb_bonus ( pnum , multibuf ) ;
2006-03-20 17:12:09 +00:00
}
2014-05-30 02:45:34 +00:00
2014-09-21 22:10:12 +00:00
void multi_do_capture_bonus ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
// Figure out the results of a network kills and add it to the
// appropriate player's tally.
int TheGoal ;
if ( pnum = = Player_num )
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You have Scored! " ) ;
2006-03-20 17:12:09 +00:00
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has Scored! " , static_cast < const char * > ( Players [ pnum ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
if ( pnum = = Player_num )
digi_play_sample ( SOUND_HUD_YOU_GOT_GOAL , F1_0 * 2 ) ;
else if ( get_team ( pnum ) = = TEAM_RED )
digi_play_sample ( SOUND_HUD_RED_GOT_GOAL , F1_0 * 2 ) ;
else
digi_play_sample ( SOUND_HUD_BLUE_GOT_GOAL , F1_0 * 2 ) ;
Players [ ( int ) pnum ] . flags & = ~ ( PLAYER_FLAGS_FLAG ) ; // Clear capture flag
team_kills [ get_team ( pnum ) ] + = 5 ;
Players [ ( int ) pnum ] . net_kills_total + = 5 ;
Players [ ( int ) pnum ] . KillGoalCount + = 5 ;
if ( Netgame . KillGoal > 0 )
{
TheGoal = Netgame . KillGoal * 5 ;
if ( Players [ ( int ) pnum ] . KillGoalCount > = TheGoal )
{
if ( pnum = = Player_num )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You reached the kill goal! " ) ;
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . shields = i2f ( 200 ) ;
}
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has reached the kill goal! " , static_cast < const char * > ( Players [ pnum ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " The control center has been destroyed! " ) ;
2006-03-20 17:12:09 +00:00
net_destroy_controlcen ( obj_find_first_of_type ( OBJ_CNTRLCEN ) ) ;
}
}
multi_sort_kill_list ( ) ;
multi_show_player_list ( ) ;
}
2013-10-27 22:00:14 +00:00
static int GetOrbBonus ( char num )
2006-03-20 17:12:09 +00:00
{
int bonus ;
bonus = num * ( num + 1 ) / 2 ;
return ( bonus ) ;
}
2014-09-21 22:10:12 +00:00
void multi_do_orb_bonus ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
// Figure out the results of a network kills and add it to the
// appropriate player's tally.
int TheGoal ;
int bonus = GetOrbBonus ( buf [ 2 ] ) ;
if ( pnum = = Player_num )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " You have scored %d points! " , bonus ) ;
2006-03-20 17:12:09 +00:00
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has scored with %d orbs! " , static_cast < const char * > ( Players [ pnum ] . callsign ) , buf [ 2 ] ) ;
2006-03-20 17:12:09 +00:00
if ( pnum = = Player_num )
digi_start_sound_queued ( SOUND_HUD_YOU_GOT_GOAL , F1_0 * 2 ) ;
else if ( Game_mode & GM_TEAM )
{
if ( get_team ( pnum ) = = TEAM_RED )
digi_play_sample ( SOUND_HUD_RED_GOT_GOAL , F1_0 * 2 ) ;
else
digi_play_sample ( SOUND_HUD_BLUE_GOT_GOAL , F1_0 * 2 ) ;
}
else
digi_play_sample ( SOUND_OPPONENT_HAS_SCORED , F1_0 * 2 ) ;
if ( bonus > PhallicLimit )
{
if ( pnum = = Player_num )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " You have the record with %d points! " , bonus ) ;
2006-03-20 17:12:09 +00:00
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has the record with %d points! " , static_cast < const char * > ( Players [ pnum ] . callsign ) , bonus ) ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_BUDDY_MET_GOAL , F1_0 * 2 ) ;
PhallicMan = pnum ;
PhallicLimit = bonus ;
}
Players [ ( int ) pnum ] . flags & = ~ ( PLAYER_FLAGS_FLAG ) ; // Clear orb flag
team_kills [ get_team ( pnum ) ] + = bonus ;
Players [ ( int ) pnum ] . net_kills_total + = bonus ;
Players [ ( int ) pnum ] . KillGoalCount + = bonus ;
team_kills [ get_team ( pnum ) ] % = 1000 ;
Players [ ( int ) pnum ] . net_kills_total % = 1000 ;
Players [ ( int ) pnum ] . KillGoalCount % = 1000 ;
if ( Netgame . KillGoal > 0 )
{
TheGoal = Netgame . KillGoal * 5 ;
if ( Players [ ( int ) pnum ] . KillGoalCount > = TheGoal )
{
if ( pnum = = Player_num )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " You reached the kill goal! " ) ;
2006-03-20 17:12:09 +00:00
Players [ Player_num ] . shields = i2f ( 200 ) ;
}
else
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has reached the kill goal! " , static_cast < const char * > ( Players [ pnum ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " The control center has been destroyed! " ) ;
2006-03-20 17:12:09 +00:00
net_destroy_controlcen ( obj_find_first_of_type ( OBJ_CNTRLCEN ) ) ;
}
}
multi_sort_kill_list ( ) ;
multi_show_player_list ( ) ;
}
2014-09-21 22:10:12 +00:00
void multi_send_got_flag ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
multibuf [ 1 ] = pnum ;
digi_start_sound_queued ( SOUND_HUD_YOU_GOT_FLAG , F1_0 * 2 ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_GOT_FLAG > ( multibuf , 2 , 2 ) ;
2006-03-20 17:12:09 +00:00
multi_send_flags ( Player_num ) ;
}
2014-09-21 22:10:12 +00:00
void multi_send_got_orb ( const playernum_t pnum )
2006-03-20 17:12:09 +00:00
{
multibuf [ 1 ] = pnum ;
digi_play_sample ( SOUND_YOU_GOT_ORB , F1_0 * 2 ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_GOT_ORB > ( multibuf , 2 , 2 ) ;
2006-03-20 17:12:09 +00:00
multi_send_flags ( Player_num ) ;
}
2014-09-21 22:10:12 +00:00
static void multi_do_got_flag ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
if ( pnum = = Player_num )
digi_start_sound_queued ( SOUND_HUD_YOU_GOT_FLAG , F1_0 * 2 ) ;
else if ( get_team ( pnum ) = = TEAM_RED )
digi_start_sound_queued ( SOUND_HUD_RED_GOT_FLAG , F1_0 * 2 ) ;
else
digi_start_sound_queued ( SOUND_HUD_BLUE_GOT_FLAG , F1_0 * 2 ) ;
Players [ ( int ) pnum ] . flags | = PLAYER_FLAGS_FLAG ;
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s picked up a flag! " , static_cast < const char * > ( Players [ pnum ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_got_orb ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-08-11 16:03:47 +00:00
Assert ( game_mode_hoard ( ) ) ;
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_TEAM )
{
if ( get_team ( pnum ) = = get_team ( Player_num ) )
digi_play_sample ( SOUND_FRIEND_GOT_ORB , F1_0 * 2 ) ;
else
digi_play_sample ( SOUND_OPPONENT_GOT_ORB , F1_0 * 2 ) ;
}
else
digi_play_sample ( SOUND_OPPONENT_GOT_ORB , F1_0 * 2 ) ;
Players [ ( int ) pnum ] . flags | = PLAYER_FLAGS_FLAG ;
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s picked up an orb! " , static_cast < const char * > ( Players [ pnum ] . callsign ) ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void DropOrb ( )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
int seed ;
2006-03-20 17:12:09 +00:00
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
Int3 ( ) ; // How did we get here? Get Leighton!
if ( ! Players [ Player_num ] . secondary_ammo [ PROXIMITY_INDEX ] )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " No orbs to drop! " ) ;
2006-03-20 17:12:09 +00:00
return ;
}
seed = d_rand ( ) ;
2013-12-29 04:28:07 +00:00
objnum_t objnum = spit_powerup ( ConsoleObject , POW_HOARD_ORB , seed ) ;
2006-03-20 17:12:09 +00:00
if ( objnum < 0 )
return ;
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Orb dropped! " ) ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_DROP_WEAPON , F1_0 ) ;
2013-12-26 22:21:16 +00:00
if ( game_mode_hoard ( ) & & objnum ! = object_none )
2006-03-20 17:12:09 +00:00
multi_send_drop_flag ( objnum , seed ) ;
Players [ Player_num ] . secondary_ammo [ PROXIMITY_INDEX ] - - ;
// If empty, tell everyone to stop drawing the box around me
if ( Players [ Player_num ] . secondary_ammo [ PROXIMITY_INDEX ] = = 0 )
2010-11-08 23:28:22 +00:00
{
Players [ Player_num ] . flags & = ~ ( PLAYER_FLAGS_FLAG ) ;
2006-03-20 17:12:09 +00:00
multi_send_flags ( Player_num ) ;
2010-11-08 23:28:22 +00:00
}
2006-03-20 17:12:09 +00:00
}
void DropFlag ( )
{
2013-12-29 04:28:07 +00:00
int seed ;
2006-03-20 17:12:09 +00:00
2013-08-11 16:03:47 +00:00
if ( ! game_mode_capture_flag ( ) & & ! game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
return ;
2013-08-11 16:03:47 +00:00
if ( game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
{
DropOrb ( ) ;
return ;
}
if ( ! ( Players [ Player_num ] . flags & PLAYER_FLAGS_FLAG ) )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " No flag to drop! " ) ;
2006-03-20 17:12:09 +00:00
return ;
}
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Flag dropped! " ) ;
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_DROP_WEAPON , F1_0 ) ;
seed = d_rand ( ) ;
2013-12-29 04:28:07 +00:00
objnum_t objnum ;
2006-03-20 17:12:09 +00:00
if ( get_team ( Player_num ) = = TEAM_RED )
objnum = spit_powerup ( ConsoleObject , POW_FLAG_BLUE , seed ) ;
else
objnum = spit_powerup ( ConsoleObject , POW_FLAG_RED , seed ) ;
if ( objnum < 0 )
return ;
2013-12-26 22:21:16 +00:00
if ( game_mode_capture_flag ( ) & & objnum ! = object_none )
2006-03-20 17:12:09 +00:00
multi_send_drop_flag ( objnum , seed ) ;
Players [ Player_num ] . flags & = ~ ( PLAYER_FLAGS_FLAG ) ;
}
2013-12-29 04:28:07 +00:00
void multi_send_drop_flag ( objnum_t objnum , int seed )
2006-03-20 17:12:09 +00:00
{
object * objp ;
int count = 0 ;
objp = & Objects [ objnum ] ;
2013-12-16 23:44:34 +00:00
count + + ;
2013-10-07 23:52:33 +00:00
multibuf [ count + + ] = ( char ) get_powerup_id ( objp ) ;
2006-03-20 17:12:09 +00:00
PUT_INTEL_SHORT ( multibuf + count , Player_num ) ; count + = 2 ;
PUT_INTEL_SHORT ( multibuf + count , objnum ) ; count + = 2 ;
PUT_INTEL_SHORT ( multibuf + count , objp - > ctype . powerup_info . count ) ; count + = 2 ;
PUT_INTEL_INT ( multibuf + count , seed ) ;
map_objnum_local_to_local ( objnum ) ;
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
if ( Game_mode & GM_NETWORK )
2013-10-07 23:52:33 +00:00
PowerupsInMine [ get_powerup_id ( objp ) ] + + ;
2006-03-20 17:12:09 +00:00
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_DROP_FLAG > ( multibuf , 12 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
static void multi_do_drop_flag ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2013-12-29 04:28:07 +00:00
int ammo , remote_objnum , seed ;
2006-03-20 17:12:09 +00:00
object * objp ;
int powerup_id ;
powerup_id = buf [ 1 ] ;
remote_objnum = GET_INTEL_SHORT ( buf + 4 ) ;
ammo = GET_INTEL_SHORT ( buf + 6 ) ;
seed = GET_INTEL_INT ( buf + 8 ) ;
objp = & Objects [ Players [ pnum ] . objnum ] ;
2013-12-29 04:28:07 +00:00
objnum_t objnum = spit_powerup ( objp , powerup_id , seed ) ;
2006-03-20 17:12:09 +00:00
map_objnum_local_to_remote ( objnum , remote_objnum , pnum ) ;
2013-12-26 22:21:16 +00:00
if ( objnum ! = object_none )
2006-03-20 17:12:09 +00:00
Objects [ objnum ] . ctype . powerup_info . count = ammo ;
2013-08-11 16:03:47 +00:00
if ( ! game_mode_hoard ( ) )
2006-03-20 17:12:09 +00:00
{
if ( Game_mode & GM_NETWORK )
PowerupsInMine [ powerup_id ] + + ;
Players [ pnum ] . flags & = ~ ( PLAYER_FLAGS_FLAG ) ;
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
static const int PowerupAdjustMapping [ ] = { 11 , 19
# if defined(DXX_BUILD_DESCENT_II)
, 39 , 41 , 44
# endif
} ;
2006-03-20 17:12:09 +00:00
int multi_powerup_is_4pack ( int id )
{
2013-08-11 22:40:08 +00:00
for ( unsigned i = 0 ; i < sizeof ( PowerupAdjustMapping ) / sizeof ( PowerupAdjustMapping [ 0 ] ) ; i + + )
2006-03-20 17:12:09 +00:00
if ( id = = PowerupAdjustMapping [ i ] )
return ( 1 ) ;
return ( 0 ) ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
int multi_powerup_is_allowed ( int id )
{
2009-03-20 12:10:38 +00:00
if ( id = = POW_INVULNERABILITY & & ! ( Netgame . AllowedItems & NETFLAG_DOINVUL ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_CLOAK & & ! ( Netgame . AllowedItems & NETFLAG_DOCLOAK ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_AFTERBURNER & & ! ( Netgame . AllowedItems & NETFLAG_DOAFTERBURNER ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_FUSION_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOFUSION ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_PHOENIX_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPHOENIX ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_HELIX_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOHELIX ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_MEGA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOMEGA ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_SMARTBOMB_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOSMART ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_GAUSS_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOGAUSS ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_VULCAN_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOVULCAN ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_PLASMA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPLASMA ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_OMEGA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOOMEGA ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_SUPER_LASER & & ! ( Netgame . AllowedItems & NETFLAG_DOSUPERLASER ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_PROXIMITY_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPROXIM ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_VULCAN_AMMO & & ( ! ( Netgame . AllowedItems & NETFLAG_DOVULCAN ) & & ! ( Netgame . AllowedItems & NETFLAG_DOGAUSS ) ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_SPREADFIRE_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOSPREAD ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_SMART_MINE & & ! ( Netgame . AllowedItems & NETFLAG_DOSMARTMINE ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_SMISSILE1_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOFLASH ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_SMISSILE1_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOFLASH ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_GUIDED_MISSILE_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOGUIDED ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_GUIDED_MISSILE_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOGUIDED ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_EARTHSHAKER_MISSILE & & ! ( Netgame . AllowedItems & NETFLAG_DOSHAKER ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_MERCURY_MISSILE_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOMERCURY ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_MERCURY_MISSILE_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOMERCURY ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_CONVERTER & & ! ( Netgame . AllowedItems & NETFLAG_DOCONVERTER ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_AMMO_RACK & & ! ( Netgame . AllowedItems & NETFLAG_DOAMMORACK ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_HEADLIGHT & & ! ( Netgame . AllowedItems & NETFLAG_DOHEADLIGHT ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_LASER & & ! ( Netgame . AllowedItems & NETFLAG_DOLASER ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_HOMING_AMMO_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOHOMING ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_HOMING_AMMO_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOHOMING ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2009-03-20 12:10:38 +00:00
if ( id = = POW_QUAD_FIRE & & ! ( Netgame . AllowedItems & NETFLAG_DOQUAD ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2013-08-11 16:03:47 +00:00
if ( id = = POW_FLAG_BLUE & & ! game_mode_capture_flag ( ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
2013-08-11 16:03:47 +00:00
if ( id = = POW_FLAG_RED & & ! game_mode_capture_flag ( ) )
2006-03-20 17:12:09 +00:00
return ( 0 ) ;
return ( 1 ) ;
}
void multi_send_finish_game ( )
{
multibuf [ 1 ] = Player_num ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_FINISH_GAME > ( multibuf , 2 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_finish_game ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
if ( buf [ 0 ] ! = MULTI_FINISH_GAME )
return ;
if ( Current_level_num ! = Last_level )
return ;
do_final_boss_hacks ( ) ;
}
2014-09-21 22:10:12 +00:00
void multi_send_trigger_specific ( const playernum_t pnum , char trig )
2006-03-20 17:12:09 +00:00
{
multibuf [ 1 ] = trig ;
2013-12-16 22:15:38 +00:00
multi_send_data_direct < MULTI_START_TRIGGER > ( multibuf , 2 , pnum , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_start_trigger ( const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
Triggers [ ( int ) buf [ 1 ] ] . flags | = TF_DISABLED ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
void multi_add_lifetime_kills ( )
{
// This function adds a kill to lifetime stats of this player, and possibly
// gives a promotion. If so, it will tell everyone else
int oldrank ;
2009-11-24 09:48:53 +00:00
if ( ! ( Game_mode & GM_NETWORK ) )
2006-03-20 17:12:09 +00:00
return ;
oldrank = GetMyNetRanking ( ) ;
2008-04-13 00:28:36 +00:00
PlayerCfg . NetlifeKills + + ;
2006-03-20 17:12:09 +00:00
if ( oldrank ! = GetMyNetRanking ( ) )
{
multi_send_ranking ( ) ;
2011-01-03 01:01:26 +00:00
if ( ! PlayerCfg . NoRankings )
2006-03-20 17:12:09 +00:00
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " You have been promoted to %s! " , RankStrings [ GetMyNetRanking ( ) ] ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
digi_play_sample ( SOUND_CONTROL_CENTER_WARNING_SIREN , F1_0 * 2 ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
digi_play_sample ( SOUND_BUDDY_MET_GOAL , F1_0 * 2 ) ;
2013-03-03 01:03:33 +00:00
# endif
2009-03-20 12:10:38 +00:00
Netgame . players [ Player_num ] . rank = GetMyNetRanking ( ) ;
2006-03-20 17:12:09 +00:00
}
}
}
void multi_add_lifetime_killed ( )
{
// This function adds a "killed" to lifetime stats of this player, and possibly
// gives a demotion. If so, it will tell everyone else
int oldrank ;
2009-11-24 09:48:53 +00:00
if ( ! ( Game_mode & GM_NETWORK ) )
2006-03-20 17:12:09 +00:00
return ;
oldrank = GetMyNetRanking ( ) ;
2008-04-13 00:28:36 +00:00
PlayerCfg . NetlifeKilled + + ;
2006-03-20 17:12:09 +00:00
if ( oldrank ! = GetMyNetRanking ( ) )
{
multi_send_ranking ( ) ;
2009-03-20 12:10:38 +00:00
Netgame . players [ Player_num ] . rank = GetMyNetRanking ( ) ;
2006-03-20 17:12:09 +00:00
2011-01-03 01:01:26 +00:00
if ( ! PlayerCfg . NoRankings )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " You have been demoted to %s! " , RankStrings [ GetMyNetRanking ( ) ] ) ;
2006-03-20 17:12:09 +00:00
}
}
void multi_send_ranking ( )
{
multibuf [ 1 ] = ( char ) Player_num ;
multibuf [ 2 ] = ( char ) GetMyNetRanking ( ) ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_RANK > ( multibuf , 3 , 2 ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:41:55 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-09-21 22:10:12 +00:00
static void multi_do_ranking ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
char rankstr [ 20 ] ;
char rank = buf [ 2 ] ;
2009-03-20 12:10:38 +00:00
if ( Netgame . players [ ( int ) pnum ] . rank < rank )
2006-03-20 17:12:09 +00:00
strcpy ( rankstr , " promoted " ) ;
2009-03-20 12:10:38 +00:00
else if ( Netgame . players [ ( int ) pnum ] . rank > rank )
2006-03-20 17:12:09 +00:00
strcpy ( rankstr , " demoted " ) ;
else
return ;
2009-03-20 12:10:38 +00:00
Netgame . players [ ( int ) pnum ] . rank = rank ;
2006-03-20 17:12:09 +00:00
2011-01-03 01:01:26 +00:00
if ( ! PlayerCfg . NoRankings )
2014-07-05 16:48:12 +00:00
HUD_init_message ( HM_MULTI , " %s has been %s to %s! " , static_cast < const char * > ( Players [ pnum ] . callsign ) , rankstr , RankStrings [ ( int ) rank ] ) ;
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:41:55 +00:00
# endif
2006-03-20 17:12:09 +00:00
2011-01-14 18:48:48 +00:00
// Decide if fire from "killer" is friendly. If yes return 1 (no harm to me) otherwise 0 (damage me)
2014-08-16 23:18:17 +00:00
int multi_maybe_disable_friendly_fire ( objptridx_t killer )
2011-01-14 18:48:48 +00:00
{
if ( ! ( Game_mode & GM_NETWORK ) ) // no Multiplayer game -> always harm me!
return 0 ;
if ( ! Netgame . NoFriendlyFire ) // friendly fire is activated -> harm me!
return 0 ;
2014-08-16 23:18:17 +00:00
if ( killer = = object_none ) // no actual killer -> harm me!
2011-05-04 10:05:59 +00:00
return 0 ;
2011-01-14 18:48:48 +00:00
if ( killer - > type ! = OBJ_PLAYER ) // not a player -> harm me!
return 0 ;
if ( Game_mode & GM_MULTI_COOP ) // coop mode -> don't harm me!
return 1 ;
else if ( Game_mode & GM_TEAM ) // team mode - find out if killer is in my team
{
2013-10-07 23:52:33 +00:00
if ( get_team ( Player_num ) = = get_team ( get_player_id ( killer ) ) ) // in my team -> don't harm me!
2011-01-14 18:48:48 +00:00
return 1 ;
else // opposite team -> harm me!
return 0 ;
}
return 0 ; // all other cases -> harm me!
}
2011-01-19 01:19:17 +00:00
/* Bounty packer sender and handler */
void multi_send_bounty ( void )
{
/* Test game mode */
if ( ! ( Game_mode & GM_BOUNTY ) )
return ;
2011-05-15 09:59:12 +00:00
if ( ! multi_i_am_master ( ) )
return ;
2011-01-19 01:19:17 +00:00
2011-05-19 00:34:14 +00:00
/* Add opcode, target ID and how often we re-assigned */
2011-01-19 01:19:17 +00:00
multibuf [ 1 ] = ( char ) Bounty_target ;
/* Send data */
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_DO_BOUNTY > ( multibuf , 2 , 2 ) ;
2011-01-19 01:19:17 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_bounty ( const ubyte * buf )
2011-01-19 01:19:17 +00:00
{
2011-05-15 09:59:12 +00:00
if ( multi_i_am_master ( ) )
return ;
2011-05-25 13:25:13 +00:00
multi_new_bounty_target ( buf [ 1 ] ) ;
2011-01-19 01:19:17 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_new_bounty_target ( const playernum_t pnum )
2011-01-19 01:19:17 +00:00
{
/* If it's already the same, don't do it */
if ( Bounty_target = = pnum )
return ;
/* Set the target */
Bounty_target = pnum ;
/* Send a message */
HUD_init_message ( HM_MULTI , " %c%c%s is the new target! " , CC_COLOR ,
BM_XRGB ( player_rgb [ Bounty_target ] . r , player_rgb [ Bounty_target ] . g , player_rgb [ Bounty_target ] . b ) ,
2014-07-05 16:48:12 +00:00
static_cast < const char * > ( Players [ Bounty_target ] . callsign ) ) ;
2011-01-19 01:19:17 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
digi_play_sample ( SOUND_CONTROL_CENTER_WARNING_SIREN , F1_0 * 3 ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2011-01-19 01:19:17 +00:00
digi_play_sample ( SOUND_BUDDY_MET_GOAL , F1_0 * 2 ) ;
2013-03-03 01:03:33 +00:00
# endif
2011-01-19 01:19:17 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_save_game ( const ubyte * buf )
2011-02-09 11:58:32 +00:00
{
int count = 1 ;
ubyte slot ;
uint id ;
char desc [ 25 ] ;
slot = * ( ubyte * ) ( buf + count ) ; count + = 1 ;
id = GET_INTEL_INT ( buf + count ) ; count + = 4 ;
memcpy ( desc , & buf [ count ] , 20 ) ; count + = 20 ;
multi_save_game ( slot , id , desc ) ;
}
2013-10-27 22:00:14 +00:00
static void multi_do_restore_game ( const ubyte * buf )
2011-02-09 11:58:32 +00:00
{
int count = 1 ;
ubyte slot ;
uint id ;
slot = * ( ubyte * ) ( buf + count ) ; count + = 1 ;
id = GET_INTEL_INT ( buf + count ) ; count + = 4 ;
multi_restore_game ( slot , id ) ;
}
2013-10-27 22:00:14 +00:00
static void multi_send_save_game ( ubyte slot , uint id , char * desc )
2011-02-09 11:58:32 +00:00
{
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2011-02-09 11:58:32 +00:00
multibuf [ count ] = slot ; count + = 1 ; // Save slot=0
PUT_INTEL_INT ( multibuf + count , id ) ; count + = 4 ; // Save id
memcpy ( & multibuf [ count ] , desc , 20 ) ; count + = 20 ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_SAVE_GAME > ( multibuf , count , 2 ) ;
2011-02-09 11:58:32 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_send_restore_game ( ubyte slot , uint id )
2011-02-09 11:58:32 +00:00
{
int count = 0 ;
2013-12-16 23:44:34 +00:00
count + = 1 ;
2011-02-09 11:58:32 +00:00
multibuf [ count ] = slot ; count + = 1 ; // Save slot=0
PUT_INTEL_INT ( multibuf + count , id ) ; count + = 4 ; // Save id
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_RESTORE_GAME > ( multibuf , count , 2 ) ;
2011-02-09 11:58:32 +00:00
}
void multi_initiate_save_game ( )
{
fix game_id = 0 ;
int i , j , slot ;
char filename [ PATH_MAX ] ;
char desc [ 24 ] ;
if ( ( Endlevel_sequence ) | | ( Control_center_destroyed ) )
return ;
if ( ! multi_i_am_master ( ) )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Only host is allowed to save a game! " ) ;
2011-02-09 11:58:32 +00:00
return ;
}
if ( ! multi_all_players_alive ( ) )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Can't save! All players must be alive! " ) ;
2011-02-09 11:58:32 +00:00
return ;
}
for ( i = 0 ; i < N_players ; i + + )
{
2014-07-05 03:32:08 +00:00
for ( j = i + 1 ; j < N_players ; j + + )
2011-02-09 11:58:32 +00:00
{
2014-07-05 16:48:12 +00:00
if ( i ! = j & & Players [ i ] . callsign = = Players [ j ] . callsign )
2011-02-09 11:58:32 +00:00
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Can't save! Multiple players with same callsign! " ) ;
2011-02-09 11:58:32 +00:00
return ;
}
}
}
memset ( & filename , ' \0 ' , PATH_MAX ) ;
memset ( & desc , ' \0 ' , 24 ) ;
slot = state_get_save_file ( filename , desc , 0 ) ;
if ( ! slot )
return ;
slot - - ;
// Make a unique game id
game_id = ( ( fix ) timer_query ( ) ) ;
game_id ^ = N_players < < 4 ;
for ( i = 0 ; i < N_players ; i + + )
2011-02-10 17:56:33 +00:00
{
fix call2i ;
2014-07-05 16:48:12 +00:00
memcpy ( & call2i , static_cast < const char * > ( Players [ i ] . callsign ) , sizeof ( fix ) ) ;
2011-02-10 17:56:33 +00:00
game_id ^ = call2i ;
}
2011-02-09 11:58:32 +00:00
if ( game_id = = 0 )
game_id = 1 ; // 0 is invalid
multi_send_save_game ( slot , game_id , desc ) ;
multi_do_frame ( ) ;
multi_save_game ( slot , game_id , desc ) ;
}
void multi_initiate_restore_game ( )
{
int i , j , slot ;
char filename [ PATH_MAX ] ;
if ( ( Endlevel_sequence ) | | ( Control_center_destroyed ) )
return ;
if ( ! multi_i_am_master ( ) )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Only host is allowed to load a game! " ) ;
2011-02-09 11:58:32 +00:00
return ;
}
if ( ! multi_all_players_alive ( ) )
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Can't load! All players must be alive! " ) ;
2011-02-09 11:58:32 +00:00
return ;
}
for ( i = 0 ; i < N_players ; i + + )
{
2014-07-05 03:32:08 +00:00
for ( j = i + 1 ; j < N_players ; j + + )
2011-02-09 11:58:32 +00:00
{
2014-07-05 16:48:12 +00:00
if ( i ! = j & & Players [ i ] . callsign = = Players [ j ] . callsign )
2011-02-09 11:58:32 +00:00
{
2013-06-23 16:27:34 +00:00
HUD_init_message_literal ( HM_MULTI , " Can't load! Multiple players with same callsign! " ) ;
2011-02-09 11:58:32 +00:00
return ;
}
}
}
2013-12-10 17:13:32 +00:00
slot = state_get_restore_file ( filename , 0 ) ;
2011-02-09 11:58:32 +00:00
if ( ! slot )
return ;
state_game_id = state_get_game_id ( filename ) ;
if ( ! state_game_id )
return ;
slot - - ;
multi_send_restore_game ( slot , state_game_id ) ;
multi_do_frame ( ) ;
multi_restore_game ( slot , state_game_id ) ;
}
void multi_save_game ( ubyte slot , uint id , char * desc )
{
char filename [ PATH_MAX ] ;
if ( ( Endlevel_sequence ) | | ( Control_center_destroyed ) )
return ;
2014-07-05 16:48:12 +00:00
snprintf ( filename , sizeof ( filename ) , PLAYER_DIRECTORY_STRING ( " %s.mg%d " ) , static_cast < const char * > ( Players [ Player_num ] . callsign ) , slot ) ;
2011-02-09 11:58:32 +00:00
HUD_init_message ( HM_MULTI , " Saving game #%d, '%s' " , slot , desc ) ;
stop_time ( ) ;
state_game_id = id ;
state_save_all_sub ( filename , desc ) ;
}
void multi_restore_game ( ubyte slot , uint id )
{
char filename [ PATH_MAX ] ;
2011-05-15 09:59:12 +00:00
int i ;
2011-02-09 11:58:32 +00:00
int thisid ;
if ( ( Endlevel_sequence ) | | ( Control_center_destroyed ) )
return ;
2014-07-05 16:48:12 +00:00
snprintf ( filename , sizeof ( filename ) , PLAYER_DIRECTORY_STRING ( " %s.mg%d " ) , static_cast < const char * > ( Players [ Player_num ] . callsign ) , slot ) ;
2011-02-09 11:58:32 +00:00
for ( i = 0 ; i < N_players ; i + + )
multi_strip_robots ( i ) ;
if ( multi_i_am_master ( ) ) // put all players to wait-state again so we can sync up properly
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
if ( Players [ i ] . connected = = CONNECT_PLAYING & & i ! = Player_num )
Players [ i ] . connected = CONNECT_WAITING ;
thisid = state_get_game_id ( filename ) ;
if ( thisid ! = id )
{
nm_messagebox ( NULL , 1 , TXT_OK , " A multi-save game was restored \n that you are missing or does not \n match that of the others. \n You must rejoin if you wish to \n continue. " ) ;
return ;
}
2011-05-15 09:59:12 +00:00
state_restore_all_sub ( filename , 0 ) ;
2011-04-19 23:47:15 +00:00
multi_send_score ( ) ; // send my restored scores. I sent 0 when I loaded the level anyways...
2011-02-09 11:58:32 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_msgsend_state ( const ubyte * buf )
2011-04-11 15:47:16 +00:00
{
2013-12-13 21:47:46 +00:00
multi_sending_message [ ( int ) buf [ 1 ] ] = ( msgsend_state_t ) buf [ 2 ] ;
2011-04-11 15:47:16 +00:00
}
2013-12-13 21:47:46 +00:00
void multi_send_msgsend_state ( msgsend_state_t state )
2011-04-11 15:47:16 +00:00
{
multibuf [ 1 ] = Player_num ;
multibuf [ 2 ] = ( char ) state ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_TYPING_STATE > ( multibuf , 3 , 2 ) ;
2011-04-11 15:47:16 +00:00
}
2011-05-25 13:25:13 +00:00
// Specific variables related to our game mode we want the clients to know about
void multi_send_gmode_update ( )
{
if ( ! multi_i_am_master ( ) )
return ;
if ( ! ( Game_mode & GM_TEAM | | Game_mode & GM_BOUNTY ) ) // expand if necessary
return ;
multibuf [ 1 ] = Netgame . team_vector ;
multibuf [ 2 ] = Bounty_target ;
2013-12-16 23:44:34 +00:00
multi_send_data < MULTI_GMODE_UPDATE > ( multibuf , 3 , 0 ) ;
2011-05-25 13:25:13 +00:00
}
2013-10-27 22:00:14 +00:00
static void multi_do_gmode_update ( const ubyte * buf )
2011-05-25 13:25:13 +00:00
{
if ( multi_i_am_master ( ) )
return ;
if ( Game_mode & GM_TEAM )
{
if ( buf [ 1 ] ! = Netgame . team_vector )
{
int t ;
Netgame . team_vector = buf [ 1 ] ;
for ( t = 0 ; t < N_players ; t + + )
if ( Players [ t ] . connected )
multi_reset_object_texture ( & Objects [ Players [ t ] . objnum ] ) ;
reset_cockpit ( ) ;
}
}
if ( Game_mode & GM_BOUNTY )
{
Bounty_target = buf [ 2 ] ; // accept silently - message about change we SHOULD have gotten due to kill computation
}
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
///
/// CODE TO LOAD HOARD DATA
///
2009-11-24 09:48:53 +00:00
int HoardEquipped ( )
{
static int checked = - 1 ;
if ( checked = = - 1 )
{
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( " hoard.ham " , 1 ) )
2009-11-24 09:48:53 +00:00
checked = 1 ;
else
checked = 0 ;
}
return ( checked ) ;
}
2006-03-20 17:12:09 +00:00
grs_bitmap Orb_icons [ 2 ] ;
2011-02-24 10:28:59 +00:00
int Hoard_goal_eclip , Hoard_bm_idx , Hoard_snd_idx ;
2006-03-20 17:12:09 +00:00
2013-10-27 22:00:14 +00:00
static void free_hoard_data ( )
2011-02-24 10:28:59 +00:00
{
int i ;
d_free ( GameBitmaps [ Hoard_bm_idx ] . bm_data ) ;
for ( i = Hoard_snd_idx ; i < Hoard_snd_idx + 4 ; i + + )
d_free ( GameSounds [ i ] . data ) ;
for ( i = 0 ; i < 2 ; i + + )
d_free ( Orb_icons [ i ] . bm_data ) ;
}
2006-03-20 17:12:09 +00:00
void init_hoard_data ( )
{
static int first_time = 1 ;
static int orb_vclip ;
int n_orb_frames , n_goal_frames ;
int orb_w , orb_h ;
int icon_w , icon_h ;
2013-01-06 21:03:57 +00:00
palette_array_t palette ;
2011-06-01 07:59:55 +00:00
PHYSFS_file * ifile ;
2011-07-14 11:38:04 +00:00
ubyte * bitmap_data1 ;
2006-03-20 17:12:09 +00:00
int i , save_pos ;
2011-07-14 11:38:04 +00:00
int bitmap_num = Hoard_bm_idx = Num_bitmap_files ;
if ( ! first_time )
free_hoard_data ( ) ;
2006-03-20 17:12:09 +00:00
2010-09-25 03:35:23 +00:00
ifile = PHYSFSX_openReadBuffered ( " hoard.ham " ) ;
2006-03-20 17:12:09 +00:00
if ( ifile = = NULL )
Error ( " can't open <hoard.ham> " ) ;
2011-06-01 07:59:55 +00:00
n_orb_frames = PHYSFSX_readShort ( ifile ) ;
orb_w = PHYSFSX_readShort ( ifile ) ;
orb_h = PHYSFSX_readShort ( ifile ) ;
save_pos = PHYSFS_tell ( ifile ) ;
PHYSFSX_fseek ( ifile , sizeof ( palette ) + n_orb_frames * orb_w * orb_h , SEEK_CUR ) ;
n_goal_frames = PHYSFSX_readShort ( ifile ) ;
PHYSFSX_fseek ( ifile , save_pos , SEEK_SET ) ;
2006-03-20 17:12:09 +00:00
2011-07-14 11:38:04 +00:00
//Allocate memory for bitmaps
MALLOC ( bitmap_data1 , ubyte , n_orb_frames * orb_w * orb_h + n_goal_frames * 64 * 64 ) ;
//Create orb vclip
orb_vclip = Num_vclips + + ;
Assert ( Num_vclips < = VCLIP_MAXNUM ) ;
Vclip [ orb_vclip ] . play_time = F1_0 / 2 ;
Vclip [ orb_vclip ] . num_frames = n_orb_frames ;
Vclip [ orb_vclip ] . frame_time = Vclip [ orb_vclip ] . play_time / Vclip [ orb_vclip ] . num_frames ;
Vclip [ orb_vclip ] . flags = 0 ;
Vclip [ orb_vclip ] . sound_num = - 1 ;
Vclip [ orb_vclip ] . light_value = F1_0 ;
for ( i = 0 ; i < n_orb_frames ; i + + ) {
Vclip [ orb_vclip ] . frames [ i ] . index = bitmap_num ;
gr_init_bitmap ( & GameBitmaps [ bitmap_num ] , BM_LINEAR , 0 , 0 , orb_w , orb_h , orb_w , bitmap_data1 ) ;
gr_set_transparent ( & GameBitmaps [ bitmap_num ] , 1 ) ;
bitmap_data1 + = orb_w * orb_h ;
bitmap_num + + ;
Assert ( bitmap_num < MAX_BITMAP_FILES ) ;
}
//Create obj powerup
Powerup_info [ POW_HOARD_ORB ] . vclip_num = orb_vclip ;
Powerup_info [ POW_HOARD_ORB ] . hit_sound = - 1 ; //Powerup_info[POW_SHIELD_BOOST].hit_sound;
Powerup_info [ POW_HOARD_ORB ] . size = Powerup_info [ POW_SHIELD_BOOST ] . size ;
Powerup_info [ POW_HOARD_ORB ] . light = Powerup_info [ POW_SHIELD_BOOST ] . light ;
//Create orb goal wall effect
Hoard_goal_eclip = Num_effects + + ;
Assert ( Num_effects < MAX_EFFECTS ) ;
Effects [ Hoard_goal_eclip ] = Effects [ 94 ] ; //copy from blue goal
Effects [ Hoard_goal_eclip ] . changing_wall_texture = NumTextures ;
Effects [ Hoard_goal_eclip ] . vc . num_frames = n_goal_frames ;
2014-08-16 18:16:59 +00:00
TmapInfo [ NumTextures ] = find_required_goal_texture ( TMI_GOAL_BLUE ) ;
2011-07-14 11:38:04 +00:00
TmapInfo [ NumTextures ] . eclip_num = Hoard_goal_eclip ;
TmapInfo [ NumTextures ] . flags = TMI_GOAL_HOARD ;
NumTextures + + ;
Assert ( NumTextures < MAX_TEXTURES ) ;
for ( i = 0 ; i < n_goal_frames ; i + + ) {
Effects [ Hoard_goal_eclip ] . vc . frames [ i ] . index = bitmap_num ;
gr_init_bitmap ( & GameBitmaps [ bitmap_num ] , BM_LINEAR , 0 , 0 , 64 , 64 , 64 , bitmap_data1 ) ;
bitmap_data1 + = 64 * 64 ;
bitmap_num + + ;
Assert ( bitmap_num < MAX_BITMAP_FILES ) ;
2006-03-20 17:12:09 +00:00
}
//Load and remap bitmap data for orb
2013-01-06 21:11:53 +00:00
PHYSFS_read ( ifile , & palette [ 0 ] , sizeof ( palette [ 0 ] ) , palette . size ( ) ) ;
2006-03-20 17:12:09 +00:00
for ( i = 0 ; i < n_orb_frames ; i + + ) {
grs_bitmap * bm = & GameBitmaps [ Vclip [ orb_vclip ] . frames [ i ] . index ] ;
2011-06-01 07:59:55 +00:00
PHYSFS_read ( ifile , bm - > bm_data , 1 , orb_w * orb_h ) ;
2006-03-20 17:12:09 +00:00
gr_remap_bitmap_good ( bm , palette , 255 , - 1 ) ;
}
//Load and remap bitmap data for goal texture
2011-06-01 07:59:55 +00:00
PHYSFSX_readShort ( ifile ) ; //skip frame count
2013-01-06 21:11:53 +00:00
PHYSFS_read ( ifile , & palette [ 0 ] , sizeof ( palette [ 0 ] ) , palette . size ( ) ) ;
2006-03-20 17:12:09 +00:00
for ( i = 0 ; i < n_goal_frames ; i + + ) {
grs_bitmap * bm = & GameBitmaps [ Effects [ Hoard_goal_eclip ] . vc . frames [ i ] . index ] ;
2011-06-01 07:59:55 +00:00
PHYSFS_read ( ifile , bm - > bm_data , 1 , 64 * 64 ) ;
2006-03-20 17:12:09 +00:00
gr_remap_bitmap_good ( bm , palette , 255 , - 1 ) ;
}
//Load and remap bitmap data for HUD icons
for ( i = 0 ; i < 2 ; i + + ) {
2011-07-14 11:38:04 +00:00
ubyte * bitmap_data2 ;
2011-06-01 07:59:55 +00:00
icon_w = PHYSFSX_readShort ( ifile ) ;
icon_h = PHYSFSX_readShort ( ifile ) ;
2011-07-14 11:38:04 +00:00
MALLOC ( bitmap_data2 , ubyte , icon_w * icon_h ) ;
gr_init_bitmap ( & Orb_icons [ i ] , BM_LINEAR , 0 , 0 , icon_w , icon_h , icon_w , bitmap_data2 ) ;
gr_set_transparent ( & Orb_icons [ i ] , 1 ) ;
2013-01-06 21:11:53 +00:00
PHYSFS_read ( ifile , & palette [ 0 ] , sizeof ( palette [ 0 ] ) , palette . size ( ) ) ;
2011-06-01 07:59:55 +00:00
PHYSFS_read ( ifile , Orb_icons [ i ] . bm_data , 1 , icon_w * icon_h ) ;
2006-03-20 17:12:09 +00:00
gr_remap_bitmap_good ( & Orb_icons [ i ] , palette , 255 , - 1 ) ;
}
2011-07-14 11:38:04 +00:00
//Load sounds for orb game
Hoard_snd_idx = Num_sound_files ;
for ( i = 0 ; i < 4 ; i + + ) {
int len ;
2006-03-20 17:12:09 +00:00
2011-07-14 11:38:04 +00:00
len = PHYSFSX_readInt ( ifile ) ; //get 11k len
2006-03-20 17:12:09 +00:00
2011-07-14 11:38:04 +00:00
if ( GameArg . SndDigiSampleRate = = SAMPLE_RATE_22K ) {
PHYSFSX_fseek ( ifile , len , SEEK_CUR ) ; //skip over 11k sample
len = PHYSFSX_readInt ( ifile ) ; //get 22k len
}
2006-03-20 17:12:09 +00:00
2011-07-14 11:38:04 +00:00
GameSounds [ Num_sound_files + i ] . length = len ;
2013-10-06 18:08:39 +00:00
MALLOC ( GameSounds [ Num_sound_files + i ] . data , ubyte , len ) ;
2011-07-14 11:38:04 +00:00
PHYSFS_read ( ifile , GameSounds [ Num_sound_files + i ] . data , 1 , len ) ;
2006-03-20 17:12:09 +00:00
2011-07-14 11:38:04 +00:00
if ( GameArg . SndDigiSampleRate = = SAMPLE_RATE_11K ) {
len = PHYSFSX_readInt ( ifile ) ; //get 22k len
PHYSFSX_fseek ( ifile , len , SEEK_CUR ) ; //skip over 22k sample
2006-03-20 17:12:09 +00:00
}
2011-07-14 11:38:04 +00:00
Sounds [ SOUND_YOU_GOT_ORB + i ] = Num_sound_files + i ;
AltSounds [ SOUND_YOU_GOT_ORB + i ] = Sounds [ SOUND_YOU_GOT_ORB + i ] ;
2006-03-20 17:12:09 +00:00
}
2011-06-01 07:59:55 +00:00
PHYSFS_close ( ifile ) ;
2011-02-24 10:28:59 +00:00
if ( first_time )
atexit ( free_hoard_data ) ;
2006-03-20 17:12:09 +00:00
first_time = 0 ;
}
2006-10-02 13:29:04 +00:00
# ifdef EDITOR
void save_hoard_data ( void )
{
grs_bitmap icon ;
2012-11-18 18:20:13 +00:00
unsigned nframes ;
2013-01-06 21:03:57 +00:00
palette_array_t palette ;
2006-10-02 13:29:04 +00:00
PHYSFS_file * ofile ;
2012-11-18 18:20:13 +00:00
int iff_error ;
unsigned i ;
2013-11-28 02:09:35 +00:00
static const char sounds [ ] [ 13 ] = { " selforb.raw " , " selforb.r22 " , //SOUND_YOU_GOT_ORB
2006-10-02 13:29:04 +00:00
" teamorb.raw " , " teamorb.r22 " , //SOUND_FRIEND_GOT_ORB
" enemyorb.raw " , " enemyorb.r22 " , //SOUND_OPPONENT_GOT_ORB
" OPSCORE1.raw " , " OPSCORE1.r22 " } ; //SOUND_OPPONENT_HAS_SCORED
ofile = PHYSFSX_openWriteBuffered ( " hoard.ham " ) ;
2014-10-04 15:02:03 +00:00
array < std : : unique_ptr < grs_bitmap > , MAX_BITMAPS_PER_BRUSH > bm ;
2014-09-27 23:06:33 +00:00
iff_error = iff_read_animbrush ( " orb.abm " , bm , & nframes , palette ) ;
2006-10-02 13:29:04 +00:00
Assert ( iff_error = = IFF_NO_ERROR ) ;
PHYSFS_writeULE16 ( ofile , nframes ) ;
PHYSFS_writeULE16 ( ofile , bm [ 0 ] - > bm_w ) ;
PHYSFS_writeULE16 ( ofile , bm [ 0 ] - > bm_h ) ;
2013-01-06 21:11:53 +00:00
PHYSFS_write ( ofile , & palette [ 0 ] , sizeof ( palette [ 0 ] ) , palette . size ( ) ) ;
2006-10-02 13:29:04 +00:00
for ( i = 0 ; i < nframes ; i + + )
PHYSFS_write ( ofile , bm [ i ] - > bm_data , bm [ i ] - > bm_w * bm [ i ] - > bm_h , 1 ) ;
2014-09-27 23:06:33 +00:00
iff_error = iff_read_animbrush ( " orbgoal.abm " , bm , & nframes , palette ) ;
2006-10-02 13:29:04 +00:00
Assert ( iff_error = = IFF_NO_ERROR ) ;
Assert ( bm [ 0 ] - > bm_w = = 64 & & bm [ 0 ] - > bm_h = = 64 ) ;
PHYSFS_writeULE16 ( ofile , nframes ) ;
2013-01-06 21:11:53 +00:00
PHYSFS_write ( ofile , & palette [ 0 ] , sizeof ( palette [ 0 ] ) , palette . size ( ) ) ;
2006-10-02 13:29:04 +00:00
for ( i = 0 ; i < nframes ; i + + )
PHYSFS_write ( ofile , bm [ i ] - > bm_data , bm [ i ] - > bm_w * bm [ i ] - > bm_h , 1 ) ;
for ( i = 0 ; i < 2 ; i + + )
{
2013-01-06 21:03:57 +00:00
iff_error = iff_read_bitmap ( i ? " orbb.bbm " : " orb.bbm " , & icon , BM_LINEAR , & palette ) ;
2006-10-02 13:29:04 +00:00
Assert ( iff_error = = IFF_NO_ERROR ) ;
PHYSFS_writeULE16 ( ofile , icon . bm_w ) ;
PHYSFS_writeULE16 ( ofile , icon . bm_h ) ;
2013-01-06 21:11:53 +00:00
PHYSFS_write ( ofile , & palette [ 0 ] , sizeof ( palette [ 0 ] ) , palette . size ( ) ) ;
2006-10-02 13:29:04 +00:00
PHYSFS_write ( ofile , icon . bm_data , icon . bm_w * icon . bm_h , 1 ) ;
}
2011-09-26 23:31:19 +00:00
( void ) iff_error ;
2006-10-02 13:29:04 +00:00
for ( i = 0 ; i < sizeof ( sounds ) / sizeof ( * sounds ) ; i + + ) {
PHYSFS_file * ifile ;
int size ;
ifile = PHYSFS_openRead ( sounds [ i ] ) ;
Assert ( ifile ! = NULL ) ;
size = PHYSFS_fileLength ( ifile ) ;
2013-12-08 18:22:17 +00:00
RAIIdubyte buf ;
2013-10-06 18:08:39 +00:00
MALLOC ( buf , ubyte , size ) ;
2006-10-02 13:29:04 +00:00
PHYSFS_read ( ifile , buf , size , 1 ) ;
PHYSFS_writeULE32 ( ofile , size ) ;
PHYSFS_write ( ofile , buf , size , 1 ) ;
PHYSFS_close ( ifile ) ;
}
PHYSFS_close ( ofile ) ;
}
# endif
2013-03-03 01:03:33 +00:00
# endif
2006-10-02 13:29:04 +00:00
2014-09-21 22:10:21 +00:00
static void multi_process_data ( const playernum_t pnum , const ubyte * buf , const uint_fast32_t type )
2006-03-20 17:12:09 +00:00
{
// Take an entire message (that has already been checked for validity,
// if necessary) and act on it.
switch ( type )
{
2012-04-15 01:05:28 +00:00
case MULTI_POSITION :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_position ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_REAPPEAR :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_reappear ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_FIRE :
2013-08-09 15:21:03 +00:00
case MULTI_FIRE_TRACK :
case MULTI_FIRE_BOMB :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_fire ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_KILL :
2014-05-30 02:45:34 +00:00
multi_do_kill ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_REMOVE_OBJECT :
if ( ! Endlevel_sequence ) multi_do_remobj ( buf ) ; break ;
2013-12-16 22:59:31 +00:00
case MULTI_PLAYER_DERES :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_player_deres ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_MESSAGE :
if ( ! Endlevel_sequence ) multi_do_message ( buf ) ; break ;
case MULTI_QUIT :
if ( ! Endlevel_sequence ) multi_do_quit ( buf ) ; break ;
case MULTI_CONTROLCEN :
if ( ! Endlevel_sequence ) multi_do_controlcen_destroy ( buf ) ; break ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2012-04-15 01:05:28 +00:00
case MULTI_SOUND_FUNCTION :
2014-05-30 02:45:34 +00:00
multi_do_sound_function ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_MARKER :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_drop_marker ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_DROP_WEAPON :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_drop_weapon ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_DROP_FLAG :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_drop_flag ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_GUIDED :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_guided ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_STOLEN_ITEMS :
if ( ! Endlevel_sequence ) multi_do_stolen_items ( buf ) ; break ;
case MULTI_WALL_STATUS :
if ( ! Endlevel_sequence ) multi_do_wall_status ( buf ) ; break ;
case MULTI_SEISMIC :
if ( ! Endlevel_sequence ) multi_do_seismic ( buf ) ; break ;
case MULTI_LIGHT :
if ( ! Endlevel_sequence ) multi_do_light ( buf ) ; break ;
2013-03-03 01:03:33 +00:00
# endif
2012-04-15 01:05:28 +00:00
case MULTI_ENDLEVEL_START :
if ( ! Endlevel_sequence ) multi_do_escape ( buf ) ; break ;
case MULTI_CLOAK :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_cloak ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_DECLOAK :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_decloak ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_DOOR_OPEN :
if ( ! Endlevel_sequence ) multi_do_door_open ( buf ) ; break ;
case MULTI_CREATE_EXPLOSION :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_create_explosion ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_CONTROLCEN_FIRE :
if ( ! Endlevel_sequence ) multi_do_controlcen_fire ( buf ) ; break ;
case MULTI_CREATE_POWERUP :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_create_powerup ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_PLAY_SOUND :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_play_sound ( pnum , buf ) ; break ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2012-04-15 01:05:28 +00:00
case MULTI_CAPTURE_BONUS :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_capture_bonus ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_ORB_BONUS :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_orb_bonus ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_GOT_FLAG :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_got_flag ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_GOT_ORB :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_got_orb ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_RANK :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_ranking ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_FINISH_GAME :
multi_do_finish_game ( buf ) ; break ; // do this one regardless of endsequence
2013-03-03 01:03:33 +00:00
# endif
2012-04-15 01:05:28 +00:00
case MULTI_ROBOT_CLAIM :
2014-05-30 02:38:16 +00:00
if ( ! Endlevel_sequence ) multi_do_claim_robot ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_ROBOT_POSITION :
2014-05-30 02:38:16 +00:00
if ( ! Endlevel_sequence ) multi_do_robot_position ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_ROBOT_EXPLODE :
if ( ! Endlevel_sequence ) multi_do_robot_explode ( buf ) ; break ;
case MULTI_ROBOT_RELEASE :
2014-05-30 02:38:16 +00:00
if ( ! Endlevel_sequence ) multi_do_release_robot ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_ROBOT_FIRE :
if ( ! Endlevel_sequence ) multi_do_robot_fire ( buf ) ; break ;
case MULTI_SCORE :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_score ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_CREATE_ROBOT :
2014-05-30 02:38:16 +00:00
if ( ! Endlevel_sequence ) multi_do_create_robot ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_TRIGGER :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_trigger ( pnum , buf ) ; break ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2012-04-15 01:05:28 +00:00
case MULTI_START_TRIGGER :
if ( ! Endlevel_sequence ) multi_do_start_trigger ( buf ) ; break ;
2013-12-19 12:48:33 +00:00
case MULTI_EFFECT_BLOWUP :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_effect_blowup ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_FLAGS :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_flags ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_DROP_BLOB :
2014-05-30 02:45:34 +00:00
if ( ! Endlevel_sequence ) multi_do_drop_blob ( pnum , buf ) ; break ;
2013-03-03 01:03:33 +00:00
# endif
2014-05-24 00:20:30 +00:00
case MULTI_BOSS_TELEPORT :
if ( ! Endlevel_sequence ) multi_do_boss_teleport ( pnum , buf ) ; break ;
case MULTI_BOSS_CLOAK :
if ( ! Endlevel_sequence ) multi_do_boss_cloak ( pnum , buf ) ; break ;
case MULTI_BOSS_START_GATE :
if ( ! Endlevel_sequence ) multi_do_boss_start_gate ( pnum , buf ) ; break ;
case MULTI_BOSS_STOP_GATE :
if ( ! Endlevel_sequence ) multi_do_boss_stop_gate ( pnum , buf ) ; break ;
case MULTI_BOSS_CREATE_ROBOT :
if ( ! Endlevel_sequence ) multi_do_boss_create_robot ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_CREATE_ROBOT_POWERUPS :
2014-05-30 02:38:16 +00:00
if ( ! Endlevel_sequence ) multi_do_create_robot_powerups ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_HOSTAGE_DOOR :
if ( ! Endlevel_sequence ) multi_do_hostage_door_status ( buf ) ; break ;
case MULTI_SAVE_GAME :
if ( ! Endlevel_sequence ) multi_do_save_game ( buf ) ; break ;
case MULTI_RESTORE_GAME :
if ( ! Endlevel_sequence ) multi_do_restore_game ( buf ) ; break ;
2013-08-11 16:23:37 +00:00
case MULTI_HEARTBEAT :
if ( ! Endlevel_sequence ) multi_do_heartbeat ( buf ) ; break ;
case MULTI_KILLGOALS :
if ( ! Endlevel_sequence ) multi_do_kill_goal_counts ( buf ) ; break ;
case MULTI_POWCAP_UPDATE :
if ( ! Endlevel_sequence ) multi_do_powcap_update ( buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_DO_BOUNTY :
if ( ! Endlevel_sequence ) multi_do_bounty ( buf ) ; break ;
case MULTI_TYPING_STATE :
multi_do_msgsend_state ( buf ) ; break ;
case MULTI_GMODE_UPDATE :
multi_do_gmode_update ( buf ) ; break ;
case MULTI_KILL_HOST :
2014-05-30 02:45:34 +00:00
multi_do_kill ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
case MULTI_KILL_CLIENT :
2014-05-30 02:45:34 +00:00
multi_do_kill ( pnum , buf ) ; break ;
2012-04-15 01:05:28 +00:00
default :
2014-09-21 22:10:21 +00:00
throw std : : runtime_error ( " invalid message type " ) ;
2006-03-20 17:12:09 +00:00
}
}
2010-12-22 00:17:59 +00:00
2011-09-13 23:15:32 +00:00
// Following functions convert object to object_rw and back.
2010-12-22 00:17:59 +00:00
// turn object to object_rw for sending
void multi_object_to_object_rw ( object * obj , object_rw * obj_rw )
{
obj_rw - > signature = obj - > signature ;
obj_rw - > type = obj - > type ;
obj_rw - > id = obj - > id ;
obj_rw - > next = obj - > next ;
obj_rw - > prev = obj - > prev ;
obj_rw - > control_type = obj - > control_type ;
obj_rw - > movement_type = obj - > movement_type ;
obj_rw - > render_type = obj - > render_type ;
obj_rw - > flags = obj - > flags ;
obj_rw - > segnum = obj - > segnum ;
obj_rw - > attached_obj = obj - > attached_obj ;
obj_rw - > pos . x = obj - > pos . x ;
obj_rw - > pos . y = obj - > pos . y ;
obj_rw - > pos . z = obj - > pos . z ;
obj_rw - > orient . rvec . x = obj - > orient . rvec . x ;
obj_rw - > orient . rvec . y = obj - > orient . rvec . y ;
obj_rw - > orient . rvec . z = obj - > orient . rvec . z ;
obj_rw - > orient . fvec . x = obj - > orient . fvec . x ;
obj_rw - > orient . fvec . y = obj - > orient . fvec . y ;
obj_rw - > orient . fvec . z = obj - > orient . fvec . z ;
obj_rw - > orient . uvec . x = obj - > orient . uvec . x ;
obj_rw - > orient . uvec . y = obj - > orient . uvec . y ;
obj_rw - > orient . uvec . z = obj - > orient . uvec . z ;
obj_rw - > size = obj - > size ;
obj_rw - > shields = obj - > shields ;
obj_rw - > last_pos . x = obj - > last_pos . x ;
obj_rw - > last_pos . y = obj - > last_pos . y ;
obj_rw - > last_pos . z = obj - > last_pos . z ;
obj_rw - > contains_type = obj - > contains_type ;
obj_rw - > contains_id = obj - > contains_id ;
obj_rw - > contains_count = obj - > contains_count ;
obj_rw - > matcen_creator = obj - > matcen_creator ;
obj_rw - > lifeleft = obj - > lifeleft ;
switch ( obj_rw - > movement_type )
{
case MT_PHYSICS :
obj_rw - > mtype . phys_info . velocity . x = obj - > mtype . phys_info . velocity . x ;
obj_rw - > mtype . phys_info . velocity . y = obj - > mtype . phys_info . velocity . y ;
obj_rw - > mtype . phys_info . velocity . z = obj - > mtype . phys_info . velocity . z ;
obj_rw - > mtype . phys_info . thrust . x = obj - > mtype . phys_info . thrust . x ;
obj_rw - > mtype . phys_info . thrust . y = obj - > mtype . phys_info . thrust . y ;
obj_rw - > mtype . phys_info . thrust . z = obj - > mtype . phys_info . thrust . z ;
obj_rw - > mtype . phys_info . mass = obj - > mtype . phys_info . mass ;
obj_rw - > mtype . phys_info . drag = obj - > mtype . phys_info . drag ;
obj_rw - > mtype . phys_info . rotvel . x = obj - > mtype . phys_info . rotvel . x ;
obj_rw - > mtype . phys_info . rotvel . y = obj - > mtype . phys_info . rotvel . y ;
obj_rw - > mtype . phys_info . rotvel . z = obj - > mtype . phys_info . rotvel . z ;
obj_rw - > mtype . phys_info . rotthrust . x = obj - > mtype . phys_info . rotthrust . x ;
obj_rw - > mtype . phys_info . rotthrust . y = obj - > mtype . phys_info . rotthrust . y ;
obj_rw - > mtype . phys_info . rotthrust . z = obj - > mtype . phys_info . rotthrust . z ;
obj_rw - > mtype . phys_info . turnroll = obj - > mtype . phys_info . turnroll ;
obj_rw - > mtype . phys_info . flags = obj - > mtype . phys_info . flags ;
break ;
case MT_SPINNING :
obj_rw - > mtype . spin_rate . x = obj - > mtype . spin_rate . x ;
obj_rw - > mtype . spin_rate . y = obj - > mtype . spin_rate . y ;
obj_rw - > mtype . spin_rate . z = obj - > mtype . spin_rate . z ;
break ;
}
switch ( obj_rw - > control_type )
{
case CT_WEAPON :
obj_rw - > ctype . laser_info . parent_type = obj - > ctype . laser_info . parent_type ;
obj_rw - > ctype . laser_info . parent_num = obj - > ctype . laser_info . parent_num ;
obj_rw - > ctype . laser_info . parent_signature = obj - > ctype . laser_info . parent_signature ;
if ( obj - > ctype . laser_info . creation_time - GameTime64 < F1_0 * ( - 18000 ) )
obj_rw - > ctype . laser_info . creation_time = F1_0 * ( - 18000 ) ;
else
obj_rw - > ctype . laser_info . creation_time = obj - > ctype . laser_info . creation_time - GameTime64 ;
obj_rw - > ctype . laser_info . last_hitobj = obj - > ctype . laser_info . last_hitobj ;
obj_rw - > ctype . laser_info . track_goal = obj - > ctype . laser_info . track_goal ;
obj_rw - > ctype . laser_info . multiplier = obj - > ctype . laser_info . multiplier ;
break ;
case CT_EXPLOSION :
obj_rw - > ctype . expl_info . spawn_time = obj - > ctype . expl_info . spawn_time ;
obj_rw - > ctype . expl_info . delete_time = obj - > ctype . expl_info . delete_time ;
obj_rw - > ctype . expl_info . delete_objnum = obj - > ctype . expl_info . delete_objnum ;
obj_rw - > ctype . expl_info . attach_parent = obj - > ctype . expl_info . attach_parent ;
obj_rw - > ctype . expl_info . prev_attach = obj - > ctype . expl_info . prev_attach ;
obj_rw - > ctype . expl_info . next_attach = obj - > ctype . expl_info . next_attach ;
break ;
case CT_AI :
{
int i ;
obj_rw - > ctype . ai_info . behavior = obj - > ctype . ai_info . behavior ;
for ( i = 0 ; i < MAX_AI_FLAGS ; i + + )
obj_rw - > ctype . ai_info . flags [ i ] = obj - > ctype . ai_info . flags [ i ] ;
obj_rw - > ctype . ai_info . hide_segment = obj - > ctype . ai_info . hide_segment ;
obj_rw - > ctype . ai_info . hide_index = obj - > ctype . ai_info . hide_index ;
obj_rw - > ctype . ai_info . path_length = obj - > ctype . ai_info . path_length ;
obj_rw - > ctype . ai_info . cur_path_index = obj - > ctype . ai_info . cur_path_index ;
obj_rw - > ctype . ai_info . danger_laser_num = obj - > ctype . ai_info . danger_laser_num ;
obj_rw - > ctype . ai_info . danger_laser_signature = obj - > ctype . ai_info . danger_laser_signature ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
obj_rw - > ctype . ai_info . follow_path_start_seg = obj - > ctype . ai_info . follow_path_start_seg ;
obj_rw - > ctype . ai_info . follow_path_end_seg = obj - > ctype . ai_info . follow_path_end_seg ;
# elif defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:23:37 +00:00
obj_rw - > ctype . ai_info . dying_sound_playing = obj - > ctype . ai_info . dying_sound_playing ;
2011-01-05 23:28:43 +00:00
if ( obj - > ctype . ai_info . dying_start_time = = 0 ) // if bot not dead, anything but 0 will kill it
obj_rw - > ctype . ai_info . dying_start_time = 0 ;
2010-12-22 00:17:59 +00:00
else
obj_rw - > ctype . ai_info . dying_start_time = obj - > ctype . ai_info . dying_start_time - GameTime64 ;
2013-03-03 01:03:33 +00:00
# endif
2010-12-22 00:17:59 +00:00
break ;
}
case CT_LIGHT :
obj_rw - > ctype . light_info . intensity = obj - > ctype . light_info . intensity ;
break ;
case CT_POWERUP :
obj_rw - > ctype . powerup_info . count = obj - > ctype . powerup_info . count ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2010-12-22 00:17:59 +00:00
if ( obj - > ctype . powerup_info . creation_time - GameTime64 < F1_0 * ( - 18000 ) )
obj_rw - > ctype . powerup_info . creation_time = F1_0 * ( - 18000 ) ;
else
obj_rw - > ctype . powerup_info . creation_time = obj - > ctype . powerup_info . creation_time - GameTime64 ;
obj_rw - > ctype . powerup_info . flags = obj - > ctype . powerup_info . flags ;
2013-03-03 01:03:33 +00:00
# endif
2010-12-22 00:17:59 +00:00
break ;
}
switch ( obj_rw - > render_type )
{
case RT_MORPH :
case RT_POLYOBJ :
case RT_NONE : // HACK below
{
int i ;
if ( obj - > render_type = = RT_NONE & & obj - > type ! = OBJ_GHOST ) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time.
break ;
obj_rw - > rtype . pobj_info . model_num = obj - > rtype . pobj_info . model_num ;
for ( i = 0 ; i < MAX_SUBMODELS ; i + + )
{
obj_rw - > rtype . pobj_info . anim_angles [ i ] . p = obj - > rtype . pobj_info . anim_angles [ i ] . p ;
obj_rw - > rtype . pobj_info . anim_angles [ i ] . b = obj - > rtype . pobj_info . anim_angles [ i ] . b ;
obj_rw - > rtype . pobj_info . anim_angles [ i ] . h = obj - > rtype . pobj_info . anim_angles [ i ] . h ;
}
obj_rw - > rtype . pobj_info . subobj_flags = obj - > rtype . pobj_info . subobj_flags ;
obj_rw - > rtype . pobj_info . tmap_override = obj - > rtype . pobj_info . tmap_override ;
obj_rw - > rtype . pobj_info . alt_textures = obj - > rtype . pobj_info . alt_textures ;
break ;
}
case RT_WEAPON_VCLIP :
case RT_HOSTAGE :
case RT_POWERUP :
case RT_FIREBALL :
obj_rw - > rtype . vclip_info . vclip_num = obj - > rtype . vclip_info . vclip_num ;
obj_rw - > rtype . vclip_info . frametime = obj - > rtype . vclip_info . frametime ;
obj_rw - > rtype . vclip_info . framenum = obj - > rtype . vclip_info . framenum ;
break ;
case RT_LASER :
break ;
}
}
// turn object_rw to object after receiving
void multi_object_rw_to_object ( object_rw * obj_rw , object * obj )
{
obj - > signature = obj_rw - > signature ;
obj - > type = obj_rw - > type ;
obj - > id = obj_rw - > id ;
obj - > next = obj_rw - > next ;
obj - > prev = obj_rw - > prev ;
obj - > control_type = obj_rw - > control_type ;
obj - > movement_type = obj_rw - > movement_type ;
obj - > render_type = obj_rw - > render_type ;
obj - > flags = obj_rw - > flags ;
obj - > segnum = obj_rw - > segnum ;
obj - > attached_obj = obj_rw - > attached_obj ;
obj - > pos . x = obj_rw - > pos . x ;
obj - > pos . y = obj_rw - > pos . y ;
obj - > pos . z = obj_rw - > pos . z ;
obj - > orient . rvec . x = obj_rw - > orient . rvec . x ;
obj - > orient . rvec . y = obj_rw - > orient . rvec . y ;
obj - > orient . rvec . z = obj_rw - > orient . rvec . z ;
obj - > orient . fvec . x = obj_rw - > orient . fvec . x ;
obj - > orient . fvec . y = obj_rw - > orient . fvec . y ;
obj - > orient . fvec . z = obj_rw - > orient . fvec . z ;
obj - > orient . uvec . x = obj_rw - > orient . uvec . x ;
obj - > orient . uvec . y = obj_rw - > orient . uvec . y ;
obj - > orient . uvec . z = obj_rw - > orient . uvec . z ;
obj - > size = obj_rw - > size ;
obj - > shields = obj_rw - > shields ;
obj - > last_pos . x = obj_rw - > last_pos . x ;
obj - > last_pos . y = obj_rw - > last_pos . y ;
obj - > last_pos . z = obj_rw - > last_pos . z ;
obj - > contains_type = obj_rw - > contains_type ;
obj - > contains_id = obj_rw - > contains_id ;
obj - > contains_count = obj_rw - > contains_count ;
obj - > matcen_creator = obj_rw - > matcen_creator ;
obj - > lifeleft = obj_rw - > lifeleft ;
switch ( obj - > movement_type )
{
case MT_PHYSICS :
obj - > mtype . phys_info . velocity . x = obj_rw - > mtype . phys_info . velocity . x ;
obj - > mtype . phys_info . velocity . y = obj_rw - > mtype . phys_info . velocity . y ;
obj - > mtype . phys_info . velocity . z = obj_rw - > mtype . phys_info . velocity . z ;
obj - > mtype . phys_info . thrust . x = obj_rw - > mtype . phys_info . thrust . x ;
obj - > mtype . phys_info . thrust . y = obj_rw - > mtype . phys_info . thrust . y ;
obj - > mtype . phys_info . thrust . z = obj_rw - > mtype . phys_info . thrust . z ;
obj - > mtype . phys_info . mass = obj_rw - > mtype . phys_info . mass ;
obj - > mtype . phys_info . drag = obj_rw - > mtype . phys_info . drag ;
obj - > mtype . phys_info . rotvel . x = obj_rw - > mtype . phys_info . rotvel . x ;
obj - > mtype . phys_info . rotvel . y = obj_rw - > mtype . phys_info . rotvel . y ;
obj - > mtype . phys_info . rotvel . z = obj_rw - > mtype . phys_info . rotvel . z ;
obj - > mtype . phys_info . rotthrust . x = obj_rw - > mtype . phys_info . rotthrust . x ;
obj - > mtype . phys_info . rotthrust . y = obj_rw - > mtype . phys_info . rotthrust . y ;
obj - > mtype . phys_info . rotthrust . z = obj_rw - > mtype . phys_info . rotthrust . z ;
obj - > mtype . phys_info . turnroll = obj_rw - > mtype . phys_info . turnroll ;
obj - > mtype . phys_info . flags = obj_rw - > mtype . phys_info . flags ;
break ;
case MT_SPINNING :
obj - > mtype . spin_rate . x = obj_rw - > mtype . spin_rate . x ;
obj - > mtype . spin_rate . y = obj_rw - > mtype . spin_rate . y ;
obj - > mtype . spin_rate . z = obj_rw - > mtype . spin_rate . z ;
break ;
}
switch ( obj - > control_type )
{
case CT_WEAPON :
obj - > ctype . laser_info . parent_type = obj_rw - > ctype . laser_info . parent_type ;
obj - > ctype . laser_info . parent_num = obj_rw - > ctype . laser_info . parent_num ;
obj - > ctype . laser_info . parent_signature = obj_rw - > ctype . laser_info . parent_signature ;
obj - > ctype . laser_info . creation_time = obj_rw - > ctype . laser_info . creation_time ;
obj - > ctype . laser_info . last_hitobj = obj_rw - > ctype . laser_info . last_hitobj ;
obj - > ctype . laser_info . track_goal = obj_rw - > ctype . laser_info . track_goal ;
obj - > ctype . laser_info . multiplier = obj_rw - > ctype . laser_info . multiplier ;
2013-08-07 22:29:56 +00:00
obj - > ctype . laser_info . track_turn_time = HOMING_TURN_TIME ;
2013-08-24 22:09:58 +00:00
# if defined(DXX_BUILD_DESCENT_II)
obj - > ctype . laser_info . last_afterburner_time = 0 ;
# endif
2010-12-22 00:17:59 +00:00
break ;
case CT_EXPLOSION :
obj - > ctype . expl_info . spawn_time = obj_rw - > ctype . expl_info . spawn_time ;
obj - > ctype . expl_info . delete_time = obj_rw - > ctype . expl_info . delete_time ;
obj - > ctype . expl_info . delete_objnum = obj_rw - > ctype . expl_info . delete_objnum ;
obj - > ctype . expl_info . attach_parent = obj_rw - > ctype . expl_info . attach_parent ;
obj - > ctype . expl_info . prev_attach = obj_rw - > ctype . expl_info . prev_attach ;
obj - > ctype . expl_info . next_attach = obj_rw - > ctype . expl_info . next_attach ;
break ;
case CT_AI :
{
int i ;
obj - > ctype . ai_info . behavior = obj_rw - > ctype . ai_info . behavior ;
for ( i = 0 ; i < MAX_AI_FLAGS ; i + + )
obj - > ctype . ai_info . flags [ i ] = obj_rw - > ctype . ai_info . flags [ i ] ;
obj - > ctype . ai_info . hide_segment = obj_rw - > ctype . ai_info . hide_segment ;
obj - > ctype . ai_info . hide_index = obj_rw - > ctype . ai_info . hide_index ;
obj - > ctype . ai_info . path_length = obj_rw - > ctype . ai_info . path_length ;
obj - > ctype . ai_info . cur_path_index = obj_rw - > ctype . ai_info . cur_path_index ;
obj - > ctype . ai_info . danger_laser_num = obj_rw - > ctype . ai_info . danger_laser_num ;
obj - > ctype . ai_info . danger_laser_signature = obj_rw - > ctype . ai_info . danger_laser_signature ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
obj - > ctype . ai_info . follow_path_start_seg = obj_rw - > ctype . ai_info . follow_path_start_seg ;
obj - > ctype . ai_info . follow_path_end_seg = obj_rw - > ctype . ai_info . follow_path_end_seg ;
# elif defined(DXX_BUILD_DESCENT_II)
2013-08-11 16:23:37 +00:00
obj - > ctype . ai_info . dying_sound_playing = obj_rw - > ctype . ai_info . dying_sound_playing ;
2010-12-22 00:17:59 +00:00
obj - > ctype . ai_info . dying_start_time = obj_rw - > ctype . ai_info . dying_start_time ;
2013-03-03 01:03:33 +00:00
# endif
2010-12-22 00:17:59 +00:00
break ;
}
case CT_LIGHT :
obj - > ctype . light_info . intensity = obj_rw - > ctype . light_info . intensity ;
break ;
case CT_POWERUP :
obj - > ctype . powerup_info . count = obj_rw - > ctype . powerup_info . count ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2010-12-22 00:17:59 +00:00
obj - > ctype . powerup_info . creation_time = obj_rw - > ctype . powerup_info . creation_time ;
obj - > ctype . powerup_info . flags = obj_rw - > ctype . powerup_info . flags ;
2013-03-03 01:03:33 +00:00
# endif
2010-12-22 00:17:59 +00:00
break ;
2013-08-03 10:54:03 +00:00
case CT_CNTRLCEN :
{
// gun points of reactor now part of the object but of course not saved in object_rw. Let's just recompute them.
int i = 0 ;
2013-10-07 23:52:33 +00:00
reactor * reactor = get_reactor_definition ( get_reactor_id ( obj ) ) ;
2013-08-03 10:54:03 +00:00
for ( i = 0 ; i < reactor - > n_guns ; i + + )
calc_controlcen_gun_point ( reactor , obj , i ) ;
break ;
}
2010-12-22 00:17:59 +00:00
}
switch ( obj - > render_type )
{
case RT_MORPH :
case RT_POLYOBJ :
case RT_NONE : // HACK below
{
int i ;
if ( obj - > render_type = = RT_NONE & & obj - > type ! = OBJ_GHOST ) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time.
break ;
obj - > rtype . pobj_info . model_num = obj_rw - > rtype . pobj_info . model_num ;
for ( i = 0 ; i < MAX_SUBMODELS ; i + + )
{
obj - > rtype . pobj_info . anim_angles [ i ] . p = obj_rw - > rtype . pobj_info . anim_angles [ i ] . p ;
obj - > rtype . pobj_info . anim_angles [ i ] . b = obj_rw - > rtype . pobj_info . anim_angles [ i ] . b ;
obj - > rtype . pobj_info . anim_angles [ i ] . h = obj_rw - > rtype . pobj_info . anim_angles [ i ] . h ;
}
obj - > rtype . pobj_info . subobj_flags = obj_rw - > rtype . pobj_info . subobj_flags ;
obj - > rtype . pobj_info . tmap_override = obj_rw - > rtype . pobj_info . tmap_override ;
obj - > rtype . pobj_info . alt_textures = obj_rw - > rtype . pobj_info . alt_textures ;
break ;
}
case RT_WEAPON_VCLIP :
case RT_HOSTAGE :
case RT_POWERUP :
case RT_FIREBALL :
obj - > rtype . vclip_info . vclip_num = obj_rw - > rtype . vclip_info . vclip_num ;
obj - > rtype . vclip_info . frametime = obj_rw - > rtype . vclip_info . frametime ;
obj - > rtype . vclip_info . framenum = obj_rw - > rtype . vclip_info . framenum ;
break ;
case RT_LASER :
break ;
}
}