2006-03-20 16:43:15 +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 - 1998 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
2007-07-18 21:36:53 +00:00
*
2007-12-29 14:18:49 +00:00
* Multiplayer code for network play .
2007-07-18 21:36:53 +00:00
*
2006-03-20 16:43:15 +00:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include "game.h"
# include "multi.h"
# include "object.h"
# include "laser.h"
# include "fuelcen.h"
# include "scores.h"
# include "gauges.h"
# include "collide.h"
# include "error.h"
# include "fireball.h"
# include "newmenu.h"
2008-04-06 20:23:28 +00:00
# include "console.h"
2006-03-20 16:43:15 +00:00
# include "wall.h"
# include "cntrlcen.h"
# include "powerup.h"
# 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 "newdemo.h"
# include "text.h"
# include "kmatrix.h"
# include "multibot.h"
# include "gameseq.h"
# include "physics.h"
# include "config.h"
# include "hudmsg.h"
# include "ctype.h" // for isalpha
# include "vers_id.h"
# include "byteswap.h"
2008-01-02 03:37:13 +00:00
# include "pstypes.h"
2006-03-20 16:43:15 +00:00
# include "strutil.h"
2009-03-20 12:10:38 +00:00
# include "u_mem.h"
2011-02-09 11:58:28 +00:00
# include "state.h"
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
# include "net_udp.h"
# endif
2006-03-20 16:43:15 +00:00
//
// Local macros and prototypes
//
// LOCALIZE ME!!
# define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0
void reset_player_object ( void ) ; // In object.c but not in object.h
2011-05-25 13:25:06 +00:00
void multi_reset_object_texture ( object * objp ) ;
2011-01-14 13:29:36 +00:00
void drop_player_eggs ( object * playerobj ) ; // from collide.c
2006-03-20 16:43:15 +00:00
void StartLevel ( void ) ; // From gameseq.c
2011-01-14 16:56:14 +00:00
void multi_do_heartbeat ( char * buf ) ;
void multi_send_heartbeat ( ) ;
void multi_do_kill_goal_counts ( char * buf ) ;
2011-01-14 13:29:36 +00:00
void multi_powcap_cap_objects ( ) ;
void multi_powcap_adjust_remote_cap ( int pnum ) ;
2011-01-19 01:19:15 +00:00
void multi_new_bounty_target ( int pnum ) ;
void multi_do_bounty ( char * buf ) ;
2011-02-09 11:58:28 +00:00
void multi_save_game ( ubyte slot , uint id , char * desc ) ;
void multi_restore_game ( ubyte slot , uint id ) ;
void multi_do_save_game ( char * buf ) ;
void multi_do_restore_game ( char * buf ) ;
2011-04-11 15:47:12 +00:00
void multi_do_msgsend_state ( char * buf ) ;
void multi_send_msgsend_state ( int state ) ;
2011-05-25 13:25:06 +00:00
void multi_send_gmode_update ( ) ;
void multi_do_gmode_update ( char * buf ) ;
2006-03-20 16:43:15 +00:00
//
// Global variables
//
2009-04-09 07:41:30 +00:00
int multi_protocol = 0 ; // set and determinate used protocol
2006-03-20 16:43:15 +00:00
int control_invul_time = 0 ;
int who_killed_controlcen = - 1 ; // -1 = noone
//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 ;
2012-04-12 00:15:23 +00:00
sbyte PKilledFlags [ MAX_NUM_NET_PLAYERS ] ;
2011-05-25 13:25:06 +00:00
int Bounty_target = 0 ;
2011-01-19 01:19:15 +00:00
2011-04-11 15:47:12 +00:00
int multi_sending_message [ MAX_NUM_NET_PLAYERS ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2006-03-20 16:43:15 +00:00
int multi_defining_message = 0 ;
int multi_message_index = 0 ;
unsigned char multibuf [ MAX_MULTI_MESSAGE_LEN + 4 ] ; // This is where multiplayer message are built
unsigned char multibuf2 [ MAX_MULTI_MESSAGE_LEN + 4 ] ;
short remote_to_local [ MAX_NUM_NET_PLAYERS ] [ MAX_OBJECTS ] ; // Remote object number for each local object
short local_to_remote [ MAX_OBJECTS ] ;
2006-10-06 14:41:31 +00:00
sbyte object_owner [ MAX_OBJECTS ] ; // Who created each object in my universe, -1 = loaded at start
2012-04-07 10:32:22 +00:00
int early_resp [ MAX_NUM_NET_PLAYERS ] ; // HACK in case we ger REAPPEAR packet before EXPLODE
2006-03-20 16:43:15 +00:00
int Net_create_objnums [ MAX_NET_CREATE_OBJECTS ] ; // For tracking object creation that will be sent to remote
int Net_create_loc = 0 ; // pointer into previous array
2009-03-20 12:10:38 +00:00
int Network_status = 0 ;
2006-03-20 16:43:15 +00:00
char Network_message [ MAX_MESSAGE_LEN ] ;
int Network_message_reciever = - 1 ;
int sorted_kills [ MAX_NUM_NET_PLAYERS ] ;
short kill_matrix [ MAX_NUM_NET_PLAYERS ] [ MAX_NUM_NET_PLAYERS ] ;
int multi_goto_secret = 0 ;
short team_kills [ 2 ] ;
int multi_quit_game = 0 ;
2011-01-19 18:55:32 +00:00
char * GMNames [ 8 ] = { " Anarchy " , " Team Anarchy " , " Robo Anarchy " , " Cooperative " , " Unknown " , " " , " " , " Bounty " } ;
char * GMNamesShrt [ 8 ] = { " ANRCHY " , " TEAM " , " ROBO " , " COOP " , " UNKNOWN " , " " , " " , " BOUNTY " } ;
2006-03-20 16:43:15 +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?
int Network_new_game = 0 ; // Is this the first level of a new game?
2011-01-14 13:29:36 +00:00
int Network_sending_extras = 0 ;
int VerifyPlayerJoined = - 1 ; // Player (num) to enter game before any ingame/extra stuff is being sent
int Player_joining_extras = - 1 ; // This is so we know who to send 'latecomer' packets to.
2009-11-24 09:48:53 +00:00
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 16:43:15 +00:00
netgame_info Netgame ;
bitmap_index multi_player_textures [ MAX_NUM_NET_PLAYERS ] [ N_PLAYER_SHIP_TEXTURES ] ;
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:03 +00:00
fix64 RefuseTimeLimit = 0 ;
2009-11-24 09:48:53 +00:00
2011-01-14 13:29:36 +00:00
char PowerupsInMine [ MAX_POWERUP_TYPES ] , MaxPowerupsAllowed [ MAX_POWERUP_TYPES ] ;
2011-01-14 16:56:14 +00:00
extern fix ThisLevelTime ;
2011-01-14 13:29:36 +00:00
2006-03-20 16:43:15 +00:00
int message_length [ MULTI_MAX_TYPE + 1 ] = {
2009-11-24 09:48:53 +00:00
25 , // POSITION
2012-04-07 10:32:22 +00:00
4 , // REAPPEAR
2006-03-20 16:43:15 +00:00
8 , // FIRE
5 , // KILL
4 , // REMOVE_OBJECT
57 , // PLAYER_EXPLODE
37 , // MESSAGE (MAX_MESSAGE_LENGTH = 40)
2 , // QUIT
4 , // PLAY_SOUND
37 , // BEGIN_SYNC
4 , // CONTROLCEN
5 , // CLAIM ROBOT
4 , // END_SYNC
2 , // CLOAK
3 , // ENDLEVEL_START
4 , // DOOR_OPEN
2 , // CREATE_EXPLOSION
16 , // CONTROLCEN_FIRE
57 , // PLAYER_DROP
19 , // CREATE_POWERUP
9 , // MISSILE_TRACK
2 , // DE-CLOAK
2 , // MENU_CHOICE
28 , // ROBOT_POSITION (shortpos_length (23) + 5 = 28)
8 , // ROBOT_EXPLODE
5 , // ROBOT_RELEASE
18 , // ROBOT_FIRE
6 , // SCORE
6 , // CREATE_ROBOT
3 , // TRIGGER
10 , // BOSS_ACTIONS
27 , // ROBOT_POWERUPS
7 , // HOSTAGE_DOOR
2011-02-09 11:58:28 +00:00
2 + 24 , //SAVE_GAME (ubyte slot, uint id, char name[20])
2 + 4 , //RESTORE_GAME (ubyte slot, uint id)
2010-12-22 00:17:49 +00:00
- 1 , // MULTI_REQ_PLAYER - NEVER USED
- 1 , // MULTI_SEND_PLAYER - NEVER USED
2011-01-14 13:29:36 +00:00
MAX_POWERUP_TYPES + 1 , // MULTI_POWCAP_UPDATE
2011-01-14 16:56:14 +00:00
5 , // MULTI_HEARTBEAT
9 , // MULTI_KILLGOALS
2011-05-25 13:25:06 +00:00
2 , // MULTI_DO_BOUNTY
2011-04-11 15:47:12 +00:00
3 , // MULTI_TYPING_STATE
2011-05-25 13:25:06 +00:00
3 , // MULTI_GMODE_UPDATE
7 , // MULTI_KILL_HOST
5 , // MULTI_KILL_CLIENT
2006-03-20 16:43:15 +00:00
} ;
void multi_reset_player_object ( object * objp ) ;
void multi_set_robot_ai ( void ) ;
2009-07-01 11:35:33 +00:00
void multi_add_lifetime_killed ( ) ;
void multi_add_lifetime_kills ( ) ;
2006-03-20 16:43:15 +00:00
2009-03-20 12:10:38 +00:00
int multi_allow_powerup_mask [ MAX_POWERUP_TYPES ] =
{ NETFLAG_DOINVUL , 0 , 0 , NETFLAG_DOLASER , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , NETFLAG_DOQUAD ,
NETFLAG_DOVULCAN , NETFLAG_DOSPREAD , NETFLAG_DOPLASMA , NETFLAG_DOFUSION ,
NETFLAG_DOPROXIM , NETFLAG_DOHOMING , NETFLAG_DOHOMING , NETFLAG_DOSMART ,
NETFLAG_DOMEGA , NETFLAG_DOVULCAN , NETFLAG_DOCLOAK , 0 , NETFLAG_DOINVUL , 0 , 0 , 0 } ;
char * multi_allow_powerup_text [ MULTI_ALLOW_POWERUP_MAX ] =
{ " Laser upgrade " , " Quad lasers " , " Vulcan cannon " , " Spreadfire cannon " , " Plasma cannon " ,
" Fusion cannon " , " Homing missiles " , " Smart missiles " , " Mega missiles " , " Proximity bombs " ,
" Cloaking " , " Invulnerability " } ;
2006-03-20 16:43:15 +00:00
//
// Functions that replace what used to be macros
//
int objnum_remote_to_local ( int remote_objnum , int owner )
{
// Map a remote object number from owner to a local object number
int result ;
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 ) )
return ( - 1 ) ;
result = remote_to_local [ owner ] [ remote_objnum ] ;
if ( result < 0 )
{
return ( - 1 ) ;
}
return ( result ) ;
}
2006-10-06 14:41:31 +00:00
int objnum_local_to_remote ( int local_objnum , sbyte * owner )
2006-03-20 16:43:15 +00:00
{
// Map a local object number to a remote + owner
int result ;
if ( ( local_objnum < 0 ) | | ( local_objnum > Highest_object_index ) ) {
* owner = - 1 ;
return ( - 1 ) ;
}
* owner = object_owner [ local_objnum ] ;
if ( * owner = = - 1 )
return ( local_objnum ) ;
if ( ( * owner > = N_players ) | | ( * owner < - 1 ) ) {
Int3 ( ) ; // Illegal!
* owner = - 1 ;
return local_objnum ;
}
result = local_to_remote [ local_objnum ] ;
if ( result < 0 )
{
Int3 ( ) ; // See Rob, object has no remote number!
}
return ( result ) ;
}
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 ( remote_objnum > - 1 ) ;
Assert ( owner > - 1 ) ;
Assert ( owner ! = Player_num ) ;
Assert ( local_objnum < MAX_OBJECTS ) ;
Assert ( remote_objnum < MAX_OBJECTS ) ;
object_owner [ local_objnum ] = owner ;
remote_to_local [ owner ] [ remote_objnum ] = local_objnum ;
local_to_remote [ local_objnum ] = remote_objnum ;
return ;
}
void
map_objnum_local_to_local ( int local_objnum )
{
// 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 ;
}
2009-04-09 07:41:30 +00:00
int multi_objnum_is_past ( int objnum )
{
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 16:43:15 +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 16:43:15 +00:00
// on the curretn Game_mode value.
//
void
multi_endlevel_score ( void )
{
2010-07-04 13:12:08 +00:00
int i , old_connect = 0 ;
2009-02-08 12:49:27 +00:00
2006-03-20 16:43:15 +00:00
// Show a score list to end of net players
2009-02-08 12:49:27 +00:00
// Save connect state and change to new connect state
2006-03-20 16:43:15 +00:00
# ifdef NETWORK
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 )
Players [ Player_num ] . connected = CONNECT_END_MENU ;
2006-03-20 16:43:15 +00:00
}
# endif
# ifdef NETWORK
Network_status = NETSTAT_ENDLEVEL ;
# endif
2011-09-13 23:15:20 +00:00
kmatrix_view ( Game_mode & GM_NETWORK ) ;
2006-03-20 16:43:15 +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 16:43:15 +00:00
if ( Game_mode & GM_MULTI_COOP )
{
for ( i = 0 ; i < MaxNumNetPlayers ; i + + )
// Reset keys
Players [ i ] . flags & = ~ ( PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY ) ;
}
2011-01-14 13:29:36 +00:00
2011-01-14 16:56:14 +00:00
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
Players [ i ] . KillGoalCount = 0 ;
2011-01-14 13:29:36 +00:00
for ( i = 0 ; i < MAX_POWERUP_TYPES ; i + + )
{
MaxPowerupsAllowed [ i ] = 0 ;
PowerupsInMine [ i ] = 0 ;
}
2006-03-20 16:43:15 +00:00
}
int
get_team ( int pnum )
{
if ( Netgame . team_vector & ( 1 < < pnum ) )
return 1 ;
else
return 0 ;
}
void
multi_new_game ( void )
{
2012-04-15 01:05:25 +00:00
int i , save_pnum = Player_num ;
2006-03-20 16:43:15 +00:00
// Reset variables for a new net game
2012-04-15 01:05:25 +00:00
for ( Player_num = 0 ; Player_num < MAX_NUM_NET_PLAYERS ; Player_num + + )
init_player_stats_game ( ) ;
Player_num = save_pnum ;
2006-03-20 16:43:15 +00:00
memset ( kill_matrix , 0 , sizeof ( kill_matrix ) ) ; // Clear kill matrix
for ( i = 0 ; i < MAX_NUM_NET_PLAYERS ; i + + )
{
sorted_kills [ i ] = i ;
2010-11-28 00:02:04 +00:00
Players [ i ] . connected = CONNECT_DISCONNECTED ;
2006-03-20 16:43:15 +00:00
Players [ i ] . net_killed_total = 0 ;
Players [ i ] . net_kills_total = 0 ;
Players [ i ] . flags = 0 ;
2011-01-14 16:56:14 +00:00
Players [ i ] . KillGoalCount = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ i ] = 0 ;
2006-03-20 16:43:15 +00:00
}
for ( i = 0 ; i < MAX_ROBOTS_CONTROLLED ; i + + )
{
2012-04-15 01:05:25 +00:00
robot_controlled [ i ] = - 1 ;
2006-03-20 16:43:15 +00:00
robot_agitation [ i ] = 0 ;
robot_fired [ i ] = 0 ;
}
2012-04-15 01:05:25 +00:00
for ( i = 0 ; i < MAX_POWERUP_TYPES ; i + + )
{
MaxPowerupsAllowed [ i ] = 0 ;
PowerupsInMine [ i ] = 0 ;
}
2006-03-20 16:43:15 +00:00
team_kills [ 0 ] = team_kills [ 1 ] = 0 ;
Endlevel_sequence = 0 ;
2012-04-15 01:05:25 +00:00
Control_center_destroyed = 0 ;
2006-03-20 16:43:15 +00:00
Player_is_dead = 0 ;
multi_quit_game = 0 ;
Show_kill_list = 1 ;
game_disable_cheats ( ) ;
Player_exploded = 0 ;
Dead_player_camera = 0 ;
2012-04-15 01:05:25 +00:00
Network_new_game = 1 ;
2006-03-20 16:43:15 +00:00
}
2012-04-15 01:05:25 +00:00
2006-03-20 16:43:15 +00:00
void
multi_make_player_ghost ( int playernum )
{
object * obj ;
// Assert(playernum != Player_num);
// Assert(playernum < MAX_NUM_NET_PLAYERS);
if ( ( playernum = = Player_num ) | | ( playernum > = MAX_NUM_NET_PLAYERS ) | | ( playernum < 0 ) )
{
Int3 ( ) ; // Non-terminal, see Rob
return ;
}
obj = & Objects [ Players [ playernum ] . objnum ] ;
obj - > type = OBJ_GHOST ;
obj - > render_type = RT_NONE ;
obj - > movement_type = MT_NONE ;
multi_reset_player_object ( obj ) ;
if ( Game_mode & GM_MULTI_ROBOTS )
multi_strip_robots ( playernum ) ;
}
void
multi_make_ghost_player ( int playernum )
{
object * obj ;
// Assert(playernum != Player_num);
// Assert(playernum < MAX_NUM_NET_PLAYERS);
if ( ( playernum = = Player_num ) | | ( playernum > = MAX_NUM_NET_PLAYERS ) )
{
Int3 ( ) ; // Non-terminal, see rob
return ;
}
obj = & Objects [ Players [ playernum ] . objnum ] ;
obj - > type = OBJ_PLAYER ;
obj - > movement_type = MT_PHYSICS ;
multi_reset_player_object ( obj ) ;
}
int multi_get_kill_list ( int * plist )
{
// 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
int kills [ MAX_NUM_NET_PLAYERS ] ;
int i ;
int changed = 1 ;
for ( i = 0 ; i < MAX_NUM_NET_PLAYERS ; i + + )
{
if ( Game_mode & GM_MULTI_COOP )
kills [ i ] = Players [ i ] . score ;
else
kills [ i ] = Players [ i ] . net_kills_total ;
}
while ( changed )
{
changed = 0 ;
for ( i = 0 ; i < N_players - 1 ; i + + )
{
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 ;
}
}
}
}
2011-01-14 16:56:14 +00:00
extern object * obj_find_first_of_type ( int ) ;
2006-03-20 16:43:15 +00:00
void multi_compute_kill ( int killer , int killed )
{
// Figure out the results of a network kills and add it to the
// appropriate player's tally.
int killed_pnum , killed_type ;
int killer_pnum , killer_type ;
2011-01-14 16:56:14 +00:00
int TheGoal ;
2006-03-20 16:43:15 +00:00
char killed_name [ ( CALLSIGN_LEN * 2 ) + 4 ] ;
char killer_name [ ( CALLSIGN_LEN * 2 ) + 4 ] ;
// 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 ;
if ( ( killed_type ! = OBJ_PLAYER ) & & ( killed_type ! = OBJ_GHOST ) )
{
Int3 ( ) ; // compute_kill passed non-player object!
return ;
}
killed_pnum = Objects [ killed ] . id ;
Assert ( ( killed_pnum > = 0 ) & & ( killed_pnum < N_players ) ) ;
if ( Game_mode & GM_TEAM )
sprintf ( killed_name , " %s (%s) " , Players [ killed_pnum ] . callsign , Netgame . team_name [ get_team ( killed_pnum ) ] ) ;
else
sprintf ( killed_name , " %s " , Players [ killed_pnum ] . callsign ) ;
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_death ( killed_pnum ) ;
digi_play_sample ( SOUND_HUD_KILL , F3_0 ) ;
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 )
2009-07-01 11:35:33 +00:00
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s. " , TXT_YOU_WERE , TXT_KILLED_BY_NONPLAY ) ;
2009-07-01 11:35:33 +00:00
multi_add_lifetime_killed ( ) ;
}
2006-03-20 16:43:15 +00:00
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 ) ;
2007-09-05 17:31:05 +00:00
return ;
2006-03-20 16:43:15 +00:00
}
else if ( ( killer_type ! = OBJ_PLAYER ) & & ( killer_type ! = OBJ_GHOST ) )
{
if ( killed_pnum = = Player_num )
2009-07-01 11:35:33 +00:00
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s. " , TXT_YOU_WERE , TXT_KILLED_BY_ROBOT ) ;
2009-07-01 11:35:33 +00:00
multi_add_lifetime_killed ( ) ;
}
2006-03-20 16:43:15 +00:00
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 16:43:15 +00:00
Players [ killed_pnum ] . net_killed_total + + ;
return ;
}
killer_pnum = Objects [ killer ] . id ;
if ( Game_mode & GM_TEAM )
sprintf ( killer_name , " %s (%s) " , Players [ killer_pnum ] . callsign , Netgame . team_name [ get_team ( killer_pnum ) ] ) ;
else
sprintf ( killer_name , " %s " , Players [ killer_pnum ] . callsign ) ;
// Beyond this point, it was definitely a player-player kill situation
if ( ( killer_pnum < 0 ) | | ( killer_pnum > = N_players ) )
Int3 ( ) ; // See rob, tracking down bug with kill HUD messages
if ( ( killed_pnum < 0 ) | | ( killed_pnum > = N_players ) )
Int3 ( ) ; // See rob, tracking down bug with kill HUD messages
if ( killer_pnum = = killed_pnum )
{
if ( Game_mode & GM_TEAM )
{
team_kills [ get_team ( killed_pnum ) ] - = 1 ;
}
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 )
2009-07-01 11:35:33 +00:00
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s! " , TXT_YOU , TXT_KILLED , TXT_YOURSELF ) ;
2009-07-01 11:35:33 +00:00
multi_add_lifetime_killed ( ) ;
}
2006-03-20 16:43:15 +00:00
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , killed_name , TXT_SUICIDE ) ;
2011-01-19 01:19:15 +00:00
/* Bounty mode needs some lovin' */
2011-05-25 13:25:06 +00:00
if ( Game_mode & GM_BOUNTY & & killed_pnum = = Bounty_target & & multi_i_am_master ( ) )
2011-01-19 01:19:15 +00:00
{
2011-05-25 13:25:06 +00:00
/* Select a random number */
int new = d_rand ( ) % MAX_NUM_NET_PLAYERS ;
/* Make sure they're valid: Don't check against kill flags,
* just in case everyone ' s dead ! */
while ( ! Players [ new ] . connected )
new = d_rand ( ) % MAX_NUM_NET_PLAYERS ;
/* Select new target - it will be sent later when we're done with this function */
multi_new_bounty_target ( new ) ;
2011-01-19 01:19:15 +00:00
}
2006-03-20 16:43:15 +00:00
}
else
{
if ( Game_mode & GM_TEAM )
{
if ( get_team ( killed_pnum ) = = get_team ( killer_pnum ) )
team_kills [ get_team ( killed_pnum ) ] - = 1 ;
else
team_kills [ get_team ( killer_pnum ) ] + = 1 ;
}
2011-01-19 01:19:15 +00:00
if ( Game_mode & GM_BOUNTY )
{
/* 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 16:43:15 +00:00
newdemo_record_multi_kill ( killer_pnum , 1 ) ;
Players [ killed_pnum ] . net_killed_total + = 1 ;
kill_matrix [ killer_pnum ] [ killed_pnum ] + = 1 ;
2007-09-05 17:31:05 +00:00
2006-03-20 16:43:15 +00:00
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 ) ;
2009-07-01 11:35:33 +00:00
multi_add_lifetime_kills ( ) ;
2006-03-20 16:43:15 +00:00
if ( ( Game_mode & GM_MULTI_COOP ) & & ( Players [ Player_num ] . score > = 1000 ) )
add_points_to_score ( - 1000 ) ;
}
else if ( killed_pnum = = Player_num )
2009-07-01 11:35:33 +00:00
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s %s! " , killer_name , TXT_KILLED , TXT_YOU ) ;
2009-07-01 11:35:33 +00:00
multi_add_lifetime_killed ( ) ;
}
2006-03-20 16:43:15 +00:00
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 16:43:15 +00:00
}
2011-01-14 16:56:14 +00:00
TheGoal = Netgame . KillGoal * 5 ;
if ( Netgame . KillGoal > 0 )
{
if ( Players [ killer_pnum ] . KillGoalCount > = TheGoal )
{
if ( killer_pnum = = Player_num )
{
HUD_init_message ( HM_MULTI , " You reached the kill goal! " ) ;
Players [ Player_num ] . shields = i2f ( 200 ) ;
}
else
HUD_init_message ( HM_MULTI , " %s has reached the kill goal! " , Players [ killer_pnum ] . callsign ) ;
HUD_init_message ( HM_MULTI , " The control center has been destroyed! " ) ;
net_destroy_controlcen ( obj_find_first_of_type ( OBJ_CNTRLCEN ) ) ;
}
}
2006-03-20 16:43:15 +00:00
multi_sort_kill_list ( ) ;
multi_show_player_list ( ) ;
}
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
}
2006-03-20 16:43:15 +00:00
void multi_do_frame ( void )
{
2011-01-14 16:56:14 +00:00
static int lasttime = 0 ;
2011-05-25 13:25:06 +00:00
static fix64 last_update_time = 0 ;
2011-01-14 16:56:14 +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 16:43:15 +00:00
{
Int3 ( ) ;
return ;
}
2011-01-14 16:56:14 +00:00
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:06 +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 16:43:15 +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 ) ;
2008-10-23 09:17:54 +00:00
2010-01-29 03:36:44 +00:00
if ( multi_quit_game )
2008-10-23 09:17:54 +00:00
{
multi_quit_game = 0 ;
2010-01-27 04:30:31 +00:00
if ( Game_wind )
window_close ( Game_wind ) ;
2008-10-23 09:17:54 +00:00
}
2006-03-20 16:43:15 +00:00
}
2007-10-31 00:49:24 +00:00
2006-03-20 16:43:15 +00:00
void
2009-11-24 09:48:53 +00:00
multi_send_data ( unsigned char * buf , int len , int priority )
2006-03-20 16:43:15 +00:00
{
2012-04-15 01:05:25 +00:00
if ( len ! = message_length [ ( int ) buf [ 0 ] ] )
Error ( " multi_send_data: Packet type %i length: %i, expected: %i \n " , buf [ 0 ] , len , message_length [ ( int ) buf [ 0 ] ] ) ;
if ( buf [ 0 ] < 0 | | buf [ 0 ] > MULTI_MAX_TYPE )
Error ( " multi_send_data: Illegal packet type %i \n " , buf [ 0 ] ) ;
2006-03-20 16:43:15 +00:00
2007-06-11 09:06:14 +00:00
if ( Game_mode & GM_NETWORK )
2006-03-20 16:43:15 +00:00
{
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_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:06 +00:00
Error ( " Protocol handling missing in multi_send_data \n " ) ;
2009-04-09 07:41:30 +00:00
break ;
}
2006-03-20 16:43:15 +00:00
}
}
2011-05-25 13:25:06 +00:00
void multi_send_data_direct ( unsigned char * buf , int len , int pnum , int priority )
{
2012-04-15 01:05:25 +00:00
if ( len ! = message_length [ ( int ) buf [ 0 ] ] )
Error ( " multi_send_data_direct: Packet type %i length: %i, expected: %i \n " , buf [ 0 ] , len , message_length [ ( int ) buf [ 0 ] ] ) ;
if ( buf [ 0 ] < 0 | | buf [ 0 ] > MULTI_MAX_TYPE )
Error ( " multi_send_data_direct: Illegal packet type %i \n " , buf [ 0 ] ) ;
if ( pnum < 0 & & pnum > MAX_NUM_NET_PLAYERS )
Error ( " multi_send_data_direct: Illegal player num: %i \n " , pnum ) ;
2011-05-25 13:25:06 +00:00
switch ( multi_protocol )
{
# ifdef USE_UDP
case MULTI_PROTO_UDP :
net_udp_send_mdata_direct ( ( ubyte * ) multibuf , len , pnum , priority ) ;
break ;
# endif
default :
Error ( " Protocol handling missing in multi_send_data_direct \n " ) ;
break ;
}
}
2006-03-20 16:43:15 +00:00
void
multi_leave_game ( void )
{
if ( ! ( Game_mode & GM_MULTI ) )
return ;
if ( Game_mode & GM_NETWORK )
{
Net_create_loc = 0 ;
multi_send_position ( Players [ Player_num ] . objnum ) ;
2011-01-14 13:29:36 +00:00
multi_powcap_cap_objects ( ) ;
2011-01-14 14:12:39 +00:00
if ( ! Player_eggs_dropped )
{
drop_player_eggs ( ConsoleObject ) ;
Player_eggs_dropped = 1 ;
}
2006-03-20 16:43:15 +00:00
multi_send_player_explode ( MULTI_PLAYER_DROP ) ;
}
multi_send_quit ( MULTI_QUIT ) ;
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 ;
}
}
2006-03-20 16:43:15 +00:00
2009-04-09 07:41:30 +00:00
plyr_save_stats ( ) ;
2006-03-20 16:43:15 +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 16:43:15 +00:00
return ( result ) ;
}
2010-01-07 14:49:07 +00:00
int multi_endlevel_poll1 ( newmenu * menu , d_event * event , void * userdata )
2009-11-24 09:48:53 +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-11-24 09:48:53 +00:00
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-11-24 09:48:53 +00:00
default :
Error ( " Protocol handling missing in multi_endlevel_poll1 \n " ) ;
break ;
}
2010-01-07 14:49:07 +00:00
return 0 ; // kill warning
2009-11-24 09:48:53 +00:00
}
2010-01-07 14:49:07 +00:00
int multi_endlevel_poll2 ( newmenu * menu , d_event * event , void * 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 :
Error ( " Protocol handling missing in multi_endlevel_poll2 \n " ) ;
break ;
}
2010-01-07 14:49:07 +00:00
return 0 ;
2009-04-09 07:41:30 +00:00
}
2009-11-24 09:48:53 +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 ( ) ;
break ;
2009-11-29 16:46:13 +00:00
# endif
2009-11-24 09:48:53 +00:00
default :
Error ( " Protocol handling missing in multi_send_endlevel_packet \n " ) ;
break ;
}
}
2006-03-20 16:43:15 +00:00
//
2007-12-29 14:18:49 +00:00
// Part 2 : functions that act on network messages and change the
2006-03-20 16:43:15 +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 ) ;
2010-01-29 03:36:44 +00:00
switch ( key )
2006-03-20 16:43:15 +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 ( ) ;
}
2010-01-29 03:36:44 +00:00
if ( multi_defining_message ) {
2011-02-02 00:36:43 +00:00
key_toggle_repeat ( 1 ) ;
2006-03-20 16:43:15 +00:00
multi_message_index = 0 ;
Network_message [ multi_message_index ] = 0 ;
}
}
char feedback_result [ 200 ] ;
void
multi_message_feedback ( void )
{
char * colon ;
int found = 0 ;
int i ;
2011-04-11 15:47:12 +00:00
if ( ! ( ( ( colon = strstr ( Network_message , " : " ) ) = = NULL ) | | ( colon - Network_message < 1 ) | | ( colon - Network_message > CALLSIGN_LEN ) ) )
2006-03-20 16:43:15 +00:00
{
sprintf ( feedback_result , " %s " , TXT_MESSAGE_SENT_TO ) ;
if ( ( Game_mode & GM_TEAM ) & & ( atoi ( Network_message ) > 0 ) & & ( atoi ( Network_message ) < 3 ) )
{
sprintf ( feedback_result + strlen ( feedback_result ) , " %s '%s' " , TXT_TEAM , Netgame . team_name [ atoi ( Network_message ) - 1 ] ) ;
found = 1 ;
}
if ( Game_mode & GM_TEAM )
{
for ( i = 0 ; i < N_players ; i + + )
{
if ( ! strncasecmp ( Netgame . team_name [ i ] , Network_message , colon - Network_message ) )
{
if ( found )
strcat ( feedback_result , " , " ) ;
found + + ;
if ( ! ( found % 4 ) )
strcat ( feedback_result , " \n " ) ;
sprintf ( feedback_result + strlen ( feedback_result ) , " %s '%s' " , TXT_TEAM , Netgame . team_name [ i ] ) ;
}
}
}
for ( i = 0 ; i < N_players ; i + + )
{
if ( ( ! strncasecmp ( Players [ i ] . callsign , Network_message , colon - Network_message ) ) & & ( i ! = Player_num ) & & ( Players [ i ] . connected ) )
{
if ( found )
strcat ( feedback_result , " , " ) ;
found + + ;
if ( ! ( found % 4 ) )
strcat ( feedback_result , " \n " ) ;
sprintf ( feedback_result + strlen ( feedback_result ) , " %s " , Players [ i ] . callsign ) ;
}
}
if ( ! found )
strcat ( feedback_result , TXT_NOBODY ) ;
else
strcat ( feedback_result , " . " ) ;
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
Assert ( strlen ( feedback_result ) < 200 ) ;
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , feedback_result ) ;
2006-03-20 16:43:15 +00:00
}
}
//added/moved on 11/10/98 by Victor Rachels to declare before this function
void multi_send_message_end ( ) ;
//end this section change - VR
void
multi_send_macro ( int key )
{
if ( ! ( Game_mode & GM_MULTI ) )
return ;
switch ( key )
{
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 ( ) ;
}
2008-04-13 00:28:36 +00:00
if ( ! PlayerCfg . NetworkMessageMacro [ key ] [ 0 ] )
2006-03-20 16:43:15 +00:00
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , TXT_NO_MACRO ) ;
2006-03-20 16:43:15 +00:00
return ;
}
2008-10-31 16:57:36 +00:00
strcpy ( Network_message , PlayerCfg . NetworkMessageMacro [ key ] ) ;
Network_message_reciever = 100 ;
2006-03-20 16:43:15 +00:00
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s '%s' " , TXT_SENDING , Network_message ) ;
2008-10-31 16:57:36 +00:00
multi_message_feedback ( ) ;
2006-03-20 16:43:15 +00:00
}
void
multi_send_message_start ( )
{
if ( Game_mode & GM_MULTI ) {
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 1 ;
multi_send_msgsend_state ( 1 ) ;
2006-03-20 16:43:15 +00:00
multi_message_index = 0 ;
Network_message [ multi_message_index ] = 0 ;
2011-02-02 00:36:43 +00:00
key_toggle_repeat ( 1 ) ;
2006-03-20 16:43:15 +00:00
}
}
// compare s1 with s2 ignoring case and only considering the
// first strlen(s2) characters of s1
int strcasecmpbegin ( const char * s1 , const char * s2 )
{
return strncasecmp ( s1 , s2 , strlen ( s2 ) ) ;
}
2007-10-31 00:49:24 +00:00
void multi_send_message_end ( )
2006-03-20 16:43:15 +00:00
{
2011-05-25 13:25:06 +00:00
int i , t ;
2006-03-20 16:43:15 +00:00
2007-10-31 00:49:24 +00:00
multi_message_index = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
multi_send_msgsend_state ( 0 ) ;
2011-02-02 00:36:43 +00:00
key_toggle_repeat ( 0 ) ;
2006-03-20 16:43:15 +00:00
2011-05-25 13:25:06 +00:00
if ( ! strnicmp ( Network_message , " /move: " , 7 ) )
{
if ( ( Game_mode & GM_NETWORK ) & & ( Game_mode & GM_TEAM ) )
{
int name_index = 7 ;
if ( strlen ( Network_message ) > 7 )
while ( Network_message [ name_index ] = = ' ' )
name_index + + ;
if ( ! multi_i_am_master ( ) )
{
HUD_init_message ( HM_MULTI , " Only %s can move players! " , Players [ multi_who_is_master ( ) ] . callsign ) ;
return ;
}
if ( strlen ( Network_message ) < = name_index )
{
HUD_init_message ( HM_MULTI , " You must specify a name to move " ) ;
return ;
}
for ( i = 0 ; i < N_players ; i + + )
if ( ( ! strnicmp ( Players [ i ] . callsign , & Network_message [ name_index ] , strlen ( Network_message ) - name_index ) ) & & ( Players [ i ] . connected ) )
{
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 ] ) ;
reset_cockpit ( ) ;
multi_send_gmode_update ( ) ;
sprintf ( Network_message , " %s has changed teams! " , Players [ i ] . callsign ) ;
if ( i = = Player_num )
{
HUD_init_message ( HM_MULTI , " You have changed teams! " ) ;
reset_cockpit ( ) ;
}
else
HUD_init_message ( HM_MULTI , " Moving %s to other team. " , Players [ i ] . callsign ) ;
break ;
}
}
}
else if ( ! strnicmp ( Network_message , " /kick: " , 7 ) & & ( Game_mode & GM_NETWORK ) )
2007-10-31 00:49:24 +00:00
{
2011-04-11 15:47:12 +00:00
int name_index = 7 ;
if ( strlen ( Network_message ) > 7 )
2007-10-31 00:49:24 +00:00
while ( Network_message [ name_index ] = = ' ' )
name_index + + ;
2006-03-20 16:43:15 +00:00
2009-04-09 07:41:30 +00:00
if ( ! multi_i_am_master ( ) )
2007-10-31 00:49:24 +00:00
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " Only %s can kick others out! " , Players [ multi_who_is_master ( ) ] . callsign ) ;
2007-10-31 00:49:24 +00:00
multi_message_index = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
2007-10-31 00:49:24 +00:00
return ;
}
if ( strlen ( Network_message ) < = name_index )
{
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " You must specify a name to kick " ) ;
2007-10-31 00:49:24 +00:00
multi_message_index = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
2007-10-31 00:49:24 +00:00
return ;
}
2006-03-20 16:43:15 +00:00
2007-10-31 00:49:24 +00:00
if ( Network_message [ name_index ] = = ' # ' & & isdigit ( Network_message [ name_index + 1 ] ) ) {
int players [ MAX_NUM_NET_PLAYERS ] ;
int listpos = Network_message [ name_index + 1 ] - ' 0 ' ;
if ( Show_kill_list = = 1 | | Show_kill_list = = 2 ) {
if ( listpos = = 0 | | listpos > = N_players ) {
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " Invalid player number for kick. " ) ;
2007-10-31 00:49:24 +00:00
multi_message_index = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
2007-10-31 00:49:24 +00:00
return ;
}
multi_get_kill_list ( players ) ;
i = players [ listpos ] ;
if ( ( i ! = Player_num ) & & ( Players [ i ] . connected ) )
goto kick_player ;
}
2010-07-13 06:35:25 +00:00
else HUD_init_message ( HM_MULTI , " You cannot use # kicking with in team display. " ) ;
2006-03-20 16:43:15 +00:00
2007-10-31 00:49:24 +00:00
multi_message_index = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
2007-10-31 00:49:24 +00:00
return ;
}
for ( i = 0 ; i < N_players ; i + + )
if ( ( ! strnicmp ( Players [ i ] . callsign , & Network_message [ name_index ] , strlen ( Network_message ) - name_index ) ) & & ( i ! = Player_num ) & & ( Players [ i ] . connected ) ) {
kick_player : ;
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_dump_player ( Netgame . players [ i ] . protocol . udp . addr , DUMP_KICKED ) ;
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 :
Error ( " Protocol handling missing in multi_send_message_end \n " ) ;
break ;
}
2007-10-31 00:49:24 +00:00
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " Dumping %s... " , Players [ i ] . callsign ) ;
2007-10-31 00:49:24 +00:00
multi_message_index = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
2007-10-31 00:49:24 +00:00
return ;
}
}
2008-12-12 15:53:13 +00:00
2011-04-11 15:47:12 +00:00
else if ( ! 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 ( ) )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " Only %s can kill the reactor this way! " , Players [ multi_who_is_master ( ) ] . callsign ) ;
2008-12-12 15:53:13 +00:00
else
{
net_destroy_controlcen ( NULL ) ;
multi_send_destroy_controlcen ( - 1 , Player_num ) ;
}
2008-12-12 15:57:00 +00:00
multi_message_index = 0 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
2008-12-12 15:57:00 +00:00
return ;
2008-12-12 15:53:13 +00:00
}
2006-03-20 16:43:15 +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 16:43:15 +00:00
multi_send_message ( ) ;
multi_message_feedback ( ) ;
2008-05-07 14:11:30 +00:00
game_flush_inputs ( ) ;
2006-03-20 16:43:15 +00:00
}
void multi_define_macro_end ( )
{
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 16:43:15 +00:00
write_player_file ( ) ;
multi_message_index = 0 ;
multi_defining_message = 0 ;
2011-02-02 00:36:43 +00:00
key_toggle_repeat ( 0 ) ;
2008-05-07 14:11:30 +00:00
game_flush_inputs ( ) ;
2006-03-20 16:43:15 +00:00
}
2010-03-31 09:18:28 +00:00
int multi_message_input_sub ( int key )
2006-03-20 16:43:15 +00:00
{
2008-05-07 14:02:01 +00:00
switch ( key )
{
case KEY_F8 :
case KEY_ESC :
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 0 ;
multi_send_msgsend_state ( 0 ) ;
2008-05-07 14:02:01 +00:00
multi_defining_message = 0 ;
2011-02-02 00:36:43 +00:00
key_toggle_repeat ( 0 ) ;
2008-05-07 14:02:01 +00:00
game_flush_inputs ( ) ;
2010-03-31 09:18:28 +00:00
return 1 ;
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 ;
2010-03-31 09:18:28 +00:00
return 1 ;
2008-05-07 14:02:01 +00:00
case KEY_ENTER :
2011-04-11 15:47:12 +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 ( ) ;
2010-03-31 09:18:28 +00:00
return 1 ;
2008-05-07 14:02:01 +00:00
default :
2008-11-17 23:38:43 +00:00
{
int ascii = key_ascii ( ) ;
2007-04-15 16:33:04 +00:00
if ( ( ascii < 255 ) & & ( ascii ! = 37 ) ) {
2006-03-20 16:43:15 +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:12 +00:00
} else if ( multi_sending_message [ Player_num ] ) {
2006-03-20 16:43:15 +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 ) {
2011-04-11 15:47:12 +00:00
multi_sending_message [ Player_num ] = 1 ;
multi_send_msgsend_state ( 1 ) ;
2006-03-20 16:43:15 +00:00
pcolon = strchr ( Network_message , ' : ' ) ;
if ( pcolon )
strcpy ( pcolon + 1 , ptext ) ;
else
strcpy ( Network_message , ptext ) ;
multi_message_index = strlen ( Network_message ) ;
}
}
}
}
}
2010-03-31 09:18:28 +00:00
return 0 ;
2006-03-20 16:43:15 +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
m [ 0 ] . type = NM_TYPE_INPUT ; m [ 0 ] . text = Network_message ; m [ 0 ] . text_len = MAX_MESSAGE_LEN - 1 ;
2010-01-07 14:49:07 +00:00
choice = newmenu_do ( NULL , TXT_SEND_MESSAGE , 1 , m , NULL , NULL ) ;
2006-03-20 16:43:15 +00:00
if ( ( choice > - 1 ) & & ( strlen ( Network_message ) > 0 ) ) {
Network_message_reciever = 100 ;
multi_message_feedback ( ) ;
}
}
void
multi_do_death ( int objnum )
{
// Do any miscellaneous stuff for a new network player after death
objnum = objnum ;
if ( ! ( Game_mode & GM_MULTI_COOP ) )
{
Players [ Player_num ] . flags | = ( PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY ) ;
}
}
void
multi_do_fire ( char * buf )
{
ubyte weapon ;
int pnum ;
2006-10-06 14:41:31 +00:00
sbyte flags ;
2006-03-20 16:43:15 +00:00
fix save_charge = Fusion_charge ;
// Act out the actual shooting
pnum = buf [ 1 ] ;
weapon = ( int ) buf [ 2 ] ;
flags = buf [ 4 ] ;
2008-05-16 11:20:33 +00:00
Network_laser_track = GET_INTEL_SHORT ( buf + 6 ) ;
2006-03-20 16:43:15 +00:00
Assert ( pnum < N_players ) ;
if ( Objects [ Players [ pnum ] . objnum ] . type = = OBJ_GHOST )
multi_make_ghost_player ( pnum ) ;
if ( weapon > = MISSILE_ADJUST )
net_missile_firing ( pnum , weapon , ( int ) buf [ 4 ] ) ;
else {
if ( weapon = = FUSION_INDEX ) {
Fusion_charge = buf [ 4 ] < < 12 ;
}
if ( weapon = = LASER_INDEX ) {
if ( flags & LASER_QUAD )
Players [ pnum ] . flags | = PLAYER_FLAGS_QUAD_LASERS ;
else
Players [ pnum ] . flags & = ~ PLAYER_FLAGS_QUAD_LASERS ;
}
do_laser_firing ( Players [ pnum ] . objnum , weapon , ( int ) buf [ 3 ] , flags , ( int ) buf [ 5 ] ) ;
if ( weapon = = FUSION_INDEX )
Fusion_charge = save_charge ;
}
}
void
multi_do_message ( char * buf )
{
2007-09-05 17:31:05 +00:00
char * colon , mesbuf [ 100 ] ;
int t ;
2006-03-20 16:43:15 +00:00
int loc = 2 ;
2011-04-11 15:47:12 +00:00
if ( ( ( colon = strstr ( buf + loc , " : " ) ) = = NULL ) | | ( colon - ( buf + loc ) < 1 ) | | ( colon - ( buf + loc ) > CALLSIGN_LEN ) )
2006-03-20 16:43:15 +00:00
{
2007-09-05 17:31:05 +00:00
int color = 0 ;
2009-01-14 19:54:45 +00:00
mesbuf [ 0 ] = CC_COLOR ;
2007-09-05 17:31:05 +00:00
if ( Game_mode & GM_TEAM )
color = get_team ( ( int ) buf [ 1 ] ) ;
else
color = ( int ) buf [ 1 ] ;
2008-02-24 14:41:27 +00:00
mesbuf [ 1 ] = BM_XRGB ( player_rgb [ color ] . r , player_rgb [ color ] . g , player_rgb [ color ] . b ) ;
2007-09-05 17:31:05 +00:00
strcpy ( & mesbuf [ 2 ] , Players [ ( int ) buf [ 1 ] ] . callsign ) ;
t = strlen ( mesbuf ) ;
mesbuf [ t ] = ' : ' ;
2008-04-06 20:23:28 +00:00
mesbuf [ t + 1 ] = CC_COLOR ;
2007-09-05 17:31:05 +00:00
mesbuf [ t + 2 ] = BM_XRGB ( 0 , 31 , 0 ) ;
mesbuf [ t + 3 ] = 0 ;
2006-03-20 16:43:15 +00:00
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , mesbuf , buf + 2 ) ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ ( int ) buf [ 1 ] ] = 0 ;
2006-03-20 16:43:15 +00:00
}
else if ( ( ! strncasecmp ( Players [ Player_num ] . callsign , buf + loc , colon - ( buf + loc ) ) ) | |
( ( Game_mode & GM_TEAM ) & & ( ( get_team ( Player_num ) = = atoi ( buf + loc ) - 1 ) | | ! strncasecmp ( Netgame . team_name [ get_team ( Player_num ) ] , buf + loc , colon - ( buf + loc ) ) ) ) )
{
2007-09-05 17:31:05 +00:00
int color = 0 ;
2009-01-14 19:54:45 +00:00
mesbuf [ 0 ] = CC_COLOR ;
2007-09-05 17:31:05 +00:00
if ( Game_mode & GM_TEAM )
color = get_team ( ( int ) buf [ 1 ] ) ;
else
color = ( int ) buf [ 1 ] ;
2008-02-24 14:41:27 +00:00
mesbuf [ 1 ] = BM_XRGB ( player_rgb [ color ] . r , player_rgb [ color ] . g , player_rgb [ color ] . b ) ;
2007-09-05 17:31:05 +00:00
strcpy ( & mesbuf [ 2 ] , Players [ ( int ) buf [ 1 ] ] . callsign ) ;
t = strlen ( mesbuf ) ;
mesbuf [ t ] = ' : ' ;
2008-04-06 20:23:28 +00:00
mesbuf [ t + 1 ] = CC_COLOR ;
2007-09-05 17:31:05 +00:00
mesbuf [ t + 2 ] = BM_XRGB ( 0 , 31 , 0 ) ;
mesbuf [ t + 3 ] = 0 ;
2006-03-20 16:43:15 +00:00
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2011-04-11 15:47:12 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , mesbuf , colon + 2 ) ;
multi_sending_message [ ( int ) buf [ 1 ] ] = 0 ;
2006-03-20 16:43:15 +00:00
}
}
void
multi_do_position ( char * buf )
2007-12-29 14:18:49 +00:00
{
2009-11-24 09:48:53 +00:00
ubyte pnum = 0 ;
2008-01-08 16:33:19 +00:00
# ifdef WORDS_BIGENDIAN
shortpos sp ;
# endif
2009-11-24 09:48:53 +00:00
pnum = buf [ 1 ] ;
2008-01-08 16:33:19 +00:00
# ifndef WORDS_BIGENDIAN
2009-11-24 09:48:53 +00:00
extract_shortpos ( & Objects [ Players [ pnum ] . objnum ] , ( shortpos * ) ( buf + 2 ) , 0 ) ;
2008-01-08 16:33:19 +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 ) ;
2008-01-08 16:33:19 +00:00
extract_shortpos ( & Objects [ Players [ pnum ] . objnum ] , & sp , 1 ) ;
# endif
2006-03-20 16:43:15 +00:00
if ( Objects [ Players [ pnum ] . objnum ] . movement_type = = MT_PHYSICS )
set_thrust_from_velocity ( & Objects [ Players [ pnum ] . objnum ] ) ;
}
void
multi_do_reappear ( char * buf )
{
short objnum ;
2012-04-07 10:32:22 +00:00
ubyte pnum = buf [ 1 ] ;
2006-03-20 16:43:15 +00:00
2012-04-07 10:32:22 +00:00
objnum = GET_INTEL_SHORT ( buf + 2 ) ;
2006-03-20 16:43:15 +00:00
Assert ( objnum > = 0 ) ;
2012-04-12 00:15:23 +00:00
if ( pnum ! = Objects [ objnum ] . id )
return ;
2006-03-20 16:43:15 +00:00
2012-04-12 00:15:23 +00:00
if ( PKilledFlags [ pnum ] < = 0 ) // player was not reported dead, so do not accept this packet
2012-04-07 10:32:22 +00:00
{
2012-04-12 00:15:23 +00:00
PKilledFlags [ pnum ] - - ;
2012-04-07 10:32:22 +00:00
return ;
}
2006-03-20 16:43:15 +00:00
multi_make_ghost_player ( Objects [ objnum ] . id ) ;
create_player_appearance_effect ( & Objects [ objnum ] ) ;
2012-04-12 00:15:23 +00:00
PKilledFlags [ pnum ] = 0 ;
2006-03-20 16:43:15 +00:00
}
void
multi_do_player_explode ( char * buf )
{
// Only call this for players, not robots. pnum is player number, not
// Object number.
object * objp ;
int count ;
int pnum ;
int i ;
char remote_created ;
pnum = buf [ 1 ] ;
# ifdef NDEBUG
if ( ( pnum < 0 ) | | ( pnum > = N_players ) )
return ;
# else
Assert ( pnum > = 0 ) ;
Assert ( pnum < N_players ) ;
# endif
# ifdef NETWORK
// If we are in the process of sending objects to a new player, reset that process
if ( Network_send_objects )
{
Network_send_objnum = - 1 ;
}
# endif
// Stuff the Players structure to prepare for the explosion
count = 2 ;
Players [ pnum ] . primary_weapon_flags = buf [ count ] ; count + + ;
Players [ pnum ] . secondary_weapon_flags = buf [ count ] ; count + + ;
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 + + ;
2008-05-16 11:20:33 +00:00
Players [ pnum ] . primary_ammo [ VULCAN_INDEX ] = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
Players [ pnum ] . flags = GET_INTEL_INT ( buf + count ) ; count + = 4 ;
2006-03-20 16:43:15 +00:00
2011-01-14 13:29:36 +00:00
multi_powcap_adjust_remote_cap ( pnum ) ;
2006-03-20 16:43:15 +00:00
objp = Objects + Players [ pnum ] . objnum ;
// 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 + + )
{
2008-05-16 11:20:33 +00:00
short s ;
s = GET_INTEL_SHORT ( buf + count ) ;
if ( ( i < Net_create_loc ) & & ( s > 0 ) & &
2006-03-20 16:43:15 +00:00
( Net_create_objnums [ i ] > 0 ) )
2008-05-16 11:20:33 +00:00
map_objnum_local_to_remote ( ( short ) Net_create_objnums [ i ] , s , pnum ) ;
2006-03-20 16:43:15 +00:00
count + = 2 ;
}
for ( i = remote_created ; i < Net_create_loc ; i + + ) {
Objects [ Net_create_objnums [ i ] ] . flags | = OF_SHOULD_BE_DEAD ;
}
2009-02-02 10:56:12 +00:00
if ( buf [ 0 ] = = MULTI_PLAYER_EXPLODE )
2006-03-20 16:43:15 +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 ) ;
}
Players [ pnum ] . flags & = ~ ( PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE ) ;
Players [ pnum ] . cloak_time = 0 ;
2012-04-07 10:32:22 +00:00
2012-04-12 00:15:23 +00:00
PKilledFlags [ pnum ] + + ;
if ( PKilledFlags [ pnum ] < 1 ) // seems we got reappear already so make him player again!
2012-04-07 10:32:22 +00:00
{
2012-04-12 00:15:23 +00:00
multi_make_ghost_player ( Objects [ Players [ pnum ] . objnum ] . id ) ;
create_player_appearance_effect ( & Objects [ Players [ pnum ] . objnum ] ) ;
PKilledFlags [ pnum ] = 0 ;
2012-04-07 10:32:22 +00:00
}
2006-03-20 16:43:15 +00:00
}
2011-05-25 13:25:06 +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 .
*/
2006-03-20 16:43:15 +00:00
void
multi_do_kill ( char * buf )
{
int killer , killed ;
int count = 1 ;
2011-05-25 13:25:06 +00:00
int pnum = ( int ) ( buf [ count ] ) ;
int type = ( int ) ( buf [ 0 ] ) ;
2011-09-13 23:15:20 +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:06 +00:00
return ;
2006-03-20 16:43:15 +00:00
if ( ( pnum < 0 ) | | ( pnum > = N_players ) )
{
Int3 ( ) ; // Invalid player number killed
return ;
}
2011-09-13 23:15:20 +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:06 +00:00
{
2011-09-13 23:15:20 +00:00
memcpy ( multibuf , buf , 5 ) ;
multibuf [ 0 ] = MULTI_KILL_HOST ;
multibuf [ 5 ] = Netgame . team_vector ;
multibuf [ 6 ] = Bounty_target ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 7 , 2 ) ;
2011-05-25 13:25:06 +00:00
}
2006-03-20 16:43:15 +00:00
2011-09-13 23:15:20 +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:06 +00:00
2011-09-13 23:15:20 +00:00
multi_compute_kill ( killer , killed ) ;
2011-05-25 13:25:06 +00:00
2011-09-13 23:15:20 +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 16:43:15 +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
void multi_do_controlcen_destroy ( char * buf )
{
2006-10-06 14:41:31 +00:00
sbyte who ;
2006-03-20 16:43:15 +00:00
short objnum ;
2008-05-16 11:20:33 +00:00
objnum = GET_INTEL_SHORT ( buf + 1 ) ;
2006-03-20 16:43:15 +00:00
who = buf [ 3 ] ;
2009-07-01 11:35:33 +00:00
if ( Control_center_destroyed ! = 1 )
2006-03-20 16:43:15 +00:00
{
if ( ( who < N_players ) & & ( who ! = Player_num ) ) {
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , Players [ who ] . callsign , TXT_HAS_DEST_CONTROL ) ;
2006-03-20 16:43:15 +00:00
}
else if ( who = = Player_num )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , TXT_YOU_DEST_CONTROL ) ;
2006-03-20 16:43:15 +00:00
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , TXT_CONTROL_DESTROYED ) ;
2006-03-20 16:43:15 +00:00
if ( objnum ! = - 1 )
net_destroy_controlcen ( Objects + objnum ) ;
else
net_destroy_controlcen ( NULL ) ;
}
}
void
2007-06-11 09:06:14 +00:00
multi_do_escape ( char * buf )
2006-03-20 16:43:15 +00:00
{
int objnum ;
objnum = Players [ ( int ) buf [ 1 ] ] . objnum ;
if ( buf [ 2 ] = = 0 )
{
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , Players [ ( int ) buf [ 1 ] ] . callsign , TXT_HAS_ESCAPED ) ;
2009-11-24 09:48:53 +00:00
2006-03-20 16:43:15 +00:00
if ( Game_mode & GM_NETWORK )
2007-06-11 09:06:14 +00:00
Players [ ( int ) buf [ 1 ] ] . connected = CONNECT_ESCAPE_TUNNEL ;
2009-11-24 09:48:53 +00:00
2006-03-20 16:43:15 +00:00
if ( ! multi_goto_secret )
multi_goto_secret = 2 ;
}
else if ( buf [ 2 ] = = 1 )
{
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , Players [ ( int ) buf [ 1 ] ] . callsign , TXT_HAS_FOUND_SECRET ) ;
2009-11-24 09:48:53 +00:00
2006-03-20 16:43:15 +00:00
if ( Game_mode & GM_NETWORK )
Players [ ( int ) buf [ 1 ] ] . connected = CONNECT_FOUND_SECRET ;
2009-11-24 09:48:53 +00:00
2006-03-20 16:43:15 +00:00
if ( ! multi_goto_secret )
multi_goto_secret = 1 ;
}
create_player_appearance_effect ( & Objects [ objnum ] ) ;
multi_make_player_ghost ( buf [ 1 ] ) ;
}
void
2007-06-11 09:06:14 +00:00
multi_do_remobj ( char * buf )
2006-03-20 16:43:15 +00:00
{
short objnum ; // which object to remove
short local_objnum ;
2006-10-06 14:41:31 +00:00
sbyte obj_owner ; // which remote list is it entered in
2006-03-20 16:43:15 +00:00
2008-05-16 11:20:33 +00:00
objnum = GET_INTEL_SHORT ( buf + 1 ) ;
2006-03-20 16:43:15 +00:00
obj_owner = buf [ 3 ] ;
Assert ( objnum > = 0 ) ;
if ( objnum < 1 )
return ;
local_objnum = objnum_remote_to_local ( objnum , obj_owner ) ; // translate to local objnum
if ( local_objnum < 0 )
{
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 16:43:15 +00:00
{
Network_send_objnum = - 1 ;
}
2011-01-14 13:29:36 +00:00
if ( Objects [ local_objnum ] . type = = OBJ_POWERUP )
if ( Game_mode & GM_NETWORK )
{
if ( multi_powerup_is_4pack ( Objects [ local_objnum ] . id ) )
{
if ( PowerupsInMine [ Objects [ local_objnum ] . id - 1 ] - 4 < 0 )
PowerupsInMine [ Objects [ local_objnum ] . id - 1 ] = 0 ;
else
PowerupsInMine [ Objects [ local_objnum ] . id - 1 ] - = 4 ;
}
else
{
if ( PowerupsInMine [ Objects [ local_objnum ] . id ] > 0 )
PowerupsInMine [ Objects [ local_objnum ] . id ] - - ;
}
}
2006-03-20 16:43:15 +00:00
Objects [ local_objnum ] . flags | = OF_SHOULD_BE_DEAD ; // quick and painless
}
2011-02-09 11:58:28 +00:00
void multi_disconnect_player ( int pnum )
2006-03-20 16:43:15 +00:00
{
2011-02-09 11:58:28 +00:00
int i , n = 0 ;
2006-03-20 16:43:15 +00:00
2011-02-09 11:58:28 +00:00
if ( ! ( Game_mode & GM_NETWORK ) )
2012-04-12 00:15:23 +00:00
return ;
if ( Players [ pnum ] . connected = = CONNECT_PLAYING )
{
digi_play_sample ( SOUND_HUD_MESSAGE , F1_0 ) ;
HUD_init_message ( HM_MULTI , " %s %s " , Players [ pnum ] . callsign , TXT_HAS_LEFT_THE_GAME ) ;
2006-03-20 16:43:15 +00:00
2012-04-12 00:15:23 +00:00
multi_sending_message [ pnum ] = 0 ;
2011-02-09 11:58:28 +00:00
2012-04-12 00:15:23 +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 */
int new = d_rand ( ) % MAX_NUM_NET_PLAYERS ;
/* Make sure they're valid: Don't check against kill flags,
* just in case everyone ' s dead ! */
while ( ! Players [ new ] . connected )
new = d_rand ( ) % MAX_NUM_NET_PLAYERS ;
/* Select new target */
multi_new_bounty_target ( new ) ;
/* Send this new data */
multi_send_bounty ( ) ;
}
}
Players [ pnum ] . connected = CONNECT_DISCONNECTED ;
Netgame . players [ pnum ] . connected = CONNECT_DISCONNECTED ;
PKilledFlags [ pnum ] = 1 ;
2011-02-09 11:58:28 +00:00
switch ( multi_protocol )
{
2009-11-29 16:46:13 +00:00
# ifdef USE_UDP
2011-02-09 11:58:28 +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:28 +00:00
default :
Error ( " Protocol handling missing in multi_disconnect_player \n " ) ;
break ;
}
2011-01-19 11:21:59 +00:00
2012-04-12 00:15:23 +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:28 +00:00
for ( i = 0 ; i < N_players ; i + + )
if ( Players [ i ] . connected ) n + + ;
if ( n = = 1 )
{
HUD_init_message ( HM_MULTI , " You are the only person remaining in this netgame " ) ;
2006-03-20 16:43:15 +00:00
}
2011-02-09 11:58:28 +00:00
}
void
multi_do_quit ( char * buf )
{
if ( ! ( Game_mode & GM_NETWORK ) )
return ;
multi_disconnect_player ( ( int ) buf [ 1 ] ) ;
2006-03-20 16:43:15 +00:00
}
void
multi_do_cloak ( char * buf )
{
int pnum ;
pnum = buf [ 1 ] ;
Assert ( pnum < N_players ) ;
Players [ pnum ] . flags | = PLAYER_FLAGS_CLOAKED ;
2010-12-22 00:17:49 +00:00
Players [ pnum ] . cloak_time = GameTime64 ;
2006-03-20 16:43:15 +00:00
ai_do_cloak_stuff ( ) ;
if ( Game_mode & GM_MULTI_ROBOTS )
multi_strip_robots ( pnum ) ;
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_cloak ( pnum ) ;
}
void
multi_do_decloak ( char * buf )
{
int pnum ;
pnum = buf [ 1 ] ;
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_record_multi_decloak ( pnum ) ;
}
void
multi_do_door_open ( char * buf )
{
int segnum ;
short side ;
segment * seg ;
wall * w ;
2008-05-16 11:20:33 +00:00
segnum = GET_INTEL_SHORT ( buf + 1 ) ;
2006-03-20 16:43:15 +00:00
side = buf [ 3 ] ;
if ( ( segnum < 0 ) | | ( segnum > Highest_segment_index ) | | ( side < 0 ) | | ( side > 5 ) )
{
Int3 ( ) ;
return ;
}
seg = & Segments [ segnum ] ;
if ( seg - > sides [ side ] . wall_num = = - 1 ) { //Opening door on illegal wall
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 ) ;
}
}
void
multi_do_create_explosion ( char * buf )
{
int pnum ;
int count = 1 ;
pnum = buf [ count + + ] ;
create_small_fireball_on_object ( & Objects [ Players [ pnum ] . objnum ] , F1_0 , 1 ) ;
}
void
multi_do_controlcen_fire ( char * buf )
{
vms_vector to_target ;
int gun_num ;
short objnum ;
int count = 1 ;
memcpy ( & to_target , buf + count , 12 ) ; count + = 12 ;
2008-01-08 16:33:19 +00:00
# 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
2008-05-16 11:20:33 +00:00
gun_num = buf [ count ] ; count + = 1 ;
objnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
2006-03-20 16:43:15 +00:00
Laser_create_new_easy ( & to_target , & Gun_pos [ gun_num ] , objnum , CONTROLCEN_WEAPON_NUM , 1 ) ;
}
void
multi_do_create_powerup ( char * buf )
{
short segnum ;
short objnum ;
int my_objnum ;
int pnum ;
int count = 1 ;
vms_vector new_pos ;
char powerup_type ;
2009-07-01 11:35:33 +00:00
if ( Endlevel_sequence | | Control_center_destroyed )
2006-03-20 16:43:15 +00:00
return ;
pnum = buf [ count + + ] ;
powerup_type = buf [ count + + ] ;
2008-05-16 11:20:33 +00:00
segnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
objnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
2006-03-20 16:43:15 +00:00
if ( ( segnum < 0 ) | | ( segnum > Highest_segment_index ) ) {
Int3 ( ) ;
return ;
}
new_pos = * ( vms_vector * ) ( buf + count ) ; count + = sizeof ( vms_vector ) ;
2009-11-24 09:48:53 +00:00
2008-01-08 16:33:19 +00:00
# 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
2006-03-20 16:43:15 +00:00
Net_create_loc = 0 ;
my_objnum = call_object_create_egg ( & Objects [ Players [ pnum ] . objnum ] , 1 , OBJ_POWERUP , powerup_type ) ;
if ( my_objnum < 0 ) {
return ;
}
2009-04-09 07:41:30 +00:00
if ( Network_send_objects & & multi_objnum_is_past ( my_objnum ) )
2006-03-20 16:43:15 +00:00
{
Network_send_objnum = - 1 ;
}
Objects [ my_objnum ] . pos = new_pos ;
vm_vec_zero ( & Objects [ my_objnum ] . mtype . phys_info . velocity ) ;
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:36 +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 ] + + ;
}
2008-04-06 20:23:28 +00:00
}
2006-03-20 16:43:15 +00:00
void
multi_do_play_sound ( char * buf )
{
int pnum = buf [ 1 ] ;
int sound_num = buf [ 2 ] ;
fix volume = buf [ 3 ] < < 12 ;
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 ) ;
}
void
multi_do_score ( char * buf )
{
int pnum = buf [ 1 ] ;
if ( ( pnum < 0 ) | | ( pnum > = N_players ) )
{
Int3 ( ) ; // Non-terminal, see rob
return ;
}
2008-05-16 11:20:33 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING ) {
int score ;
score = GET_INTEL_INT ( buf + 2 ) ;
newdemo_record_multi_score ( pnum , score ) ;
}
2006-03-20 16:43:15 +00:00
2008-05-16 11:20:33 +00:00
Players [ pnum ] . score = GET_INTEL_INT ( buf + 2 ) ;
2006-03-20 16:43:15 +00:00
multi_sort_kill_list ( ) ;
}
void
multi_do_trigger ( char * buf )
{
int pnum = buf [ 1 ] ;
int trigger = buf [ 2 ] ;
if ( ( pnum < 0 ) | | ( pnum > = N_players ) | | ( pnum = = Player_num ) )
{
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 ) ;
}
void multi_do_hostage_door_status ( char * buf )
{
// Update hit point status of a door
int count = 1 ;
int wallnum ;
fix hps ;
2008-05-16 11:20:33 +00:00
wallnum = GET_INTEL_SHORT ( buf + count ) ; count + = 2 ;
hps = GET_INTEL_INT ( buf + count ) ; count + = 4 ;
2006-03-20 16:43:15 +00:00
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 16:43:15 +00:00
dead_player_end ( ) ;
Players [ Player_num ] . homing_object_dist = - F1_0 ; // Turn off homing sound.
Dead_player_camera = 0 ;
Endlevel_sequence = 0 ;
reset_rear_view ( ) ;
}
void
multi_reset_player_object ( object * objp )
{
int i ;
//Init physics for a non-console player
Assert ( objp > = Objects ) ;
Assert ( objp < = Objects + Highest_object_index ) ;
Assert ( ( objp - > type = = OBJ_PLAYER ) | | ( objp - > type = = OBJ_GHOST ) ) ;
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 ) ;
objp - > mtype . phys_info . brakes = objp - > mtype . phys_info . turnroll = 0 ;
objp - > mtype . phys_info . mass = Player_ship - > mass ;
objp - > mtype . phys_info . drag = Player_ship - > drag ;
2011-02-09 11:58:28 +00:00
if ( objp - > type = = OBJ_PLAYER )
objp - > mtype . phys_info . flags | = PF_TURNROLL | PF_LEVELLING | PF_WIGGLE ;
else
objp - > mtype . phys_info . flags & = ~ ( PF_TURNROLL | PF_LEVELLING | PF_WIGGLE ) ;
2006-03-20 16:43:15 +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
2011-05-25 13:25:06 +00:00
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 ;
2006-03-20 16:43:15 +00:00
if ( Game_mode & GM_TEAM )
id = get_team ( objp - > id ) ;
else
id = objp - > id ;
if ( id = = 0 )
objp - > rtype . pobj_info . alt_textures = 0 ;
else {
2011-06-04 20:50:35 +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 16:43:15 +00:00
2012-03-28 10:26:19 +00:00
for ( i = 0 ; i < Polygon_models [ objp - > rtype . pobj_info . model_num ] . n_textures ; i + + )
2006-03-20 16:43:15 +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 ;
}
}
void
multi_process_data ( char * buf , int len )
{
// Take an entire message (that has already been checked for validity,
// if necessary) and act on it.
int type ;
len = len ;
type = buf [ 0 ] ;
if ( type > MULTI_MAX_TYPE )
{
Int3 ( ) ;
return ;
}
switch ( type )
{
case MULTI_POSITION :
if ( ! Endlevel_sequence ) multi_do_position ( buf ) ; break ;
case MULTI_REAPPEAR :
if ( ! Endlevel_sequence ) multi_do_reappear ( buf ) ; break ;
case MULTI_FIRE :
2009-02-02 10:56:12 +00:00
if ( ! Endlevel_sequence ) multi_do_fire ( buf ) ; break ;
2006-03-20 16:43:15 +00:00
case MULTI_KILL :
multi_do_kill ( buf ) ; break ;
case MULTI_REMOVE_OBJECT :
if ( ! Endlevel_sequence ) multi_do_remobj ( buf ) ; break ;
case MULTI_PLAYER_DROP :
case MULTI_PLAYER_EXPLODE :
if ( ! Endlevel_sequence ) multi_do_player_explode ( buf ) ; break ;
case MULTI_MESSAGE :
if ( ! Endlevel_sequence ) multi_do_message ( buf ) ; break ;
case MULTI_QUIT :
if ( ! Endlevel_sequence ) multi_do_quit ( buf ) ; break ;
case MULTI_BEGIN_SYNC :
break ;
case MULTI_CONTROLCEN :
if ( ! Endlevel_sequence ) multi_do_controlcen_destroy ( buf ) ; break ;
case MULTI_ENDLEVEL_START :
if ( ! Endlevel_sequence ) multi_do_escape ( buf ) ; break ;
case MULTI_END_SYNC :
break ;
case MULTI_CLOAK :
if ( ! Endlevel_sequence ) multi_do_cloak ( buf ) ; break ;
case MULTI_DECLOAK :
if ( ! Endlevel_sequence ) multi_do_decloak ( buf ) ; break ;
case MULTI_DOOR_OPEN :
if ( ! Endlevel_sequence ) multi_do_door_open ( buf ) ; break ;
case MULTI_CREATE_EXPLOSION :
if ( ! Endlevel_sequence ) multi_do_create_explosion ( buf ) ; break ;
case MULTI_CONTROLCEN_FIRE :
if ( ! Endlevel_sequence ) multi_do_controlcen_fire ( buf ) ; break ;
case MULTI_CREATE_POWERUP :
if ( ! Endlevel_sequence ) multi_do_create_powerup ( buf ) ; break ;
case MULTI_PLAY_SOUND :
if ( ! Endlevel_sequence ) multi_do_play_sound ( buf ) ; break ;
case MULTI_ROBOT_CLAIM :
if ( ! Endlevel_sequence ) multi_do_claim_robot ( buf ) ; break ;
case MULTI_ROBOT_POSITION :
if ( ! Endlevel_sequence ) multi_do_robot_position ( buf ) ; break ;
case MULTI_ROBOT_EXPLODE :
if ( ! Endlevel_sequence ) multi_do_robot_explode ( buf ) ; break ;
case MULTI_ROBOT_RELEASE :
if ( ! Endlevel_sequence ) multi_do_release_robot ( buf ) ; break ;
case MULTI_ROBOT_FIRE :
if ( ! Endlevel_sequence ) multi_do_robot_fire ( buf ) ; break ;
case MULTI_SCORE :
if ( ! Endlevel_sequence ) multi_do_score ( buf ) ; break ;
case MULTI_CREATE_ROBOT :
if ( ! Endlevel_sequence ) multi_do_create_robot ( buf ) ; break ;
case MULTI_TRIGGER :
if ( ! Endlevel_sequence ) multi_do_trigger ( buf ) ; break ;
case MULTI_BOSS_ACTIONS :
if ( ! Endlevel_sequence ) multi_do_boss_actions ( buf ) ; break ;
case MULTI_CREATE_ROBOT_POWERUPS :
if ( ! Endlevel_sequence ) multi_do_create_robot_powerups ( buf ) ; break ;
case MULTI_HOSTAGE_DOOR :
if ( ! Endlevel_sequence ) multi_do_hostage_door_status ( buf ) ; break ;
2011-02-09 11:58:28 +00:00
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 ;
2011-01-14 13:29:36 +00:00
case MULTI_POWCAP_UPDATE :
if ( ! Endlevel_sequence ) multi_do_powcap_update ( buf ) ; break ;
2011-01-14 16:56:14 +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 ;
2011-01-19 01:19:15 +00:00
case MULTI_DO_BOUNTY :
if ( ! Endlevel_sequence ) multi_do_bounty ( buf ) ; break ;
2011-04-11 15:47:12 +00:00
case MULTI_TYPING_STATE :
multi_do_msgsend_state ( buf ) ; break ;
2011-05-25 13:25:06 +00:00
case MULTI_GMODE_UPDATE :
multi_do_gmode_update ( buf ) ; break ;
case MULTI_KILL_HOST :
multi_do_kill ( buf ) ; break ;
case MULTI_KILL_CLIENT :
multi_do_kill ( buf ) ; break ;
2006-03-20 16:43:15 +00:00
default :
Int3 ( ) ;
}
}
void
multi_process_bigdata ( char * buf , int len )
{
// Takes a bunch of messages, check them for validity,
// and pass them to multi_process_data.
int type , sub_len , bytes_processed = 0 ;
while ( bytes_processed < len ) {
type = buf [ bytes_processed ] ;
if ( ( type < 0 ) | | ( type > MULTI_MAX_TYPE ) ) {
2008-04-06 20:23:28 +00:00
con_printf ( CON_DEBUG , " multi_process_bigdata: Invalid packet type %d! \n " , type ) ;
2006-03-20 16:43:15 +00:00
return ;
}
2007-10-31 00:49:24 +00:00
sub_len = message_length [ type ] ;
2006-03-20 16:43:15 +00:00
Assert ( sub_len > 0 ) ;
if ( ( bytes_processed + sub_len ) > len ) {
2008-04-06 20:23:28 +00:00
con_printf ( CON_DEBUG , " multi_process_bigdata: packet type %d too short (%d>%d)! \n " , type , ( bytes_processed + sub_len ) , len ) ;
2006-03-20 16:43:15 +00:00
Int3 ( ) ;
return ;
}
multi_process_data ( & buf [ bytes_processed ] , sub_len ) ;
bytes_processed + = sub_len ;
}
}
//
// Part 2 : Functions that send communication messages to inform the other
// players of something we did.
//
2011-09-15 08:45:45 +00:00
void multi_send_fire ( int laser_gun , int laser_level , int laser_flags , int laser_fired , short laser_track )
2006-03-20 16:43:15 +00:00
{
2012-04-15 01:05:25 +00:00
multi_do_protocol_frame ( 1 , 0 ) ; // provoke positional update if possible
2011-09-15 08:45:45 +00:00
multibuf [ 0 ] = ( char ) MULTI_FIRE ;
multibuf [ 1 ] = ( char ) Player_num ;
multibuf [ 2 ] = ( char ) laser_gun ;
multibuf [ 3 ] = ( char ) laser_level ;
multibuf [ 4 ] = ( char ) laser_flags ;
multibuf [ 5 ] = ( char ) laser_fired ;
PUT_INTEL_SHORT ( multibuf + 6 , laser_track ) ;
2006-03-20 16:43:15 +00:00
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 8 , 1 ) ;
2006-03-20 16:43:15 +00:00
}
void
multi_send_destroy_controlcen ( int objnum , int player )
{
if ( player = = Player_num )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , TXT_YOU_DEST_CONTROL ) ;
2006-03-20 16:43:15 +00:00
else if ( ( player > 0 ) & & ( player < N_players ) )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , " %s %s " , Players [ player ] . callsign , TXT_HAS_DEST_CONTROL ) ;
2006-03-20 16:43:15 +00:00
else
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_MULTI , TXT_CONTROL_DESTROYED ) ;
2006-03-20 16:43:15 +00:00
multibuf [ 0 ] = ( char ) MULTI_CONTROLCEN ;
2008-05-16 11:20:33 +00:00
PUT_INTEL_SHORT ( multibuf + 1 , objnum ) ;
2006-03-20 16:43:15 +00:00
multibuf [ 3 ] = player ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 4 , 2 ) ;
2006-03-20 16:43:15 +00:00
}
void
multi_send_endlevel_start ( int secret )
{
multibuf [ 0 ] = ( char ) MULTI_ENDLEVEL_START ;
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 ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 3 , 2 ) ;
2006-03-20 16:43:15 +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 16:43:15 +00:00
}
}
void
multi_send_player_explode ( char type )
{
int count = 0 ;
int i ;
Assert ( ( type = = MULTI_PLAYER_DROP ) | | ( type = = MULTI_PLAYER_EXPLODE ) ) ;
if ( Network_send_objects )
{
Network_send_objnum = - 1 ;
}
2011-05-13 20:21:10 +00:00
multi_send_position ( Players [ Player_num ] . objnum ) ;
2006-03-20 16:43:15 +00:00
multibuf [ count + + ] = type ;
multibuf [ count + + ] = Player_num ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . primary_weapon_flags ;
multibuf [ count + + ] = ( char ) Players [ Player_num ] . secondary_weapon_flags ;
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 ] ;
2008-05-16 11:20:33 +00:00
PUT_INTEL_SHORT ( multibuf + count , Players [ Player_num ] . primary_ammo [ VULCAN_INDEX ] ) ;
2006-03-20 16:43:15 +00:00
count + = 2 ;
2008-05-16 11:20:33 +00:00
PUT_INTEL_INT ( multibuf + count , Players [ Player_num ] . flags ) ;
2006-03-20 16:43:15 +00:00
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 ) {
#if 0 // Now legal, happens if there are too much powerups in mine
Int3 ( ) ; // Illegal value in created egg object numbers
# endif
continue ;
}
2008-05-16 11:20:33 +00:00
PUT_INTEL_SHORT ( multibuf + count , Net_create_objnums [ i ] ) ; count + = 2 ;
2006-03-20 16:43:15 +00:00
// We created these objs so our local number = the network number
map_objnum_local_to_local ( ( short ) Net_create_objnums [ i ] ) ;
}
Net_create_loc = 0 ;
if ( count > message_length [ MULTI_PLAYER_EXPLODE ] )
{
Int3 ( ) ; // See Rob
}
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , message_length [ MULTI_PLAYER_EXPLODE ] , 2 ) ;
2006-03-20 16:43:15 +00:00
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_CLOAKED )
multi_send_decloak ( ) ;
2009-11-24 09:48:53 +00:00
2006-03-20 16:43:15 +00:00
multi_strip_robots ( Player_num ) ;
}
2011-01-14 13:29:36 +00:00
extern ubyte Secondary_weapon_to_powerup [ ] , Primary_weapon_to_powerup [ ] ;
extern int Proximity_dropped ;
/*
* Powerup capping : Keep track of how many powerups are in level and kill these which would exceed initial limit .
*/
// Count the initial amount of Powerups in the level
void multi_powcap_count_powerups_in_mine ( void )
{
int i ;
for ( i = 0 ; i < MAX_POWERUP_TYPES ; i + + )
PowerupsInMine [ i ] = 0 ;
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
if ( Objects [ i ] . type = = OBJ_POWERUP )
{
if ( multi_powerup_is_4pack ( Objects [ i ] . id ) )
PowerupsInMine [ Objects [ i ] . id - 1 ] + = 4 ;
else
PowerupsInMine [ Objects [ i ] . id ] + + ;
}
}
}
// We want to drop something. Kill every Powerup which exceeds the level limit
void multi_powcap_cap_objects ( )
{
char type ;
int index ;
if ( ! ( Game_mode & GM_NETWORK ) )
return ;
Players [ Player_num ] . secondary_ammo [ PROXIMITY_INDEX ] + = Proximity_dropped ;
Proximity_dropped = 0 ;
for ( index = 0 ; index < MAX_PRIMARY_WEAPONS ; index + + )
{
type = Primary_weapon_to_powerup [ index ] ;
if ( PowerupsInMine [ ( int ) type ] > = MaxPowerupsAllowed [ ( int ) type ] )
if ( Players [ Player_num ] . primary_weapon_flags & ( 1 < < index ) )
{
2011-01-14 14:12:39 +00:00
con_printf ( CON_VERBOSE , " PIM=%d MPA=%d \n " , PowerupsInMine [ ( int ) type ] , MaxPowerupsAllowed [ ( int ) type ] ) ;
con_printf ( CON_VERBOSE , " Killing a primary cuz there's too many! (%d) \n " , type ) ;
2011-01-14 13:29:36 +00:00
Players [ Player_num ] . primary_weapon_flags & = ( ~ ( 1 < < index ) ) ;
}
}
Players [ Player_num ] . secondary_ammo [ 2 ] / = 4 ;
for ( index = 0 ; index < MAX_SECONDARY_WEAPONS ; index + + )
{
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 ] ) ;
2011-01-14 14:12:39 +00:00
con_printf ( CON_VERBOSE , " Hey! I killed secondary type %d because PIM=%d MPA=%d \n " , type , PowerupsInMine [ ( int ) type ] , MaxPowerupsAllowed [ ( int ) type ] ) ;
2011-01-14 13:29:36 +00:00
}
}
Players [ Player_num ] . secondary_ammo [ 2 ] * = 4 ;
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 ) ;
}
// Adds players inventory to multi cap
void multi_powcap_adjust_cap_for_player ( int pnum )
{
char type ;
int index ;
if ( ! ( Game_mode & GM_NETWORK ) )
return ;
for ( index = 0 ; index < MAX_PRIMARY_WEAPONS ; index + + )
{
type = Primary_weapon_to_powerup [ index ] ;
if ( Players [ pnum ] . primary_weapon_flags & ( 1 < < index ) )
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 ] + + ;
}
void multi_powcap_adjust_remote_cap ( int pnum )
{
char type ;
int index ;
if ( ! ( Game_mode & GM_NETWORK ) )
return ;
for ( index = 0 ; index < MAX_PRIMARY_WEAPONS ; index + + )
{
type = Primary_weapon_to_powerup [ index ] ;
if ( Players [ pnum ] . primary_weapon_flags & ( 1 < < index ) )
PowerupsInMine [ ( int ) type ] + + ;
}
for ( index = 0 ; index < MAX_SECONDARY_WEAPONS ; index + + )
{
type = Secondary_weapon_to_powerup [ index ] ;
if ( index = = 2 ) // PROX? Those bastards...
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 ] + + ;
}
2006-03-20 16:43:15 +00:00
void
multi_send_message ( void )
{
int loc = 0 ;
if ( Network_message_reciever ! = - 1 )
{
multibuf [ loc ] = ( char ) MULTI_MESSAGE ; loc + = 1 ;
multibuf [ loc ] = ( char ) Player_num ; loc + = 1 ;
2007-06-11 09:06:14 +00:00
strncpy ( ( char * ) multibuf + loc , Network_message , MAX_MESSAGE_LEN ) ; loc + = MAX_MESSAGE_LEN ;
2006-03-20 16:43:15 +00:00
multibuf [ loc - 1 ] = ' \0 ' ;
2009-11-24 09:48:53 +00:00
multi_send_data ( multibuf , loc , 0 ) ;
2006-03-20 16:43:15 +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 ) ;
2006-03-20 16:43:15 +00:00
multibuf [ 0 ] = ( char ) MULTI_REAPPEAR ;
2012-04-07 10:32:22 +00:00
multibuf [ 1 ] = ( char ) Player_num ;
PUT_INTEL_SHORT ( multibuf + 2 , Players [ Player_num ] . objnum ) ;
2008-05-16 11:20:33 +00:00
2012-04-07 10:32:22 +00:00
multi_send_data ( multibuf , 4 , 2 ) ;
2011-02-09 11:58:28 +00:00
PKilledFlags [ Player_num ] = 0 ;
2006-03-20 16:43:15 +00:00
}
void
multi_send_position ( int objnum )
{
2008-01-08 16:33:19 +00:00
# ifdef WORDS_BIGENDIAN
shortpos sp ;
# endif
2006-03-20 16:43:15 +00:00
int count = 0 ;
multibuf [ count + + ] = ( char ) MULTI_POSITION ;
2009-11-24 09:48:53 +00:00
multibuf [ count + + ] = ( char ) Player_num ;
2008-01-08 16:33:19 +00:00
# ifndef WORDS_BIGENDIAN
create_shortpos ( ( shortpos * ) ( multibuf + count ) , Objects + objnum , 0 ) ;
2006-03-20 16:43:15 +00:00
count + = sizeof ( shortpos ) ;
2008-01-08 16:33:19 +00:00
# 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
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , count , 2 ) ;
2006-03-20 16:43:15 +00:00
multi_send_data ( multibuf , count , 0 ) ;
}
2011-05-25 13:25:06 +00:00
/*
2011-09-13 23:15:20 +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:06 +00:00
*/
2006-03-20 16:43:15 +00:00
void
multi_send_kill ( int objnum )
{
// I died, tell the world.
int killer_objnum ;
int count = 0 ;
2011-09-13 23:15:20 +00:00
Assert ( Objects [ objnum ] . id = = Player_num ) ;
killer_objnum = Players [ Player_num ] . killer_objnum ;
2011-05-25 13:25:06 +00:00
2011-09-13 23:15:20 +00:00
if ( multi_i_am_master ( ) )
multibuf [ count ] = ( char ) MULTI_KILL_HOST ;
else
multibuf [ count ] = ( char ) MULTI_KILL_CLIENT ;
count + = 1 ;
multibuf [ count ] = Player_num ; count + = 1 ;
2011-05-25 13:25:06 +00:00
2011-09-13 23:15:20 +00:00
if ( killer_objnum > - 1 )
{
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 16:43:15 +00:00
2011-09-13 23:15:20 +00:00
if ( multi_i_am_master ( ) )
{
2011-05-25 13:25:06 +00:00
multi_compute_kill ( killer_objnum , objnum ) ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , count , 2 ) ;
2008-05-16 11:20:33 +00:00
}
2006-03-20 16:43:15 +00:00
else
2011-09-15 08:45:45 +00:00
multi_send_data_direct ( ( ubyte * ) 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 16:43:15 +00:00
2011-09-13 23:15:20 +00:00
if ( Game_mode & GM_MULTI_ROBOTS )
multi_strip_robots ( Player_num ) ;
2011-05-25 13:25:06 +00:00
2011-09-13 23:15:20 +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 16:43:15 +00:00
}
void
multi_send_remobj ( int objnum )
{
// Tell the other guy to remove an object from his list
2006-10-06 14:41:31 +00:00
sbyte obj_owner ;
2006-03-20 16:43:15 +00:00
short remote_objnum ;
2011-01-14 13:29:36 +00:00
if ( Objects [ objnum ] . type = = OBJ_POWERUP & & ( Game_mode & GM_NETWORK ) )
{
if ( multi_powerup_is_4pack ( Objects [ objnum ] . id ) )
{
if ( PowerupsInMine [ Objects [ objnum ] . id - 1 ] - 4 < 0 )
PowerupsInMine [ Objects [ objnum ] . id - 1 ] = 0 ;
else
PowerupsInMine [ Objects [ objnum ] . id - 1 ] - = 4 ;
}
else
{
if ( PowerupsInMine [ Objects [ objnum ] . id ] > 0 )
PowerupsInMine [ Objects [ objnum ] . id ] - - ;
}
}
2006-03-20 16:43:15 +00:00
multibuf [ 0 ] = ( char ) MULTI_REMOVE_OBJECT ;
remote_objnum = objnum_local_to_remote ( ( short ) objnum , & obj_owner ) ;
2008-05-16 11:20:33 +00:00
PUT_INTEL_SHORT ( multibuf + 1 , remote_objnum ) ; // Map to network objnums
2006-03-20 16:43:15 +00:00
multibuf [ 3 ] = obj_owner ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 4 , 2 ) ;
2006-03-20 16:43:15 +00:00
2009-04-09 07:41:30 +00:00
if ( Network_send_objects & & multi_objnum_is_past ( objnum ) )
2006-03-20 16:43:15 +00:00
{
Network_send_objnum = - 1 ;
}
}
void
multi_send_quit ( int why )
{
// I am quitting the game, tell the other guy the bad news.
Assert ( why = = MULTI_QUIT ) ;
multibuf [ 0 ] = ( char ) why ;
multibuf [ 1 ] = Player_num ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 2 , 2 ) ;
2006-03-20 16:43:15 +00:00
}
void
multi_send_cloak ( void )
{
// Broadcast a change in our pflags (made to support cloaking)
multibuf [ 0 ] = MULTI_CLOAK ;
multibuf [ 1 ] = ( char ) Player_num ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 2 , 2 ) ;
2006-03-20 16:43:15 +00:00
if ( Game_mode & GM_MULTI_ROBOTS )
multi_strip_robots ( Player_num ) ;
}
void
multi_send_decloak ( void )
{
// Broadcast a change in our pflags (made to support cloaking)
multibuf [ 0 ] = MULTI_DECLOAK ;
multibuf [ 1 ] = ( char ) Player_num ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 2 , 2 ) ;
2006-03-20 16:43:15 +00:00
}
void
multi_send_door_open ( int segnum , int side )
{
multibuf [ 0 ] = MULTI_DOOR_OPEN ;
2008-05-16 11:20:33 +00:00
PUT_INTEL_SHORT ( multibuf + 1 , segnum ) ;
2006-10-06 14:41:31 +00:00
multibuf [ 3 ] = ( sbyte ) side ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 4 , 2 ) ;
2006-03-20 16:43:15 +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.
void
multi_send_create_explosion ( int pnum )
{
// Send all data needed to create a remote explosion
int count = 0 ;
multibuf [ count ] = MULTI_CREATE_EXPLOSION ; count + = 1 ;
2006-10-06 14:41:31 +00:00
multibuf [ count ] = ( sbyte ) pnum ; count + = 1 ;
2006-03-20 16:43:15 +00:00
// -----------
// Total size = 2
multi_send_data ( multibuf , count , 0 ) ;
}
2008-01-08 16:33:19 +00:00
2006-03-20 16:43:15 +00:00
void
multi_send_controlcen_fire ( vms_vector * to_goal , int best_gun_num , int objnum )
{
2008-01-08 16:33:19 +00:00
# ifdef WORDS_BIGENDIAN
vms_vector swapped_vec ;
# endif
2006-03-20 16:43:15 +00:00
int count = 0 ;
2008-01-08 16:33:19 +00:00
multibuf [ count ] = MULTI_CONTROLCEN_FIRE ; count + = 1 ;
# 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
2006-03-20 16:43:15 +00:00
multi_send_data ( multibuf , count , 0 ) ;
}
void
multi_send_create_powerup ( int powerup_type , int segnum , int objnum , vms_vector * pos )
{
// Create a powerup on a remote machine, used for remote
// placement of used powerups like missiles and cloaking
// powerups.
2008-01-08 16:33:19 +00:00
# ifdef WORDS_BIGENDIAN
vms_vector swapped_vec ;
# endif
2006-03-20 16:43:15 +00:00
int count = 0 ;
2008-01-08 16:33:19 +00:00
2009-11-24 09:48:53 +00:00
multi_send_position ( Players [ Player_num ] . objnum ) ;
2011-01-14 13:29:36 +00:00
if ( Game_mode & GM_NETWORK )
{
if ( multi_powerup_is_4pack ( powerup_type ) )
PowerupsInMine [ powerup_type - 1 ] + = 4 ;
else
PowerupsInMine [ powerup_type ] + + ;
}
2008-01-08 16:33:19 +00:00
multibuf [ count ] = MULTI_CREATE_POWERUP ; count + = 1 ;
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 ;
2009-11-24 09:48:53 +00:00
# ifndef WORDS_BIGENDIAN
2008-01-08 16:33:19 +00:00
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 ;
2006-03-20 16:43:15 +00:00
# endif
2008-01-08 16:33:19 +00:00
// -----------
// Total = 19
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , count , 2 ) ;
2006-03-20 16:43:15 +00:00
2009-04-09 07:41:30 +00:00
if ( Network_send_objects & & multi_objnum_is_past ( objnum ) )
2006-03-20 16:43:15 +00:00
{
Network_send_objnum = - 1 ;
}
map_objnum_local_to_local ( objnum ) ;
2008-01-08 16:33:19 +00:00
}
2006-03-20 16:43:15 +00:00
void
multi_send_play_sound ( int sound_num , fix volume )
{
int count = 0 ;
multibuf [ count ] = MULTI_PLAY_SOUND ; count + = 1 ;
multibuf [ count ] = Player_num ; count + = 1 ;
multibuf [ count ] = ( char ) sound_num ; count + = 1 ;
multibuf [ count ] = ( char ) ( volume > > 12 ) ; count + = 1 ;
// -----------
// Total = 4
2009-11-24 09:48:53 +00:00
multi_send_data ( multibuf , count , 0 ) ;
2006-03-20 16:43:15 +00:00
}
void
multi_send_audio_taunt ( int taunt_num )
{
# ifdef AUDIO_TAUNTS
int audio_taunts [ 4 ] = {
// Begin addition by GF
SOUND_CONTROL_CENTER_WARNING_SIREN ,
SOUND_HOMING_WARNING ,
SOUND_CONTROL_CENTER_DESTROYED ,
SOUND_MINE_BLEW_UP
// End addition by GF
} ;
Assert ( taunt_num > = 0 ) ;
Assert ( taunt_num < 4 ) ;
digi_play_sample ( audio_taunts [ taunt_num ] , F1_0 ) ;
multi_send_play_sound ( audio_taunts [ taunt_num ] , F1_0 ) ;
# endif
}
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 ( ) ;
multibuf [ count ] = MULTI_SCORE ; count + = 1 ;
multibuf [ count ] = Player_num ; count + = 1 ;
2008-05-16 11:20:33 +00:00
PUT_INTEL_INT ( multibuf + count , Players [ Player_num ] . score ) ; count + = 4 ;
2006-03-20 16:43:15 +00:00
multi_send_data ( multibuf , count , 0 ) ;
}
}
void
multi_send_trigger ( int triggernum )
{
// Send an event to trigger something in the mine
int count = 0 ;
multibuf [ count ] = MULTI_TRIGGER ; count + = 1 ;
multibuf [ count ] = Player_num ; count + = 1 ;
multibuf [ count ] = ( ubyte ) triggernum ; count + = 1 ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , count , 2 ) ;
2006-03-20 16:43:15 +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 ) ;
2008-05-16 11:20:33 +00:00
multibuf [ count ] = MULTI_HOSTAGE_DOOR ; count + = 1 ;
PUT_INTEL_SHORT ( multibuf + count , wallnum ) ; count + = 2 ;
PUT_INTEL_INT ( multibuf + count , Walls [ wallnum ] . hps ) ; count + = 4 ;
2006-03-20 16:43:15 +00:00
multi_send_data ( multibuf , count , 0 ) ;
}
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:14 +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:14 +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 16:43:15 +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 16:43:15 +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.
int i ;
int cloak_count , inv_count ;
Assert ( Game_mode & GM_MULTI ) ;
Assert ( NumNetPlayerPositions > 0 ) ;
2011-01-19 01:19:15 +00:00
Bounty_target = 0 ;
2009-11-24 09:48:53 +00:00
multi_consistency_error ( 1 ) ;
2011-02-09 11:58:28 +00:00
for ( i = 0 ; i < MAX_NUM_NET_PLAYERS ; i + + )
2011-04-11 15:47:12 +00:00
{
2012-04-12 00:15:23 +00:00
PKilledFlags [ i ] = 1 ;
2011-04-11 15:47:12 +00:00
multi_sending_message [ i ] = 0 ;
}
2011-02-09 11:58:28 +00:00
2006-03-20 16:43:15 +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 16:43:15 +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
}
if ( Game_mode & GM_MULTI_ROBOTS )
{
multi_set_robot_ai ( ) ; // Set all Robot AI to types we can cope with
}
2011-01-14 13:29:36 +00:00
if ( Game_mode & GM_NETWORK )
{
multi_powcap_adjust_cap_for_player ( Player_num ) ;
multi_send_powcap_update ( ) ;
}
2006-03-20 16:43:15 +00:00
inv_count = 0 ;
cloak_count = 0 ;
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
int objnum ;
if ( ( Objects [ i ] . type = = OBJ_HOSTAGE ) & & ! ( Game_mode & GM_MULTI_COOP ) )
{
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 ) ;
obj_delete ( i ) ;
if ( objnum ! = - 1 )
{
Objects [ objnum ] . rtype . vclip_info . vclip_num = Powerup_info [ POW_SHIELD_BOOST ] . vclip_num ;
Objects [ objnum ] . rtype . vclip_info . frametime = Vclip [ Objects [ objnum ] . rtype . vclip_info . vclip_num ] . frame_time ;
Objects [ objnum ] . rtype . vclip_info . framenum = 0 ;
Objects [ objnum ] . mtype . phys_info . drag = 512 ; //1024;
Objects [ objnum ] . mtype . phys_info . mass = F1_0 ;
vm_vec_zero ( & Objects [ objnum ] . mtype . phys_info . velocity ) ;
}
continue ;
}
if ( Objects [ i ] . type = = OBJ_POWERUP )
{
2011-01-14 13:29:36 +00:00
if ( Objects [ i ] . id = = POW_EXTRA_LIFE )
2006-03-20 16:43:15 +00:00
{
2011-01-14 13:29:36 +00:00
if ( ! ( Netgame . AllowedItems & NETFLAG_DOINVUL ) )
{
Objects [ i ] . id = POW_SHIELD_BOOST ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ Objects [ i ] . id ] . vclip_num ;
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
}
else
{
Objects [ i ] . id = POW_INVULNERABILITY ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ Objects [ i ] . id ] . vclip_num ;
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
}
2006-03-20 16:43:15 +00:00
}
2011-01-14 13:29:36 +00:00
if ( ! ( Game_mode & GM_MULTI_COOP ) )
if ( ( Objects [ i ] . id > = POW_KEY_BLUE ) & & ( Objects [ i ] . id < = POW_KEY_GOLD ) )
{
Objects [ i ] . id = POW_SHIELD_BOOST ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ Objects [ i ] . id ] . vclip_num ;
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
}
2006-03-20 16:43:15 +00:00
if ( Objects [ i ] . id = = POW_INVULNERABILITY ) {
2011-01-14 13:29:36 +00:00
if ( inv_count > = 3 | | ( ! ( Netgame . AllowedItems & NETFLAG_DOINVUL ) ) ) {
2006-03-20 16:43:15 +00:00
Objects [ i ] . id = POW_SHIELD_BOOST ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ Objects [ i ] . id ] . vclip_num ;
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
} else
inv_count + + ;
}
if ( Objects [ i ] . id = = POW_CLOAK ) {
2011-01-14 13:29:36 +00:00
if ( cloak_count > = 3 | | ( ! ( Netgame . AllowedItems & NETFLAG_DOCLOAK ) ) ) {
2006-03-20 16:43:15 +00:00
Objects [ i ] . id = POW_SHIELD_BOOST ;
Objects [ i ] . rtype . vclip_info . vclip_num = Powerup_info [ Objects [ i ] . id ] . vclip_num ;
Objects [ i ] . rtype . vclip_info . frametime = Vclip [ Objects [ i ] . rtype . vclip_info . vclip_num ] . frame_time ;
} else
cloak_count + + ;
}
2011-01-14 13:29:36 +00:00
if ( Objects [ i ] . id = = POW_FUSION_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOFUSION ) )
bash_to_shield ( i , " fusion " ) ;
if ( Objects [ i ] . id = = POW_MEGA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOMEGA ) )
bash_to_shield ( i , " mega " ) ;
if ( Objects [ i ] . id = = POW_SMARTBOMB_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOSMART ) )
bash_to_shield ( i , " smartmissile " ) ;
if ( Objects [ i ] . id = = POW_VULCAN_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOVULCAN ) )
bash_to_shield ( i , " vulcan " ) ;
if ( Objects [ i ] . id = = POW_PLASMA_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPLASMA ) )
bash_to_shield ( i , " plasma " ) ;
if ( Objects [ i ] . id = = POW_PROXIMITY_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOPROXIM ) )
bash_to_shield ( i , " proximity " ) ;
if ( Objects [ i ] . id = = POW_VULCAN_AMMO & & ( ! ( Netgame . AllowedItems & NETFLAG_DOVULCAN ) ) )
bash_to_shield ( i , " vulcan ammo " ) ;
if ( Objects [ i ] . id = = POW_SPREADFIRE_WEAPON & & ! ( Netgame . AllowedItems & NETFLAG_DOSPREAD ) )
bash_to_shield ( i , " spread " ) ;
if ( Objects [ i ] . id = = POW_LASER & & ! ( Netgame . AllowedItems & NETFLAG_DOLASER ) )
bash_to_shield ( i , " Laser powerup " ) ;
if ( Objects [ i ] . id = = POW_HOMING_AMMO_1 & & ! ( Netgame . AllowedItems & NETFLAG_DOHOMING ) )
bash_to_shield ( i , " Homing " ) ;
if ( Objects [ i ] . id = = POW_HOMING_AMMO_4 & & ! ( Netgame . AllowedItems & NETFLAG_DOHOMING ) )
bash_to_shield ( i , " Homing " ) ;
if ( Objects [ i ] . id = = POW_QUAD_FIRE & & ! ( Netgame . AllowedItems & NETFLAG_DOQUAD ) )
bash_to_shield ( i , " Quad Lasers " ) ;
2006-03-20 16:43:15 +00:00
}
}
multi_sort_kill_list ( ) ;
multi_show_player_list ( ) ;
ConsoleObject - > control_type = CT_FLYING ;
reset_player_object ( ) ;
}
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 ;
}
}
2006-03-20 16:43:15 +00:00
void multi_set_robot_ai ( void )
{
// Go through the objects array looking for robots and setting
// them to certain supported types of NET AI behavior.
// int i;
//
// for (i = 0; i <= Highest_object_index; i++)
// {
// if (Objects[i].type == OBJ_ROBOT) {
// Objects[i].ai_info.REMOTE_OWNER = -1;
// if (Objects[i].ai_info.behavior == AIB_STATION)
// Objects[i].ai_info.behavior = AIB_NORMAL;
// }
// }
}
int multi_delete_extra_objects ( )
{
int i ;
int nnp = 0 ;
object * objp ;
// 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!
objp = Objects ;
for ( i = 0 ; i < = Highest_object_index ; i + + ) {
if ( ( objp - > type = = OBJ_PLAYER ) | | ( objp - > type = = OBJ_GHOST ) )
nnp + + ;
else if ( ( objp - > type = = OBJ_ROBOT ) & & ( Game_mode & GM_MULTI_ROBOTS ) )
;
else if ( ( objp - > type ! = OBJ_NONE ) & & ( objp - > type ! = OBJ_PLAYER ) & & ( objp - > type ! = OBJ_POWERUP ) & & ( objp - > type ! = OBJ_CNTRLCEN ) & & ( objp - > type ! = OBJ_HOSTAGE ) )
obj_delete ( i ) ;
objp + + ;
}
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 )
2006-03-20 16:43:15 +00:00
{
2011-09-13 23:15:20 +00:00
return ( Player_num = = 0 ) ;
2006-03-20 16:43:15 +00:00
}
2009-03-20 12:10:38 +00:00
2009-11-24 09:48:53 +00:00
// Returns the Player_num of Master/Host of this game
2009-04-09 07:41:30 +00:00
int multi_who_is_master ( void )
{
2011-09-13 23:15:20 +00:00
return 0 ;
2009-04-09 07:41:30 +00:00
}
2006-03-20 16:43:15 +00:00
void change_playernum_to ( int new_Player_num )
{
2007-08-09 14:29:53 +00:00
// if (Player_num > -1)
// memcpy( Players[new_Player_num].callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
2007-08-09 14:43:56 +00:00
if ( Player_num > - 1 )
{
char * buf ;
MALLOC ( buf , char , CALLSIGN_LEN + 1 ) ;
memcpy ( buf , Players [ Player_num ] . callsign , CALLSIGN_LEN + 1 ) ;
strcpy ( Players [ new_Player_num ] . callsign , buf ) ;
2008-01-23 17:25:09 +00:00
d_free ( buf ) ;
2007-08-09 14:43:56 +00:00
}
2006-03-20 16:43:15 +00:00
Player_num = new_Player_num ;
}
2011-02-09 11:58:28 +00:00
int multi_all_players_alive ( )
{
int i ;
for ( i = 0 ; i < N_players ; i + + )
{
if ( PKilledFlags [ i ] & & Players [ i ] . connected )
return ( 0 ) ;
}
return ( 1 ) ;
}
2011-01-14 13:29:36 +00:00
void multi_send_powcap_update ( )
{
int i ;
multibuf [ 0 ] = MULTI_POWCAP_UPDATE ;
for ( i = 0 ; i < MAX_POWERUP_TYPES ; i + + )
multibuf [ i + 1 ] = MaxPowerupsAllowed [ i ] ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , MAX_POWERUP_TYPES + 1 , 2 ) ;
2011-01-14 13:29:36 +00:00
}
void multi_do_powcap_update ( char * buf )
{
int i ;
for ( i = 0 ; i < MAX_POWERUP_TYPES ; i + + )
if ( buf [ i + 1 ] > MaxPowerupsAllowed [ i ] )
MaxPowerupsAllowed [ i ] = buf [ i + 1 ] ;
}
# define POWERUPADJUSTS 2
int PowerupAdjustMapping [ ] = { 11 , 19 } ;
int multi_powerup_is_4pack ( int id )
{
int i ;
for ( i = 0 ; i < POWERUPADJUSTS ; i + + )
if ( id = = PowerupAdjustMapping [ i ] )
return ( 1 ) ;
return ( 0 ) ;
}
2011-01-14 16:56:14 +00:00
void multi_send_kill_goal_counts ( )
{
int i , count = 1 ;
multibuf [ 0 ] = MULTI_KILLGOALS ;
for ( i = 0 ; i < MAX_PLAYERS ; i + + )
{
* ( char * ) ( multibuf + count ) = ( char ) Players [ i ] . KillGoalCount ;
count + + ;
}
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , count , 2 ) ;
2011-01-14 16:56:14 +00:00
}
void multi_do_kill_goal_counts ( char * buf )
{
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 ;
multibuf [ 0 ] = MULTI_HEARTBEAT ;
PUT_INTEL_INT ( multibuf + 1 , ThisLevelTime ) ;
multi_send_data ( multibuf , 5 , 0 ) ;
}
void multi_do_heartbeat ( char * buf )
{
fix num ;
num = GET_INTEL_INT ( buf + 1 ) ;
ThisLevelTime = num ;
}
void multi_check_for_killgoal_winner ( )
{
int i , best = 0 , bestnum = 0 ;
object * objp ;
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 )
{
HUD_init_message ( HM_MULTI , " You have the best score at %d kills! " , best ) ;
//Players[Player_num].shields=i2f(200);
}
else
HUD_init_message ( HM_MULTI , " %s has the best score with %d kills! " , Players [ bestnum ] . callsign , best ) ;
HUD_init_message ( HM_MULTI , " The control center has been destroyed! " ) ;
objp = obj_find_first_of_type ( OBJ_CNTRLCEN ) ;
net_destroy_controlcen ( objp ) ;
}
2009-07-01 11:35:33 +00:00
void multi_add_lifetime_kills ( )
{
// This function adds a kill to lifetime stats of this player
// Trivial, but syncing with D2X
PlayerCfg . NetlifeKills + + ;
}
void multi_add_lifetime_killed ( )
{
// This function adds a "killed" to lifetime stats of this player
// Trivial, but syncing with D2X
PlayerCfg . NetlifeKilled + + ;
}
2010-12-22 00:17:49 +00:00
2011-01-14 18:48:36 +00:00
// Decide if fire from "killer" is friendly. If yes return 1 (no harm to me) otherwise 0 (damage me)
int multi_maybe_disable_friendly_fire ( object * killer )
{
if ( ! ( Game_mode & GM_NETWORK ) ) // no Multiplayer game -> always harm me!
return 0 ;
if ( ! Netgame . NoFriendlyFire ) // friendly fire is activated -> harm me!
return 0 ;
2011-05-04 10:05:43 +00:00
if ( killer = = NULL ) // no actual killer -> harm me!
return 0 ;
2011-01-14 18:48:36 +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
{
if ( get_team ( Player_num ) = = get_team ( killer - > id ) ) // in my team -> don't harm me!
return 1 ;
else // opposite team -> harm me!
return 0 ;
}
return 0 ; // all other cases -> harm me!
}
2011-01-19 01:19:15 +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:11 +00:00
if ( ! multi_i_am_master ( ) )
return ;
2011-01-19 01:19:15 +00:00
2011-05-19 00:34:06 +00:00
/* Add opcode, target ID and how often we re-assigned */
2011-01-19 01:19:15 +00:00
multibuf [ 0 ] = MULTI_DO_BOUNTY ;
multibuf [ 1 ] = ( char ) Bounty_target ;
/* Send data */
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 2 , 2 ) ;
2011-01-19 01:19:15 +00:00
}
void multi_do_bounty ( char * buf )
{
2011-05-15 09:59:11 +00:00
if ( multi_i_am_master ( ) )
return ;
2011-05-25 13:25:06 +00:00
multi_new_bounty_target ( buf [ 1 ] ) ;
2011-01-19 01:19:15 +00:00
}
void multi_new_bounty_target ( int pnum )
{
/* 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 ) ,
Players [ Bounty_target ] . callsign ) ;
2011-01-19 11:21:59 +00:00
digi_play_sample ( SOUND_CONTROL_CENTER_WARNING_SIREN , F1_0 * 3 ) ;
2011-01-19 01:19:15 +00:00
}
2011-02-09 11:58:28 +00:00
void multi_do_save_game ( char * buf )
{
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 ) ;
}
void multi_do_restore_game ( char * buf )
{
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 ) ;
}
void multi_send_save_game ( ubyte slot , uint id , char * desc )
{
int count = 0 ;
multibuf [ count ] = MULTI_SAVE_GAME ; count + = 1 ;
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 ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , count , 2 ) ;
2011-02-09 11:58:28 +00:00
}
void multi_send_restore_game ( ubyte slot , uint id )
{
int count = 0 ;
multibuf [ count ] = MULTI_RESTORE_GAME ; count + = 1 ;
multibuf [ count ] = slot ; count + = 1 ; // Save slot=0
PUT_INTEL_INT ( multibuf + count , id ) ; count + = 4 ; // Save id
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , count , 2 ) ;
2011-02-09 11:58:28 +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 ( ) )
{
HUD_init_message ( HM_MULTI , " Only host is allowed to save a game! " ) ;
return ;
}
if ( ! multi_all_players_alive ( ) )
{
HUD_init_message ( HM_MULTI , " Can't save! All players must be alive! " ) ;
return ;
}
for ( i = 0 ; i < N_players ; i + + )
{
for ( j = 0 ; j < N_players ; j + + )
{
if ( i ! = j & & ! stricmp ( Players [ i ] . callsign , Players [ j ] . callsign ) )
{
HUD_init_message ( HM_MULTI , " Can't save! Multiple players with same callsign! " ) ;
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:31 +00:00
{
fix call2i ;
memcpy ( & call2i , Players [ i ] . callsign , sizeof ( fix ) ) ;
game_id ^ = call2i ;
}
2011-02-09 11:58:28 +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 ) ;
}
extern int state_get_game_id ( char * ) ;
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 ( ) )
{
HUD_init_message ( HM_MULTI , " Only host is allowed to load a game! " ) ;
return ;
}
if ( ! multi_all_players_alive ( ) )
{
HUD_init_message ( HM_MULTI , " Can't load! All players must be alive! " ) ;
return ;
}
for ( i = 0 ; i < N_players ; i + + )
{
for ( j = 0 ; j < N_players ; j + + )
{
if ( i ! = j & & ! stricmp ( Players [ i ] . callsign , Players [ j ] . callsign ) )
{
HUD_init_message ( HM_MULTI , " Can't load! Multiple players with same callsign! " ) ;
return ;
}
}
}
slot = state_get_restore_file ( filename ) ;
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 ;
snprintf ( filename , PATH_MAX , GameArg . SysUsePlayersDir ? " Players/%s.mg%d " : " %s.mg%d " , Players [ Player_num ] . callsign , slot ) ;
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:11 +00:00
int i ;
2011-02-09 11:58:28 +00:00
int thisid ;
if ( ( Endlevel_sequence ) | | ( Control_center_destroyed ) )
return ;
snprintf ( filename , PATH_MAX , GameArg . SysUsePlayersDir ? " Players/%s.mg%d " : " %s.mg%d " , Players [ Player_num ] . callsign , slot ) ;
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:11 +00:00
state_restore_all_sub ( filename ) ;
2011-04-19 23:47:12 +00:00
multi_send_score ( ) ; // send my restored scores. I sent 0 when I loaded the level anyways...
2011-02-09 11:58:28 +00:00
}
2011-04-11 15:47:12 +00:00
void multi_do_msgsend_state ( char * buf )
{
multi_sending_message [ ( int ) buf [ 1 ] ] = ( int ) buf [ 2 ] ;
}
void multi_send_msgsend_state ( int state )
{
multibuf [ 0 ] = ( char ) MULTI_TYPING_STATE ;
multibuf [ 1 ] = Player_num ;
multibuf [ 2 ] = ( char ) state ;
2011-09-15 08:45:45 +00:00
multi_send_data ( multibuf , 3 , 2 ) ;
2011-04-11 15:47:12 +00:00
}
2011-05-25 13:25:06 +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 [ 0 ] = ( char ) MULTI_GMODE_UPDATE ;
multibuf [ 1 ] = Netgame . team_vector ;
multibuf [ 2 ] = Bounty_target ;
multi_send_data ( multibuf , 3 , 0 ) ;
}
void multi_do_gmode_update ( char * buf )
{
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
}
}
2011-09-13 23:15:20 +00:00
// Following functions convert object to object_rw and back.
2010-12-22 00:17:49 +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 . brakes = obj - > mtype . phys_info . brakes ;
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 . 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 ;
obj_rw - > ctype . ai_info . danger_laser_signature = obj - > ctype . ai_info . danger_laser_signature ;
obj_rw - > ctype . ai_info . danger_laser_num = obj - > ctype . ai_info . danger_laser_num ;
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 ;
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 . brakes = obj_rw - > mtype . phys_info . brakes ;
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 ;
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 . 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 ;
obj - > ctype . ai_info . danger_laser_signature = obj_rw - > ctype . ai_info . danger_laser_signature ;
obj - > ctype . ai_info . danger_laser_num = obj_rw - > ctype . ai_info . danger_laser_num ;
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 ;
break ;
}
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 ;
}
}