Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
| 3 | * described in COPYING.txt. |
||
| 4 | * Portions of this file are copyright Parallax Software and licensed |
||
| 5 | * according to the Parallax license below. |
||
| 6 | * See COPYING.txt for license details. |
||
| 7 | |||
| 8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
| 9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
| 10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
| 11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
| 12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
| 13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
| 14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
| 15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
| 16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
| 17 | COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
| 18 | */ |
||
| 19 | |||
| 20 | /* |
||
| 21 | * |
||
| 22 | * Defines and exported variables for multi.c |
||
| 23 | * |
||
| 24 | */ |
||
| 25 | |||
| 26 | #pragma once |
||
| 27 | |||
| 28 | #include <type_traits> |
||
| 29 | #include "dxxsconf.h" |
||
| 30 | #include "fwd-partial_range.h" |
||
| 31 | #include "fwd-player.h" |
||
| 32 | #include "player-callsign.h" |
||
| 33 | #include "player-flags.h" |
||
| 34 | #include "weapon.h" |
||
| 35 | #include "mission.h" |
||
| 36 | #include "newmenu.h" |
||
| 37 | #include "powerup.h" |
||
| 38 | #include "fwd-object.h" |
||
| 39 | #include "fwd-wall.h" |
||
| 40 | #include "window.h" |
||
| 41 | #include "game.h" |
||
| 42 | #include "gameplayopt.h" |
||
| 43 | |||
| 44 | #ifdef _WIN32 |
||
| 45 | #include <winsock2.h> |
||
| 46 | #include <ws2tcpip.h> |
||
| 47 | #include <io.h> |
||
| 48 | #else |
||
| 49 | #include <sys/socket.h> |
||
| 50 | #include <netinet/in.h> |
||
| 51 | #include <netdb.h> |
||
| 52 | #include <arpa/inet.h> |
||
| 53 | #include <unistd.h> |
||
| 54 | #include <stdint.h> |
||
| 55 | #include <sys/time.h> |
||
| 56 | #endif |
||
| 57 | |||
| 58 | #ifdef __cplusplus |
||
| 59 | #include <stdexcept> |
||
| 60 | #include "digi.h" |
||
| 61 | #include "pack.h" |
||
| 62 | #include "ntstring.h" |
||
| 63 | #include "compiler-static_assert.h" |
||
| 64 | #include <array> |
||
| 65 | |||
| 66 | namespace dcx { |
||
| 67 | |||
| 68 | struct _sockaddr |
||
| 69 | { |
||
| 70 | union { |
||
| 71 | sockaddr sa; |
||
| 72 | sockaddr_in sin; |
||
| 73 | #if DXX_USE_IPv6 |
||
| 74 | sockaddr_in6 sin6; |
||
| 75 | #define DXX_IPv6(v4,v6) v6 |
||
| 76 | #else |
||
| 77 | #define DXX_IPv6(v4,v6) v4 |
||
| 78 | #endif |
||
| 79 | }; |
||
| 80 | enum { |
||
| 81 | presentation_buffer_size = DXX_IPv6(INET_ADDRSTRLEN, INET6_ADDRSTRLEN), |
||
| 82 | }; |
||
| 83 | static int address_family() |
||
| 84 | { |
||
| 85 | return DXX_IPv6(AF_INET, AF_INET6); |
||
| 86 | } |
||
| 87 | static int protocol_family() |
||
| 88 | { |
||
| 89 | return DXX_IPv6(PF_INET, PF_INET6); |
||
| 90 | } |
||
| 91 | #undef DXX_IPv6 |
||
| 92 | }; |
||
| 93 | |||
| 94 | // PROTOCOL VARIABLES AND DEFINES |
||
| 95 | extern int multi_protocol; // set and determinate used protocol |
||
| 96 | |||
| 97 | } |
||
| 98 | #define MULTI_PROTO_UDP 1 // UDP protocol |
||
| 99 | |||
| 100 | // What version of the multiplayer protocol is this? Increment each time something drastic changes in Multiplayer without the version number changes. Reset to 0 each time the version of the game changes |
||
| 101 | #define MULTI_PROTO_VERSION static_cast<uint16_t>(11) |
||
| 102 | // PROTOCOL VARIABLES AND DEFINES - END |
||
| 103 | |||
| 104 | // limits for Packets (i.e. positional updates) per sec |
||
| 105 | #define DEFAULT_PPS 30 |
||
| 106 | #define MIN_PPS 5 |
||
| 107 | #define MAX_PPS 40 |
||
| 108 | |||
| 109 | #define MAX_MESSAGE_LEN 35 |
||
| 110 | |||
| 111 | |||
| 112 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 113 | #define MAX_NET_CREATE_OBJECTS 20 |
||
| 114 | #define MAX_MULTI_MESSAGE_LEN 90 //didn't change it, just moved it up |
||
| 115 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 116 | #define MAX_NET_CREATE_OBJECTS 40 |
||
| 117 | #define MAX_MULTI_MESSAGE_LEN 120 |
||
| 118 | |||
| 119 | #endif |
||
| 120 | |||
| 121 | #define NETGAME_ANARCHY 0 |
||
| 122 | #define NETGAME_TEAM_ANARCHY 1 |
||
| 123 | #define NETGAME_ROBOT_ANARCHY 2 |
||
| 124 | #define NETGAME_COOPERATIVE 3 |
||
| 125 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 126 | #define NETGAME_CAPTURE_FLAG 4 |
||
| 127 | #define NETGAME_HOARD 5 |
||
| 128 | #define NETGAME_TEAM_HOARD 6 |
||
| 129 | #endif |
||
| 130 | #define NETGAME_BOUNTY 7 |
||
| 131 | |||
| 132 | #define NETSTAT_MENU 0 |
||
| 133 | #define NETSTAT_PLAYING 1 |
||
| 134 | #define NETSTAT_BROWSING 2 |
||
| 135 | #define NETSTAT_WAITING 3 |
||
| 136 | #define NETSTAT_STARTING 4 |
||
| 137 | #define NETSTAT_ENDLEVEL 5 |
||
| 138 | |||
| 139 | #define CONNECT_DISCONNECTED 0 |
||
| 140 | #define CONNECT_PLAYING 1 |
||
| 141 | #define CONNECT_WAITING 2 |
||
| 142 | #define CONNECT_DIED_IN_MINE 3 |
||
| 143 | #define CONNECT_FOUND_SECRET 4 |
||
| 144 | #define CONNECT_ESCAPE_TUNNEL 5 |
||
| 145 | #define CONNECT_END_MENU 6 |
||
| 146 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 147 | #define CONNECT_KMATRIX_WAITING 7 // Like CONNECT_WAITING but used especially in kmatrix.c to seperate "escaped" and "waiting" |
||
| 148 | #endif |
||
| 149 | |||
| 150 | // reasons for a packet with type PID_DUMP |
||
| 151 | #define DUMP_CLOSED 0 // no new players allowed after game started |
||
| 152 | #define DUMP_FULL 1 // player cound maxed out |
||
| 153 | #define DUMP_ENDLEVEL 2 |
||
| 154 | #define DUMP_DORK 3 |
||
| 155 | #define DUMP_ABORTED 4 |
||
| 156 | #define DUMP_CONNECTED 5 // never used |
||
| 157 | #define DUMP_LEVEL 6 |
||
| 158 | #define DUMP_KICKED 7 |
||
| 159 | #define DUMP_PKTTIMEOUT 8 |
||
| 160 | |||
| 161 | #if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II) |
||
| 162 | #define NETFLAG_LABEL_QUAD "Quad Lasers" |
||
| 163 | #define NETFLAG_LABEL_VULCAN "Vulcan cannon" |
||
| 164 | #define NETFLAG_LABEL_SPREAD "Spreadfire cannon" |
||
| 165 | #define NETFLAG_LABEL_PLASMA "Plasma cannon" |
||
| 166 | #define NETFLAG_LABEL_FUSION "Fusion cannon" |
||
| 167 | #define for_each_netflag_value(VALUE) \ |
||
| 168 | VALUE(NETFLAG_DOLASER, "Laser upgrade") \ |
||
| 169 | VALUE(NETFLAG_DOQUAD, NETFLAG_LABEL_QUAD) \ |
||
| 170 | VALUE(NETFLAG_DOVULCAN, NETFLAG_LABEL_VULCAN) \ |
||
| 171 | VALUE(NETFLAG_DOSPREAD, NETFLAG_LABEL_SPREAD) \ |
||
| 172 | VALUE(NETFLAG_DOPLASMA, NETFLAG_LABEL_PLASMA) \ |
||
| 173 | VALUE(NETFLAG_DOFUSION, NETFLAG_LABEL_FUSION) \ |
||
| 174 | VALUE(NETFLAG_DOHOMING, "Homing Missiles") \ |
||
| 175 | VALUE(NETFLAG_DOPROXIM, "Proximity Bombs") \ |
||
| 176 | VALUE(NETFLAG_DOSMART, "Smart Missiles") \ |
||
| 177 | VALUE(NETFLAG_DOMEGA, "Mega Missiles") \ |
||
| 178 | VALUE(NETFLAG_DOCLOAK, "Cloaking") \ |
||
| 179 | VALUE(NETFLAG_DOINVUL, "Invulnerability") \ |
||
| 180 | D2X_MP_NETFLAGS(VALUE) \ |
||
| 181 | |||
| 182 | #define for_each_netgrant_value(VALUE) \ |
||
| 183 | VALUE(NETGRANT_QUAD, NETFLAG_LABEL_QUAD) \ |
||
| 184 | VALUE(NETGRANT_VULCAN, NETFLAG_LABEL_VULCAN) \ |
||
| 185 | VALUE(NETGRANT_SPREAD, NETFLAG_LABEL_SPREAD) \ |
||
| 186 | VALUE(NETGRANT_PLASMA, NETFLAG_LABEL_PLASMA) \ |
||
| 187 | VALUE(NETGRANT_FUSION, NETFLAG_LABEL_FUSION) \ |
||
| 188 | D2X_MP_NETGRANT(VALUE) |
||
| 189 | |||
| 190 | #define MULTI_GAME_TYPE_COUNT 8 |
||
| 191 | namespace dsx { |
||
| 192 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 193 | constexpr std::integral_constant<unsigned, 13> MULTI_GAME_NAME_LENGTH{}; |
||
| 194 | constexpr std::integral_constant<unsigned, 18> MULTI_ALLOW_POWERUP_TEXT_LENGTH{}; |
||
| 195 | #define MULTI_ALLOW_POWERUP_MAX 12 |
||
| 196 | #define D2X_MP_NETFLAGS(VALUE) |
||
| 197 | #define DXX_GRANT_LASER_LEVEL_BITS 2 |
||
| 198 | #define D2X_MP_NETGRANT(VALUE) |
||
| 199 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 200 | constexpr std::integral_constant<unsigned, 17> MULTI_GAME_NAME_LENGTH{}; |
||
| 201 | constexpr std::integral_constant<unsigned, 21> MULTI_ALLOW_POWERUP_TEXT_LENGTH{}; |
||
| 202 | #define MULTI_ALLOW_POWERUP_MAX 26 |
||
| 203 | #define NETFLAG_LABEL_GAUSS "Gauss cannon" |
||
| 204 | #define NETFLAG_LABEL_HELIX "Helix cannon" |
||
| 205 | #define NETFLAG_LABEL_PHOENIX "Phoenix cannon" |
||
| 206 | #define NETFLAG_LABEL_OMEGA "Omega cannon" |
||
| 207 | #define NETFLAG_LABEL_AFTERBURNER "Afterburners" |
||
| 208 | #define NETFLAG_LABEL_AMMORACK "Ammo rack" |
||
| 209 | #define NETFLAG_LABEL_CONVERTER "Energy Converter" |
||
| 210 | #define NETFLAG_LABEL_HEADLIGHT "Headlight" |
||
| 211 | #define D2X_MP_NETFLAGS(VALUE) \ |
||
| 212 | VALUE(NETFLAG_DOSUPERLASER, "Super lasers") \ |
||
| 213 | VALUE(NETFLAG_DOGAUSS, NETFLAG_LABEL_GAUSS) \ |
||
| 214 | VALUE(NETFLAG_DOHELIX, NETFLAG_LABEL_HELIX) \ |
||
| 215 | VALUE(NETFLAG_DOPHOENIX, NETFLAG_LABEL_PHOENIX) \ |
||
| 216 | VALUE(NETFLAG_DOOMEGA, NETFLAG_LABEL_OMEGA) \ |
||
| 217 | VALUE(NETFLAG_DOFLASH, "Flash Missiles") \ |
||
| 218 | VALUE(NETFLAG_DOGUIDED, "Guided Missiles") \ |
||
| 219 | VALUE(NETFLAG_DOSMARTMINE, "Smart Mines") \ |
||
| 220 | VALUE(NETFLAG_DOMERCURY, "Mercury Missiles") \ |
||
| 221 | VALUE(NETFLAG_DOSHAKER, "Earthshaker Missiles") \ |
||
| 222 | VALUE(NETFLAG_DOAFTERBURNER, NETFLAG_LABEL_AFTERBURNER) \ |
||
| 223 | VALUE(NETFLAG_DOAMMORACK, NETFLAG_LABEL_AMMORACK) \ |
||
| 224 | VALUE(NETFLAG_DOCONVERTER, NETFLAG_LABEL_CONVERTER) \ |
||
| 225 | VALUE(NETFLAG_DOHEADLIGHT, NETFLAG_LABEL_HEADLIGHT) |
||
| 226 | |||
| 227 | #define DXX_GRANT_LASER_LEVEL_BITS 3 |
||
| 228 | #define D2X_MP_NETGRANT(VALUE) \ |
||
| 229 | VALUE(NETGRANT_GAUSS, NETFLAG_LABEL_GAUSS) \ |
||
| 230 | VALUE(NETGRANT_HELIX, NETFLAG_LABEL_HELIX) \ |
||
| 231 | VALUE(NETGRANT_PHOENIX, NETFLAG_LABEL_PHOENIX) \ |
||
| 232 | VALUE(NETGRANT_OMEGA, NETFLAG_LABEL_OMEGA) \ |
||
| 233 | VALUE(NETGRANT_AFTERBURNER, NETFLAG_LABEL_AFTERBURNER) \ |
||
| 234 | VALUE(NETGRANT_AMMORACK, NETFLAG_LABEL_AMMORACK) \ |
||
| 235 | VALUE(NETGRANT_CONVERTER, NETFLAG_LABEL_CONVERTER) \ |
||
| 236 | VALUE(NETGRANT_HEADLIGHT, NETFLAG_LABEL_HEADLIGHT) |
||
| 237 | |||
| 238 | #endif |
||
| 239 | } |
||
| 240 | |||
| 241 | #define define_netflag_bit_enum(NAME,STR) BIT_##NAME, |
||
| 242 | #define define_netflag_bit_mask(NAME,STR) static constexpr auto NAME = std::integral_constant<unsigned, (1 << BIT_##NAME)>{}; |
||
| 243 | #define define_netflag_powerup_mask(NAME,STR) | (NAME) |
||
| 244 | enum { for_each_netflag_value(define_netflag_bit_enum) }; |
||
| 245 | // Bitmask for netgame_info->AllowedItems to set allowed items in Netgame |
||
| 246 | for_each_netflag_value(define_netflag_bit_mask); |
||
| 247 | enum { NETFLAG_DOPOWERUP = 0 for_each_netflag_value(define_netflag_powerup_mask) }; |
||
| 248 | enum { |
||
| 249 | BIT_NETGRANT_LASER = DXX_GRANT_LASER_LEVEL_BITS - 1, |
||
| 250 | for_each_netgrant_value(define_netflag_bit_enum) |
||
| 251 | BIT_NETGRANT_MAXIMUM |
||
| 252 | }; |
||
| 253 | for_each_netgrant_value(define_netflag_bit_mask); |
||
| 254 | #undef define_netflag_bit_enum |
||
| 255 | #undef define_netflag_bit_mask |
||
| 256 | #undef define_netflag_powerup_mask |
||
| 257 | |||
| 258 | namespace dsx { |
||
| 259 | |||
| 260 | struct packed_spawn_granted_items |
||
| 261 | { |
||
| 262 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 263 | typedef uint8_t mask_type; |
||
| 264 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 265 | typedef uint16_t mask_type; |
||
| 266 | #endif |
||
| 267 | mask_type mask; |
||
| 268 | static_assert(BIT_NETGRANT_MAXIMUM <= sizeof(mask) << 3, "mask too small"); |
||
| 269 | packed_spawn_granted_items() = default; |
||
| 270 | constexpr packed_spawn_granted_items(mask_type m) : |
||
| 271 | mask(m) |
||
| 272 | { |
||
| 273 | } |
||
| 274 | template <unsigned U> |
||
| 275 | constexpr packed_spawn_granted_items(std::integral_constant<unsigned, U>) : |
||
| 276 | mask(U) |
||
| 277 | { |
||
| 278 | assert_equal(U, static_cast<mask_type>(U), "truncation error"); |
||
| 279 | } |
||
| 280 | explicit operator bool() const { return mask; } |
||
| 281 | bool has_quad_laser() const { return mask & NETGRANT_QUAD; } |
||
| 282 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 283 | bool has_afterburner() const { return mask & NETGRANT_AFTERBURNER; } |
||
| 284 | #endif |
||
| 285 | }; |
||
| 286 | |||
| 287 | class packed_netduplicate_items |
||
| 288 | { |
||
| 289 | public: |
||
| 290 | enum |
||
| 291 | { |
||
| 292 | primary_shift = 0, |
||
| 293 | primary_width = 3, |
||
| 294 | secondary_shift = primary_shift + primary_width, |
||
| 295 | secondary_width = 3, |
||
| 296 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 297 | accessory_shift = secondary_shift + secondary_width, |
||
| 298 | accessory_width = 3, |
||
| 299 | #endif |
||
| 300 | }; |
||
| 301 | private: |
||
| 302 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 303 | typedef uint8_t count_type; |
||
| 304 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 305 | typedef uint16_t count_type; |
||
| 306 | #endif |
||
| 307 | count_type count; |
||
| 308 | template <uint_fast32_t shift, uint_fast32_t width> |
||
| 309 | uint_fast32_t get_sub_field() const |
||
| 310 | { |
||
| 311 | static_assert(shift + width <= sizeof(count) << 3, "shift+width too big"); |
||
| 312 | constexpr auto low_mask = (1 << width) - 1; |
||
| 313 | return (count >> shift) & low_mask; |
||
| 314 | } |
||
| 315 | public: |
||
| 316 | template <uint_fast32_t shift, uint_fast32_t width> |
||
| 317 | void set_sub_field(uint_fast32_t value) |
||
| 318 | { |
||
| 319 | constexpr auto low_mask = (1 << width) - 1; |
||
| 320 | constexpr auto shifted_mask = low_mask << shift; |
||
| 321 | count = (count & ~shifted_mask) | (value << shift); |
||
| 322 | } |
||
| 323 | #define DEFINE_ACCESSOR(N) \ |
||
| 324 | uint_fast32_t get_##N##_count() const \ |
||
| 325 | { \ |
||
| 326 | return get_sub_field<N##_shift, N##_width>(); \ |
||
| 327 | } \ |
||
| 328 | void set_##N##_count(uint_fast32_t value) \ |
||
| 329 | { \ |
||
| 330 | set_sub_field<N##_shift, N##_width>(value); \ |
||
| 331 | } |
||
| 332 | DEFINE_ACCESSOR(primary); |
||
| 333 | DEFINE_ACCESSOR(secondary); |
||
| 334 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 335 | DEFINE_ACCESSOR(accessory); |
||
| 336 | #endif |
||
| 337 | count_type get_packed_field() const |
||
| 338 | { |
||
| 339 | return count; |
||
| 340 | } |
||
| 341 | void set_packed_field(count_type c) |
||
| 342 | { |
||
| 343 | count = c; |
||
| 344 | } |
||
| 345 | }; |
||
| 346 | |||
| 347 | static inline laser_level_t map_granted_flags_to_laser_level(const packed_spawn_granted_items &grant) |
||
| 348 | { |
||
| 349 | /* Laser level in lowest bits */ |
||
| 350 | return laser_level_t(grant.mask & ((1 << DXX_GRANT_LASER_LEVEL_BITS) - 1)); |
||
| 351 | } |
||
| 352 | player_flags map_granted_flags_to_player_flags(packed_spawn_granted_items grant); |
||
| 353 | uint_fast32_t map_granted_flags_to_primary_weapon_flags(packed_spawn_granted_items grant); |
||
| 354 | uint16_t map_granted_flags_to_vulcan_ammo(packed_spawn_granted_items grant); |
||
| 355 | void multi_digi_link_sound_to_pos(int soundnum, vcsegptridx_t segnum, unsigned sidenum, const vms_vector &pos, int forever, fix max_volume); |
||
| 356 | void multi_object_to_object_rw(object &obj, object_rw *obj_rw); |
||
| 357 | void multi_object_rw_to_object(object_rw *obj_rw, object &obj); |
||
| 358 | |||
| 359 | using GMNames_array = std::array<char[MULTI_GAME_NAME_LENGTH], MULTI_GAME_TYPE_COUNT>; |
||
| 360 | extern const GMNames_array GMNames; |
||
| 361 | using multi_allow_powerup_text_array = std::array<char[MULTI_ALLOW_POWERUP_TEXT_LENGTH], MULTI_ALLOW_POWERUP_MAX>; |
||
| 362 | extern const multi_allow_powerup_text_array multi_allow_powerup_text; |
||
| 363 | extern const std::array<char[8], MULTI_GAME_TYPE_COUNT> GMNamesShrt; |
||
| 364 | } |
||
| 365 | |||
| 366 | namespace dcx { |
||
| 367 | extern std::array<objnum_t, MAX_NET_CREATE_OBJECTS> Net_create_objnums; |
||
| 368 | extern unsigned Net_create_loc; |
||
| 369 | } |
||
| 370 | |||
| 371 | namespace dsx { |
||
| 372 | |||
| 373 | void multi_send_fire(int laser_gun, int laser_level, int laser_flags, int laser_fired, objnum_t laser_track, imobjptridx_t is_bomb_objnum); |
||
| 374 | void multi_send_destroy_controlcen(objnum_t objnum, playernum_t player); |
||
| 375 | void multi_send_position(object &objnum); |
||
| 376 | void multi_send_kill(vmobjptridx_t objnum); |
||
| 377 | void multi_send_remobj(vmobjidx_t objnum); |
||
| 378 | void multi_send_door_open(vcsegidx_t segnum, unsigned side, uint8_t flag); |
||
| 379 | void multi_send_drop_weapon(vmobjptridx_t objnum,int seed); |
||
| 380 | void multi_reset_player_object(object &objp); |
||
| 381 | int multi_maybe_disable_friendly_fire(const object *killer); |
||
| 382 | } |
||
| 383 | #endif |
||
| 384 | |||
| 385 | enum msgsend_state_t { |
||
| 386 | msgsend_none, |
||
| 387 | msgsend_typing, |
||
| 388 | msgsend_automap, |
||
| 389 | }; |
||
| 390 | |||
| 391 | enum deres_type_t { |
||
| 392 | deres_explode, |
||
| 393 | deres_drop, |
||
| 394 | }; |
||
| 395 | |||
| 396 | // Exported functions |
||
| 397 | |||
| 398 | struct owned_remote_objnum |
||
| 399 | { |
||
| 400 | int8_t owner; |
||
| 401 | uint16_t objnum; |
||
| 402 | }; |
||
| 403 | |||
| 404 | extern int GetMyNetRanking(); |
||
| 405 | extern void ClipRank (ubyte *rank); |
||
| 406 | objnum_t objnum_remote_to_local(uint16_t remote_obj, int8_t owner); |
||
| 407 | uint16_t objnum_local_to_remote(objnum_t local_obj, int8_t *owner); |
||
| 408 | owned_remote_objnum objnum_local_to_remote(objnum_t local); |
||
| 409 | void map_objnum_local_to_remote(int local, int remote, int owner); |
||
| 410 | void map_objnum_local_to_local(objnum_t objnum); |
||
| 411 | void reset_network_objects(); |
||
| 412 | int multi_objnum_is_past(objnum_t objnum); |
||
| 413 | void multi_do_ping_frame(); |
||
| 414 | |||
| 415 | void multi_init_objects(void); |
||
| 416 | void multi_do_protocol_frame(int force, int listen); |
||
| 417 | window_event_result multi_do_frame(); |
||
| 418 | |||
| 419 | #ifdef dsx |
||
| 420 | namespace dsx { |
||
| 421 | |||
| 422 | enum class multi_endlevel_type : bool |
||
| 423 | { |
||
| 424 | normal, |
||
| 425 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 426 | secret, |
||
| 427 | #endif |
||
| 428 | }; |
||
| 429 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 430 | void multi_send_endlevel_start(multi_endlevel_type); |
||
| 431 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 432 | void multi_send_endlevel_start(); |
||
| 433 | static inline void multi_send_endlevel_start(multi_endlevel_type) |
||
| 434 | { |
||
| 435 | multi_send_endlevel_start(); |
||
| 436 | } |
||
| 437 | #endif |
||
| 438 | void multi_send_player_deres(deres_type_t type); |
||
| 439 | void multi_send_create_powerup(powerup_type_t powerup_type, vcsegidx_t segnum, vcobjidx_t objnum, const vms_vector &pos); |
||
| 440 | } |
||
| 441 | void multi_send_play_sound(int sound_num, fix volume, sound_stack once); |
||
| 442 | #endif |
||
| 443 | void multi_send_reappear(); |
||
| 444 | void multi_send_create_explosion(playernum_t); |
||
| 445 | void multi_send_controlcen_fire(const vms_vector &to_target, int gun_num, objnum_t objnum); |
||
| 446 | namespace dcx { |
||
| 447 | void multi_send_cloak(void); |
||
| 448 | void multi_send_decloak(void); |
||
| 449 | } |
||
| 450 | void multi_digi_play_sample(int sndnum, fix max_volume); |
||
| 451 | void multi_digi_play_sample_once(int soundnum, fix max_volume); |
||
| 452 | void multi_send_score(void); |
||
| 453 | void multi_send_trigger(int trigger); |
||
| 454 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 455 | namespace dsx { |
||
| 456 | extern char Multi_is_guided; |
||
| 457 | void multi_send_flags(playernum_t); |
||
| 458 | struct marker_message_text_t; |
||
| 459 | void multi_send_drop_marker(unsigned player, const vms_vector &position, player_marker_index messagenum, const marker_message_text_t &text); |
||
| 460 | void multi_send_markers(); |
||
| 461 | void multi_send_guided_info (const object_base &miss, char); |
||
| 462 | void multi_send_orb_bonus(playernum_t pnum, uint8_t); |
||
| 463 | void multi_send_got_orb(playernum_t pnum); |
||
| 464 | void multi_send_effect_blowup(vcsegidx_t segnum, unsigned side, const vms_vector &pnt); |
||
| 465 | void multi_send_vulcan_weapon_ammo_adjust(const vmobjptridx_t objnum); |
||
| 466 | } |
||
| 467 | #ifndef RELEASE |
||
| 468 | void multi_add_lifetime_kills(int count); |
||
| 469 | #endif |
||
| 470 | #endif |
||
| 471 | void multi_send_bounty( void ); |
||
| 472 | |||
| 473 | void multi_consistency_error(int reset); |
||
| 474 | window_event_result multi_level_sync(); |
||
| 475 | int multi_endlevel(int *secret); |
||
| 476 | using multi_endlevel_poll = int(newmenu *menu,const d_event &event, const unused_newmenu_userdata_t *); |
||
| 477 | multi_endlevel_poll *get_multi_endlevel_poll2(); |
||
| 478 | void multi_send_endlevel_packet(); |
||
| 479 | #ifdef dsx |
||
| 480 | namespace dsx { |
||
| 481 | void multi_send_hostage_door_status(vcwallptridx_t wallnum); |
||
| 482 | void multi_prep_level_objects(const d_vclip_array &Vclip); |
||
| 483 | void multi_prep_level_player(); |
||
| 484 | void multi_leave_game(void); |
||
| 485 | } |
||
| 486 | #endif |
||
| 487 | void multi_process_bigdata(playernum_t pnum, const ubyte *buf, uint_fast32_t len); |
||
| 488 | void multi_do_death(int objnum); |
||
| 489 | #ifdef dsx |
||
| 490 | namespace dsx { |
||
| 491 | void multi_make_ghost_player(playernum_t); |
||
| 492 | void multi_make_player_ghost(playernum_t); |
||
| 493 | } |
||
| 494 | #endif |
||
| 495 | void multi_define_macro(int key); |
||
| 496 | void multi_send_macro(int key); |
||
| 497 | int multi_get_kill_list(playernum_array_t &sorted_kills); |
||
| 498 | void multi_new_game(void); |
||
| 499 | #ifdef dsx |
||
| 500 | namespace dsx { |
||
| 501 | void multi_sort_kill_list(void); |
||
| 502 | } |
||
| 503 | #endif |
||
| 504 | void multi_reset_stuff(void); |
||
| 505 | int get_team(playernum_t pnum); |
||
| 506 | void multi_disconnect_player(playernum_t); |
||
| 507 | |||
| 508 | #ifdef dsx |
||
| 509 | namespace dsx { |
||
| 510 | void multi_initiate_save_game(); |
||
| 511 | void multi_initiate_restore_game(); |
||
| 512 | void multi_execute_save_game(d_game_unique_state::save_slot slot, const d_game_unique_state::savegame_description &desc, partial_range_t<const player *> player_range); |
||
| 513 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 514 | static inline void multi_send_got_flag (playernum_t) {} |
||
| 515 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 516 | void multi_send_got_flag (playernum_t); |
||
| 517 | #endif |
||
| 518 | } |
||
| 519 | #endif |
||
| 520 | |||
| 521 | // Exported variables |
||
| 522 | |||
| 523 | namespace dcx { |
||
| 524 | extern int Network_status; |
||
| 525 | |||
| 526 | // IMPORTANT: These variables needed for player rejoining done by protocol-specific code |
||
| 527 | extern int Network_send_objects; |
||
| 528 | extern int Network_send_object_mode; |
||
| 529 | extern int Network_send_objnum; |
||
| 530 | extern int Network_rejoined; |
||
| 531 | extern int Network_sending_extras; |
||
| 532 | extern int VerifyPlayerJoined; |
||
| 533 | extern int Player_joining_extras; |
||
| 534 | extern int Network_player_added; |
||
| 535 | |||
| 536 | extern std::array<std::array<uint16_t, MAX_PLAYERS>, MAX_PLAYERS> kill_matrix; |
||
| 537 | extern std::array<int16_t, 2> team_kills; |
||
| 538 | |||
| 539 | extern ushort my_segments_checksum; |
||
| 540 | |||
| 541 | //do we draw the kill list on the HUD? |
||
| 542 | extern int Show_kill_list; |
||
| 543 | extern int Show_reticle_name; |
||
| 544 | extern fix Show_kill_list_timer; |
||
| 545 | |||
| 546 | // Used to send network messages |
||
| 547 | |||
| 548 | extern ntstring<MAX_MESSAGE_LEN - 1> Network_message; |
||
| 549 | extern int Network_message_reciever; |
||
| 550 | |||
| 551 | // Which player 'owns' each local object for network purposes |
||
| 552 | extern std::array<sbyte, MAX_OBJECTS> object_owner; |
||
| 553 | |||
| 554 | extern int multi_quit_game; |
||
| 555 | |||
| 556 | extern std::array<msgsend_state_t, MAX_PLAYERS> multi_sending_message; |
||
| 557 | extern int multi_defining_message; |
||
| 558 | } |
||
| 559 | window_event_result multi_message_input_sub(int key); |
||
| 560 | extern void multi_send_message_start(); |
||
| 561 | void multi_send_msgsend_state(msgsend_state_t state); |
||
| 562 | |||
| 563 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 564 | namespace dsx { |
||
| 565 | extern std::array<grs_main_bitmap, 2> Orb_icons; |
||
| 566 | struct hoard_highest_record |
||
| 567 | { |
||
| 568 | unsigned points; |
||
| 569 | unsigned player = UINT_MAX; |
||
| 570 | }; |
||
| 571 | |||
| 572 | extern hoard_highest_record hoard_highest_record_stats; |
||
| 573 | } |
||
| 574 | #endif |
||
| 575 | namespace dcx { |
||
| 576 | extern playernum_t Bounty_target; |
||
| 577 | |||
| 578 | extern std::array<std::array<bitmap_index, N_PLAYER_SHIP_TEXTURES>, MAX_PLAYERS> multi_player_textures; |
||
| 579 | |||
| 580 | extern const std::array<char[16], 10> RankStrings; |
||
| 581 | #define GetRankStringWithSpace(I) (PlayerCfg.NoRankings ? std::pair<const char *, const char *>("", "") : std::pair<const char *, const char *>(RankStrings[I], " ")) |
||
| 582 | |||
| 583 | // Globals for protocol-bound Refuse-functions |
||
| 584 | extern char RefuseThisPlayer,WaitForRefuseAnswer,RefuseTeam,RefusePlayerName[12]; |
||
| 585 | extern fix64 RefuseTimeLimit; |
||
| 586 | #define REFUSE_INTERVAL (F1_0*8) |
||
| 587 | } |
||
| 588 | |||
| 589 | #ifdef dsx |
||
| 590 | namespace dsx { |
||
| 591 | struct bit_game_flags { |
||
| 592 | unsigned closed : 1; |
||
| 593 | unsigned : 1; |
||
| 594 | unsigned show_on_map : 1; |
||
| 595 | /* |
||
| 596 | * These #define are written to .NGP files and to the network. |
||
| 597 | * Changing them breaks ABI compatibility. |
||
| 598 | * The bit flags need not match in value, and are converted below in |
||
| 599 | * pack_game_flags / unpack_game_flags. |
||
| 600 | */ |
||
| 601 | #define NETGAME_FLAG_CLOSED 1 |
||
| 602 | #define NETGAME_FLAG_SHOW_MAP 4 |
||
| 603 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 604 | unsigned hoard : 1; |
||
| 605 | unsigned team_hoard : 1; |
||
| 606 | unsigned endlevel : 1; |
||
| 607 | unsigned forming : 1; |
||
| 608 | #define NETGAME_FLAG_HOARD 8 |
||
| 609 | #define NETGAME_FLAG_TEAM_HOARD 16 |
||
| 610 | #define NETGAME_FLAG_REALLY_ENDLEVEL 32 |
||
| 611 | #define NETGAME_FLAG_REALLY_FORMING 64 |
||
| 612 | #endif |
||
| 613 | } __pack__; |
||
| 614 | } |
||
| 615 | |||
| 616 | namespace dcx { |
||
| 617 | struct packed_game_flags |
||
| 618 | { |
||
| 619 | unsigned char value; |
||
| 620 | }; |
||
| 621 | |||
| 622 | #if DXX_USE_TRACKER |
||
| 623 | enum TrackerNATHolePunchWarn : uint8_t |
||
| 624 | { |
||
| 625 | Unset, |
||
| 626 | UserEnabledHP, |
||
| 627 | UserRejectedHP, |
||
| 628 | }; |
||
| 629 | #endif |
||
| 630 | } |
||
| 631 | |||
| 632 | namespace dsx { |
||
| 633 | |||
| 634 | static inline bit_game_flags unpack_game_flags(const packed_game_flags *p) |
||
| 635 | { |
||
| 636 | bit_game_flags flags; |
||
| 637 | flags.closed = !!(p->value & NETGAME_FLAG_CLOSED); |
||
| 638 | flags.show_on_map = !!(p->value & NETGAME_FLAG_SHOW_MAP); |
||
| 639 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 640 | flags.hoard = !!(p->value & NETGAME_FLAG_HOARD); |
||
| 641 | flags.team_hoard = !!(p->value & NETGAME_FLAG_TEAM_HOARD); |
||
| 642 | flags.endlevel = !!(p->value & NETGAME_FLAG_REALLY_ENDLEVEL); |
||
| 643 | flags.forming = !!(p->value & NETGAME_FLAG_REALLY_FORMING); |
||
| 644 | #endif |
||
| 645 | return flags; |
||
| 646 | } |
||
| 647 | |||
| 648 | static inline packed_game_flags pack_game_flags(const bit_game_flags *flags) |
||
| 649 | { |
||
| 650 | packed_game_flags p; |
||
| 651 | p.value = |
||
| 652 | (flags->closed ? NETGAME_FLAG_CLOSED : 0) | |
||
| 653 | (flags->show_on_map ? NETGAME_FLAG_SHOW_MAP : 0) | |
||
| 654 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 655 | (flags->hoard ? NETGAME_FLAG_HOARD : 0) | |
||
| 656 | (flags->team_hoard ? NETGAME_FLAG_TEAM_HOARD : 0) | |
||
| 657 | (flags->endlevel ? NETGAME_FLAG_REALLY_ENDLEVEL : 0) | |
||
| 658 | (flags->forming ? NETGAME_FLAG_REALLY_FORMING : 0) | |
||
| 659 | #endif |
||
| 660 | 0; |
||
| 661 | return p; |
||
| 662 | } |
||
| 663 | |||
| 664 | #define NETGAME_NAME_LEN 25 |
||
| 665 | |||
| 666 | extern struct netgame_info Netgame; |
||
| 667 | } |
||
| 668 | #endif |
||
| 669 | |||
| 670 | #define multi_i_am_master() (Player_num == 0) |
||
| 671 | void change_playernum_to(playernum_t new_pnum); |
||
| 672 | |||
| 673 | // Multiplayer powerup capping |
||
| 674 | void MultiLevelInv_InitializeCount(); |
||
| 675 | void MultiLevelInv_Recount(); |
||
| 676 | #ifdef dsx |
||
| 677 | namespace dsx { |
||
| 678 | extern bool MultiLevelInv_AllowSpawn(powerup_type_t powerup_type); |
||
| 679 | } |
||
| 680 | #endif |
||
| 681 | extern void MultiLevelInv_Repopulate(fix frequency); |
||
| 682 | #ifdef dsx |
||
| 683 | namespace dsx { |
||
| 684 | uint_fast32_t multi_powerup_is_allowed(const unsigned id, const unsigned AllowedItems); |
||
| 685 | uint_fast32_t multi_powerup_is_allowed(const unsigned id, const unsigned AllowedItems, const unsigned SpawnGrantedItems); |
||
| 686 | void show_netgame_info(const netgame_info &netgame); |
||
| 687 | extern void multi_send_player_inventory(int priority); |
||
| 688 | const char *multi_common_deny_save_game(const fvcobjptr &vcobjptr, partial_range_t<const player *> player_range); |
||
| 689 | const char *multi_interactive_deny_save_game(const fvcobjptr &vcobjptr, partial_range_t<const player *> player_range, const d_level_unique_control_center_state &); |
||
| 690 | } |
||
| 691 | #endif |
||
| 692 | extern void multi_send_kill_goal_counts(); |
||
| 693 | void multi_check_for_killgoal_winner(); |
||
| 694 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 695 | namespace dsx { |
||
| 696 | extern void multi_send_stolen_items(); |
||
| 697 | void multi_send_trigger_specific(playernum_t pnum, uint8_t trig); |
||
| 698 | void multi_send_door_open_specific(playernum_t pnum, vcsegidx_t segnum, unsigned side, uint8_t flag); |
||
| 699 | void multi_send_wall_status_specific(playernum_t pnum,uint16_t wallnum,ubyte type,ubyte flags,ubyte state); |
||
| 700 | void multi_send_light_specific (playernum_t pnum, vcsegptridx_t segnum, uint8_t val); |
||
| 701 | void multi_send_capture_bonus (playernum_t pnum); |
||
| 702 | int multi_all_players_alive(const fvcobjptr &, partial_range_t<const player *>); |
||
| 703 | void multi_send_seismic(fix); |
||
| 704 | void multi_send_drop_blobs(playernum_t); |
||
| 705 | void multi_send_sound_function (char,char); |
||
| 706 | void DropFlag(); |
||
| 707 | void multi_send_finish_game (); |
||
| 708 | void init_hoard_data(d_vclip_array &Vclip); |
||
| 709 | void multi_apply_goal_textures(); |
||
| 710 | void multi_send_escort_goal(const d_unique_buddy_state &); |
||
| 711 | void multi_recv_escort_goal(d_unique_buddy_state &, const uint8_t *); |
||
| 712 | |||
| 713 | int HoardEquipped(); |
||
| 714 | #if DXX_USE_EDITOR |
||
| 715 | void save_hoard_data(void); |
||
| 716 | #endif |
||
| 717 | } |
||
| 718 | #endif |
||
| 719 | |||
| 720 | //how to encode missiles & flares in weapon packets |
||
| 721 | #define MISSILE_ADJUST 100 |
||
| 722 | #define FLARE_ADJUST 127 |
||
| 723 | |||
| 724 | /* |
||
| 725 | * The Network Players structure |
||
| 726 | * Contains protocol-specific data with designated prefixes and general player-related data. |
||
| 727 | * Note that not all of these infos will be sent to other users - some are used and/or set locally, only. |
||
| 728 | */ |
||
| 729 | struct netplayer_info : prohibit_void_ptr<netplayer_info> |
||
| 730 | { |
||
| 731 | #if DXX_USE_UDP |
||
| 732 | union |
||
| 733 | { |
||
| 734 | #if DXX_USE_UDP |
||
| 735 | struct |
||
| 736 | { |
||
| 737 | struct _sockaddr addr; // IP address of this peer |
||
| 738 | } udp; |
||
| 739 | #endif |
||
| 740 | } protocol; |
||
| 741 | #endif |
||
| 742 | callsign_t callsign; |
||
| 743 | sbyte connected; |
||
| 744 | ubyte rank; |
||
| 745 | fix ping; |
||
| 746 | fix64 LastPacketTime; |
||
| 747 | }; |
||
| 748 | |||
| 749 | #ifdef dsx |
||
| 750 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 751 | struct ThiefModifier |
||
| 752 | { |
||
| 753 | enum Flags : uint8_t { |
||
| 754 | Absent = 1, |
||
| 755 | NoEnergyWeapons, |
||
| 756 | }; |
||
| 757 | }; |
||
| 758 | #endif |
||
| 759 | |||
| 760 | namespace dsx { |
||
| 761 | /* |
||
| 762 | * The Network Game structure |
||
| 763 | * Contains protocol-specific data with designated prefixes and general game-related data. |
||
| 764 | * Note that not all of these infos will be sent to clients - some are used and/or set locally, only. |
||
| 765 | */ |
||
| 766 | struct netgame_info : prohibit_void_ptr<netgame_info>, ignore_window_pointer_t |
||
| 767 | { |
||
| 768 | using play_time_allowed_abi_ratio = std::ratio<5 * 60>; |
||
| 769 | #if DXX_USE_UDP |
||
| 770 | union |
||
| 771 | { |
||
| 772 | #if DXX_USE_UDP |
||
| 773 | struct |
||
| 774 | { |
||
| 775 | struct _sockaddr addr; // IP address of this netgame's host |
||
| 776 | std::array<short, 4> program_iver; // IVER of program for version checking |
||
| 777 | sbyte valid; // Status of Netgame info: -1 = Failed, Wrong version; 0 = No info, yet; 1 = Success |
||
| 778 | uint8_t your_index; // Tell player his designated (re)join position in players[] |
||
| 779 | fix GameID; |
||
| 780 | } udp; |
||
| 781 | #endif |
||
| 782 | } protocol; |
||
| 783 | #endif |
||
| 784 | ntstring<NETGAME_NAME_LEN> game_name; |
||
| 785 | ntstring<MISSION_NAME_LEN> mission_title; |
||
| 786 | ntstring<8> mission_name; |
||
| 787 | int levelnum; |
||
| 788 | Difficulty_level_type difficulty; |
||
| 789 | ubyte gamemode; |
||
| 790 | ubyte RefusePlayers; |
||
| 791 | ubyte game_status; |
||
| 792 | ubyte numplayers; |
||
| 793 | ubyte max_numplayers; |
||
| 794 | ubyte numconnected; |
||
| 795 | bit_game_flags game_flag; |
||
| 796 | ubyte team_vector; |
||
| 797 | uint8_t SecludedSpawns; |
||
| 798 | uint8_t MouselookFlags; |
||
| 799 | uint32_t AllowedItems; |
||
| 800 | packed_spawn_granted_items SpawnGrantedItems; |
||
| 801 | packed_netduplicate_items DuplicatePowerups; |
||
| 802 | unsigned ShufflePowerupSeed; |
||
| 803 | d_mp_gameplay_options MPGameplayOptions; |
||
| 804 | #if defined(DXX_BUILD_DESCENT_II) |
||
| 805 | uint8_t Allow_marker_view; |
||
| 806 | uint8_t AlwaysLighting; |
||
| 807 | uint8_t ThiefModifierFlags; |
||
| 808 | uint8_t AllowGuidebot; |
||
| 809 | #endif |
||
| 810 | uint8_t ShowEnemyNames; |
||
| 811 | uint8_t BrightPlayers; |
||
| 812 | uint8_t InvulAppear; |
||
| 813 | ushort segments_checksum; |
||
| 814 | int KillGoal; |
||
| 815 | /* The UI enforces that this steps in units of 5 minutes, but for |
||
| 816 | * efficiency, it is stored as ticks (1 second = F1_0). The UI |
||
| 817 | * imposes a maximum value that is small enough that overflow is |
||
| 818 | * impossible. |
||
| 819 | */ |
||
| 820 | d_time_fix PlayTimeAllowed; |
||
| 821 | fix level_time; |
||
| 822 | int control_invul_time; |
||
| 823 | int monitor_vector; |
||
| 824 | short PacketsPerSec; |
||
| 825 | ubyte PacketLossPrevention; |
||
| 826 | ubyte NoFriendlyFire; |
||
| 827 | std::array<callsign_t, 2> team_name; |
||
| 828 | std::array<uint32_t, MAX_PLAYERS> locations; |
||
| 829 | std::array<std::array<uint16_t, MAX_PLAYERS>, MAX_PLAYERS> kills; |
||
| 830 | std::array<int16_t, 2> team_kills; |
||
| 831 | std::array<uint16_t, MAX_PLAYERS> killed; |
||
| 832 | std::array<uint16_t, MAX_PLAYERS> player_kills; |
||
| 833 | std::array<uint32_t, MAX_PLAYERS> player_score; |
||
| 834 | std::array<player_flags, MAX_PLAYERS> net_player_flags; |
||
| 835 | std::array<netplayer_info, MAX_PLAYERS> players; |
||
| 836 | #if DXX_USE_TRACKER |
||
| 837 | ubyte Tracker; |
||
| 838 | TrackerNATHolePunchWarn TrackerNATWarned; |
||
| 839 | #endif |
||
| 840 | }; |
||
| 841 | |||
| 842 | |||
| 843 | /* |
||
| 844 | * Structure holding all powerup types we want to keep track of. Used to cap or respawn powerups and keep the level inventory steady. |
||
| 845 | * Using uint32_t because we don't count powerup units but what the powerup contains (1 or 4 missiles, vulcam amount, etc) so we can keep track of overhead. |
||
| 846 | * I'm sorry if this isn't very optimized but I found this easier to handle than a single variable per powerup. |
||
| 847 | */ |
||
| 848 | struct multi_level_inv |
||
| 849 | { |
||
| 850 | std::array<uint32_t, MAX_POWERUP_TYPES> Initial; // initial (level start) count of this powerup type |
||
| 851 | std::array<uint32_t, MAX_POWERUP_TYPES> Current; // current count of this powerup type |
||
| 852 | std::array<fix, MAX_POWERUP_TYPES> RespawnTimer; // incremented by FrameTime if initial-current > 0 and triggers respawn after 2 seconds. Since we deal with a certain delay from clients, their inventory updates may happen a while after they remove the powerup object and we do not want to respawn it on accident during that time window! |
||
| 853 | }; |
||
| 854 | } |
||
| 855 | #endif |
||
| 856 | |||
| 857 | namespace multi |
||
| 858 | { |
||
| 859 | struct level_checksum_mismatch : std::runtime_error |
||
| 860 | { |
||
| 861 | level_checksum_mismatch() : |
||
| 862 | runtime_error("level checksum mismatch") |
||
| 863 | { |
||
| 864 | } |
||
| 865 | }; |
||
| 866 | struct local_player_not_playing : std::runtime_error |
||
| 867 | { |
||
| 868 | local_player_not_playing() : |
||
| 869 | runtime_error("local player not playing") |
||
| 870 | { |
||
| 871 | } |
||
| 872 | }; |
||
| 873 | } |
||
| 874 | |||
| 875 | /* Stub for mods that remap player colors */ |
||
| 876 | static inline unsigned get_player_color(unsigned pnum) |
||
| 877 | { |
||
| 878 | return pnum; |
||
| 879 | } |
||
| 880 | |||
| 881 | static inline unsigned get_team_color(unsigned tnum) |
||
| 882 | { |
||
| 883 | return tnum; |
||
| 884 | } |
||
| 885 | |||
| 886 | static inline unsigned get_player_or_team_color(unsigned pnum) |
||
| 887 | { |
||
| 888 | return Game_mode & GM_TEAM |
||
| 889 | ? get_team_color(get_team(pnum)) |
||
| 890 | : get_player_color(pnum); |
||
| 891 | } |
||
| 892 | |||
| 893 | #endif |