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 |