2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ( " PARALLAX " ) . PARALLAX , IN DISTRIBUTING THE CODE TO
END - USERS , AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN , GRANTS A
ROYALTY - FREE , PERPETUAL LICENSE TO SUCH END - USERS FOR USE BY SUCH END - USERS
IN USING , DISPLAYING , AND CREATING DERIVATIVE WORKS THEREOF , SO LONG AS
SUCH USE , DISPLAY OR CREATION IS FOR NON - COMMERCIAL , ROYALTY OR REVENUE
FREE PURPOSES . IN NO EVENT SHALL THE END - USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE - BEARING PURPOSES . THE END - USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE .
COPYRIGHT 1993 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* Multiplayer robot code
*
*/
2017-06-25 20:46:03 +00:00
# include <type_traits>
2013-12-16 23:44:34 +00:00
# include "multiinternal.h"
2006-03-20 17:12:09 +00:00
# include <string.h>
# include <stdlib.h>
2015-03-22 04:16:49 +00:00
# include <stdexcept>
2006-03-20 17:12:09 +00:00
# include "vecmat.h"
# include "object.h"
# include "multibot.h"
# include "game.h"
2020-12-20 20:39:07 +00:00
# include "net_udp.h"
2006-03-20 17:12:09 +00:00
# include "laser.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "timer.h"
2015-07-25 23:10:45 +00:00
# include "player.h"
2006-03-20 17:12:09 +00:00
# include "ai.h"
# include "fireball.h"
# include "aistruct.h"
2013-12-26 04:18:28 +00:00
# include "gameseg.h"
2006-03-20 17:12:09 +00:00
# include "robot.h"
# include "powerup.h"
# include "gauges.h"
# include "fuelcen.h"
# include "morph.h"
# include "digi.h"
# include "sounds.h"
# include "effects.h"
2020-07-22 03:11:18 +00:00
# include "automap.h"
2006-03-20 17:12:09 +00:00
# include "physics.h"
2014-07-03 01:47:29 +00:00
# include "byteutil.h"
2012-11-11 00:14:30 +00:00
# include "escort.h"
2006-03-20 17:12:09 +00:00
2014-07-12 04:02:04 +00:00
# include "compiler-range_for.h"
2020-08-10 03:45:14 +00:00
# include "d_levelstate.h"
2015-02-14 22:48:27 +00:00
# include "partial_range.h"
2014-07-12 04:02:04 +00:00
2022-07-16 15:26:12 +00:00
namespace dcx {
namespace {
2022-07-16 15:26:12 +00:00
std : : array < multi_send_robot_position_priority , MAX_ROBOTS_CONTROLLED > robot_send_pending ;
2022-07-16 15:26:12 +00:00
}
2022-07-16 15:26:12 +00:00
std : : array < objnum_t , MAX_ROBOTS_CONTROLLED > robot_controlled ;
2022-07-16 15:26:12 +00:00
std : : array < int , MAX_ROBOTS_CONTROLLED > robot_agitation ;
std : : bitset < MAX_ROBOTS_CONTROLLED > robot_fired ;
}
2022-07-16 15:26:12 +00:00
2016-08-25 04:05:32 +00:00
namespace dsx {
2022-02-05 13:30:56 +00:00
namespace {
2022-07-09 13:39:29 +00:00
static int multi_add_controlled_robot ( vmobjptridx_t objnum , int agitation ) ;
2022-02-05 13:30:56 +00:00
void multi_drop_robot_powerups ( object & objnum ) ;
2022-07-16 15:26:12 +00:00
static void multi_send_robot_position_sub ( const vmobjptridx_t objnum , multiplayer_data_priority now ) ;
2019-12-22 05:34:08 +00:00
static void multi_send_release_robot ( vmobjptridx_t objnum ) ;
2017-06-10 03:31:02 +00:00
static void multi_delete_controlled_robot ( const vmobjptridx_t objnum ) ;
2022-07-09 13:39:29 +00:00
}
}
2006-03-20 17:12:09 +00:00
//
// Code for controlling robots in multiplayer games
//
# define STANDARD_EXPL_DELAY (F1_0 / 4)
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# define MIN_CONTROL_TIME F1_0*2
# define ROBOT_TIMEOUT F1_0*3
# define MAX_TO_DELETE 67
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
# define MIN_CONTROL_TIME F1_0*1
# define ROBOT_TIMEOUT F1_0*2
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
# define MIN_TO_ADD 60
2020-05-02 21:18:42 +00:00
std : : array < fix64 , MAX_ROBOTS_CONTROLLED > robot_controlled_time ,
2015-04-02 02:36:52 +00:00
robot_last_send_time ,
robot_last_message_time ;
2013-03-30 19:41:33 +00:00
ubyte robot_fire_buf [ MAX_ROBOTS_CONTROLLED ] [ 18 + 3 ] ;
2006-03-20 17:12:09 +00:00
# define MULTI_ROBOT_PRIORITY(objnum, pnum) (((objnum % 4) + pnum) % N_players)
//#define MULTI_ROBOT_PRIORITY(objnum, pnum) multi_robot_priority(objnum, pnum)
//int multi_robot_priority(int objnum, int pnum)
//{
// return( ((objnum % 4) + pnum) % N_players);
//}
2017-06-10 03:31:02 +00:00
int multi_can_move_robot ( const vmobjptridx_t objnum , int agitation )
2006-03-20 17:12:09 +00:00
{
2019-08-06 02:59:40 +00:00
auto & BossUniqueState = LevelUniqueObjectState . BossState ;
2006-03-20 17:12:09 +00:00
// Determine whether or not I am allowed to move this robot.
// Claim robot if necessary.
2016-01-09 16:38:10 +00:00
if ( Player_dead_state = = player_dead_state : : exploded )
2006-03-20 17:12:09 +00:00
return 0 ;
2022-02-05 13:30:56 +00:00
auto & objrobot = * objnum ;
if ( objrobot . type ! = OBJ_ROBOT )
2006-03-20 17:12:09 +00:00
{
2018-12-30 00:43:59 +00:00
# ifndef NDEBUG
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
# endif
return 0 ;
2018-12-30 00:43:59 +00:00
}
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2022-02-05 13:30:56 +00:00
if ( Robot_info [ get_robot_id ( objrobot ) ] . boss_flag & & BossUniqueState . Boss_dying )
2018-12-30 00:43:59 +00:00
return 0 ;
2022-02-05 13:30:56 +00:00
else if ( objrobot . ctype . ai_info . REMOTE_OWNER = = Player_num ) // Already my robot!
2006-03-20 17:12:09 +00:00
{
2022-02-05 13:30:56 +00:00
const auto slot_num = objrobot . ctype . ai_info . REMOTE_SLOT_NUM ;
2006-03-20 17:12:09 +00:00
if ( ( slot_num < 0 ) | | ( slot_num > = MAX_ROBOTS_CONTROLLED ) )
{
2018-12-30 00:43:59 +00:00
return 0 ;
2006-03-20 17:12:09 +00:00
}
if ( robot_fired [ slot_num ] ) {
2018-12-30 00:43:59 +00:00
return 0 ;
2006-03-20 17:12:09 +00:00
}
else {
robot_agitation [ slot_num ] = agitation ;
2010-12-22 00:17:59 +00:00
robot_last_message_time [ slot_num ] = GameTime64 ;
2018-12-30 00:43:59 +00:00
return 1 ;
2006-03-20 17:12:09 +00:00
}
}
2022-02-05 13:30:56 +00:00
else if ( objrobot . ctype . ai_info . REMOTE_OWNER ! = - 1 | | agitation < MIN_TO_ADD )
2006-03-20 17:12:09 +00:00
{
if ( agitation = = ROBOT_FIRE_AGITATION ) // Special case for firing at non-player
{
2018-12-30 00:43:59 +00:00
return 1 ; // Try to fire at player even tho we're not in control!
2006-03-20 17:12:09 +00:00
}
else
2018-12-30 00:43:59 +00:00
return 0 ;
2006-03-20 17:12:09 +00:00
}
else
2018-12-30 00:43:59 +00:00
return multi_add_controlled_robot ( objnum , agitation ) ;
2006-03-20 17:12:09 +00:00
}
2016-08-25 04:05:31 +00:00
void multi_check_robot_timeout ( )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2010-12-22 00:17:59 +00:00
static fix64 lastcheck = 0 ;
2006-03-20 17:12:09 +00:00
int i ;
2010-12-22 00:17:59 +00:00
if ( GameTime64 > lastcheck + F1_0 | | lastcheck > GameTime64 )
2006-03-20 17:12:09 +00:00
{
2010-12-22 00:17:59 +00:00
lastcheck = GameTime64 ;
2006-03-20 17:12:09 +00:00
for ( i = 0 ; i < MAX_ROBOTS_CONTROLLED ; i + + )
{
2014-08-20 02:14:29 +00:00
if ( robot_controlled [ i ] ! = object_none & & robot_last_send_time [ i ] + ROBOT_TIMEOUT < GameTime64 )
2006-03-20 17:12:09 +00:00
{
2017-06-10 03:31:02 +00:00
const auto & & robot_objp = vmobjptridx ( robot_controlled [ i ] ) ;
2016-01-09 16:38:14 +00:00
if ( robot_objp - > ctype . ai_info . REMOTE_OWNER ! = Player_num )
2006-03-20 17:12:09 +00:00
{
2014-08-20 02:14:29 +00:00
robot_controlled [ i ] = object_none ;
2006-03-20 17:12:09 +00:00
Int3 ( ) ; // Non-terminal but Rob is interesting, step over please...
return ;
}
2022-07-16 15:26:12 +00:00
if ( robot_send_pending [ i ] ! = multi_send_robot_position_priority : : _0 )
multi_send_robot_position ( robot_objp , multi_send_robot_position_priority : : _2 ) ;
2016-01-09 16:38:14 +00:00
multi_send_release_robot ( robot_objp ) ;
2006-03-20 17:12:09 +00:00
// multi_delete_controlled_robot(robot_controlled[i]);
// robot_controlled[i] = -1;
}
}
}
}
2016-08-25 04:05:31 +00:00
void multi_strip_robots ( const int playernum )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptr = Objects . vmptr ;
auto & vmobjptridx = Objects . vmptridx ;
2006-03-20 17:12:09 +00:00
// Grab all robots away from a player
// (player died or exited the game)
if ( Game_mode & GM_MULTI_ROBOTS ) {
if ( playernum = = Player_num )
2014-07-12 04:02:04 +00:00
{
2015-02-05 03:03:49 +00:00
range_for ( const auto r , robot_controlled )
2014-08-20 02:14:29 +00:00
if ( r ! = object_none )
2017-06-10 03:31:02 +00:00
multi_delete_controlled_robot ( vmobjptridx ( r ) ) ;
2014-07-12 04:02:04 +00:00
}
2006-03-20 17:12:09 +00:00
2016-09-11 18:49:17 +00:00
/* clang-3.7 crashes with a segmentation fault if asked to
* implicitly convert 1u to std : : size_t in partial_range inline
* chain . Add a conversion up front , which seems to avoid the
* bug . The value must not be cast on non - clang targets because
* some non - clang targets issue a ` - Wuseless - cast ` diagnostic
* for the cast . Fortunately , clang does not understand
* ` - Wuseless - cast ` , so the cast can be used on all clang
* targets , even ones where it is useless .
*
* This crash was first seen in x86_64 - pc - linux - gnu - clang - 3.7 ,
* then later reported by kreator in ` Apple LLVM version 7.3 .0 `
* on ` x86_64 - apple - darwin15 .6 .0 ` .
*
* Comment from kreator regarding the clang crash bug :
* This has been reported with Apple , bug report 28247284
*/
# ifdef __clang__
# define DXX_partial_range_vobjptr_skip_distance static_cast<std::size_t>
# else
# define DXX_partial_range_vobjptr_skip_distance
# endif
2017-06-10 03:31:02 +00:00
range_for ( const auto & & objp , partial_range ( vmobjptr , DXX_partial_range_vobjptr_skip_distance ( 1u ) , vmobjptr . count ( ) ) )
2016-09-11 18:49:17 +00:00
# undef DXX_partial_range_vobjptr_skip_distance
2015-06-13 22:42:18 +00:00
{
2018-06-24 05:06:15 +00:00
auto & obj = * objp ;
if ( obj . type = = OBJ_ROBOT & & obj . ctype . ai_info . REMOTE_OWNER = = playernum )
2015-06-13 22:42:18 +00:00
{
2020-08-10 03:45:13 +00:00
assert ( obj . control_source = = object : : control_type : : ai | | obj . control_source = = object : : control_type : : None | | obj . control_source = = object : : control_type : : morph ) ;
2018-06-24 05:06:15 +00:00
obj . ctype . ai_info . REMOTE_OWNER = - 1 ;
2006-03-20 17:12:09 +00:00
if ( playernum = = Player_num )
2018-06-24 05:06:15 +00:00
obj . ctype . ai_info . REMOTE_SLOT_NUM = HANDS_OFF_PERIOD ;
2006-03-20 17:12:09 +00:00
else
2018-06-24 05:06:15 +00:00
obj . ctype . ai_info . REMOTE_SLOT_NUM = 0 ;
2006-03-20 17:12:09 +00:00
}
2015-06-13 22:42:18 +00:00
}
2006-03-20 17:12:09 +00:00
}
// Note -- only call this with playernum == Player_num if all other players
// already know that we are clearing house. This does not send a release
// message for each controlled robot!!
}
2016-08-25 04:05:32 +00:00
namespace dsx {
2022-07-09 13:39:29 +00:00
namespace {
2017-06-10 03:31:02 +00:00
int multi_add_controlled_robot ( const vmobjptridx_t objnum , int agitation )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vcobjptr = Objects . vcptr ;
auto & vmobjptridx = Objects . vmptridx ;
2006-03-20 17:12:09 +00:00
int i ;
2017-02-22 03:05:43 +00:00
int lowest_agitation = INT32_MAX ; // MAX POSITIVE INT
2006-03-20 17:12:09 +00:00
int lowest_agitated_bot = - 1 ;
int first_free_robot = - 1 ;
// Try to add a new robot to the controlled list, return 1 if added, 0 if not.
2022-02-05 13:30:56 +00:00
auto & objrobot = * objnum ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2022-02-05 13:30:56 +00:00
if ( Robot_info [ get_robot_id ( objrobot ) ] . boss_flag ) // this is a boss, so make sure he gets a slot
2006-03-20 17:12:09 +00:00
agitation = ( agitation * 3 ) + Player_num ;
2013-03-03 01:03:33 +00:00
# endif
2022-02-05 13:30:56 +00:00
if ( objrobot . ctype . ai_info . REMOTE_SLOT_NUM > 0 )
2006-03-20 17:12:09 +00:00
{
2022-02-05 13:30:56 +00:00
objrobot . ctype . ai_info . REMOTE_SLOT_NUM - = 1 ;
2006-03-20 17:12:09 +00:00
return 0 ;
}
for ( i = 0 ; i < MAX_ROBOTS_CONTROLLED ; i + + )
{
2015-12-03 03:26:49 +00:00
if ( robot_controlled [ i ] = = object_none | | vcobjptr ( robot_controlled [ i ] ) - > type ! = OBJ_ROBOT ) {
2006-03-20 17:12:09 +00:00
first_free_robot = i ;
break ;
}
2010-12-22 00:17:59 +00:00
if ( robot_last_message_time [ i ] + ROBOT_TIMEOUT < GameTime64 ) {
2017-06-10 03:31:02 +00:00
const auto & & robot_objp = vmobjptridx ( robot_controlled [ i ] ) ;
2022-07-16 15:26:12 +00:00
if ( robot_send_pending [ i ] ! = multi_send_robot_position_priority : : _0 )
multi_send_robot_position ( robot_objp , multi_send_robot_position_priority : : _2 ) ;
2016-01-09 16:38:14 +00:00
multi_send_release_robot ( robot_objp ) ;
2006-03-20 17:12:09 +00:00
first_free_robot = i ;
break ;
}
2014-08-20 02:14:29 +00:00
if ( robot_agitation [ i ] < lowest_agitation & & robot_controlled_time [ i ] + MIN_CONTROL_TIME < GameTime64 )
2006-03-20 17:12:09 +00:00
{
lowest_agitation = robot_agitation [ i ] ;
lowest_agitated_bot = i ;
}
}
if ( first_free_robot ! = - 1 ) // Room left for new robots
i = first_free_robot ;
2013-03-03 01:03:33 +00:00
else if ( ( agitation > lowest_agitation )
# if defined(DXX_BUILD_DESCENT_I)
& & ( lowest_agitation < = MAX_TO_DELETE )
# endif
) // Replace some old robot with a more agitated one
2006-03-20 17:12:09 +00:00
{
2017-06-10 03:31:02 +00:00
const auto & & robot_objp = vmobjptridx ( robot_controlled [ lowest_agitated_bot ] ) ;
2022-07-16 15:26:12 +00:00
if ( robot_send_pending [ lowest_agitated_bot ] ! = multi_send_robot_position_priority : : _0 )
multi_send_robot_position ( robot_objp , multi_send_robot_position_priority : : _2 ) ;
2016-01-09 16:38:14 +00:00
multi_send_release_robot ( robot_objp ) ;
2006-03-20 17:12:09 +00:00
i = lowest_agitated_bot ;
}
else {
return ( 0 ) ; // Sorry, can't squeeze him in!
}
multi_send_claim_robot ( objnum ) ;
robot_controlled [ i ] = objnum ;
robot_agitation [ i ] = agitation ;
2022-02-05 13:30:56 +00:00
objrobot . ctype . ai_info . REMOTE_OWNER = Player_num ;
objrobot . ctype . ai_info . REMOTE_SLOT_NUM = i ;
2010-12-22 00:17:59 +00:00
robot_controlled_time [ i ] = GameTime64 ;
robot_last_send_time [ i ] = robot_last_message_time [ i ] = GameTime64 ;
2006-03-20 17:12:09 +00:00
return ( 1 ) ;
}
2017-06-10 03:31:02 +00:00
void multi_delete_controlled_robot ( const vmobjptridx_t objnum )
2006-03-20 17:12:09 +00:00
{
int i ;
// Delete robot object number objnum from list of controlled robots because it is dead
for ( i = 0 ; i < MAX_ROBOTS_CONTROLLED ; i + + )
if ( robot_controlled [ i ] = = objnum )
break ;
if ( i = = MAX_ROBOTS_CONTROLLED )
return ;
2022-02-05 13:30:56 +00:00
auto & objrobot = * objnum ;
if ( objrobot . ctype . ai_info . REMOTE_SLOT_NUM ! = i )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // can't release this bot!
return ;
}
2022-02-05 13:30:56 +00:00
objrobot . ctype . ai_info . REMOTE_OWNER = - 1 ;
objrobot . ctype . ai_info . REMOTE_SLOT_NUM = 0 ;
2014-08-20 02:14:29 +00:00
robot_controlled [ i ] = object_none ;
2022-07-16 15:26:12 +00:00
robot_send_pending [ i ] = multi_send_robot_position_priority : : _0 ;
2006-03-20 17:12:09 +00:00
robot_fired [ i ] = 0 ;
}
2022-07-09 13:39:29 +00:00
}
}
2006-03-20 17:12:09 +00:00
2014-09-13 23:45:13 +00:00
struct multi_claim_robot
2006-03-20 17:12:09 +00:00
{
2014-09-13 23:45:13 +00:00
uint8_t pnum ;
int8_t owner ;
2015-06-13 22:42:15 +00:00
uint16_t robjnum ;
2014-09-13 23:45:13 +00:00
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_ROBOT_CLAIM , multi_claim_robot , b , ( b . pnum , b . owner , b . robjnum ) ) ;
2006-03-20 17:12:09 +00:00
2017-06-10 03:31:02 +00:00
void multi_send_claim_robot ( const vmobjptridx_t objnum )
2014-09-13 23:45:13 +00:00
{
2014-08-13 02:05:30 +00:00
if ( objnum - > type ! = OBJ_ROBOT )
2014-09-13 23:45:13 +00:00
throw std : : runtime_error ( " claiming non-robot " ) ; // See rob
2006-03-20 17:12:09 +00:00
// The AI tells us we should take control of this robot.
2014-09-13 23:45:13 +00:00
auto r = objnum_local_to_remote ( objnum ) ;
2022-07-09 13:39:29 +00:00
multi_serialize_write ( multiplayer_data_priority : : _2 , multi_claim_robot { static_cast < uint8_t > ( Player_num ) , r . owner , r . objnum } ) ;
2006-03-20 17:12:09 +00:00
}
2022-07-09 13:39:29 +00:00
namespace dsx {
namespace {
2017-06-10 03:31:02 +00:00
void multi_send_release_robot ( const vmobjptridx_t objnum )
2006-03-20 17:12:09 +00:00
{
2017-08-11 23:43:53 +00:00
multi_command < MULTI_ROBOT_RELEASE > multibuf ;
2014-08-13 02:05:30 +00:00
if ( objnum - > type ! = OBJ_ROBOT )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // See rob
return ;
}
multi_delete_controlled_robot ( objnum ) ;
multibuf [ 1 ] = Player_num ;
2021-11-01 03:37:19 +00:00
const auto & & [ obj_owner , remote_objnum ] = objnum_local_to_remote ( objnum ) ;
multibuf [ 4 ] = obj_owner ;
PUT_INTEL_SHORT ( & multibuf [ 2 ] , remote_objnum ) ;
2006-03-20 17:12:09 +00:00
2022-07-09 13:39:29 +00:00
multi_send_data ( multibuf , multiplayer_data_priority : : _2 ) ;
2006-03-20 17:12:09 +00:00
}
2022-07-09 13:39:29 +00:00
}
}
2022-07-16 15:26:12 +00:00
void multi_send_robot_frame ( )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2006-03-20 17:12:09 +00:00
static int last_sent = 0 ;
int i ;
2022-07-16 15:26:12 +00:00
const unsigned sent = 0 ;
2006-03-20 17:12:09 +00:00
for ( i = 0 ; i < MAX_ROBOTS_CONTROLLED ; i + + )
{
int sending = ( last_sent + 1 + i ) % MAX_ROBOTS_CONTROLLED ;
2022-07-16 15:26:12 +00:00
if ( robot_controlled [ sending ] ! = object_none & & ( underlying_value ( robot_send_pending [ sending ] ) > sent | | robot_fired [ sending ] > sent ) )
2006-03-20 17:12:09 +00:00
{
2022-07-16 15:26:12 +00:00
if ( auto & pending = robot_send_pending [ sending ] ; pending ! = multi_send_robot_position_priority : : _0 )
2006-03-20 17:12:09 +00:00
{
2022-07-16 15:26:12 +00:00
const auto p = std : : exchange ( pending , multi_send_robot_position_priority : : _0 ) ;
2022-07-16 15:26:12 +00:00
multi_send_robot_position_sub ( vmobjptridx ( robot_controlled [ sending ] ) , underlying_value ( p ) > 1 ? multiplayer_data_priority : : _1 : multiplayer_data_priority : : _0 ) ;
2006-03-20 17:12:09 +00:00
}
2022-07-16 15:26:12 +00:00
if ( auto & & b = robot_fired [ sending ] )
2006-03-20 17:12:09 +00:00
{
2022-07-16 15:26:12 +00:00
b = 0 ;
2022-07-09 13:39:29 +00:00
multi_send_data < MULTI_ROBOT_FIRE > ( robot_fire_buf [ sending ] , 18 , multiplayer_data_priority : : _1 ) ;
2006-03-20 17:12:09 +00:00
}
last_sent = sending ;
}
}
Assert ( ( last_sent > = 0 ) & & ( last_sent < = MAX_ROBOTS_CONTROLLED ) ) ;
}
2019-06-27 03:26:20 +00:00
namespace dsx {
2022-07-09 13:39:29 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2015-09-03 13:13:56 +00:00
/*
* The thief bot moves around even when not controlled by a player . Due to its erratic and random behaviour , it ' s movement will diverge heavily between players and cause it to teleport when a player takes over .
* To counter this , let host update positions when no one controls it OR the client which does .
2020-12-20 20:39:07 +00:00
* Seperated this function to allow the positions being updated more frequently then multi_send_robot_frame ( see dispatch_table : : do_protocol_frame ( ) ) .
2015-09-03 13:13:56 +00:00
*/
void multi_send_thief_frame ( )
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2015-09-03 13:13:56 +00:00
if ( ! ( Game_mode & GM_MULTI_ROBOTS ) )
return ;
2017-06-10 03:31:02 +00:00
range_for ( const auto & & objp , vmobjptridx )
2015-09-03 13:13:56 +00:00
{
2015-12-03 03:26:49 +00:00
if ( objp - > type = = OBJ_ROBOT )
2015-09-03 13:13:56 +00:00
{
2017-08-26 19:47:51 +00:00
if ( robot_is_thief ( Robot_info [ get_robot_id ( objp ) ] ) )
2015-09-03 13:13:56 +00:00
{
2015-12-03 03:26:49 +00:00
if ( ( multi_i_am_master ( ) & & objp - > ctype . ai_info . REMOTE_OWNER = = - 1 ) | | objp - > ctype . ai_info . REMOTE_OWNER = = Player_num )
2022-07-16 15:26:12 +00:00
multi_send_robot_position_sub ( objp , multiplayer_data_priority : : _1 ) ;
2015-09-03 13:13:56 +00:00
return ;
}
}
}
}
2019-06-27 03:26:20 +00:00
2015-09-03 13:13:56 +00:00
# endif
2022-07-09 13:39:29 +00:00
namespace {
2022-07-16 15:26:12 +00:00
void multi_send_robot_position_sub ( const vmobjptridx_t objnum , const multiplayer_data_priority priority )
2006-03-20 17:12:09 +00:00
{
2017-08-11 23:43:53 +00:00
multi_command < MULTI_ROBOT_POSITION > multibuf ;
2006-03-20 17:12:09 +00:00
int loc = 0 ;
2013-12-16 23:44:34 +00:00
loc + = 1 ;
2015-06-28 17:20:46 +00:00
multibuf [ loc ] = Player_num ; loc + = 1 ;
2021-11-01 03:37:19 +00:00
const auto & & [ obj_owner , remote_objnum ] = objnum_local_to_remote ( objnum ) ;
multibuf [ loc + 2 ] = obj_owner ;
PUT_INTEL_SHORT ( & multibuf [ loc ] , remote_objnum ) ; loc + = 3 ; // 5
2015-06-28 17:20:46 +00:00
quaternionpos qpp { } ;
2018-03-31 21:53:01 +00:00
create_quaternionpos ( qpp , objnum ) ;
2017-08-11 23:43:53 +00:00
PUT_INTEL_SHORT ( & multibuf [ loc ] , qpp . orient . w ) ; loc + = 2 ;
PUT_INTEL_SHORT ( & multibuf [ loc ] , qpp . orient . x ) ; loc + = 2 ;
PUT_INTEL_SHORT ( & multibuf [ loc ] , qpp . orient . y ) ; loc + = 2 ;
PUT_INTEL_SHORT ( & multibuf [ loc ] , qpp . orient . z ) ; loc + = 2 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . pos . x ) ; loc + = 4 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . pos . y ) ; loc + = 4 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . pos . z ) ; loc + = 4 ;
2022-07-02 18:10:45 +00:00
PUT_INTEL_SEGNUM ( & multibuf [ loc ] , qpp . segment ) ; loc + = 2 ;
2017-08-11 23:43:53 +00:00
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . vel . x ) ; loc + = 4 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . vel . y ) ; loc + = 4 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . vel . z ) ; loc + = 4 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . rotvel . x ) ; loc + = 4 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . rotvel . y ) ; loc + = 4 ;
PUT_INTEL_INT ( & multibuf [ loc ] , qpp . rotvel . z ) ; loc + = 4 ; // 46 + 5 = 51
2006-03-20 17:12:09 +00:00
2022-07-16 15:26:12 +00:00
multi_send_data ( multibuf , priority ) ;
2006-03-20 17:12:09 +00:00
}
2022-07-09 13:39:29 +00:00
}
}
2022-07-16 15:26:12 +00:00
void multi_send_robot_position ( object & obj , const multi_send_robot_position_priority force )
2006-03-20 17:12:09 +00:00
{
// Send robot position to other player(s). Includes a byte
// value describing whether or not they fired a weapon
if ( ! ( Game_mode & GM_MULTI ) )
return ;
2016-04-06 03:34:15 +00:00
if ( obj . type ! = OBJ_ROBOT )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // See rob
return ;
}
2016-04-06 03:34:15 +00:00
if ( obj . ctype . ai_info . REMOTE_OWNER ! = Player_num )
2006-03-20 17:12:09 +00:00
return ;
// Objects[objnum].phys_info.drag = Robot_info[Objects[objnum].id].drag; // Set drag to normal
2016-04-06 03:34:15 +00:00
const auto slot = obj . ctype . ai_info . REMOTE_SLOT_NUM ;
robot_last_send_time [ slot ] = GameTime64 ;
2022-07-16 15:26:12 +00:00
robot_send_pending [ slot ] = force ;
2006-03-20 17:12:09 +00:00
return ;
}
2017-06-10 03:31:02 +00:00
void multi_send_robot_fire ( const vmobjptridx_t obj , int gun_num , const vms_vector & fire )
2006-03-20 17:12:09 +00:00
{
2017-08-11 23:43:53 +00:00
multi_command < MULTI_ROBOT_FIRE > multibuf ;
2015-09-10 11:05:10 +00:00
// Send robot fire event
int loc = 0 ;
loc + = 1 ;
multibuf [ loc ] = Player_num ; loc + = 1 ;
2021-11-01 03:37:19 +00:00
const auto & & [ obj_owner , remote_objnum ] = objnum_local_to_remote ( obj ) ;
multibuf [ loc + 2 ] = obj_owner ;
PUT_INTEL_SHORT ( & multibuf [ loc ] , remote_objnum ) ;
2015-09-10 11:05:10 +00:00
loc + = 3 ;
multibuf [ loc ] = gun_num ; loc + = 1 ;
2020-07-05 23:34:33 +00:00
if constexpr ( words_bigendian )
2015-09-10 11:05:10 +00:00
{
vms_vector swapped_vec ;
2016-07-15 03:43:03 +00:00
swapped_vec . x = INTEL_INT ( static_cast < int > ( fire . x ) ) ;
swapped_vec . y = INTEL_INT ( static_cast < int > ( fire . y ) ) ;
swapped_vec . z = INTEL_INT ( static_cast < int > ( fire . z ) ) ;
2015-09-10 11:05:10 +00:00
memcpy ( & multibuf [ loc ] , & swapped_vec , sizeof ( vms_vector ) ) ;
}
else
{
memcpy ( & multibuf [ loc ] , & fire , sizeof ( vms_vector ) ) ;
}
loc + = sizeof ( vms_vector ) ; // 12
// --------------------------
// Total = 18
2006-03-20 17:12:09 +00:00
2015-09-10 11:05:10 +00:00
if ( obj - > ctype . ai_info . REMOTE_OWNER = = Player_num )
{
2022-01-08 17:48:09 +00:00
const auto slot = obj - > ctype . ai_info . REMOTE_SLOT_NUM ;
2015-09-10 11:05:10 +00:00
if ( slot < 0 | | slot > = MAX_ROBOTS_CONTROLLED )
{
return ;
}
2022-07-16 15:26:12 +00:00
if ( auto & & b = robot_fired [ slot ] )
2015-09-10 11:05:10 +00:00
{
// Int3(); // ROB!
return ;
}
2022-07-16 15:26:12 +00:00
else
b = 1 ;
2017-08-11 23:43:53 +00:00
memcpy ( robot_fire_buf [ slot ] , multibuf . data ( ) , loc ) ;
2015-09-10 11:05:10 +00:00
}
else
2022-07-09 13:39:29 +00:00
multi_send_data ( multibuf , multiplayer_data_priority : : _1 ) ; // Not our robot, send ASAP
2006-03-20 17:12:09 +00:00
}
2014-09-14 01:14:33 +00:00
struct multi_explode_robot
2006-03-20 17:12:09 +00:00
{
2014-09-14 01:14:33 +00:00
int16_t robj_killer , robj_killed ;
int8_t owner_killer , owner_killed ;
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_ROBOT_EXPLODE , multi_explode_robot , b , ( b . robj_killer , b . robj_killed , b . owner_killer , b . owner_killed ) ) ;
2013-02-21 00:20:26 +00:00
2017-06-10 03:31:02 +00:00
void multi_send_robot_explode ( const imobjptridx_t objnum , objnum_t killer )
2014-09-14 01:14:33 +00:00
{
// Send robot explosion event to the other players
const auto k = objnum_local_to_remote ( killer ) ;
multi_explode_robot e ;
e . robj_killer = k . objnum ;
e . owner_killer = k . owner ;
const auto d = objnum_local_to_remote ( objnum ) ;
e . robj_killed = d . objnum ;
e . owner_killed = d . owner ;
2022-07-09 13:39:29 +00:00
multi_serialize_write ( multiplayer_data_priority : : _2 , e ) ;
2006-03-20 17:12:09 +00:00
multi_delete_controlled_robot ( objnum ) ;
}
2021-11-01 03:37:20 +00:00
void multi_send_create_robot ( const station_number station , const objnum_t objnum , const int type )
2006-03-20 17:12:09 +00:00
{
2017-08-11 23:43:53 +00:00
multi_command < MULTI_CREATE_ROBOT > multibuf ;
2006-03-20 17:12:09 +00:00
// Send create robot information
int loc = 0 ;
2013-12-16 23:44:34 +00:00
loc + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ loc ] = Player_num ; loc + = 1 ;
2021-11-01 03:37:20 +00:00
static_assert ( sizeof ( underlying_value ( station ) ) = = 1 ) ;
multibuf [ loc ] = underlying_value ( station ) ; loc + = 1 ;
2017-08-11 23:43:53 +00:00
PUT_INTEL_SHORT ( & multibuf [ loc ] , objnum ) ; loc + = 2 ;
2006-03-20 17:12:09 +00:00
multibuf [ loc ] = type ; loc + = 1 ;
2013-12-29 04:28:07 +00:00
map_objnum_local_to_local ( objnum ) ;
2006-03-20 17:12:09 +00:00
2022-07-09 13:39:29 +00:00
multi_send_data ( multibuf , multiplayer_data_priority : : _2 ) ;
2006-03-20 17:12:09 +00:00
}
2019-06-27 03:26:20 +00:00
namespace {
2014-05-24 00:20:30 +00:00
struct boss_teleport
2006-03-20 17:12:09 +00:00
{
2014-05-24 00:20:30 +00:00
objnum_t objnum ;
segnum_t where ;
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_BOSS_TELEPORT , boss_teleport , b , ( b . objnum , b . where ) ) ;
2006-03-20 17:12:09 +00:00
2014-05-24 00:20:30 +00:00
struct boss_cloak
{
objnum_t objnum ;
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_BOSS_CLOAK , boss_cloak , b , ( b . objnum ) ) ;
struct boss_start_gate
{
objnum_t objnum ;
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_BOSS_START_GATE , boss_start_gate , b , ( b . objnum ) ) ;
struct boss_stop_gate
{
objnum_t objnum ;
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_BOSS_STOP_GATE , boss_stop_gate , b , ( b . objnum ) ) ;
struct boss_create_robot
{
objnum_t objnum ;
objnum_t objrobot ;
segnum_t where ;
uint8_t robot_type ;
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_BOSS_CREATE_ROBOT , boss_create_robot , b , ( b . objnum , b . objrobot , b . where , b . robot_type ) ) ;
2019-06-27 03:26:20 +00:00
# if defined(DXX_BUILD_DESCENT_II)
struct update_buddy_state
{
uint8_t Looking_for_marker ;
escort_goal_t Escort_special_goal ;
int Last_buddy_key ;
} ;
DEFINE_MULTIPLAYER_SERIAL_MESSAGE ( MULTI_UPDATE_BUDDY_STATE , update_buddy_state , b , ( b . Looking_for_marker , b . Escort_special_goal , b . Last_buddy_key ) ) ;
# endif
}
2022-07-09 13:39:29 +00:00
namespace {
2014-05-24 00:20:30 +00:00
template < typename T , typename . . . Args >
static inline void multi_send_boss_action ( objnum_t bossobjnum , Args & & . . . args )
{
2022-07-09 13:39:29 +00:00
multi_serialize_write ( multiplayer_data_priority : : _2 , T { bossobjnum , std : : forward < Args > ( args ) . . . } ) ;
2014-05-24 00:20:30 +00:00
}
2022-07-09 13:39:29 +00:00
}
2016-08-25 04:05:32 +00:00
namespace dsx {
2017-06-10 03:31:02 +00:00
void multi_send_boss_teleport ( const vmobjptridx_t bossobj , const vcsegidx_t where )
2014-05-24 00:20:30 +00:00
{
// Boss is up for grabs after teleporting
Assert ( ( bossobj - > ctype . ai_info . REMOTE_SLOT_NUM > = 0 ) & & ( bossobj - > ctype . ai_info . REMOTE_SLOT_NUM < MAX_ROBOTS_CONTROLLED ) ) ;
multi_delete_controlled_robot ( bossobj ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2015-05-23 16:18:20 +00:00
bossobj - > ctype . ai_info . REMOTE_SLOT_NUM = HANDS_OFF_PERIOD ; // Hands-off period!
2013-03-03 01:03:33 +00:00
# endif
2014-05-24 00:20:30 +00:00
multi_send_boss_action < boss_teleport > ( bossobj , where ) ;
}
2016-08-25 04:05:32 +00:00
}
2014-05-24 00:20:30 +00:00
void multi_send_boss_cloak ( objnum_t bossobjnum )
{
multi_send_boss_action < boss_cloak > ( bossobjnum ) ;
}
void multi_send_boss_start_gate ( objnum_t bossobjnum )
{
multi_send_boss_action < boss_start_gate > ( bossobjnum ) ;
}
void multi_send_boss_stop_gate ( objnum_t bossobjnum )
{
multi_send_boss_action < boss_stop_gate > ( bossobjnum ) ;
}
2017-06-10 03:31:02 +00:00
void multi_send_boss_create_robot ( vmobjidx_t bossobjnum , const vmobjptridx_t objrobot )
2014-05-24 00:20:30 +00:00
{
2016-10-29 23:16:16 +00:00
map_objnum_local_to_local ( objrobot ) ;
2016-10-29 23:16:16 +00:00
multi_send_boss_action < boss_create_robot > ( bossobjnum , objrobot , objrobot - > segnum , get_robot_id ( objrobot ) ) ;
2006-03-20 17:12:09 +00:00
}
2014-05-24 00:20:30 +00:00
2006-03-20 17:12:09 +00:00
# define MAX_ROBOT_POWERUPS 4
2016-08-25 04:05:32 +00:00
namespace dsx {
2022-07-09 13:39:29 +00:00
namespace {
2018-06-24 05:06:15 +00:00
static void multi_send_create_robot_powerups ( const object_base & del_obj )
2006-03-20 17:12:09 +00:00
{
2017-08-11 23:43:53 +00:00
multi_command < MULTI_CREATE_ROBOT_POWERUPS > multibuf ;
2006-03-20 17:12:09 +00:00
// Send create robot information
int loc = 0 ;
2013-12-16 23:44:34 +00:00
loc + = 1 ;
2006-03-20 17:12:09 +00:00
multibuf [ loc ] = Player_num ; loc + = 1 ;
2018-06-24 05:06:15 +00:00
multibuf [ loc ] = del_obj . contains_count ; loc + = 1 ;
multibuf [ loc ] = del_obj . contains_type ; loc + = 1 ;
multibuf [ loc ] = del_obj . contains_id ; loc + = 1 ;
2022-07-02 18:10:45 +00:00
PUT_INTEL_SEGNUM ( & multibuf [ loc ] , del_obj . segnum ) ; loc + = 2 ;
2020-07-05 23:34:33 +00:00
if constexpr ( words_bigendian )
2015-06-13 22:42:21 +00:00
{
vms_vector swapped_vec ;
2018-06-24 05:06:15 +00:00
swapped_vec . x = INTEL_INT ( static_cast < int > ( del_obj . pos . x ) ) ;
swapped_vec . y = INTEL_INT ( static_cast < int > ( del_obj . pos . y ) ) ;
swapped_vec . z = INTEL_INT ( static_cast < int > ( del_obj . pos . z ) ) ;
2015-06-13 22:42:21 +00:00
memcpy ( & multibuf [ loc ] , & swapped_vec , sizeof ( vms_vector ) ) ;
loc + = 12 ;
}
else
{
2018-06-24 05:06:15 +00:00
memcpy ( & multibuf [ loc ] , & del_obj . pos , sizeof ( vms_vector ) ) ;
2015-06-13 22:42:21 +00:00
loc + = 12 ;
}
2006-03-20 17:12:09 +00:00
2017-08-11 23:43:53 +00:00
memset ( & multibuf [ loc ] , - 1 , MAX_ROBOT_POWERUPS * sizeof ( short ) ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2018-06-24 05:06:15 +00:00
if ( del_obj . contains_count ! = Net_create_loc )
2006-03-20 17:12:09 +00:00
Int3 ( ) ; //Get Jason, a bad thing happened
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( ( Net_create_loc > MAX_ROBOT_POWERUPS ) | | ( Net_create_loc < 1 ) )
{
Int3 ( ) ; // See Rob
}
2016-02-12 04:02:28 +00:00
range_for ( const auto i , partial_const_range ( Net_create_objnums , Net_create_loc ) )
2006-03-20 17:12:09 +00:00
{
2017-08-11 23:43:53 +00:00
PUT_INTEL_SHORT ( & multibuf [ loc ] , i ) ;
2006-03-20 17:12:09 +00:00
loc + = 2 ;
2015-02-14 22:48:27 +00:00
map_objnum_local_to_local ( i ) ;
2006-03-20 17:12:09 +00:00
}
Net_create_loc = 0 ;
2022-07-09 13:39:29 +00:00
multi_send_data ( multibuf , multiplayer_data_priority : : _2 ) ;
2006-03-20 17:12:09 +00:00
}
2016-08-25 04:05:32 +00:00
}
2022-07-09 13:39:29 +00:00
}
2006-03-20 17:12:09 +00:00
2014-09-21 22:10:12 +00:00
void multi_do_claim_robot ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2014-09-13 23:45:13 +00:00
multi_claim_robot b ;
multi_serialize_read ( buf , b ) ;
2014-11-20 03:00:41 +00:00
auto botnum = objnum_remote_to_local ( b . robjnum , b . owner ) ;
2015-06-13 22:42:15 +00:00
if ( botnum > Highest_object_index )
{
2006-03-20 17:12:09 +00:00
return ;
}
2017-06-10 03:31:02 +00:00
const auto & & botp = vmobjptridx ( botnum ) ;
2015-12-03 03:26:49 +00:00
if ( botp - > type ! = OBJ_ROBOT )
{
2006-03-20 17:12:09 +00:00
return ;
}
2015-12-03 03:26:49 +00:00
if ( botp - > ctype . ai_info . REMOTE_OWNER ! = - 1 )
2006-03-20 17:12:09 +00:00
{
2015-12-03 03:26:49 +00:00
if ( MULTI_ROBOT_PRIORITY ( b . robjnum , pnum ) < = MULTI_ROBOT_PRIORITY ( b . robjnum , botp - > ctype . ai_info . REMOTE_OWNER ) )
2006-03-20 17:12:09 +00:00
return ;
}
// Perform the requested change
2015-12-03 03:26:49 +00:00
if ( botp - > ctype . ai_info . REMOTE_OWNER = = Player_num )
2006-03-20 17:12:09 +00:00
{
2016-01-09 16:38:14 +00:00
multi_delete_controlled_robot ( botp ) ;
2006-03-20 17:12:09 +00:00
}
2015-12-03 03:26:49 +00:00
botp - > ctype . ai_info . REMOTE_OWNER = pnum ;
botp - > ctype . ai_info . REMOTE_SLOT_NUM = 0 ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_do_release_robot ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptr = Objects . vmptr ;
2013-12-29 04:28:07 +00:00
short remote_botnum ;
2006-03-20 17:12:09 +00:00
remote_botnum = GET_INTEL_SHORT ( buf + 2 ) ;
2015-03-22 22:48:47 +00:00
auto botnum = objnum_remote_to_local ( remote_botnum , buf [ 4 ] ) ;
2006-03-20 17:12:09 +00:00
2015-06-13 22:42:15 +00:00
if ( botnum > Highest_object_index )
{
2006-03-20 17:12:09 +00:00
return ;
}
2017-06-10 03:31:02 +00:00
const auto & & botp = vmobjptr ( botnum ) ;
2015-12-03 03:26:49 +00:00
if ( botp - > type ! = OBJ_ROBOT )
{
2006-03-20 17:12:09 +00:00
return ;
}
2015-12-03 03:26:49 +00:00
if ( botp - > ctype . ai_info . REMOTE_OWNER ! = pnum )
2006-03-20 17:12:09 +00:00
{
return ;
}
// Perform the requested change
2015-12-03 03:26:49 +00:00
botp - > ctype . ai_info . REMOTE_OWNER = - 1 ;
botp - > ctype . ai_info . REMOTE_SLOT_NUM = 0 ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_do_robot_position ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2006-03-20 17:12:09 +00:00
// Process robot movement sent by another player
2013-12-29 04:28:07 +00:00
short remote_botnum ;
2006-03-20 17:12:09 +00:00
int loc = 1 ;
2014-05-30 02:38:16 +00:00
; loc + = 1 ;
2006-03-20 17:12:09 +00:00
remote_botnum = GET_INTEL_SHORT ( buf + loc ) ;
2015-03-22 22:48:47 +00:00
auto botnum = objnum_remote_to_local ( remote_botnum , buf [ loc + 2 ] ) ; loc + = 3 ;
2006-03-20 17:12:09 +00:00
2015-06-13 22:42:15 +00:00
if ( botnum > Highest_object_index )
{
2006-03-20 17:12:09 +00:00
return ;
}
2017-06-10 03:31:02 +00:00
const auto robot = vmobjptridx ( botnum ) ;
2014-12-23 04:20:27 +00:00
if ( ( robot - > type ! = OBJ_ROBOT ) | | ( robot - > flags & OF_EXPLODING ) ) {
2006-03-20 17:12:09 +00:00
return ;
}
2022-07-02 18:10:45 +00:00
2014-12-23 04:20:27 +00:00
if ( robot - > ctype . ai_info . REMOTE_OWNER ! = pnum )
2006-03-20 17:12:09 +00:00
{
2014-12-23 04:20:27 +00:00
if ( robot - > ctype . ai_info . REMOTE_OWNER = = - 1 )
2006-03-20 17:12:09 +00:00
{
// Robot claim packet must have gotten lost, let this player claim it.
2015-05-23 16:18:20 +00:00
if ( robot - > ctype . ai_info . REMOTE_SLOT_NUM > = MAX_ROBOTS_CONTROLLED ) { // == HANDS_OFF_PERIOD should do the same trick
2014-12-23 04:20:27 +00:00
robot - > ctype . ai_info . REMOTE_OWNER = pnum ;
robot - > ctype . ai_info . REMOTE_SLOT_NUM = 0 ;
2006-03-20 17:12:09 +00:00
}
else
2014-12-23 04:20:27 +00:00
robot - > ctype . ai_info . REMOTE_SLOT_NUM + + ;
2006-03-20 17:12:09 +00:00
}
else
{
return ;
}
}
2014-12-23 04:20:27 +00:00
set_thrust_from_velocity ( robot ) ; // Try to smooth out movement
2006-03-20 17:12:09 +00:00
// Objects[botnum].phys_info.drag = Robot_info[Objects[botnum].id].drag >> 4; // Set drag to low
2015-06-28 17:20:46 +00:00
quaternionpos qpp { } ;
qpp . orient . w = GET_INTEL_SHORT ( & buf [ loc ] ) ; loc + = 2 ;
qpp . orient . x = GET_INTEL_SHORT ( & buf [ loc ] ) ; loc + = 2 ;
qpp . orient . y = GET_INTEL_SHORT ( & buf [ loc ] ) ; loc + = 2 ;
qpp . orient . z = GET_INTEL_SHORT ( & buf [ loc ] ) ; loc + = 2 ;
qpp . pos . x = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
qpp . pos . y = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
qpp . pos . z = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
2022-07-02 18:10:45 +00:00
if ( const auto s = segnum_t { GET_INTEL_SHORT ( & buf [ loc ] ) } ; vmsegidx_t : : check_nothrow_index ( s ) )
{
qpp . segment = s ;
loc + = 2 ;
}
else
return ;
2015-06-28 17:20:46 +00:00
qpp . vel . x = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
qpp . vel . y = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
qpp . vel . z = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
qpp . rotvel . x = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
qpp . rotvel . y = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
qpp . rotvel . z = GET_INTEL_INT ( & buf [ loc ] ) ; loc + = 4 ;
2018-03-31 21:53:01 +00:00
extract_quaternionpos ( robot , qpp ) ;
2006-03-20 17:12:09 +00:00
}
2016-04-09 21:40:27 +00:00
static inline vms_vector calc_gun_point ( const object_base & obj , unsigned gun_num )
2014-11-02 03:41:01 +00:00
{
vms_vector v ;
return calc_gun_point ( v , obj , gun_num ) , v ;
}
2016-08-25 04:05:32 +00:00
namespace dsx {
2016-08-25 04:05:31 +00:00
void multi_do_robot_fire ( const uint8_t * const buf )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2006-03-20 17:12:09 +00:00
// Send robot fire event
int loc = 1 ;
short remote_botnum ;
2011-07-12 13:34:42 +00:00
int gun_num ;
2014-10-30 03:11:06 +00:00
vms_vector fire ;
2015-09-10 11:05:10 +00:00
loc + = 1 ; // pnum
2006-03-20 17:12:09 +00:00
remote_botnum = GET_INTEL_SHORT ( buf + loc ) ;
2015-09-10 11:05:10 +00:00
auto botnum = objnum_remote_to_local ( remote_botnum , buf [ loc + 2 ] ) ; loc + = 3 ;
2016-06-16 03:56:44 +00:00
gun_num = static_cast < int8_t > ( buf [ loc ] ) ; loc + = 1 ;
2006-03-20 17:12:09 +00:00
memcpy ( & fire , buf + loc , sizeof ( vms_vector ) ) ;
2016-08-17 04:44:22 +00:00
fire . x = INTEL_INT ( fire . x ) ;
fire . y = INTEL_INT ( fire . y ) ;
fire . z = INTEL_INT ( fire . z ) ;
2006-03-20 17:12:09 +00:00
2015-06-13 22:42:15 +00:00
if ( botnum > Highest_object_index )
2006-03-20 17:12:09 +00:00
return ;
2014-12-23 04:20:27 +00:00
2017-06-10 03:31:02 +00:00
auto botp = vmobjptridx ( botnum ) ;
2014-12-23 04:20:27 +00:00
if ( botp - > type ! = OBJ_ROBOT | | botp - > flags & OF_EXPLODING )
return ;
2015-09-10 11:05:10 +00:00
2016-04-09 21:40:27 +00:00
using pt_weapon = std : : pair < vms_vector , weapon_id_type > ;
const pt_weapon pw =
2006-03-20 17:12:09 +00:00
// Do the firing
2016-04-09 21:40:27 +00:00
( gun_num = = - 1
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
| | gun_num = = - 2
# endif
)
2016-04-09 21:40:27 +00:00
? pt_weapon ( vm_vec_add ( botp - > pos , fire ) ,
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2015-12-03 03:26:49 +00:00
gun_num ! = - 1 ? weapon_id_type : : SUPERPROX_ID :
2013-03-03 01:03:33 +00:00
# endif
2016-04-09 21:40:27 +00:00
weapon_id_type : : PROXIMITY_ID )
: pt_weapon ( calc_gun_point ( botp , gun_num ) , get_robot_weapon ( Robot_info [ get_robot_id ( botp ) ] , 1 ) ) ;
2022-07-09 13:39:29 +00:00
Laser_create_new_easy ( Robot_info , fire , pw . first , botp , pw . second , weapon_sound_flag : : audible ) ;
2016-08-25 04:05:32 +00:00
}
2006-03-20 17:12:09 +00:00
2022-07-09 13:39:29 +00:00
int multi_explode_robot_sub ( const d_robot_info_array & Robot_info , const vmobjptridx_t robot )
2006-03-20 17:12:09 +00:00
{
2019-08-06 02:59:40 +00:00
auto & BossUniqueState = LevelUniqueObjectState . BossState ;
2022-02-05 13:30:56 +00:00
auto & objrobot = * robot ;
if ( objrobot . type ! = OBJ_ROBOT ) { // Object is robot?
2006-03-20 17:12:09 +00:00
return 0 ;
}
2022-02-05 13:30:56 +00:00
if ( objrobot . flags & OF_EXPLODING ) { // Object not already exploding
2006-03-20 17:12:09 +00:00
return 0 ;
}
// Data seems valid, explode the sucker
2020-12-20 20:39:07 +00:00
if ( Network_send_objects & & multi : : dispatch - > objnum_is_past ( robot ) )
2006-03-20 17:12:09 +00:00
{
Network_send_objnum = - 1 ;
}
// Drop non-random KEY powerups locally only!
2022-02-05 13:30:56 +00:00
if ( objrobot . contains_count > 0 & & objrobot . contains_type = = OBJ_POWERUP & & ( Game_mode & GM_MULTI_COOP ) & & objrobot . contains_id > = POW_KEY_BLUE & & objrobot . contains_id < = POW_KEY_GOLD )
2006-03-20 17:12:09 +00:00
{
2022-07-09 13:39:29 +00:00
object_create_robot_egg ( Robot_info , objrobot ) ;
2006-03-20 17:12:09 +00:00
}
2022-02-05 13:30:56 +00:00
else if ( objrobot . ctype . ai_info . REMOTE_OWNER = = Player_num )
2006-03-20 17:12:09 +00:00
{
2014-01-11 23:53:58 +00:00
multi_drop_robot_powerups ( robot ) ;
multi_delete_controlled_robot ( robot ) ;
2006-03-20 17:12:09 +00:00
}
2022-02-05 13:30:56 +00:00
else if ( objrobot . ctype . ai_info . REMOTE_OWNER = = - 1 & & multi_i_am_master ( ) )
2006-03-20 17:12:09 +00:00
{
2014-01-11 23:53:58 +00:00
multi_drop_robot_powerups ( robot ) ;
2006-03-20 17:12:09 +00:00
}
2022-02-05 13:30:56 +00:00
const auto robot_id = get_robot_id ( objrobot ) ;
if ( robot_is_thief ( Robot_info [ robot_id ] ) )
2022-02-05 13:30:56 +00:00
drop_stolen_items ( vmsegptridx , LevelUniqueObjectState , Vclip , robot ) ;
2022-05-29 18:44:59 +00:00
if ( Robot_info [ robot_id ] . boss_flag )
2022-02-05 13:30:56 +00:00
{
2019-08-06 02:59:40 +00:00
if ( ! BossUniqueState . Boss_dying )
2022-07-09 13:39:29 +00:00
start_boss_death_sequence ( LevelUniqueObjectState . BossState , Robot_info , robot ) ;
2006-03-20 17:12:09 +00:00
else
return ( 0 ) ;
2013-03-03 01:03:33 +00:00
}
# if defined(DXX_BUILD_DESCENT_II)
2022-02-05 13:30:56 +00:00
else if ( Robot_info [ robot_id ] . death_roll ) {
2006-03-20 17:12:09 +00:00
start_robot_death_sequence ( robot ) ;
2013-03-03 01:03:33 +00:00
}
# endif
else
{
# if defined(DXX_BUILD_DESCENT_II)
2015-11-27 03:56:13 +00:00
if ( robot_id = = SPECIAL_REACTOR_ROBOT )
2006-03-20 17:12:09 +00:00
special_reactor_stuff ( ) ;
2015-11-27 03:56:13 +00:00
if ( Robot_info [ robot_id ] . kamikaze )
2022-07-09 13:39:29 +00:00
explode_object ( LevelUniqueObjectState , Robot_info , LevelSharedSegmentState , LevelUniqueSegmentState , robot , 1 ) ; // Kamikaze, explode right away, IN YOUR FACE!
2006-03-20 17:12:09 +00:00
else
2013-03-03 01:03:33 +00:00
# endif
2022-07-09 13:39:29 +00:00
explode_object ( LevelUniqueObjectState , Robot_info , LevelSharedSegmentState , LevelUniqueSegmentState , robot , STANDARD_EXPL_DELAY ) ;
2006-03-20 17:12:09 +00:00
}
return 1 ;
}
2022-07-09 13:39:29 +00:00
void multi_do_robot_explode ( const d_robot_info_array & Robot_info , const uint8_t * const buf )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2014-09-14 01:14:33 +00:00
multi_explode_robot b ;
multi_serialize_read ( buf , b ) ;
2014-11-20 03:00:41 +00:00
auto killer = objnum_remote_to_local ( b . robj_killer , b . owner_killer ) ;
auto botnum = objnum_remote_to_local ( b . robj_killed , b . owner_killed ) ;
2006-03-20 17:12:09 +00:00
// Explode robot controlled by other player
2015-06-13 22:42:15 +00:00
if ( botnum > Highest_object_index )
{
2006-03-20 17:12:09 +00:00
return ;
}
2017-06-10 03:31:02 +00:00
const auto robot = vmobjptridx ( botnum ) ;
2022-07-09 13:39:29 +00:00
const auto rval = multi_explode_robot_sub ( Robot_info , robot ) ;
2018-04-30 01:11:29 +00:00
if ( ! rval )
return ;
2006-03-20 17:12:09 +00:00
2018-04-30 01:11:29 +00:00
+ + Players [ 0u ] . num_kills_level ;
+ + Players [ 0u ] . num_kills_total ;
if ( killer = = get_local_player ( ) . objnum )
2021-09-12 16:20:52 +00:00
add_points_to_score ( ConsoleObject - > ctype . player_info , Robot_info [ get_robot_id ( robot ) ] . score_value , Game_mode ) ;
2006-03-20 17:12:09 +00:00
}
2022-07-09 13:39:29 +00:00
void multi_do_create_robot ( const d_robot_info_array & Robot_info , const d_vclip_array & Vclip , const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
2020-02-26 05:07:34 +00:00
auto & LevelUniqueMorphObjectState = LevelUniqueObjectState . MorphObjectState ;
2019-02-02 18:36:39 +00:00
auto & Station = LevelUniqueFuelcenterState . Station ;
2020-05-17 23:35:25 +00:00
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2021-11-01 03:37:20 +00:00
const auto untrusted_fuelcen_num = buf [ 2 ] ;
2006-03-20 17:12:09 +00:00
int type = buf [ 5 ] ;
2013-12-29 04:28:07 +00:00
objnum_t objnum ;
2006-03-20 17:12:09 +00:00
objnum = GET_INTEL_SHORT ( buf + 3 ) ;
2021-11-01 03:37:20 +00:00
if ( ! LevelUniqueFuelcenterState . Station . valid_index ( untrusted_fuelcen_num ) )
return ;
if ( untrusted_fuelcen_num > = LevelUniqueFuelcenterState . Num_fuelcenters | | pnum > = N_players )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // Bogus data
return ;
}
2021-11-01 03:37:20 +00:00
auto & robotcen = Station [ ( station_number { untrusted_fuelcen_num } ) ] ;
2006-03-20 17:12:09 +00:00
// Play effect and sound
2021-11-01 03:37:20 +00:00
// Set robot center flags, in case we become the master for the next one
robotcen . Flag = 0 ;
robotcen . Capacity - = EnergyToCreateOneRobot ;
robotcen . Timer = 0 ;
const auto & & robotcen_segp = vmsegptridx ( robotcen . segnum ) ;
2018-12-30 00:43:57 +00:00
auto & vcvertptr = Vertices . vcptr ;
2018-03-12 03:43:47 +00:00
const auto & & cur_object_loc = compute_segment_center ( vcvertptr , robotcen_segp ) ;
2016-01-09 16:38:14 +00:00
if ( const auto & & obj = object_create_explosion ( robotcen_segp , cur_object_loc , i2f ( 10 ) , VCLIP_MORPHING_ROBOT ) )
2018-09-19 02:13:30 +00:00
extract_orient_from_segment ( vcvertptr , obj - > orient , robotcen_segp ) ;
2006-03-20 17:12:09 +00:00
if ( Vclip [ VCLIP_MORPHING_ROBOT ] . sound_num > - 1 )
2022-06-05 17:44:52 +00:00
digi_link_sound_to_pos ( Vclip [ VCLIP_MORPHING_ROBOT ] . sound_num , robotcen_segp , sidenum_t : : WLEFT , cur_object_loc , 0 , F1_0 ) ;
2006-03-20 17:12:09 +00:00
2022-07-09 13:39:29 +00:00
const auto & & obj = create_morph_robot ( Robot_info , robotcen_segp , cur_object_loc , type ) ;
2013-12-24 04:53:59 +00:00
if ( obj = = object_none )
2006-03-20 17:12:09 +00:00
return ; // Cannot create object!
2021-11-01 03:37:20 +00:00
obj - > matcen_creator = untrusted_fuelcen_num | 0x80 ;
2006-03-20 17:12:09 +00:00
// extract_orient_from_segment(&obj->orient, &Segments[robotcen->segnum]);
2014-10-29 03:24:31 +00:00
const auto direction = vm_vec_sub ( ConsoleObject - > pos , obj - > pos ) ;
2014-10-01 02:28:42 +00:00
vm_vector_2_matrix ( obj - > orient , direction , & obj - > orient . uvec , nullptr ) ;
2020-02-26 05:07:34 +00:00
morph_start ( LevelUniqueMorphObjectState , LevelSharedPolygonModelState , obj ) ;
2006-03-20 17:12:09 +00:00
2013-12-24 04:53:59 +00:00
map_objnum_local_to_remote ( obj , objnum , pnum ) ;
2006-03-20 17:12:09 +00:00
Assert ( obj - > ctype . ai_info . REMOTE_OWNER = = - 1 ) ;
}
2019-06-27 03:26:20 +00:00
# if defined(DXX_BUILD_DESCENT_II)
void multi_send_escort_goal ( const d_unique_buddy_state & BuddyState )
{
update_buddy_state b ;
2020-07-22 03:11:18 +00:00
b . Looking_for_marker = static_cast < uint8_t > ( BuddyState . Looking_for_marker ) ;
2019-06-27 03:26:20 +00:00
b . Escort_special_goal = BuddyState . Escort_special_goal ;
b . Last_buddy_key = BuddyState . Last_buddy_key ;
2022-07-09 13:39:29 +00:00
multi_serialize_write ( multiplayer_data_priority : : _2 , b ) ;
2019-06-27 03:26:20 +00:00
}
void multi_recv_escort_goal ( d_unique_buddy_state & BuddyState , const uint8_t * const buf )
{
update_buddy_state b ;
multi_serialize_read ( buf , b ) ;
2020-07-22 03:11:18 +00:00
const auto Looking_for_marker = b . Looking_for_marker ;
BuddyState . Looking_for_marker = MarkerState . imobjidx . valid_index ( Looking_for_marker )
? static_cast < game_marker_index > ( Looking_for_marker )
: game_marker_index : : None ;
2019-06-27 03:26:20 +00:00
BuddyState . Escort_special_goal = b . Escort_special_goal ;
BuddyState . Last_buddy_key = b . Last_buddy_key ;
BuddyState . Buddy_messages_suppressed = 0 ;
BuddyState . Last_buddy_message_time = GameTime64 - 2 * F1_0 ;
BuddyState . Escort_goal_object = ESCORT_GOAL_UNSPECIFIED ;
}
# endif
2022-07-09 13:39:29 +00:00
void multi_do_boss_teleport ( const d_robot_info_array & Robot_info , const d_vclip_array & Vclip , const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
2019-08-06 02:59:40 +00:00
auto & BossUniqueState = LevelUniqueObjectState . BossState ;
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
2020-05-17 23:35:25 +00:00
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2019-03-03 00:31:08 +00:00
auto & vcobjptr = Objects . vcptr ;
auto & vmobjptr = Objects . vmptr ;
2014-05-24 00:20:30 +00:00
boss_teleport b ;
multi_serialize_read ( buf , b ) ;
2019-04-28 00:53:40 +00:00
const auto & & guarded_boss_obj = Objects . vmptridx . check_untrusted ( b . objnum ) ;
if ( ! guarded_boss_obj )
return ;
const auto & & boss_obj = * guarded_boss_obj ;
2013-10-07 23:52:33 +00:00
if ( ( boss_obj - > type ! = OBJ_ROBOT ) | | ! ( Robot_info [ get_robot_id ( boss_obj ) ] . boss_flag ) )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // Got boss actions for a robot who's not a boss?
return ;
}
2019-04-28 00:53:40 +00:00
const auto & & guarded_teleport_segnum = vmsegptridx . check_untrusted ( b . where ) ;
if ( ! guarded_teleport_segnum )
return ;
const auto & & teleport_segnum = * guarded_teleport_segnum ;
2018-12-30 00:43:57 +00:00
auto & vcvertptr = Vertices . vcptr ;
2018-03-12 03:43:47 +00:00
compute_segment_center ( vcvertptr , boss_obj - > pos , teleport_segnum ) ;
2018-03-12 03:43:46 +00:00
obj_relink ( vmobjptr , vmsegptr , boss_obj , teleport_segnum ) ;
2019-08-06 02:59:40 +00:00
BossUniqueState . Last_teleport_time = GameTime64 ;
2006-03-20 17:12:09 +00:00
2017-08-13 20:38:32 +00:00
const auto boss_dir = vm_vec_sub ( vcobjptr ( vcplayerptr ( pnum ) - > objnum ) - > pos , boss_obj - > pos ) ;
2014-10-01 02:28:42 +00:00
vm_vector_2_matrix ( boss_obj - > orient , boss_dir , nullptr , nullptr ) ;
2014-05-24 00:20:30 +00:00
2022-06-05 17:44:52 +00:00
digi_link_sound_to_pos ( Vclip [ VCLIP_MORPHING_ROBOT ] . sound_num , teleport_segnum , sidenum_t : : WLEFT , boss_obj - > pos , 0 , F1_0 ) ;
2014-05-24 00:20:30 +00:00
digi_kill_sound_linked_to_object ( boss_obj ) ;
2022-07-09 13:39:29 +00:00
boss_link_see_sound ( Robot_info , boss_obj ) ;
2014-05-24 00:20:30 +00:00
ai_local * ailp = & boss_obj - > ctype . ai_info . ail ;
ailp - > next_fire = 0 ;
if ( boss_obj - > ctype . ai_info . REMOTE_OWNER = = Player_num )
{
2014-08-20 02:14:29 +00:00
multi_delete_controlled_robot ( boss_obj ) ;
2014-05-24 00:20:30 +00:00
}
boss_obj - > ctype . ai_info . REMOTE_OWNER = - 1 ; // Boss is up for grabs again!
boss_obj - > ctype . ai_info . REMOTE_SLOT_NUM = 0 ; // Available immediately!
}
2015-01-18 01:58:33 +00:00
void multi_do_boss_cloak ( const ubyte * buf )
2014-05-24 00:20:30 +00:00
{
2019-08-06 02:59:40 +00:00
auto & BossUniqueState = LevelUniqueObjectState . BossState ;
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2014-05-24 00:20:30 +00:00
boss_cloak b ;
multi_serialize_read ( buf , b ) ;
2019-04-28 00:53:40 +00:00
const auto & & guarded_boss_obj = vmobjptridx . check_untrusted ( b . objnum ) ;
if ( ! guarded_boss_obj )
return ;
const auto & & boss_obj = * guarded_boss_obj ;
if ( boss_obj - > type ! = OBJ_ROBOT | | ! Robot_info [ get_robot_id ( boss_obj ) ] . boss_flag )
2014-05-24 00:20:30 +00:00
{
Int3 ( ) ; // Got boss actions for a robot who's not a boss?
return ;
}
2019-08-06 02:59:40 +00:00
BossUniqueState . Boss_hit_this_frame = 0 ;
2015-02-08 06:06:01 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2019-08-06 02:59:40 +00:00
BossUniqueState . Boss_hit_time = - F1_0 * 10 ;
2013-03-03 01:03:33 +00:00
# endif
2019-08-06 02:59:40 +00:00
BossUniqueState . Boss_cloak_start_time = GameTime64 ;
2014-05-24 00:20:30 +00:00
boss_obj - > ctype . ai_info . CLOAKED = 1 ;
}
2016-08-25 04:05:32 +00:00
}
2006-03-20 17:12:09 +00:00
2015-01-18 01:58:33 +00:00
void multi_do_boss_start_gate ( const ubyte * buf )
2014-05-24 00:20:30 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2014-05-24 00:20:30 +00:00
boss_start_gate b ;
multi_serialize_read ( buf , b ) ;
2019-04-28 00:53:40 +00:00
const auto & & guarded_boss_obj = vmobjptridx . check_untrusted ( b . objnum ) ;
if ( ! guarded_boss_obj )
return ;
const object_base & boss_obj = * guarded_boss_obj ;
if ( boss_obj . type ! = OBJ_ROBOT | | ! Robot_info [ get_robot_id ( boss_obj ) ] . boss_flag )
2014-05-24 00:20:30 +00:00
{
Int3 ( ) ; // Got boss actions for a robot who's not a boss?
return ;
}
restart_effect ( ECLIP_NUM_BOSS ) ;
}
2015-01-18 01:58:33 +00:00
void multi_do_boss_stop_gate ( const ubyte * buf )
2014-05-24 00:20:30 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2014-05-24 00:20:30 +00:00
boss_start_gate b ;
multi_serialize_read ( buf , b ) ;
2019-04-28 00:53:40 +00:00
const auto & & guarded_boss_obj = vmobjptridx . check_untrusted ( b . objnum ) ;
if ( ! guarded_boss_obj )
return ;
const object_base & boss_obj = * guarded_boss_obj ;
if ( boss_obj . type ! = OBJ_ROBOT | | ! Robot_info [ get_robot_id ( boss_obj ) ] . boss_flag )
2014-05-24 00:20:30 +00:00
{
Int3 ( ) ; // Got boss actions for a robot who's not a boss?
return ;
}
stop_effect ( ECLIP_NUM_BOSS ) ;
}
2014-09-21 22:10:12 +00:00
void multi_do_boss_create_robot ( const playernum_t pnum , const ubyte * buf )
2014-05-24 00:20:30 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2014-05-24 00:20:30 +00:00
boss_create_robot b ;
multi_serialize_read ( buf , b ) ;
2019-04-28 00:53:40 +00:00
const auto & & guarded_boss_obj = vmobjptridx . check_untrusted ( b . objnum ) ;
if ( ! guarded_boss_obj )
return ;
const object_base & boss_obj = * guarded_boss_obj ;
if ( boss_obj . type ! = OBJ_ROBOT | | ! Robot_info [ get_robot_id ( boss_obj ) ] . boss_flag )
2014-05-24 00:20:30 +00:00
{
Int3 ( ) ; // Got boss actions for a robot who's not a boss?
return ;
}
// Do some validity checking
2015-06-13 22:42:15 +00:00
if ( b . objrobot > = MAX_OBJECTS )
2014-05-24 00:20:30 +00:00
{
Int3 ( ) ; // See Rob, bad data in boss gate action message
return ;
2006-03-20 17:12:09 +00:00
}
2014-05-24 00:20:30 +00:00
// Gate one in!
2022-07-09 13:39:29 +00:00
const auto & & robot = gate_in_robot ( Robot_info , b . robot_type , vmsegptridx ( b . where ) ) ;
2016-10-29 23:16:16 +00:00
if ( robot ! = object_none )
map_objnum_local_to_remote ( robot , b . objrobot , pnum ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-21 22:10:12 +00:00
void multi_do_create_robot_powerups ( const playernum_t pnum , const ubyte * buf )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptr = Objects . vmptr ;
2006-03-20 17:12:09 +00:00
// Code to drop remote-controlled robot powerups
int loc = 1 ;
2014-05-30 02:38:16 +00:00
; loc + = 1 ;
2015-05-09 17:39:01 +00:00
uint8_t contains_count = buf [ loc ] ; loc + = 1 ;
uint8_t contains_type = buf [ loc ] ; loc + = 1 ;
uint8_t contains_id = buf [ loc ] ; loc + = 1 ;
2022-07-02 18:10:45 +00:00
const auto segnum = segnum_t { GET_INTEL_SHORT ( & buf [ loc ] ) } ; loc + = 2 ;
if ( ! vmsegidx_t : : check_nothrow_index ( segnum ) )
return ;
2015-05-09 17:39:01 +00:00
vms_vector pos ;
memcpy ( & pos , & buf [ loc ] , sizeof ( pos ) ) ; loc + = 12 ;
2006-03-20 17:12:09 +00:00
2015-05-09 17:39:01 +00:00
vms_vector velocity { } ;
2016-08-17 04:44:22 +00:00
pos . x = INTEL_INT ( pos . x ) ;
pos . y = INTEL_INT ( pos . y ) ;
pos . z = INTEL_INT ( pos . z ) ;
2006-03-20 17:12:09 +00:00
2014-09-20 23:47:27 +00:00
Assert ( pnum < N_players ) ;
2006-03-20 17:12:09 +00:00
Assert ( pnum ! = Player_num ) ; // What? How'd we send ourselves this?
Net_create_loc = 0 ;
d_srand ( 1245L ) ;
2022-07-09 13:39:29 +00:00
if ( ! object_create_robot_egg ( LevelSharedRobotInfoState . Robot_info , contains_type , contains_id , contains_count , velocity , pos , vmsegptridx ( segnum ) ) )
2006-03-20 17:12:09 +00:00
return ; // Object buffer full
Assert ( ( Net_create_loc > 0 ) & & ( Net_create_loc < = MAX_ROBOT_POWERUPS ) ) ;
2016-02-12 04:02:28 +00:00
range_for ( const auto i , partial_const_range ( Net_create_objnums , Net_create_loc ) )
2006-03-20 17:12:09 +00:00
{
short s ;
s = GET_INTEL_SHORT ( buf + loc ) ;
if ( s ! = - 1 )
2015-02-14 22:48:27 +00:00
map_objnum_local_to_remote ( i , s , pnum ) ;
2006-03-20 17:12:09 +00:00
else
2017-06-10 03:31:02 +00:00
vmobjptr ( i ) - > flags | = OF_SHOULD_BE_DEAD ; // Delete objects other guy didn't create one of
2006-03-20 17:12:09 +00:00
loc + = 2 ;
}
}
2022-02-05 13:30:56 +00:00
namespace dsx {
namespace {
void multi_drop_robot_powerups ( object & del_obj )
2006-03-20 17:12:09 +00:00
{
// Code to handle dropped robot powerups in network mode ONLY!
2022-02-05 13:30:56 +00:00
if ( del_obj . type ! = OBJ_ROBOT )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ; // dropping powerups for non-robot, Rob's fault
return ;
}
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2017-08-26 19:47:51 +00:00
auto & robptr = Robot_info [ get_robot_id ( del_obj ) ] ;
2006-03-20 17:12:09 +00:00
Net_create_loc = 0 ;
2022-02-06 16:12:31 +00:00
bool created = false ;
2022-02-05 13:30:56 +00:00
if ( del_obj . contains_count > 0 )
{
2006-03-20 17:12:09 +00:00
// If dropping a weapon that the player has, drop energy instead, unless it's vulcan, in which case drop vulcan ammo.
2022-02-05 13:30:56 +00:00
if ( del_obj . contains_type = = OBJ_POWERUP ) {
2006-03-20 17:12:09 +00:00
maybe_replace_powerup_with_energy ( del_obj ) ;
2022-02-05 13:30:56 +00:00
if ( ! multi_powerup_is_allowed ( del_obj . contains_id , Netgame . AllowedItems ) )
del_obj . contains_id = POW_SHIELD_BOOST ;
2006-03-20 17:12:09 +00:00
// No key drops in non-coop games!
if ( ! ( Game_mode & GM_MULTI_COOP ) ) {
2022-02-05 13:30:56 +00:00
if ( del_obj . contains_id > = POW_KEY_BLUE & & del_obj . contains_id < = POW_KEY_GOLD )
del_obj . contains_count = 0 ;
2006-03-20 17:12:09 +00:00
}
}
d_srand ( 1245L ) ;
2022-02-05 13:30:56 +00:00
if ( del_obj . contains_count > 0 )
2022-07-09 13:39:29 +00:00
created = object_create_robot_egg ( LevelSharedRobotInfoState . Robot_info , del_obj ) ;
2006-03-20 17:12:09 +00:00
}
2022-02-05 13:30:56 +00:00
else if ( del_obj . ctype . ai_info . REMOTE_OWNER = = - 1 ) // No random goodies for robots we weren't in control of
2006-03-20 17:12:09 +00:00
return ;
2017-08-26 19:47:51 +00:00
else if ( robptr . contains_count ) {
2016-07-07 03:08:13 +00:00
d_srand ( static_cast < fix > ( timer_query ( ) ) ) ;
2017-08-26 19:47:51 +00:00
if ( ( ( d_rand ( ) * 16 ) > > 15 ) < robptr . contains_prob ) {
2022-02-05 13:30:56 +00:00
del_obj . contains_count = ( ( d_rand ( ) * robptr . contains_count ) > > 15 ) + 1 ;
del_obj . contains_type = robptr . contains_type ;
del_obj . contains_id = robptr . contains_id ;
if ( del_obj . contains_type = = OBJ_POWERUP )
2006-03-20 17:12:09 +00:00
{
maybe_replace_powerup_with_energy ( del_obj ) ;
2022-02-05 13:30:56 +00:00
if ( ! multi_powerup_is_allowed ( del_obj . contains_id , Netgame . AllowedItems ) )
del_obj . contains_id = POW_SHIELD_BOOST ;
2006-03-20 17:12:09 +00:00
}
d_srand ( 1245L ) ;
2022-02-05 13:30:56 +00:00
if ( del_obj . contains_count > 0 )
2022-07-09 13:39:29 +00:00
created = object_create_robot_egg ( LevelSharedRobotInfoState . Robot_info , del_obj ) ;
2006-03-20 17:12:09 +00:00
}
}
2022-02-06 16:12:31 +00:00
if ( created )
2006-03-20 17:12:09 +00:00
// Transmit the object creation to the other players
multi_send_create_robot_powerups ( del_obj ) ;
}
2022-02-05 13:30:56 +00:00
}
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------
// Robot *robot got whacked by player player_num and requests permission to do something about it.
// Note: This function will be called regardless of whether Game_mode is a multiplayer mode, so it
// should quick-out if not in a multiplayer mode. On the other hand, it only gets called when a
// player or player weapon whacks a robot, so it happens rarely.
2017-06-10 03:31:02 +00:00
void multi_robot_request_change ( const vmobjptridx_t robot , int player_num )
2006-03-20 17:12:09 +00:00
{
if ( ! ( Game_mode & GM_MULTI_ROBOTS ) )
return ;
2022-02-05 13:30:56 +00:00
auto & objrobot = * robot ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2022-02-05 13:30:56 +00:00
if ( objrobot . ctype . ai_info . REMOTE_OWNER ! = Player_num )
2013-03-03 01:03:33 +00:00
return ;
# endif
2006-03-20 17:12:09 +00:00
2022-02-05 13:30:56 +00:00
const auto slot = objrobot . ctype . ai_info . REMOTE_SLOT_NUM ;
2006-03-20 17:12:09 +00:00
2015-05-23 16:18:20 +00:00
if ( slot = = HANDS_OFF_PERIOD )
2015-04-19 19:12:33 +00:00
{
2022-02-05 13:30:56 +00:00
con_printf ( CON_DEBUG , " Suppressing debugger trap for hands off robot %hu with player %i " , robot . get_unchecked_index ( ) , player_num ) ;
2015-04-19 19:12:33 +00:00
return ;
}
2006-03-20 17:12:09 +00:00
if ( ( slot < 0 ) | | ( slot > = MAX_ROBOTS_CONTROLLED ) ) {
Int3 ( ) ;
return ;
}
2015-04-19 04:18:54 +00:00
if ( robot_controlled [ slot ] = = object_none )
return ;
2015-12-22 04:18:51 +00:00
const auto & & rcrobot = robot . absolute_sibling ( robot_controlled [ slot ] ) ;
2021-11-01 03:37:19 +00:00
const auto remote_objnum = objnum_local_to_remote ( robot ) . objnum ;
if ( remote_objnum > = MAX_OBJECTS )
2006-03-20 17:12:09 +00:00
return ;
if ( ( robot_agitation [ slot ] < 70 ) | | ( MULTI_ROBOT_PRIORITY ( remote_objnum , player_num ) > MULTI_ROBOT_PRIORITY ( remote_objnum , Player_num ) ) | | ( d_rand ( ) > 0x4400 ) )
{
2022-07-16 15:26:12 +00:00
if ( robot_send_pending [ slot ] ! = multi_send_robot_position_priority : : _0 )
multi_send_robot_position ( rcrobot , multi_send_robot_position_priority : : _0 ) ;
2015-04-19 04:18:54 +00:00
multi_send_release_robot ( rcrobot ) ;
2022-02-05 13:30:56 +00:00
objrobot . ctype . ai_info . REMOTE_SLOT_NUM = HANDS_OFF_PERIOD ; // Hands-off period
2006-03-20 17:12:09 +00:00
}
}
2019-06-27 03:26:20 +00:00
2016-08-25 04:05:32 +00:00
}