NETWORK.C 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007
  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
  12. */
  13. /*
  14. * $Source: f:/miner/source/main/rcs/network.c $
  15. * $Revision: 2.11 $
  16. * $Author: john $
  17. * $Date: 1995/07/18 10:57:56 $
  18. *
  19. * Routines for managing network play.
  20. *
  21. */
  22. #pragma off (unreferenced)
  23. static char rcsid[] = "$Id: network.c 2.11 1995/07/18 10:57:56 john Exp $";
  24. #pragma on (unreferenced)
  25. #ifdef NETWORK
  26. #include <i86.h>
  27. #include <dos.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <conio.h>
  32. #include "types.h"
  33. #include "args.h"
  34. #include "timer.h"
  35. #include "mono.h"
  36. #include "ipx.h"
  37. #include "newmenu.h"
  38. #include "key.h"
  39. #include "gauges.h"
  40. #include "object.h"
  41. #include "error.h"
  42. #include "netmisc.h"
  43. #include "laser.h"
  44. #include "gamesave.h"
  45. #include "gamemine.h"
  46. #include "player.h"
  47. #include "gameseq.h"
  48. #include "fireball.h"
  49. #include "network.h"
  50. #include "game.h"
  51. #include "multi.h"
  52. #include "endlevel.h"
  53. #include "palette.h"
  54. #include "fuelcen.h"
  55. #include "menu.h"
  56. #include "sounds.h"
  57. #include "text.h"
  58. #include "kmatrix.h"
  59. #include "newdemo.h"
  60. #include "multibot.h"
  61. #include "wall.h"
  62. #include "bm.h"
  63. #include "effects.h"
  64. #include "physics.h"
  65. #ifdef SHAREWARE
  66. #define PID_REQUEST 11
  67. #define PID_SYNC 13
  68. #define PID_PDATA 14
  69. #define PID_ADDPLAYER 15
  70. #define PID_DUMP 17
  71. #define PID_ENDLEVEL 18
  72. #define PID_QUIT_JOINING 20
  73. #define PID_OBJECT_DATA 21
  74. #define PID_GAME_LIST 22
  75. #define PID_GAME_INFO 24
  76. #else
  77. #define PID_REQUEST 25
  78. #define PID_SYNC 27
  79. #define PID_PDATA 28
  80. #define PID_ADDPLAYER 29
  81. #define PID_DUMP 31
  82. #define PID_ENDLEVEL 32
  83. #define PID_QUIT_JOINING 34
  84. #define PID_OBJECT_DATA 35
  85. #define PID_GAME_LIST 36
  86. #define PID_GAME_INFO 37
  87. #endif
  88. #define NETGAME_ANARCHY 0
  89. #define NETGAME_TEAM_ANARCHY 1
  90. #define NETGAME_ROBOT_ANARCHY 2
  91. #define NETGAME_COOPERATIVE 3
  92. typedef struct endlevel_info {
  93. ubyte type;
  94. ubyte player_num;
  95. byte connected;
  96. short kill_matrix[MAX_PLAYERS][MAX_PLAYERS];
  97. short kills;
  98. short killed;
  99. ubyte seconds_left;
  100. } endlevel_info;
  101. #define MAX_ACTIVE_NETGAMES 4
  102. netgame_info Active_games[MAX_ACTIVE_NETGAMES];
  103. int num_active_games = 0;
  104. int Network_debug=0;
  105. int Network_active=0;
  106. int Network_status = 0;
  107. int Network_games_changed = 0;
  108. int Network_socket = 0;
  109. int Network_allow_socket_changes = 0;
  110. // For rejoin object syncing
  111. int Network_rejoined = 0; // Did WE rejoin this game?
  112. int Network_new_game = 0; // Is this the first level of a new game?
  113. int Network_send_objects = 0; // Are we in the process of sending objects to a player?
  114. int Network_send_objnum = -1; // What object are we sending next?
  115. int Network_player_added = 0; // Is this a new player or a returning player?
  116. int Network_send_object_mode = 0; // What type of objects are we sending, static or dynamic?
  117. sequence_packet Network_player_rejoining; // Who is rejoining now?
  118. fix LastPacketTime[MAX_PLAYERS]; // For timeouts of idle/crashed players
  119. int PacketUrgent = 0;
  120. frame_info MySyncPack;
  121. ubyte MySyncPackInitialized = 0; // Set to 1 if the MySyncPack is zeroed.
  122. ushort my_segments_checksum = 0;
  123. sequence_packet My_Seq;
  124. extern obj_position Player_init[MAX_PLAYERS];
  125. #define DUMP_CLOSED 0
  126. #define DUMP_FULL 1
  127. #define DUMP_ENDLEVEL 2
  128. #define DUMP_DORK 3
  129. #define DUMP_ABORTED 4
  130. #define DUMP_CONNECTED 5
  131. #define DUMP_LEVEL 6
  132. int network_wait_for_snyc();
  133. void
  134. network_init(void)
  135. {
  136. // So you want to play a netgame, eh? Let's a get a few things
  137. // straight
  138. int save_pnum = Player_num;
  139. memset(&Netgame, 0, sizeof(netgame_info));
  140. memset(&My_Seq, 0, sizeof(sequence_packet));
  141. My_Seq.type = PID_REQUEST;
  142. memcpy(My_Seq.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
  143. memcpy(My_Seq.player.node, ipx_get_my_local_address(), 6);
  144. memcpy(My_Seq.player.server, ipx_get_my_server_address(), 4 );
  145. for (Player_num = 0; Player_num < MAX_NUM_NET_PLAYERS; Player_num++)
  146. init_player_stats_game();
  147. Player_num = save_pnum;
  148. multi_new_game();
  149. Network_new_game = 1;
  150. Fuelcen_control_center_destroyed = 0;
  151. network_flush();
  152. }
  153. #define ENDLEVEL_SEND_INTERVAL F1_0*2
  154. #define ENDLEVEL_IDLE_TIME F1_0*10
  155. void
  156. network_endlevel_poll( int nitems, newmenu_item * menus, int * key, int citem )
  157. {
  158. // Polling loop for End-of-level menu
  159. static fix t1 = 0;
  160. int i = 0;
  161. int num_ready = 0;
  162. int num_escaped = 0;
  163. int goto_secret = 0;
  164. int previous_state[MAX_NUM_NET_PLAYERS];
  165. int previous_seconds_left;
  166. menus = menus;
  167. citem = citem;
  168. nitems = nitems;
  169. key = key;
  170. // Send our endlevel packet at regular intervals
  171. if (timer_get_approx_seconds() > t1+ENDLEVEL_SEND_INTERVAL)
  172. {
  173. network_send_endlevel_packet();
  174. t1 = timer_get_approx_seconds();
  175. }
  176. for (i = 0; i < N_players; i++)
  177. previous_state[i] = Players[i].connected;
  178. previous_seconds_left = Fuelcen_seconds_left;
  179. network_listen();
  180. for (i = 0; i < N_players; i++)
  181. {
  182. if (previous_state[i] != Players[i].connected)
  183. {
  184. sprintf(menus[i].text, "%s %s", Players[i].callsign, CONNECT_STATES(Players[i].connected));
  185. menus[i].redraw = 1;
  186. }
  187. if (Players[i].connected == 1)
  188. {
  189. // Check timeout for idle players
  190. if (timer_get_approx_seconds() > LastPacketTime[i]+ENDLEVEL_IDLE_TIME)
  191. {
  192. mprintf((0, "idle timeout for player %d.\n", i));
  193. Players[i].connected = 0;
  194. network_send_endlevel_sub(i);
  195. }
  196. }
  197. if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
  198. num_ready++;
  199. if (Players[i].connected != 1)
  200. num_escaped++;
  201. if (Players[i].connected == 4)
  202. goto_secret = 1;
  203. }
  204. if (num_escaped == N_players) // All players are out of the mine
  205. {
  206. Fuelcen_seconds_left = -1;
  207. }
  208. if (previous_seconds_left != Fuelcen_seconds_left)
  209. {
  210. if (Fuelcen_seconds_left < 0)
  211. {
  212. sprintf(menus[N_players].text, TXT_REACTOR_EXPLODED);
  213. menus[N_players].redraw = 1;
  214. }
  215. else
  216. {
  217. sprintf(menus[N_players].text, "%s: %d %s ", TXT_TIME_REMAINING, Fuelcen_seconds_left, TXT_SECONDS);
  218. menus[N_players].redraw = 1;
  219. }
  220. }
  221. if (num_ready == N_players) // All players have checked in or are disconnected
  222. {
  223. if (goto_secret)
  224. *key = -3;
  225. else
  226. *key = -2;
  227. }
  228. }
  229. void
  230. network_endlevel_poll2( int nitems, newmenu_item * menus, int * key, int citem )
  231. {
  232. // Polling loop for End-of-level menu
  233. static fix t1 = 0;
  234. int i = 0;
  235. int num_ready = 0;
  236. int goto_secret = 0;
  237. menus = menus;
  238. citem = citem;
  239. nitems = nitems;
  240. key = key;
  241. // Send our endlevel packet at regular intervals
  242. if (timer_get_approx_seconds() > t1+ENDLEVEL_SEND_INTERVAL)
  243. {
  244. network_send_endlevel_packet();
  245. t1 = timer_get_approx_seconds();
  246. }
  247. network_listen();
  248. for (i = 0; i < N_players; i++)
  249. {
  250. if ((Players[i].connected != 1) && (Players[i].connected != 5) && (Players[i].connected != 6))
  251. num_ready++;
  252. if (Players[i].connected == 4)
  253. goto_secret = 1;
  254. }
  255. if (num_ready == N_players) // All players have checked in or are disconnected
  256. {
  257. if (goto_secret)
  258. *key = -3;
  259. else
  260. *key = -2;
  261. }
  262. }
  263. int
  264. network_endlevel(int *secret)
  265. {
  266. // Do whatever needs to be done between levels
  267. newmenu_item m[MAX_NUM_NET_PLAYERS+1];
  268. char menu_text[MAX_NUM_NET_PLAYERS+1][80];
  269. int i, choice;
  270. char text[80];
  271. Function_mode = FMODE_MENU;
  272. network_flush();
  273. Network_status = NETSTAT_ENDLEVEL; // We are between levels
  274. network_listen();
  275. network_send_endlevel_packet();
  276. newmenu:
  277. // Setup menu text pointers and zero them
  278. for (i=0; i<N_players; i++)
  279. {
  280. m[i].type = NM_TYPE_TEXT;
  281. m[i].text = menu_text[i];
  282. sprintf(m[i].text, "%s %s", Players[i].callsign, CONNECT_STATES(Players[i].connected));
  283. LastPacketTime[i] = timer_get_approx_seconds();
  284. }
  285. m[N_players].type = NM_TYPE_TEXT;
  286. m[N_players].text = menu_text[N_players];
  287. if (Fuelcen_seconds_left < 0)
  288. sprintf(m[N_players].text, TXT_REACTOR_EXPLODED);
  289. else
  290. sprintf(m[N_players].text, "%s: %d %s ", TXT_TIME_REMAINING, Fuelcen_seconds_left, TXT_SECONDS);
  291. menu:
  292. sprintf(text, "%s\n%s", TXT_WAITING, TXT_ESC_ABORT);
  293. choice=newmenu_do3(NULL, text, N_players+1, m, network_endlevel_poll, 0, "STARS.PCX", 300, 160);
  294. if (choice==-1) {
  295. newmenu_item m2[2];
  296. m2[0].type = m2[1].type = NM_TYPE_MENU;
  297. m2[0].text = TXT_YES; m2[1].text = TXT_NO;
  298. choice = newmenu_do1(NULL, TXT_SURE_LEAVE_GAME, 2, m2, network_endlevel_poll2, 1);
  299. if (choice == 0)
  300. {
  301. Players[Player_num].connected = 0;
  302. network_send_endlevel_packet();
  303. network_send_endlevel_packet();
  304. longjmp(LeaveGame,0);
  305. }
  306. if (choice > -2)
  307. goto newmenu;
  308. }
  309. // kmatrix_view();
  310. if (choice > -2)
  311. goto menu;
  312. if (choice == -3)
  313. *secret = 1; // If any player went to the secret level, we go to the secret level
  314. network_send_endlevel_packet();
  315. network_send_endlevel_packet();
  316. MySyncPackInitialized = 0;
  317. network_update_netgame();
  318. return(0);
  319. }
  320. int
  321. can_join_netgame(netgame_info *game)
  322. {
  323. // Can this player rejoin a netgame in progress?
  324. int i, num_players;
  325. if (game->game_status == NETSTAT_STARTING)
  326. return 1;
  327. if (game->game_status != NETSTAT_PLAYING)
  328. return 0;
  329. // Game is in progress, figure out if this guy can re-join it
  330. num_players = game->numplayers;
  331. if (!(game->game_flags & NETGAME_FLAG_CLOSED)) {
  332. // Look for player that is not connected
  333. if (game->numplayers < game->max_numplayers)
  334. return 1;
  335. for (i = 0; i < num_players; i++) {
  336. if (game->players[i].connected == 0)
  337. return 1;
  338. }
  339. return 0;
  340. }
  341. // Search to see if we were already in this closed netgame in progress
  342. for (i = 0; i < num_players; i++)
  343. if ( (!stricmp(Players[Player_num].callsign, game->players[i].callsign)) &&
  344. (!memcmp(My_Seq.player.node, game->players[i].node, 6)) &&
  345. (!memcmp(My_Seq.player.server, game->players[i].server, 4)) )
  346. break;
  347. if (i != num_players)
  348. return 1;
  349. return 0;
  350. }
  351. void
  352. network_disconnect_player(int playernum)
  353. {
  354. // A player has disconnected from the net game, take whatever steps are
  355. // necessary
  356. if (playernum == Player_num)
  357. {
  358. Int3(); // Weird, see Rob
  359. return;
  360. }
  361. Players[playernum].connected = 0;
  362. Netgame.players[playernum].connected = 0;
  363. // create_player_appearance_effect(&Objects[Players[playernum].objnum]);
  364. multi_make_player_ghost(playernum);
  365. #ifndef SHAREWARE
  366. if (Newdemo_state == ND_STATE_RECORDING)
  367. newdemo_record_multi_disconnect(playernum);
  368. multi_strip_robots(playernum);
  369. #endif
  370. }
  371. void
  372. network_new_player(sequence_packet *their)
  373. {
  374. int objnum;
  375. int pnum;
  376. pnum = their->player.connected;
  377. Assert(pnum >= 0);
  378. Assert(pnum < MaxNumNetPlayers);
  379. objnum = Players[pnum].objnum;
  380. #ifndef SHAREWARE
  381. if (Newdemo_state == ND_STATE_RECORDING) {
  382. int new_player;
  383. if (pnum == N_players)
  384. new_player = 1;
  385. else
  386. new_player = 0;
  387. newdemo_record_multi_connect(pnum, new_player, their->player.callsign);
  388. }
  389. #endif
  390. memcpy(Players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1);
  391. memcpy(Netgame.players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1);
  392. #ifndef SHAREWARE
  393. if ( (*(uint *)their->player.server) != 0 )
  394. ipx_get_local_target( their->player.server, their->player.node, Players[pnum].net_address );
  395. else
  396. #endif
  397. memcpy(Players[pnum].net_address, their->player.node, 6);
  398. memcpy(Netgame.players[pnum].node, their->player.node, 6);
  399. memcpy(Netgame.players[pnum].server, their->player.server, 4);
  400. Players[pnum].n_packets_got = 0;
  401. Players[pnum].connected = 1;
  402. Players[pnum].net_kills_total = 0;
  403. Players[pnum].net_killed_total = 0;
  404. memset(kill_matrix[pnum], 0, MAX_PLAYERS*sizeof(short));
  405. Players[pnum].score = 0;
  406. Players[pnum].flags = 0;
  407. if (pnum == N_players)
  408. {
  409. N_players++;
  410. Netgame.numplayers = N_players;
  411. }
  412. digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
  413. HUD_init_message("'%s' %s\n", their->player.callsign, TXT_JOINING);
  414. multi_make_ghost_player(pnum);
  415. #ifndef SHAREWARE
  416. multi_send_score();
  417. #endif
  418. // create_player_appearance_effect(&Objects[objnum]);
  419. }
  420. void network_welcome_player(sequence_packet *their)
  421. {
  422. // Add a player to a game already in progress
  423. ubyte local_address[6];
  424. int player_num;
  425. int i;
  426. // Don't accept new players if we're ending this level. Its safe to
  427. // ignore since they'll request again later
  428. if ((Endlevel_sequence) || (Fuelcen_control_center_destroyed))
  429. {
  430. mprintf((0, "Ignored request from new player to join during endgame.\n"));
  431. network_dump_player(their->player.server,their->player.node, DUMP_ENDLEVEL);
  432. return;
  433. }
  434. if (Network_send_objects)
  435. {
  436. // Ignore silently, we're already responding to someone and we can't
  437. // do more than one person at a time. If we don't dump them they will
  438. // re-request in a few seconds.
  439. return;
  440. }
  441. if (their->player.connected != Current_level_num)
  442. {
  443. mprintf((0, "Dumping player due to old level number.\n"));
  444. network_dump_player(their->player.server, their->player.node, DUMP_LEVEL);
  445. return;
  446. }
  447. player_num = -1;
  448. memset(&Network_player_rejoining, 0, sizeof(sequence_packet));
  449. Network_player_added = 0;
  450. #ifndef SHAREWARE
  451. if ( (*(uint *)their->player.server) != 0 )
  452. ipx_get_local_target( their->player.server, their->player.node, local_address );
  453. else
  454. #endif
  455. memcpy(local_address, their->player.node, 6);
  456. for (i = 0; i < N_players; i++)
  457. {
  458. if ( (!stricmp(Players[i].callsign, their->player.callsign )) && (!memcmp(Players[i].net_address,local_address, 6)) )
  459. {
  460. player_num = i;
  461. break;
  462. }
  463. }
  464. if (player_num == -1)
  465. {
  466. // Player is new to this game
  467. if ( !(Netgame.game_flags & NETGAME_FLAG_CLOSED) && (N_players < MaxNumNetPlayers))
  468. {
  469. // Add player in an open slot, game not full yet
  470. player_num = N_players;
  471. Network_player_added = 1;
  472. }
  473. else if (Netgame.game_flags & NETGAME_FLAG_CLOSED)
  474. {
  475. // Slots are open but game is closed
  476. network_dump_player(their->player.server, their->player.node, DUMP_CLOSED);
  477. return;
  478. }
  479. else
  480. {
  481. // Slots are full but game is open, see if anyone is
  482. // disconnected and replace the oldest player with this new one
  483. int oldest_player = -1;
  484. fix oldest_time = timer_get_approx_seconds();
  485. Assert(N_players == MaxNumNetPlayers);
  486. for (i = 0; i < N_players; i++)
  487. {
  488. if ( (!Players[i].connected) && (LastPacketTime[i] < oldest_time))
  489. {
  490. oldest_time = LastPacketTime[i];
  491. oldest_player = i;
  492. }
  493. }
  494. if (oldest_player == -1)
  495. {
  496. // Everyone is still connected
  497. network_dump_player(their->player.server, their->player.node, DUMP_FULL);
  498. return;
  499. }
  500. else
  501. {
  502. // Found a slot!
  503. player_num = oldest_player;
  504. Network_player_added = 1;
  505. }
  506. }
  507. }
  508. else
  509. {
  510. // Player is reconnecting
  511. if (Players[player_num].connected)
  512. {
  513. mprintf((0, "Extra REQUEST from player ignored.\n"));
  514. return;
  515. }
  516. #ifndef SHAREWARE
  517. if (Newdemo_state == ND_STATE_RECORDING)
  518. newdemo_record_multi_reconnect(player_num);
  519. #endif
  520. Network_player_added = 0;
  521. digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
  522. HUD_init_message("'%s' %s", Players[player_num].callsign, TXT_REJOIN);
  523. }
  524. // Send updated Objects data to the new/returning player
  525. Network_player_rejoining = *their;
  526. Network_player_rejoining.player.connected = player_num;
  527. Network_send_objects = 1;
  528. Network_send_objnum = -1;
  529. network_send_objects();
  530. }
  531. int network_objnum_is_past(int objnum)
  532. {
  533. // determine whether or not a given object number has already been sent
  534. // to a re-joining player.
  535. int player_num = Network_player_rejoining.player.connected;
  536. int obj_mode = !((object_owner[objnum] == -1) || (object_owner[objnum] == player_num));
  537. if (!Network_send_objects)
  538. return 0; // We're not sending objects to a new player
  539. if (obj_mode > Network_send_object_mode)
  540. return 0;
  541. else if (obj_mode < Network_send_object_mode)
  542. return 1;
  543. else if (objnum < Network_send_objnum)
  544. return 1;
  545. else
  546. return 0;
  547. }
  548. #define OBJ_PACKETS_PER_FRAME 1
  549. #ifndef SHAREWARE
  550. void network_send_door_updates(void)
  551. {
  552. // Send door status when new player joins
  553. int i;
  554. for (i = 0; i < Num_walls; i++)
  555. {
  556. if ((Walls[i].type == WALL_DOOR) && ((Walls[i].state == WALL_DOOR_OPENING) || (Walls[i].state == WALL_DOOR_WAITING)))
  557. multi_send_door_open(Walls[i].segnum, Walls[i].sidenum);
  558. else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].flags & WALL_BLASTED))
  559. multi_send_door_open(Walls[i].segnum, Walls[i].sidenum);
  560. else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].hps != WALL_HPS))
  561. multi_send_hostage_door_status(i);
  562. }
  563. }
  564. void network_process_monitor_vector(int vector)
  565. {
  566. int i, j;
  567. int count = 0;
  568. segment *seg;
  569. for (i=0; i <= Highest_segment_index; i++)
  570. {
  571. int tm, ec, bm;
  572. seg = &Segments[i];
  573. for (j = 0; j < 6; j++)
  574. {
  575. if ( ((tm = seg->sides[j].tmap_num2) != 0) &&
  576. ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) &&
  577. ((bm = Effects[ec].dest_bm_num) != -1) )
  578. {
  579. if (vector & (1 << count))
  580. {
  581. seg->sides[j].tmap_num2 = bm | (tm&0xc000);
  582. mprintf((0, "Monitor %d blown up.\n", count));
  583. }
  584. else
  585. mprintf((0, "Monitor %d intact.\n", count));
  586. count++;
  587. Assert(count < 32);
  588. }
  589. }
  590. }
  591. }
  592. int network_create_monitor_vector(void)
  593. {
  594. int i, j, k;
  595. int num_blown_bitmaps = 0;
  596. int monitor_num = 0;
  597. int blown_bitmaps[7];
  598. int vector = 0;
  599. segment *seg;
  600. for (i=0; i < Num_effects; i++)
  601. {
  602. if (Effects[i].dest_bm_num > 0) {
  603. for (j = 0; j < num_blown_bitmaps; j++)
  604. if (blown_bitmaps[j] == Effects[i].dest_bm_num)
  605. break;
  606. if (j == num_blown_bitmaps)
  607. blown_bitmaps[num_blown_bitmaps++] = Effects[i].dest_bm_num;
  608. }
  609. }
  610. for (i = 0; i < num_blown_bitmaps; i++)
  611. mprintf((0, "Blown bitmap #%d = %d.\n", i, blown_bitmaps[i]));
  612. Assert(num_blown_bitmaps <= 7);
  613. for (i=0; i <= Highest_segment_index; i++)
  614. {
  615. int tm, ec;
  616. seg = &Segments[i];
  617. for (j = 0; j < 6; j++)
  618. {
  619. if ((tm = seg->sides[j].tmap_num2) != 0)
  620. {
  621. if ( ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) &&
  622. (Effects[ec].dest_bm_num != -1) )
  623. {
  624. mprintf((0, "Monitor %d intact.\n", monitor_num));
  625. monitor_num++;
  626. Assert(monitor_num < 32);
  627. }
  628. else
  629. {
  630. for (k = 0; k < num_blown_bitmaps; k++)
  631. {
  632. if ((tm&0x3fff) == blown_bitmaps[k])
  633. {
  634. mprintf((0, "Monitor %d destroyed.\n", monitor_num));
  635. vector |= (1 << monitor_num);
  636. monitor_num++;
  637. Assert(monitor_num < 32);
  638. break;
  639. }
  640. }
  641. }
  642. }
  643. }
  644. }
  645. mprintf((0, "Final monitor vector %x.\n", vector));
  646. return(vector);
  647. }
  648. #endif
  649. void network_stop_resync(sequence_packet *their)
  650. {
  651. if ( (!memcmp(Network_player_rejoining.player.node, their->player.node, 6)) &&
  652. (!memcmp(Network_player_rejoining.player.server, their->player.server, 4)) &&
  653. (!stricmp(Network_player_rejoining.player.callsign, their->player.callsign)) )
  654. {
  655. mprintf((0, "Aborting resync for player %s.\n", their->player.callsign));
  656. Network_send_objects = 0;
  657. Network_send_objnum = -1;
  658. }
  659. }
  660. byte object_buffer[IPX_MAX_DATA_SIZE];
  661. void network_send_objects(void)
  662. {
  663. short remote_objnum;
  664. byte owner;
  665. int loc, i, h;
  666. static int obj_count = 0;
  667. static int frame_num = 0;
  668. int obj_count_frame = 0;
  669. int player_num = Network_player_rejoining.player.connected;
  670. // Send clear objects array trigger and send player num
  671. Assert(Network_send_objects != 0);
  672. Assert(player_num >= 0);
  673. Assert(player_num < MaxNumNetPlayers);
  674. if (Endlevel_sequence || Fuelcen_control_center_destroyed)
  675. {
  676. // Endlevel started before we finished sending the goods, we'll
  677. // have to stop and try again after the level.
  678. network_dump_player(Network_player_rejoining.player.server,Network_player_rejoining.player.node, DUMP_ENDLEVEL);
  679. Network_send_objects = 0;
  680. return;
  681. }
  682. for (h = 0; h < OBJ_PACKETS_PER_FRAME; h++) // Do more than 1 per frame, try to speed it up without
  683. // over-stressing the receiver.
  684. {
  685. obj_count_frame = 0;
  686. memset(object_buffer, 0, IPX_MAX_DATA_SIZE);
  687. object_buffer[0] = PID_OBJECT_DATA;
  688. loc = 3;
  689. if (Network_send_objnum == -1)
  690. {
  691. obj_count = 0;
  692. Network_send_object_mode = 0;
  693. // mprintf((0, "Sending object array to player %d.\n", player_num));
  694. *(short *)(object_buffer+loc) = -1; loc += 2;
  695. object_buffer[loc] = player_num; loc += 1;
  696. loc += 2; // Placeholder for remote_objnum, not used here
  697. Network_send_objnum = 0;
  698. obj_count_frame = 1;
  699. frame_num = 0;
  700. }
  701. for (i = Network_send_objnum; i <= Highest_object_index; i++)
  702. {
  703. if ((Objects[i].type != OBJ_POWERUP) && (Objects[i].type != OBJ_PLAYER) &&
  704. (Objects[i].type != OBJ_CNTRLCEN) && (Objects[i].type != OBJ_GHOST) &&
  705. (Objects[i].type != OBJ_ROBOT) && (Objects[i].type != OBJ_HOSTAGE))
  706. continue;
  707. if ((Network_send_object_mode == 0) && ((object_owner[i] != -1) && (object_owner[i] != player_num)))
  708. continue;
  709. if ((Network_send_object_mode == 1) && ((object_owner[i] == -1) || (object_owner[i] == player_num)))
  710. continue;
  711. if ( ((IPX_MAX_DATA_SIZE-1) - loc) < (sizeof(object)+5) )
  712. break; // Not enough room for another object
  713. obj_count_frame++;
  714. obj_count++;
  715. remote_objnum = objnum_local_to_remote((short)i, &owner);
  716. Assert(owner == object_owner[i]);
  717. *(short *)(object_buffer+loc) = i; loc += 2;
  718. object_buffer[loc] = owner; loc += 1;
  719. *(short *)(object_buffer+loc) = remote_objnum; loc += 2;
  720. memcpy(object_buffer+loc, &Objects[i], sizeof(object)); loc += sizeof(object);
  721. // mprintf((0, "..packing object %d, remote %d\n", i, remote_objnum));
  722. }
  723. if (obj_count_frame) // Send any objects we've buffered
  724. {
  725. frame_num++;
  726. Network_send_objnum = i;
  727. object_buffer[1] = obj_count_frame;
  728. object_buffer[2] = frame_num;
  729. // mprintf((0, "Object packet %d contains %d objects.\n", frame_num, obj_count_frame));
  730. Assert(loc <= IPX_MAX_DATA_SIZE);
  731. ipx_send_internetwork_packet_data( object_buffer, loc, Network_player_rejoining.player.server, Network_player_rejoining.player.node );
  732. // OLD ipx_send_packet_data(object_buffer, loc, &Network_player_rejoining.player.node);
  733. }
  734. if (i > Highest_object_index)
  735. {
  736. if (Network_send_object_mode == 0)
  737. {
  738. Network_send_objnum = 0;
  739. Network_send_object_mode = 1; // go to next mode
  740. }
  741. else
  742. {
  743. Assert(Network_send_object_mode == 1);
  744. frame_num++;
  745. // Send count so other side can make sure he got them all
  746. // mprintf((0, "Sending end marker in packet #%d.\n", frame_num));
  747. mprintf((0, "Sent %d objects.\n", obj_count));
  748. object_buffer[0] = PID_OBJECT_DATA;
  749. object_buffer[1] = 1;
  750. object_buffer[2] = frame_num;
  751. *(short *)(object_buffer+3) = -2;
  752. *(short *)(object_buffer+6) = obj_count;
  753. //OLD ipx_send_packet_data(object_buffer, 8, &Network_player_rejoining.player.node);
  754. ipx_send_internetwork_packet_data(object_buffer, 8, Network_player_rejoining.player.server, Network_player_rejoining.player.node);
  755. // Send sync packet which tells the player who he is and to start!
  756. network_send_rejoin_sync(player_num);
  757. // Turn off send object mode
  758. Network_send_objnum = -1;
  759. Network_send_objects = 0;
  760. obj_count = 0;
  761. return;
  762. } // mode == 1;
  763. } // i > Highest_object_index
  764. } // For PACKETS_PER_FRAME
  765. }
  766. void network_send_rejoin_sync(int player_num)
  767. {
  768. int i, j;
  769. Players[player_num].connected = 1; // connect the new guy
  770. LastPacketTime[player_num] = timer_get_approx_seconds();
  771. if (Endlevel_sequence || Fuelcen_control_center_destroyed)
  772. {
  773. // Endlevel started before we finished sending the goods, we'll
  774. // have to stop and try again after the level.
  775. network_dump_player(Network_player_rejoining.player.server,Network_player_rejoining.player.node, DUMP_ENDLEVEL);
  776. Network_send_objects = 0;
  777. return;
  778. }
  779. if (Network_player_added)
  780. {
  781. Network_player_rejoining.type = PID_ADDPLAYER;
  782. Network_player_rejoining.player.connected = player_num;
  783. network_new_player(&Network_player_rejoining);
  784. for (i = 0; i < N_players; i++)
  785. {
  786. if ((i != player_num) && (i != Player_num) && (Players[i].connected))
  787. ipx_send_packet_data( (ubyte *)&Network_player_rejoining, sizeof(sequence_packet), Netgame.players[i].server, Netgame.players[i].node, Players[i].net_address);
  788. }
  789. }
  790. // Send sync packet to the new guy
  791. network_update_netgame();
  792. // Fill in the kill list
  793. for (j=0; j<MAX_PLAYERS; j++)
  794. {
  795. for (i=0; i<MAX_PLAYERS;i++)
  796. Netgame.kills[j][i] = kill_matrix[j][i];
  797. Netgame.killed[j] = Players[j].net_killed_total;
  798. Netgame.player_kills[j] = Players[j].net_kills_total;
  799. #ifndef SHAREWARE
  800. Netgame.player_score[j] = Players[j].score;
  801. #endif
  802. }
  803. #ifndef SHAREWARE
  804. Netgame.level_time = Players[Player_num].time_level;
  805. Netgame.monitor_vector = network_create_monitor_vector();
  806. #endif
  807. mprintf((0, "Sending rejoin sync packet!!!\n"));
  808. ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.server, Network_player_rejoining.player.node );
  809. ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.server, Network_player_rejoining.player.node ); // repeat for safety
  810. ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Network_player_rejoining.player.server, Network_player_rejoining.player.node ); // repeat for safety
  811. #ifndef SHAREWARE
  812. network_send_door_updates();
  813. #endif
  814. return;
  815. }
  816. char * network_get_player_name( int objnum )
  817. {
  818. if ( objnum < 0 ) return NULL;
  819. if ( Objects[objnum].type != OBJ_PLAYER ) return NULL;
  820. if ( Objects[objnum].id >= MAX_PLAYERS ) return NULL;
  821. if ( Objects[objnum].id >= N_players ) return NULL;
  822. return Players[Objects[objnum].id].callsign;
  823. }
  824. void network_add_player(sequence_packet *p)
  825. {
  826. int i;
  827. mprintf((0, "Got add player request!\n"));
  828. for (i=0; i<N_players; i++ ) {
  829. if ( !memcmp( Netgame.players[i].node, p->player.node, 6) && !memcmp(Netgame.players[i].server, p->player.server, 4))
  830. return; // already got them
  831. }
  832. if ( N_players >= MAX_PLAYERS )
  833. return; // too many of em
  834. memcpy( Netgame.players[N_players].callsign, p->player.callsign, CALLSIGN_LEN+1 );
  835. memcpy( Netgame.players[N_players].node, p->player.node, 6 );
  836. memcpy( Netgame.players[N_players].server, p->player.server, 4 );
  837. Netgame.players[N_players].connected = 1;
  838. Players[N_players].connected = 1;
  839. LastPacketTime[N_players] = timer_get_approx_seconds();
  840. N_players++;
  841. Netgame.numplayers = N_players;
  842. // Broadcast updated info
  843. network_send_game_info(NULL);
  844. }
  845. // One of the players decided not to join the game
  846. void network_remove_player(sequence_packet *p)
  847. {
  848. int i,pn;
  849. pn = -1;
  850. for (i=0; i<N_players; i++ ) {
  851. if (!memcmp(Netgame.players[i].node, p->player.node, 6) && !memcmp(Netgame.players[i].server, p->player.server, 4)) {
  852. pn = i;
  853. break;
  854. }
  855. }
  856. if (pn < 0 ) return;
  857. for (i=pn; i<N_players-1; i++ ) {
  858. memcpy( Netgame.players[i].callsign, Netgame.players[i+1].callsign, CALLSIGN_LEN+1 );
  859. memcpy( Netgame.players[i].node, Netgame.players[i+1].node, 6 );
  860. memcpy( Netgame.players[i].server, Netgame.players[i+1].server, 4 );
  861. }
  862. N_players--;
  863. Netgame.numplayers = N_players;
  864. // Broadcast new info
  865. network_send_game_info(NULL);
  866. }
  867. void
  868. network_dump_player(ubyte * server, ubyte *node, int why)
  869. {
  870. // Inform player that he was not chosen for the netgame
  871. sequence_packet temp;
  872. temp.type = PID_DUMP;
  873. memcpy(temp.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
  874. temp.player.connected = why;
  875. ipx_send_internetwork_packet_data( (ubyte *)&temp, sizeof(sequence_packet), server, node);
  876. }
  877. void
  878. network_send_game_list_request(void)
  879. {
  880. // Send a broadcast request for game info
  881. sequence_packet me;
  882. mprintf((0, "Sending game_list request.\n"));
  883. memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
  884. memcpy( me.player.node, ipx_get_my_local_address(), 6 );
  885. memcpy( me.player.server, ipx_get_my_server_address(), 4 );
  886. me.type = PID_GAME_LIST;
  887. ipx_send_broadcast_packet_data( (ubyte *)&me, sizeof(sequence_packet) );
  888. }
  889. void
  890. network_update_netgame(void)
  891. {
  892. // Update the netgame struct with current game variables
  893. int i, j;
  894. if (Network_status == NETSTAT_STARTING)
  895. return;
  896. Netgame.numplayers = N_players;
  897. Netgame.game_status = Network_status;
  898. Netgame.max_numplayers = MaxNumNetPlayers;
  899. for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
  900. {
  901. Netgame.players[i].connected = Players[i].connected;
  902. for(j = 0; j < MAX_NUM_NET_PLAYERS; j++)
  903. Netgame.kills[i][j] = kill_matrix[i][j];
  904. Netgame.killed[i] = Players[i].net_killed_total;
  905. Netgame.player_kills[i] = Players[i].net_kills_total;
  906. #ifndef SHAREWARE
  907. Netgame.player_score[i] = Players[i].score;
  908. Netgame.player_flags[i] = (Players[i].flags & (PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY));
  909. #endif
  910. }
  911. Netgame.team_kills[0] = team_kills[0];
  912. Netgame.team_kills[1] = team_kills[1];
  913. Netgame.levelnum = Current_level_num;
  914. }
  915. void
  916. network_send_endlevel_sub(int player_num)
  917. {
  918. endlevel_info end;
  919. int i;
  920. // Send an endlevel packet for a player
  921. end.type = PID_ENDLEVEL;
  922. end.player_num = player_num;
  923. end.connected = Players[player_num].connected;
  924. end.kills = Players[player_num].net_kills_total;
  925. end.killed = Players[player_num].net_killed_total;
  926. memcpy(end.kill_matrix, kill_matrix[player_num], MAX_PLAYERS*sizeof(short));
  927. if (Players[player_num].connected == 1) // Still playing
  928. {
  929. Assert(Fuelcen_control_center_destroyed);
  930. end.seconds_left = Fuelcen_seconds_left;
  931. }
  932. // mprintf((0, "Sending endlevel packet.\n"));
  933. for (i = 0; i < N_players; i++)
  934. {
  935. if ((i != Player_num) && (i!=player_num) && (Players[i].connected))
  936. ipx_send_packet_data((ubyte *)&end, sizeof(endlevel_info), Netgame.players[i].server, Netgame.players[i].node,Players[i].net_address);
  937. }
  938. }
  939. void
  940. network_send_endlevel_packet(void)
  941. {
  942. // Send an updated endlevel status to other hosts
  943. network_send_endlevel_sub(Player_num);
  944. }
  945. void
  946. network_send_game_info(sequence_packet *their)
  947. {
  948. // Send game info to someone who requested it
  949. char old_type, old_status;
  950. mprintf((0, "Sending game info.\n"));
  951. network_update_netgame(); // Update the values in the netgame struct
  952. old_type = Netgame.type;
  953. old_status = Netgame.game_status;
  954. Netgame.type = PID_GAME_INFO;
  955. if (Endlevel_sequence || Fuelcen_control_center_destroyed)
  956. Netgame.game_status = NETSTAT_ENDLEVEL;
  957. if (!their)
  958. ipx_send_broadcast_packet_data((ubyte *)&Netgame, sizeof(netgame_info));
  959. else
  960. ipx_send_internetwork_packet_data((ubyte *)&Netgame, sizeof(netgame_info), their->player.server, their->player.node);
  961. Netgame.type = old_type;
  962. Netgame.game_status = old_status;
  963. }
  964. int network_send_request(void)
  965. {
  966. // Send a request to join a game 'Netgame'. Returns 0 if we can join this
  967. // game, non-zero if there is some problem.
  968. int i;
  969. Assert(Netgame.numplayers > 0);
  970. for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
  971. if (Netgame.players[i].connected)
  972. break;
  973. Assert(i < MAX_NUM_NET_PLAYERS);
  974. mprintf((0, "Sending game enroll request to player %d. Level = %d\n", i, Netgame.levelnum));
  975. // segments_checksum = netmisc_calc_checksum( Segments, sizeof(segment)*(Highest_segment_index+1) );
  976. My_Seq.type = PID_REQUEST;
  977. My_Seq.player.connected = Current_level_num;
  978. ipx_send_internetwork_packet_data((ubyte *)&My_Seq, sizeof(sequence_packet), Netgame.players[i].server, Netgame.players[i].node);
  979. return i;
  980. }
  981. void network_process_gameinfo(ubyte *data)
  982. {
  983. int i, j;
  984. netgame_info *new;
  985. new = (netgame_info *)data;
  986. Network_games_changed = 1;
  987. mprintf((0, "Got game data for game %s.\n", new->game_name));
  988. for (i = 0; i < num_active_games; i++)
  989. if (!stricmp(Active_games[i].game_name, new->game_name) && !memcmp(Active_games[i].players[0].node, new->players[0].node, 6)
  990. && !memcmp(Active_games[i].players[0].server, new->players[0].server, 4))
  991. break;
  992. if (i == MAX_ACTIVE_NETGAMES)
  993. {
  994. mprintf((0, "Too many netgames.\n"));
  995. return;
  996. }
  997. memcpy(&Active_games[i], data, sizeof(netgame_info));
  998. if (i == num_active_games)
  999. num_active_games++;
  1000. if (Active_games[i].numplayers == 0)
  1001. {
  1002. // Delete this game
  1003. for (j = i; j < num_active_games-1; j++)
  1004. memcpy(&Active_games[j], &Active_games[j+1], sizeof(netgame_info));
  1005. num_active_games--;
  1006. }
  1007. }
  1008. void network_process_dump(sequence_packet *their)
  1009. {
  1010. // Our request for join was denied. Tell the user why.
  1011. mprintf((0, "Dumped by player %s, type %d.\n", their->player.callsign, their->player.connected));
  1012. nm_messagebox(NULL, 1, TXT_OK, NET_DUMP_STRINGS(their->player.connected));
  1013. Network_status = NETSTAT_MENU;
  1014. }
  1015. void network_process_request(sequence_packet *their)
  1016. {
  1017. // Player is ready to receieve a sync packet
  1018. int i;
  1019. mprintf((0, "Player %s ready for sync.\n", their->player.callsign));
  1020. for (i = 0; i < N_players; i++)
  1021. if (!memcmp(their->player.server, Netgame.players[i].server, 4) && !memcmp(their->player.node, Netgame.players[i].node, 6) && (!stricmp(their->player.callsign, Netgame.players[i].callsign))) {
  1022. Players[i].connected = 1;
  1023. break;
  1024. }
  1025. }
  1026. void network_process_packet(ubyte *data, int length )
  1027. {
  1028. sequence_packet *their = (sequence_packet *)data;
  1029. // mprintf( (0, "Got packet of length %d, type %d\n", length, their->type ));
  1030. // if ( length < sizeof(sequence_packet) ) return;
  1031. length = length;
  1032. switch( their->type ) {
  1033. case PID_GAME_INFO:
  1034. mprintf((0, "GOT a PID_GAME_INFO!\n"));
  1035. if (length != sizeof(netgame_info))
  1036. mprintf((0, " Invalid size %d for netgame packet.\n", length));
  1037. if (Network_status == NETSTAT_BROWSING)
  1038. network_process_gameinfo(data);
  1039. break;
  1040. case PID_GAME_LIST:
  1041. // Someone wants a list of games
  1042. mprintf((0, "Got a PID_GAME_LIST!\n"));
  1043. if ((Network_status == NETSTAT_PLAYING) || (Network_status == NETSTAT_STARTING) || (Network_status == NETSTAT_ENDLEVEL))
  1044. if (network_i_am_master())
  1045. network_send_game_info(their);
  1046. break;
  1047. case PID_ADDPLAYER:
  1048. mprintf( (0, "Got NEWPLAYER message from %s.\n", their->player.callsign));
  1049. network_new_player(their);
  1050. break;
  1051. case PID_REQUEST:
  1052. mprintf( (0, "Got REQUEST from '%s'\n", their->player.callsign ));
  1053. if (Network_status == NETSTAT_STARTING)
  1054. {
  1055. // Someone wants to join our game!
  1056. network_add_player(their);
  1057. }
  1058. else if (Network_status == NETSTAT_WAITING)
  1059. {
  1060. // Someone is ready to recieve a sync packet
  1061. network_process_request(their);
  1062. }
  1063. else if (Network_status == NETSTAT_PLAYING)
  1064. {
  1065. // Someone wants to join a game in progress!
  1066. network_welcome_player(their);
  1067. }
  1068. break;
  1069. case PID_DUMP:
  1070. if (Network_status == NETSTAT_WAITING)
  1071. network_process_dump(their);
  1072. break;
  1073. case PID_QUIT_JOINING:
  1074. if (Network_status == NETSTAT_STARTING)
  1075. network_remove_player( their );
  1076. else if ((Network_status == NETSTAT_PLAYING) && (Network_send_objects))
  1077. network_stop_resync( their );
  1078. break;
  1079. case PID_SYNC:
  1080. if (Network_status == NETSTAT_WAITING) {
  1081. network_read_sync_packet((netgame_info *)data);
  1082. }
  1083. break;
  1084. case PID_PDATA:
  1085. if ((Game_mode&GM_NETWORK) && ((Network_status == NETSTAT_PLAYING)||(Network_status == NETSTAT_ENDLEVEL) )) {
  1086. network_read_pdata_packet((frame_info *)data);
  1087. }
  1088. break;
  1089. case PID_OBJECT_DATA:
  1090. if (Network_status == NETSTAT_WAITING)
  1091. network_read_object_packet(data);
  1092. break;
  1093. case PID_ENDLEVEL:
  1094. if ((Network_status == NETSTAT_ENDLEVEL) || (Network_status == NETSTAT_PLAYING))
  1095. network_read_endlevel_packet(data);
  1096. else
  1097. mprintf((0, "Junked endlevel packet.\n"));
  1098. break;
  1099. default:
  1100. mprintf((0, "Ignoring invalid packet type.\n"));
  1101. Int3(); // Invalid network packet type, see ROB
  1102. }
  1103. }
  1104. #ifndef NDEBUG
  1105. void dump_segments()
  1106. {
  1107. FILE * fp;
  1108. fp = fopen( "TEST.DMP", "wb" );
  1109. fwrite( Segments, sizeof(segment)*(Highest_segment_index+1),1, fp );
  1110. fclose(fp);
  1111. mprintf( (0, "SS=%d\n", sizeof(segment) ));
  1112. }
  1113. #endif
  1114. void
  1115. network_read_endlevel_packet( ubyte *data )
  1116. {
  1117. // Special packet for end of level syncing
  1118. int playernum;
  1119. endlevel_info *end;
  1120. end = (endlevel_info *)data;
  1121. playernum = end->player_num;
  1122. Assert(playernum != Player_num);
  1123. Assert(playernum < N_players);
  1124. if ((Network_status == NETSTAT_PLAYING) && (end->connected != 0))
  1125. return; // Only accept disconnect packets if we're not out of the level yet
  1126. Players[playernum].connected = end->connected;
  1127. memcpy(&kill_matrix[playernum][0], end->kill_matrix, MAX_PLAYERS*sizeof(short));
  1128. Players[playernum].net_kills_total = end->kills;
  1129. Players[playernum].net_killed_total = end->killed;
  1130. if ((Players[playernum].connected == 1) && (end->seconds_left < Fuelcen_seconds_left))
  1131. Fuelcen_seconds_left = end->seconds_left;
  1132. LastPacketTime[playernum] = timer_get_approx_seconds();
  1133. // mprintf((0, "Got endlevel packet from player %d.\n", playernum));
  1134. }
  1135. void
  1136. network_pack_objects(void)
  1137. {
  1138. // Switching modes, pack the object array
  1139. special_reset_objects();
  1140. }
  1141. int
  1142. network_verify_objects(int remote, int local)
  1143. {
  1144. int i;
  1145. int nplayers, got_controlcen=0;
  1146. if ((remote-local) > 10)
  1147. return(-1);
  1148. if (Game_mode & GM_MULTI_ROBOTS)
  1149. got_controlcen = 1;
  1150. nplayers = 0;
  1151. for (i = 0; i <= Highest_object_index; i++)
  1152. {
  1153. if ((Objects[i].type == OBJ_PLAYER) || (Objects[i].type == OBJ_GHOST))
  1154. nplayers++;
  1155. if (Objects[i].type == OBJ_CNTRLCEN)
  1156. got_controlcen=1;
  1157. }
  1158. if (got_controlcen && (nplayers >= MaxNumNetPlayers))
  1159. return(0);
  1160. return(1);
  1161. }
  1162. void
  1163. network_read_object_packet( ubyte *data )
  1164. {
  1165. // Object from another net player we need to sync with
  1166. short objnum, remote_objnum;
  1167. byte obj_owner;
  1168. int segnum, i;
  1169. object *obj;
  1170. static int my_pnum = 0;
  1171. static int mode = 0;
  1172. static int object_count = 0;
  1173. static int frame_num = 0;
  1174. int nobj = data[1];
  1175. int loc = 3;
  1176. int remote_frame_num = data[2];
  1177. frame_num++;
  1178. // mprintf((0, "Object packet %d (remote #%d) contains %d objects.\n", frame_num, remote_frame_num, nobj));
  1179. for (i = 0; i < nobj; i++)
  1180. {
  1181. objnum = *(short *)(data+loc); loc += 2;
  1182. obj_owner = data[loc]; loc += 1;
  1183. remote_objnum = *(short *)(data+loc); loc += 2;
  1184. if (objnum == -1)
  1185. {
  1186. // Clear object array
  1187. mprintf((0, "Clearing object array.\n"));
  1188. init_objects();
  1189. Network_rejoined = 1;
  1190. my_pnum = obj_owner;
  1191. change_playernum_to(my_pnum);
  1192. mode = 1;
  1193. object_count = 0;
  1194. frame_num = 1;
  1195. }
  1196. else if (objnum == -2)
  1197. {
  1198. // Special debug checksum marker for entire send
  1199. if (mode == 1)
  1200. {
  1201. network_pack_objects();
  1202. mode = 0;
  1203. }
  1204. mprintf((0, "Objnum -2 found in frame local %d remote %d.\n", frame_num, remote_frame_num));
  1205. mprintf((0, "Got %d objects, expected %d.\n", object_count, remote_objnum));
  1206. if (remote_objnum != object_count) {
  1207. Int3();
  1208. }
  1209. if (network_verify_objects(remote_objnum, object_count))
  1210. {
  1211. // Failed to sync up
  1212. nm_messagebox(NULL, 1, TXT_OK, TXT_NET_SYNC_FAILED);
  1213. Network_status = NETSTAT_MENU;
  1214. return;
  1215. }
  1216. frame_num = 0;
  1217. }
  1218. else
  1219. {
  1220. if (frame_num != remote_frame_num)
  1221. Int3();
  1222. object_count++;
  1223. if ((obj_owner == my_pnum) || (obj_owner == -1))
  1224. {
  1225. if (mode != 1)
  1226. Int3(); // SEE ROB
  1227. objnum = remote_objnum;
  1228. //if (objnum > Highest_object_index)
  1229. //{
  1230. // Highest_object_index = objnum;
  1231. // num_objects = Highest_object_index+1;
  1232. //}
  1233. }
  1234. else {
  1235. if (mode == 1)
  1236. {
  1237. network_pack_objects();
  1238. mode = 0;
  1239. }
  1240. objnum = obj_allocate();
  1241. }
  1242. if (objnum != -1) {
  1243. obj = &Objects[objnum];
  1244. if (obj->segnum != -1)
  1245. obj_unlink(objnum);
  1246. Assert(obj->segnum == -1);
  1247. Assert(objnum < MAX_OBJECTS);
  1248. memcpy(obj,data+loc,sizeof(object)); loc += sizeof(object);
  1249. segnum = obj->segnum;
  1250. obj->next = obj->prev = obj->segnum = -1;
  1251. obj->attached_obj = -1;
  1252. if (segnum > -1)
  1253. obj_link(obj-Objects,segnum);
  1254. if (obj_owner == my_pnum)
  1255. map_objnum_local_to_local(objnum);
  1256. else if (obj_owner != -1)
  1257. map_objnum_local_to_remote(objnum, remote_objnum, obj_owner);
  1258. else
  1259. object_owner[objnum] = -1;
  1260. }
  1261. } // For a standard onbject
  1262. } // For each object in packet
  1263. }
  1264. void network_sync_poll( int nitems, newmenu_item * menus, int * key, int citem )
  1265. {
  1266. // Polling loop waiting for sync packet to start game
  1267. static fix t1 = 0;
  1268. menus = menus;
  1269. citem = citem;
  1270. nitems = nitems;
  1271. network_listen();
  1272. if (Network_status != NETSTAT_WAITING) // Status changed to playing, exit the menu
  1273. *key = -2;
  1274. if (!Network_rejoined && (timer_get_approx_seconds() > t1+F1_0*2))
  1275. {
  1276. int i;
  1277. // Poll time expired, re-send request
  1278. t1 = timer_get_approx_seconds();
  1279. mprintf((0, "Re-sending join request.\n"));
  1280. i = network_send_request();
  1281. if (i < 0)
  1282. *key = -2;
  1283. }
  1284. }
  1285. void network_start_poll( int nitems, newmenu_item * menus, int * key, int citem )
  1286. {
  1287. int i,n,nm;
  1288. key=key;
  1289. citem=citem;
  1290. Assert(Network_status == NETSTAT_STARTING);
  1291. if (!menus[0].value) {
  1292. menus[0].value = 1;
  1293. menus[0].redraw = 1;
  1294. }
  1295. for (i=1; i<nitems; i++ ) {
  1296. if ( (i>= N_players) && (menus[i].value) ) {
  1297. menus[i].value = 0;
  1298. menus[i].redraw = 1;
  1299. }
  1300. }
  1301. nm = 0;
  1302. for (i=0; i<nitems; i++ ) {
  1303. if ( menus[i].value ) {
  1304. nm++;
  1305. if ( nm > N_players ) {
  1306. menus[i].value = 0;
  1307. menus[i].redraw = 1;
  1308. }
  1309. }
  1310. }
  1311. if ( nm > MaxNumNetPlayers ) {
  1312. nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, MaxNumNetPlayers, TXT_NETPLAYERS_IN );
  1313. // Turn off the last player highlighted
  1314. for (i = N_players; i > 0; i--)
  1315. if (menus[i].value == 1)
  1316. {
  1317. menus[i].value = 0;
  1318. menus[i].redraw = 1;
  1319. break;
  1320. }
  1321. }
  1322. if (nitems > MAX_PLAYERS ) return;
  1323. n = Netgame.numplayers;
  1324. network_listen();
  1325. if (n < Netgame.numplayers )
  1326. {
  1327. sprintf( menus[N_players-1].text, "%d. %-16s", N_players, Netgame.players[N_players-1].callsign );
  1328. menus[N_players-1].redraw = 1;
  1329. if (N_players <= MaxNumNetPlayers)
  1330. {
  1331. menus[N_players-1].value = 1;
  1332. }
  1333. }
  1334. else if ( n > Netgame.numplayers )
  1335. {
  1336. // One got removed...
  1337. for (i=0; i<N_players; i++ )
  1338. {
  1339. sprintf( menus[i].text, "%d. %-16s", i+1, Netgame.players[i].callsign );
  1340. if (i < MaxNumNetPlayers)
  1341. menus[i].value = 1;
  1342. else
  1343. menus[i].value = 0;
  1344. menus[i].redraw = 1;
  1345. }
  1346. for (i=N_players; i<n; i++ )
  1347. {
  1348. sprintf( menus[i].text, "%d. ", i+1 ); // Clear out the deleted entries...
  1349. menus[i].value = 0;
  1350. menus[i].redraw = 1;
  1351. }
  1352. }
  1353. }
  1354. int opt_cinvul;
  1355. int last_cinvul=0;
  1356. int opt_mode;
  1357. #pragma off (unreferenced)
  1358. void network_game_param_poll( int nitems, newmenu_item * menus, int * key, int citem )
  1359. {
  1360. #ifdef SHAREWARE
  1361. return;
  1362. #else
  1363. #ifndef ROCKWELL_CODE
  1364. if (menus[opt_mode+2].value && !menus[opt_mode+6].value) {
  1365. menus[opt_mode+6].value = 1;
  1366. menus[opt_mode+6].redraw = 1;
  1367. }
  1368. if (menus[opt_mode+4].value) {
  1369. if (!menus[opt_mode+7].value) {
  1370. menus[opt_mode+7].value = 1;
  1371. menus[opt_mode+7].redraw = 1;
  1372. }
  1373. }
  1374. #endif
  1375. if ( last_cinvul != menus[opt_cinvul].value ) {
  1376. sprintf( menus[opt_cinvul].text, "%s: %d %s", TXT_REACTOR_LIFE, menus[opt_cinvul].value*5, TXT_MINUTES_ABBREV );
  1377. last_cinvul = menus[opt_cinvul].value;
  1378. menus[opt_cinvul].redraw = 1;
  1379. }
  1380. #endif
  1381. }
  1382. #pragma on (unreferenced)
  1383. int network_get_game_params( char * game_name, int *mode, int *game_flags, int *level )
  1384. {
  1385. int i;
  1386. int opt, opt_name, opt_level, opt_closed, opt_difficulty;
  1387. newmenu_item m[16];
  1388. char name[NETGAME_NAME_LEN+1];
  1389. char slevel[5];
  1390. char level_text[32];
  1391. char srinvul[32];
  1392. #ifndef SHAREWARE
  1393. int new_mission_num;
  1394. int anarchy_only;
  1395. new_mission_num = multi_choose_mission(&anarchy_only);
  1396. if (new_mission_num < 0)
  1397. return -1;
  1398. strcpy(Netgame.mission_name, Mission_list[new_mission_num].filename);
  1399. strcpy(Netgame.mission_title, Mission_list[new_mission_num].mission_name);
  1400. Netgame.control_invul_time = control_invul_time;
  1401. #endif
  1402. sprintf( name, "%s%s", Players[Player_num].callsign, TXT_S_GAME );
  1403. sprintf( slevel, "1" );
  1404. opt = 0;
  1405. m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_DESCRIPTION; opt++;
  1406. opt_name = opt;
  1407. m[opt].type = NM_TYPE_INPUT; m[opt].text = name; m[opt].text_len = NETGAME_NAME_LEN; opt++;
  1408. sprintf(level_text, "%s (1-%d)", TXT_LEVEL_, Last_level);
  1409. if (Last_secret_level < -1)
  1410. sprintf(level_text+strlen(level_text)-1, ", S1-S%d)", -Last_secret_level);
  1411. else if (Last_secret_level == -1)
  1412. sprintf(level_text+strlen(level_text)-1, ", S1)");
  1413. Assert(strlen(level_text) < 32);
  1414. m[opt].type = NM_TYPE_TEXT; m[opt].text = level_text; opt++;
  1415. opt_level = opt;
  1416. m[opt].type = NM_TYPE_INPUT; m[opt].text = slevel; m[opt].text_len=4; opt++;
  1417. #ifdef ROCKWELL_CODE
  1418. opt_mode = 0;
  1419. #else
  1420. opt_mode = opt;
  1421. m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_MODE; opt++;
  1422. m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY; m[opt].value=1; m[opt].group=0; opt++;
  1423. m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_TEAM_ANARCHY; m[opt].value=0; m[opt].group=0; opt++;
  1424. m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_ANARCHY_W_ROBOTS; m[opt].value=0; m[opt].group=0; opt++;
  1425. m[opt].type = NM_TYPE_RADIO; m[opt].text = TXT_COOPERATIVE; m[opt].value=0; m[opt].group=0; opt++;
  1426. #endif
  1427. m[opt].type = NM_TYPE_TEXT; m[opt].text = TXT_OPTIONS; opt++;
  1428. opt_closed = opt;
  1429. m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_CLOSED_GAME; m[opt].value=0; opt++;
  1430. #ifndef SHAREWARE
  1431. // m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_IDS; m[opt].value=0; opt++;
  1432. m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_ON_MAP; m[opt].value=0; opt++;
  1433. #endif
  1434. opt_difficulty = opt;
  1435. m[opt].type = NM_TYPE_SLIDER; m[opt].value=Player_default_difficulty; m[opt].text=TXT_DIFFICULTY; m[opt].min_value=0; m[opt].max_value=(NDL-1); opt++;
  1436. // m[opt].type = NM_TYPE_TEXT; m[opt].text = "Reactor Invulnerability (mins)"; opt++;
  1437. // opt_cinvul = opt;
  1438. // sprintf( srinvul, "%d", control_invul_time );
  1439. // m[opt].type = NM_TYPE_INPUT; m[opt].text = srinvul; m[opt].text_len=2; opt++;
  1440. opt_cinvul = opt;
  1441. sprintf( srinvul, "%s: %d %s", TXT_REACTOR_LIFE, 5*control_invul_time, TXT_MINUTES_ABBREV );
  1442. last_cinvul = control_invul_time;
  1443. m[opt].type = NM_TYPE_SLIDER; m[opt].value=control_invul_time; m[opt].text= srinvul; m[opt].min_value=0; m[opt].max_value=15; opt++;
  1444. Assert(opt <= 16);
  1445. menu:
  1446. i = newmenu_do1( NULL, TXT_NETGAME_SETUP, opt, m, network_game_param_poll, 1 );
  1447. if ( i > -1 ) {
  1448. int j;
  1449. for (j = 0; j < num_active_games; j++)
  1450. if (!stricmp(Active_games[j].game_name, name))
  1451. {
  1452. nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_DUPLICATE_NAME);
  1453. goto menu;
  1454. }
  1455. strcpy( game_name, name );
  1456. if (!strnicmp(slevel, "s", 1))
  1457. *level = -atoi(slevel+1);
  1458. else
  1459. *level = atoi(slevel);
  1460. if ((*level < Last_secret_level) || (*level > Last_level) || (*level == 0))
  1461. {
  1462. nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_LEVEL_OUT_RANGE );
  1463. sprintf(slevel, "1");
  1464. goto menu;
  1465. }
  1466. #ifdef ROCKWELL_CODE
  1467. *mode = NETGAME_COOPERATIVE;
  1468. #else
  1469. if ( m[opt_mode+1].value )
  1470. *mode = NETGAME_ANARCHY;
  1471. else if (m[opt_mode+2].value) {
  1472. *mode = NETGAME_TEAM_ANARCHY;
  1473. } else if (anarchy_only) {
  1474. nm_messagebox(NULL, 1, TXT_OK, TXT_ANARCHY_ONLY_MISSION);
  1475. m[opt_mode+2].value = 0;
  1476. m[opt_mode+3].value = 0;
  1477. m[opt_mode].value = 1;
  1478. goto menu;
  1479. } else if ( m[opt_mode+3].value )
  1480. *mode = NETGAME_ROBOT_ANARCHY;
  1481. else if ( m[opt_mode+4].value )
  1482. *mode = NETGAME_COOPERATIVE;
  1483. else Int3(); // Invalid mode -- see Rob
  1484. #endif // ifdef ROCKWELL
  1485. if (m[opt_closed].value)
  1486. *game_flags |= NETGAME_FLAG_CLOSED;
  1487. #ifndef SHAREWARE
  1488. // if (m[opt_closed+1].value)
  1489. // *game_flags |= NETGAME_FLAG_SHOW_ID;
  1490. if (m[opt_closed+1].value)
  1491. *game_flags |= NETGAME_FLAG_SHOW_MAP;
  1492. #endif
  1493. Difficulty_level = m[opt_difficulty].value;
  1494. //control_invul_time = atoi( srinvul )*60*F1_0;
  1495. control_invul_time = m[opt_cinvul].value;
  1496. Netgame.control_invul_time = control_invul_time*5*F1_0*60;
  1497. }
  1498. return i;
  1499. }
  1500. void
  1501. network_set_game_mode(int gamemode)
  1502. {
  1503. Show_kill_list = 1;
  1504. if ( gamemode == NETGAME_ANARCHY )
  1505. Game_mode = GM_NETWORK;
  1506. else if ( gamemode == NETGAME_ROBOT_ANARCHY )
  1507. Game_mode = GM_NETWORK | GM_MULTI_ROBOTS;
  1508. else if ( gamemode == NETGAME_COOPERATIVE )
  1509. Game_mode = GM_NETWORK | GM_MULTI_COOP | GM_MULTI_ROBOTS;
  1510. else if ( gamemode == NETGAME_TEAM_ANARCHY )
  1511. {
  1512. Game_mode = GM_NETWORK | GM_TEAM;
  1513. Show_kill_list = 2;
  1514. }
  1515. else
  1516. Int3();
  1517. if (Game_mode & GM_MULTI_ROBOTS)
  1518. MaxNumNetPlayers = 4;
  1519. else
  1520. MaxNumNetPlayers = 8;
  1521. }
  1522. int
  1523. network_find_game(void)
  1524. {
  1525. // Find out whether or not there is space left on this socket
  1526. fix t1;
  1527. Network_status = NETSTAT_BROWSING;
  1528. num_active_games = 0;
  1529. show_boxed_message(TXT_WAIT);
  1530. network_send_game_list_request();
  1531. t1 = timer_get_approx_seconds() + F1_0*2;
  1532. while (timer_get_approx_seconds() < t1) // Wait 3 seconds for replies
  1533. network_listen();
  1534. clear_boxed_message();
  1535. // mprintf((0, "%s %d %s\n", TXT_FOUND, num_active_games, TXT_ACTIVE_GAMES));
  1536. if (num_active_games < MAX_ACTIVE_NETGAMES)
  1537. return 0;
  1538. return 1;
  1539. }
  1540. void network_read_sync_packet( netgame_info * sp )
  1541. {
  1542. int i, j;
  1543. char temp_callsign[CALLSIGN_LEN+1];
  1544. // This function is now called by all people entering the netgame.
  1545. // mprintf( (0, "%s %d\n", TXT_STARTING_NETGAME, sp->levelnum ));
  1546. if (sp != &Netgame)
  1547. memcpy( &Netgame, sp, sizeof(netgame_info) );
  1548. N_players = sp->numplayers;
  1549. Difficulty_level = sp->difficulty;
  1550. Network_status = sp->game_status;
  1551. Assert(Function_mode != FMODE_GAME);
  1552. // New code, 11/27
  1553. mprintf((1, "Netgame.checksum = %d, calculated checksum = %d.\n", Netgame.segments_checksum, my_segments_checksum));
  1554. if (Netgame.segments_checksum != my_segments_checksum)
  1555. {
  1556. Network_status = NETSTAT_MENU;
  1557. nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NETLEVEL_NMATCH);
  1558. #ifdef NDEBUG
  1559. return;
  1560. #endif
  1561. }
  1562. // Discover my player number
  1563. memcpy(temp_callsign, Players[Player_num].callsign, CALLSIGN_LEN+1);
  1564. Player_num = -1;
  1565. for (i=0; i<MAX_NUM_NET_PLAYERS; i++ ) {
  1566. Players[i].net_kills_total = 0;
  1567. // Players[i].net_killed_total = 0;
  1568. }
  1569. for (i=0; i<N_players; i++ ) {
  1570. if ((!memcmp( sp->players[i].node, My_Seq.player.node, 6 )) &&
  1571. (!stricmp( sp->players[i].callsign, temp_callsign)) )
  1572. {
  1573. Assert(Player_num == -1); // Make sure we don't find ourselves twice! Looking for interplay reported bug
  1574. change_playernum_to(i);
  1575. }
  1576. memcpy( Players[i].callsign, sp->players[i].callsign, CALLSIGN_LEN+1 );
  1577. #ifndef SHAREWARE
  1578. if ( (*(uint *)sp->players[i].server) != 0 )
  1579. ipx_get_local_target( sp->players[i].server, sp->players[i].node, Players[i].net_address );
  1580. else
  1581. #endif
  1582. memcpy( Players[i].net_address, sp->players[i].node, 6 );
  1583. Players[i].n_packets_got=0; // How many packets we got from them
  1584. Players[i].n_packets_sent=0; // How many packets we sent to them
  1585. Players[i].connected = sp->players[i].connected;
  1586. Players[i].net_kills_total += sp->player_kills[i];
  1587. #ifndef SHAREWARE
  1588. if ((Network_rejoined) || (i != Player_num))
  1589. Players[i].score = sp->player_score[i];
  1590. #endif
  1591. for (j = 0; j < MAX_NUM_NET_PLAYERS; j++)
  1592. {
  1593. kill_matrix[i][j] = sp->kills[i][j];
  1594. }
  1595. }
  1596. if ( Player_num < 0 ) {
  1597. Network_status = NETSTAT_MENU;
  1598. return;
  1599. }
  1600. if (Network_rejoined)
  1601. for (i=0; i<N_players;i++)
  1602. Players[i].net_killed_total = sp->killed[i];
  1603. #ifndef SHAREWARE
  1604. if (Network_rejoined) {
  1605. network_process_monitor_vector(sp->monitor_vector);
  1606. Players[Player_num].time_level = sp->level_time;
  1607. }
  1608. #endif
  1609. team_kills[0] = sp->team_kills[0];
  1610. team_kills[1] = sp->team_kills[1];
  1611. Players[Player_num].connected = 1;
  1612. Netgame.players[Player_num].connected = 1;
  1613. if (!Network_rejoined)
  1614. for (i=0; i<MaxNumNetPlayers; i++) {
  1615. Objects[Players[i].objnum].pos = Player_init[Netgame.locations[i]].pos;
  1616. Objects[Players[i].objnum].orient = Player_init[Netgame.locations[i]].orient;
  1617. obj_relink(Players[i].objnum,Player_init[Netgame.locations[i]].segnum);
  1618. }
  1619. Objects[Players[Player_num].objnum].type = OBJ_PLAYER;
  1620. Network_status = NETSTAT_PLAYING;
  1621. Function_mode = FMODE_GAME;
  1622. multi_sort_kill_list();
  1623. }
  1624. void
  1625. network_send_sync(void)
  1626. {
  1627. int i, j, np;
  1628. // Randomize their starting locations...
  1629. srand( TICKER );
  1630. for (i=0; i<MaxNumNetPlayers; i++ )
  1631. {
  1632. if (Players[i].connected)
  1633. Players[i].connected = 1; // Get rid of endlevel connect statuses
  1634. if (Game_mode & GM_MULTI_COOP)
  1635. Netgame.locations[i] = i;
  1636. else {
  1637. do
  1638. {
  1639. np = rand() % MaxNumNetPlayers;
  1640. for (j=0; j<i; j++ )
  1641. {
  1642. if (Netgame.locations[j]==np)
  1643. {
  1644. np =-1;
  1645. break;
  1646. }
  1647. }
  1648. } while (np<0);
  1649. // np is a location that is not used anywhere else..
  1650. Netgame.locations[i]=np;
  1651. // mprintf((0, "Player %d starting in location %d\n" ,i ,np ));
  1652. }
  1653. }
  1654. // Push current data into the sync packet
  1655. network_update_netgame();
  1656. Netgame.game_status = NETSTAT_PLAYING;
  1657. Netgame.type = PID_SYNC;
  1658. Netgame.segments_checksum = my_segments_checksum;
  1659. for (i=0; i<N_players; i++ ) {
  1660. if ((!Players[i].connected) || (i == Player_num))
  1661. continue;
  1662. // Send several times, extras will be ignored
  1663. ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Netgame.players[i].server, Netgame.players[i].node);
  1664. ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Netgame.players[i].server, Netgame.players[i].node);
  1665. ipx_send_internetwork_packet_data( (ubyte *)&Netgame, sizeof(netgame_info), Netgame.players[i].server, Netgame.players[i].node);
  1666. }
  1667. network_read_sync_packet(&Netgame); // Read it myself, as if I had sent it
  1668. }
  1669. int
  1670. network_select_teams(void)
  1671. {
  1672. #ifndef SHAREWARE
  1673. newmenu_item m[MAX_PLAYERS+4];
  1674. int choice, opt, opt_team_b;
  1675. ubyte team_vector = 0;
  1676. char team_names[2][CALLSIGN_LEN+1];
  1677. int i;
  1678. int pnums[MAX_PLAYERS+2];
  1679. // One-time initialization
  1680. for (i = N_players/2; i < N_players; i++) // Put first half of players on team A
  1681. {
  1682. team_vector |= (1 << i);
  1683. }
  1684. sprintf(team_names[0], "%s", TXT_BLUE);
  1685. sprintf(team_names[1], "%s", TXT_RED);
  1686. // Here comes da menu
  1687. menu:
  1688. m[0].type = NM_TYPE_INPUT; m[0].text = team_names[0]; m[0].text_len = CALLSIGN_LEN;
  1689. opt = 1;
  1690. for (i = 0; i < N_players; i++)
  1691. {
  1692. if (!(team_vector & (1 << i)))
  1693. {
  1694. m[opt].type = NM_TYPE_MENU; m[opt].text = Netgame.players[i].callsign; pnums[opt] = i; opt++;
  1695. }
  1696. }
  1697. opt_team_b = opt;
  1698. m[opt].type = NM_TYPE_INPUT; m[opt].text = team_names[1]; m[opt].text_len = CALLSIGN_LEN; opt++;
  1699. for (i = 0; i < N_players; i++)
  1700. {
  1701. if (team_vector & (1 << i))
  1702. {
  1703. m[opt].type = NM_TYPE_MENU; m[opt].text = Netgame.players[i].callsign; pnums[opt] = i; opt++;
  1704. }
  1705. }
  1706. m[opt].type = NM_TYPE_TEXT; m[opt].text = ""; opt++;
  1707. m[opt].type = NM_TYPE_MENU; m[opt].text = TXT_ACCEPT; opt++;
  1708. Assert(opt <= MAX_PLAYERS+4);
  1709. choice = newmenu_do(NULL, TXT_TEAM_SELECTION, opt, m, NULL);
  1710. if (choice == opt-1)
  1711. {
  1712. if ((opt-2-opt_team_b < 2) || (opt_team_b == 1))
  1713. {
  1714. nm_messagebox(NULL, 1, TXT_OK, TXT_TEAM_MUST_ONE);
  1715. goto menu;
  1716. }
  1717. Netgame.team_vector = team_vector;
  1718. strcpy(Netgame.team_name[0], team_names[0]);
  1719. strcpy(Netgame.team_name[1], team_names[1]);
  1720. return 1;
  1721. }
  1722. else if ((choice > 0) && (choice < opt_team_b)) {
  1723. team_vector |= (1 << pnums[choice]);
  1724. }
  1725. else if ((choice > opt_team_b) && (choice < opt-2)) {
  1726. team_vector &= ~(1 << pnums[choice]);
  1727. }
  1728. else if (choice == -1)
  1729. return 0;
  1730. goto menu;
  1731. #else
  1732. return 0;
  1733. #endif
  1734. }
  1735. int
  1736. network_select_players(void)
  1737. {
  1738. int i, j;
  1739. newmenu_item m[MAX_PLAYERS];
  1740. char text[MAX_PLAYERS][25];
  1741. char title[50];
  1742. int save_nplayers;
  1743. network_add_player( &My_Seq );
  1744. for (i=0; i< MAX_PLAYERS; i++ ) {
  1745. sprintf( text[i], "%d. %-16s", i+1, "" );
  1746. m[i].type = NM_TYPE_CHECK; m[i].text = text[i]; m[i].value = 0;
  1747. }
  1748. m[0].value = 1; // Assume server will play...
  1749. sprintf( text[0], "%d. %-16s", 1, Players[Player_num].callsign );
  1750. sprintf( title, "%s %d %s", TXT_TEAM_SELECT, MaxNumNetPlayers, TXT_TEAM_PRESS_ENTER );
  1751. GetPlayersAgain:
  1752. j=newmenu_do1( NULL, title, MAX_PLAYERS, m, network_start_poll, 1 );
  1753. save_nplayers = N_players;
  1754. if (j<0)
  1755. {
  1756. // Aborted!
  1757. // Dump all players and go back to menu mode
  1758. abort:
  1759. for (i=1; i<N_players; i++)
  1760. network_dump_player(Netgame.players[i].server,Netgame.players[i].node, DUMP_ABORTED);
  1761. Netgame.numplayers = 0;
  1762. network_send_game_info(0); // Tell everyone we're bailing
  1763. Network_status = NETSTAT_MENU;
  1764. return(0);
  1765. }
  1766. // Count number of players chosen
  1767. N_players = 0;
  1768. for (i=0; i<save_nplayers; i++ )
  1769. {
  1770. if (m[i].value)
  1771. N_players++;
  1772. }
  1773. if ( N_players > MaxNumNetPlayers) {
  1774. nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, MaxNumNetPlayers, TXT_NETPLAYERS_IN );
  1775. N_players = save_nplayers;
  1776. goto GetPlayersAgain;
  1777. }
  1778. #ifdef NDEBUG
  1779. if ( N_players < 2 ) {
  1780. nm_messagebox( TXT_ERROR, 1, TXT_OK, TXT_TEAM_ATLEAST_TWO );
  1781. N_players = save_nplayers;
  1782. goto GetPlayersAgain;
  1783. }
  1784. #endif
  1785. #ifdef NDEBUG
  1786. if ( (Netgame.gamemode == NETGAME_TEAM_ANARCHY) && (N_players < 3) ) {
  1787. nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_TEAM_ATLEAST_THREE );
  1788. N_players = save_nplayers;
  1789. goto GetPlayersAgain;
  1790. }
  1791. #endif
  1792. // Remove players that aren't marked.
  1793. N_players = 0;
  1794. for (i=0; i<save_nplayers; i++ ) {
  1795. if (m[i].value)
  1796. {
  1797. if (i > N_players)
  1798. {
  1799. memcpy(Netgame.players[N_players].callsign, Netgame.players[i].callsign, CALLSIGN_LEN+1);
  1800. memcpy(Netgame.players[N_players].node, Netgame.players[i].node, 6);
  1801. memcpy(Netgame.players[N_players].server, Netgame.players[i].server, 4);
  1802. }
  1803. Players[N_players].connected = 1;
  1804. N_players++;
  1805. }
  1806. else
  1807. {
  1808. network_dump_player(Netgame.players[i].server,Netgame.players[i].node, DUMP_DORK);
  1809. }
  1810. }
  1811. for (i = N_players; i < MAX_NUM_NET_PLAYERS; i++) {
  1812. memset(Netgame.players[i].callsign, 0, CALLSIGN_LEN+1);
  1813. memset(Netgame.players[i].node, 0, 6);
  1814. memset(Netgame.players[i].server, 0, 4);
  1815. }
  1816. if (Netgame.gamemode == NETGAME_TEAM_ANARCHY)
  1817. if (!network_select_teams())
  1818. goto abort;
  1819. return(1);
  1820. }
  1821. void
  1822. network_start_game(void)
  1823. {
  1824. int i;
  1825. char game_name[NETGAME_NAME_LEN+1];
  1826. int chosen_game_mode, game_flags, level;
  1827. Assert( sizeof(frame_info) < IPX_MAX_DATA_SIZE );
  1828. mprintf((0, "Using frame_info len %d, max %d.\n", sizeof(frame_info), IPX_MAX_DATA_SIZE));
  1829. if ( !Network_active )
  1830. {
  1831. nm_messagebox(NULL, 1, TXT_OK, TXT_IPX_NOT_FOUND );
  1832. return;
  1833. }
  1834. network_init();
  1835. change_playernum_to(0);
  1836. if (network_find_game())
  1837. {
  1838. nm_messagebox(NULL, 1, TXT_OK, TXT_NET_FULL);
  1839. return;
  1840. }
  1841. game_flags = 0;
  1842. i = network_get_game_params( game_name, &chosen_game_mode, &game_flags, &level );
  1843. if (i<0) return;
  1844. N_players = 0;
  1845. // LoadLevel(level); Old, no longer used.
  1846. Netgame.difficulty = Difficulty_level;
  1847. Netgame.gamemode = chosen_game_mode;
  1848. Netgame.game_status = NETSTAT_STARTING;
  1849. Netgame.numplayers = 0;
  1850. Netgame.max_numplayers = MaxNumNetPlayers;
  1851. Netgame.levelnum = level;
  1852. Netgame.game_flags = game_flags;
  1853. Netgame.protocol_version = MULTI_PROTO_VERSION;
  1854. strcpy(Netgame.game_name, game_name);
  1855. Network_status = NETSTAT_STARTING;
  1856. network_set_game_mode(Netgame.gamemode);
  1857. if(network_select_players())
  1858. {
  1859. StartNewLevel(Netgame.levelnum);
  1860. }
  1861. else
  1862. Game_mode = GM_GAME_OVER;
  1863. }
  1864. void restart_net_searching(newmenu_item * m)
  1865. {
  1866. int i;
  1867. N_players = 0;
  1868. num_active_games = 0;
  1869. memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES);
  1870. for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
  1871. sprintf(m[(2*i)+1].text, "%d. ", i+1);
  1872. sprintf(m[(2*i)+2].text, " \n");
  1873. m[(2*i)+1].redraw = 1;
  1874. m[(2*i)+2].redraw = 1;
  1875. }
  1876. Network_games_changed = 1;
  1877. }
  1878. void network_join_poll( int nitems, newmenu_item * menus, int * key, int citem )
  1879. {
  1880. // Polling loop for Join Game menu
  1881. static fix t1 = 0;
  1882. int i, osocket;
  1883. menus = menus;
  1884. citem = citem;
  1885. nitems = nitems;
  1886. key = key;
  1887. if (Network_allow_socket_changes ) {
  1888. osocket = Network_socket;
  1889. if ( *key==KEY_PAGEUP ) { Network_socket--; *key = 0; }
  1890. if ( *key==KEY_PAGEDOWN ) { Network_socket++; *key = 0; }
  1891. if ( Network_socket+IPX_DEFAULT_SOCKET > 0x8000 )
  1892. Network_socket = 0x8000 - IPX_DEFAULT_SOCKET;
  1893. if ( Network_socket+IPX_DEFAULT_SOCKET < 0 )
  1894. Network_socket = IPX_DEFAULT_SOCKET;
  1895. if (Network_socket != osocket ) {
  1896. sprintf( menus[0].text, "%s %+d", TXT_CURRENT_IPX_SOCKET, Network_socket );
  1897. menus[0].redraw = 1;
  1898. mprintf(( 0, "Changing to socket %d\n", Network_socket ));
  1899. network_listen();
  1900. ipx_change_default_socket( IPX_DEFAULT_SOCKET + Network_socket );
  1901. restart_net_searching(menus);
  1902. network_send_game_list_request();
  1903. return;
  1904. }
  1905. }
  1906. if (timer_get_approx_seconds() > t1+F1_0*4)
  1907. {
  1908. t1 = timer_get_approx_seconds();
  1909. network_send_game_list_request();
  1910. }
  1911. network_listen();
  1912. if (!Network_games_changed)
  1913. return;
  1914. Network_games_changed = 0;
  1915. // Copy the active games data into the menu options
  1916. for (i = 0; i < num_active_games; i++)
  1917. {
  1918. int game_status = Active_games[i].game_status;
  1919. int j, nplayers = 0;
  1920. char levelname[4];
  1921. for (j = 0; j < Active_games[i].numplayers; j++)
  1922. if (Active_games[i].players[j].connected)
  1923. nplayers++;
  1924. if (Active_games[i].levelnum < 0)
  1925. sprintf(levelname, "S%d", -Active_games[i].levelnum);
  1926. else
  1927. sprintf(levelname, "%d", Active_games[i].levelnum);
  1928. sprintf(menus[(2*i)+1].text, "%d. %s (%s)", i+1, Active_games[i].game_name, MODE_NAMES(Active_games[i].gamemode));
  1929. if (game_status == NETSTAT_STARTING)
  1930. {
  1931. sprintf(menus[(2*i)+2].text, "%s%s %s%d\n", TXT_NET_FORMING, levelname, TXT_NET_PLAYERS, nplayers);
  1932. }
  1933. else if (game_status == NETSTAT_PLAYING)
  1934. {
  1935. if (can_join_netgame(&Active_games[i]))
  1936. sprintf(menus[(2*i)+2].text, "%s%s %s%d\n", TXT_NET_JOIN, levelname, TXT_NET_PLAYERS, nplayers);
  1937. else
  1938. sprintf(menus[(2*i)+2].text, "%s\n", TXT_NET_CLOSED);
  1939. }
  1940. else
  1941. sprintf(menus[(2*i)+2].text, "%s\n", TXT_NET_BETWEEN);
  1942. if (strlen(Active_games[i].mission_name) > 0)
  1943. sprintf(menus[(2*i)+2].text+strlen(menus[(2*i)+2].text), "%s%s", TXT_MISSION, Active_games[i].mission_title);
  1944. Assert(strlen(menus[(2*i)+2].text) < 70);
  1945. menus[(2*i)+1].redraw = 1;
  1946. menus[(2*i)+2].redraw = 1;
  1947. }
  1948. for (i = num_active_games; i < MAX_ACTIVE_NETGAMES; i++)
  1949. {
  1950. sprintf(menus[(2*i)+1].text, "%d. ", i+1);
  1951. sprintf(menus[(2*i)+2].text, " \n");
  1952. menus[(2*i)+1].redraw = 1;
  1953. menus[(2*i)+2].redraw = 1;
  1954. }
  1955. }
  1956. int
  1957. network_wait_for_sync(void)
  1958. {
  1959. char text[60];
  1960. newmenu_item m[2];
  1961. int i, choice;
  1962. Network_status = NETSTAT_WAITING;
  1963. m[0].type=NM_TYPE_TEXT; m[0].text = text;
  1964. m[1].type=NM_TYPE_TEXT; m[1].text = TXT_NET_LEAVE;
  1965. i = network_send_request();
  1966. if (i < 0)
  1967. return(-1);
  1968. sprintf( m[0].text, "%s\n'%s' %s", TXT_NET_WAITING, Netgame.players[i].callsign, TXT_NET_TO_ENTER );
  1969. menu:
  1970. choice=newmenu_do( NULL, TXT_WAIT, 2, m, network_sync_poll );
  1971. if (choice > -1)
  1972. goto menu;
  1973. if (Network_status != NETSTAT_PLAYING)
  1974. {
  1975. sequence_packet me;
  1976. // if (Network_status == NETSTAT_ENDLEVEL)
  1977. // {
  1978. // network_send_endlevel_packet(0);
  1979. // longjmp(LeaveGame, 0);
  1980. // }
  1981. mprintf((0, "Aborting join.\n"));
  1982. me.type = PID_QUIT_JOINING;
  1983. memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
  1984. memcpy( me.player.node, ipx_get_my_local_address(), 6 );
  1985. memcpy( me.player.server, ipx_get_my_server_address(), 4 );
  1986. ipx_send_internetwork_packet_data( (ubyte *)&me, sizeof(sequence_packet), Netgame.players[0].server, Netgame.players[0].node );
  1987. N_players = 0;
  1988. Function_mode = FMODE_MENU;
  1989. Game_mode = GM_GAME_OVER;
  1990. return(-1); // they cancelled
  1991. }
  1992. return(0);
  1993. }
  1994. void
  1995. network_request_poll( int nitems, newmenu_item * menus, int * key, int citem )
  1996. {
  1997. // Polling loop for waiting-for-requests menu
  1998. int i = 0;
  1999. int num_ready = 0;
  2000. menus = menus;
  2001. citem = citem;
  2002. nitems = nitems;
  2003. key = key;
  2004. // Send our endlevel packet at regular intervals
  2005. // if (timer_get_approx_seconds() > t1+ENDLEVEL_SEND_INTERVAL)
  2006. // {
  2007. // network_send_endlevel_packet();
  2008. // t1 = timer_get_approx_seconds();
  2009. // }
  2010. network_listen();
  2011. for (i = 0; i < N_players; i++)
  2012. {
  2013. if ((Players[i].connected == 1) || (Players[i].connected == 0))
  2014. num_ready++;
  2015. }
  2016. if (num_ready == N_players) // All players have checked in or are disconnected
  2017. {
  2018. *key = -2;
  2019. }
  2020. }
  2021. void
  2022. network_wait_for_requests(void)
  2023. {
  2024. // Wait for other players to load the level before we send the sync
  2025. int choice, i;
  2026. newmenu_item m[1];
  2027. Network_status = NETSTAT_WAITING;
  2028. m[0].type=NM_TYPE_TEXT; m[0].text = TXT_NET_LEAVE;
  2029. mprintf((0, "Entered wait_for_requests : N_players = %d.\n", N_players));
  2030. for (choice = 0; choice < N_players; choice++)
  2031. mprintf((0, "Players[%d].connected = %d.\n", choice, Players[choice].connected));
  2032. Network_status = NETSTAT_WAITING;
  2033. network_flush();
  2034. Players[Player_num].connected = 1;
  2035. menu:
  2036. choice = newmenu_do(NULL, TXT_WAIT, 1, m, network_request_poll);
  2037. if (choice == -1)
  2038. {
  2039. // User aborted
  2040. choice = nm_messagebox(NULL, 3, TXT_YES, TXT_NO, TXT_START_NOWAIT, TXT_QUITTING_NOW);
  2041. if (choice == 2)
  2042. return;
  2043. if (choice != 0)
  2044. goto menu;
  2045. // User confirmed abort
  2046. for (i=0; i < N_players; i++)
  2047. if ((Players[i].connected != 0) && (i != Player_num))
  2048. network_dump_player(Netgame.players[i].server, Netgame.players[i].node, DUMP_ABORTED);
  2049. longjmp(LeaveGame, 0);
  2050. }
  2051. else if (choice != -2)
  2052. goto menu;
  2053. }
  2054. int
  2055. network_level_sync(void)
  2056. {
  2057. // Do required syncing between (before) levels
  2058. int result;
  2059. mprintf((0, "Player %d entering network_level_sync.\n", Player_num));
  2060. MySyncPackInitialized = 0;
  2061. // my_segments_checksum = netmisc_calc_checksum(Segments, sizeof(segment)*(Highest_segment_index+1));
  2062. network_flush(); // Flush any old packets
  2063. if (N_players == 0)
  2064. result = network_wait_for_sync();
  2065. else if (network_i_am_master())
  2066. {
  2067. network_wait_for_requests();
  2068. network_send_sync();
  2069. result = 0;
  2070. }
  2071. else
  2072. result = network_wait_for_sync();
  2073. if (result)
  2074. {
  2075. Players[Player_num].connected = 0;
  2076. network_send_endlevel_packet();
  2077. longjmp(LeaveGame, 0);
  2078. }
  2079. return(0);
  2080. }
  2081. void network_join_game()
  2082. {
  2083. int choice, i;
  2084. char menu_text[(MAX_ACTIVE_NETGAMES*2)+1][70];
  2085. newmenu_item m[((MAX_ACTIVE_NETGAMES)*2)+1];
  2086. if ( !Network_active )
  2087. {
  2088. nm_messagebox(NULL, 1, TXT_OK, TXT_IPX_NOT_FOUND);
  2089. return;
  2090. }
  2091. network_init();
  2092. N_players = 0;
  2093. setjmp(LeaveGame);
  2094. Network_status = NETSTAT_BROWSING; // We are looking at a game menu
  2095. network_listen(); // Throw out old info
  2096. network_send_game_list_request(); // broadcast a request for lists
  2097. num_active_games = 0;
  2098. memset(m, 0, sizeof(newmenu_item)*(MAX_ACTIVE_NETGAMES*2));
  2099. memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES);
  2100. m[0].text = menu_text[0];
  2101. m[0].type = NM_TYPE_TEXT;
  2102. if (Network_allow_socket_changes)
  2103. sprintf( m[0].text, "Current IPX Socket is default%+d", Network_socket );
  2104. else
  2105. sprintf( m[0].text, "" );
  2106. for (i = 0; i < MAX_ACTIVE_NETGAMES; i++) {
  2107. m[2*i+1].text = menu_text[2*i+1];
  2108. m[2*i+2].text = menu_text[2*i+2];
  2109. m[2*i+1].type = NM_TYPE_MENU;
  2110. m[2*i+2].type = NM_TYPE_TEXT;
  2111. sprintf(m[(2*i)+1].text, "%d. ", i+1);
  2112. sprintf(m[(2*i)+2].text, " \n");
  2113. m[(2*i)+1].redraw = 1;
  2114. m[(2*i)+2].redraw = 1;
  2115. }
  2116. Network_games_changed = 1;
  2117. remenu:
  2118. choice=newmenu_do1(NULL, TXT_NET_SEARCHING, (MAX_ACTIVE_NETGAMES)*2+1, m, network_join_poll, 0 );
  2119. if (choice==-1) {
  2120. Network_status = NETSTAT_MENU;
  2121. return; // they cancelled
  2122. }
  2123. choice--;
  2124. choice /= 2;
  2125. if (choice >=num_active_games)
  2126. {
  2127. nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_INVALID_CHOICE);
  2128. goto remenu;
  2129. }
  2130. // Choice has been made and looks legit
  2131. if (Active_games[choice].game_status == NETSTAT_ENDLEVEL)
  2132. {
  2133. nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_NET_GAME_BETWEEN2);
  2134. goto remenu;
  2135. }
  2136. if (Active_games[choice].protocol_version != MULTI_PROTO_VERSION)
  2137. {
  2138. nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_VERSION_MISMATCH);
  2139. goto remenu;
  2140. }
  2141. #ifndef SHAREWARE
  2142. {
  2143. // Check for valid mission name
  2144. mprintf((0, "Loading mission:%s.\n", Active_games[choice].mission_name));
  2145. if (!load_mission_by_name(Active_games[choice].mission_name))
  2146. {
  2147. nm_messagebox(NULL, 1, TXT_OK, TXT_MISSION_NOT_FOUND);
  2148. goto remenu;
  2149. }
  2150. }
  2151. #endif
  2152. if (!can_join_netgame(&Active_games[choice]))
  2153. {
  2154. if (Active_games[choice].numplayers == Active_games[choice].max_numplayers)
  2155. nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_GAME_FULL);
  2156. else
  2157. nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_IN_PROGRESS);
  2158. goto remenu;
  2159. }
  2160. // Choice is valid, prepare to join in
  2161. memcpy(&Netgame, &Active_games[choice], sizeof(netgame_info));
  2162. Difficulty_level = Netgame.difficulty;
  2163. MaxNumNetPlayers = Netgame.max_numplayers;
  2164. change_playernum_to(1);
  2165. network_set_game_mode(Netgame.gamemode);
  2166. StartNewLevel(Netgame.levelnum);
  2167. return; // look ma, we're in a game!!!
  2168. }
  2169. void network_leave_game()
  2170. {
  2171. network_do_frame(1, 1);
  2172. if ((network_i_am_master()) && (Network_status == NETSTAT_STARTING))
  2173. {
  2174. Netgame.numplayers = 0;
  2175. network_send_game_info(0);
  2176. }
  2177. Players[Player_num].connected = 0;
  2178. network_send_endlevel_packet();
  2179. change_playernum_to(0);
  2180. Game_mode = GM_GAME_OVER;
  2181. network_flush();
  2182. }
  2183. void network_flush()
  2184. {
  2185. ubyte packet[IPX_MAX_DATA_SIZE];
  2186. if (!Network_active)
  2187. return;
  2188. while (ipx_get_packet_data(packet) > 0)
  2189. ;
  2190. }
  2191. void network_listen()
  2192. {
  2193. int size;
  2194. ubyte packet[IPX_MAX_DATA_SIZE];
  2195. if (!Network_active) return;
  2196. if (!(Game_mode & GM_NETWORK) && (Function_mode == FMODE_GAME))
  2197. mprintf((0, "Calling network_listen() when not in net game.\n"));
  2198. size = ipx_get_packet_data( packet );
  2199. while ( size > 0 ) {
  2200. network_process_packet( packet, size );
  2201. size = ipx_get_packet_data( packet );
  2202. }
  2203. }
  2204. void network_send_data( ubyte * ptr, int len, int urgent )
  2205. {
  2206. char check;
  2207. if (Endlevel_sequence)
  2208. return;
  2209. if (!MySyncPackInitialized) {
  2210. MySyncPackInitialized = 1;
  2211. memset( &MySyncPack, 0, sizeof(frame_info) );
  2212. }
  2213. if (urgent)
  2214. PacketUrgent = 1;
  2215. if ((MySyncPack.data_size+len) > NET_XDATA_SIZE ) {
  2216. check = ptr[0];
  2217. network_do_frame(1, 0);
  2218. if (MySyncPack.data_size != 0) {
  2219. mprintf((0, "%d bytes were added to data by network_do_frame!\n", MySyncPack.data_size));
  2220. Int3();
  2221. }
  2222. // Int3(); // Trying to send too much!
  2223. // return;
  2224. mprintf((0, "Packet overflow, sending additional packet, type %d len %d.\n", ptr[0], len));
  2225. Assert(check == ptr[0]);
  2226. }
  2227. Assert(MySyncPack.data_size+len <= NET_XDATA_SIZE);
  2228. memcpy( &MySyncPack.data[MySyncPack.data_size], ptr, len );
  2229. MySyncPack.data_size += len;
  2230. }
  2231. void network_timeout_player(int playernum)
  2232. {
  2233. // Remove a player from the game if we haven't heard from them in
  2234. // a long time.
  2235. int i, n = 0;
  2236. Assert(playernum < N_players);
  2237. Assert(playernum > -1);
  2238. network_disconnect_player(playernum);
  2239. create_player_appearance_effect(&Objects[Players[playernum].objnum]);
  2240. digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
  2241. HUD_init_message("%s %s", Players[playernum].callsign, TXT_DISCONNECTING);
  2242. for (i = 0; i < N_players; i++)
  2243. if (Players[i].connected)
  2244. n++;
  2245. if (n == 1)
  2246. {
  2247. nm_messagebox(NULL, 1, TXT_OK, TXT_YOU_ARE_ONLY);
  2248. }
  2249. }
  2250. fix last_send_time = 0;
  2251. fix last_timeout_check = 0;
  2252. void network_do_frame(int force, int listen)
  2253. {
  2254. int i;
  2255. if (!(Game_mode&GM_NETWORK)) return;
  2256. if ((Network_status != NETSTAT_PLAYING) || (Endlevel_sequence)) // Don't send postion during escape sequence...
  2257. goto listen;
  2258. last_send_time += FrameTime;
  2259. last_timeout_check += FrameTime;
  2260. // Send out packet 10 times per second maximum... unless they fire, then send more often...
  2261. if ( (last_send_time>F1_0/10) || (Network_laser_fired) || force || PacketUrgent ) {
  2262. if ( Players[Player_num].connected ) {
  2263. int objnum = Players[Player_num].objnum;
  2264. PacketUrgent = 0;
  2265. if (listen) {
  2266. multi_send_robot_frame(0);
  2267. multi_send_fire(); // Do firing if needed..
  2268. }
  2269. // mprintf((0, "Send packet, %f secs, %d bytes.\n", f2fl(last_send_time), MySyncPack.data_size));
  2270. last_send_time = 0;
  2271. MySyncPack.type = PID_PDATA;
  2272. MySyncPack.playernum = Player_num;
  2273. #ifdef SHAREWARE
  2274. MySyncPack.objnum = Players[Player_num].objnum;
  2275. #endif
  2276. MySyncPack.obj_segnum = Objects[objnum].segnum;
  2277. MySyncPack.obj_pos = Objects[objnum].pos;
  2278. MySyncPack.obj_orient = Objects[objnum].orient;
  2279. #ifdef SHAREWARE
  2280. MySyncPack.obj_phys_info = Objects[objnum].mtype.phys_info;
  2281. #else
  2282. MySyncPack.phys_velocity = Objects[objnum].mtype.phys_info.velocity;
  2283. MySyncPack.phys_rotvel = Objects[objnum].mtype.phys_info.rotvel;
  2284. #endif
  2285. MySyncPack.obj_render_type = Objects[objnum].render_type;
  2286. MySyncPack.level_num = Current_level_num;
  2287. for (i=0; i<N_players; i++ ) {
  2288. if ( (Players[i].connected) && (i!=Player_num ) ) {
  2289. MySyncPack.numpackets = Players[i].n_packets_sent++;
  2290. // mprintf((0, "sync pack is %d bytes long.\n", sizeof(frame_info)));
  2291. ipx_send_packet_data( (ubyte *)&MySyncPack, sizeof(frame_info)-NET_XDATA_SIZE+MySyncPack.data_size, Netgame.players[i].server, Netgame.players[i].node,Players[i].net_address );
  2292. }
  2293. }
  2294. MySyncPack.data_size = 0; // Start data over at 0 length.
  2295. if (Fuelcen_control_center_destroyed)
  2296. network_send_endlevel_packet();
  2297. //mprintf( (0, "Packet has %d bytes appended (TS=%d)\n", MySyncPack.data_size, sizeof(frame_info)-NET_XDATA_SIZE+MySyncPack.data_size ));
  2298. }
  2299. }
  2300. if (!listen)
  2301. return;
  2302. if ((last_timeout_check > F1_0) && !(Fuelcen_control_center_destroyed))
  2303. {
  2304. fix approx_time = timer_get_approx_seconds();
  2305. // Check for player timeouts
  2306. for (i = 0; i < N_players; i++)
  2307. {
  2308. if ((i != Player_num) && (Players[i].connected == 1))
  2309. {
  2310. if ((LastPacketTime[i] == 0) || (LastPacketTime[i] > approx_time))
  2311. {
  2312. LastPacketTime[i] = approx_time;
  2313. continue;
  2314. }
  2315. if ((approx_time - LastPacketTime[i]) > (5*F1_0))
  2316. network_timeout_player(i);
  2317. }
  2318. }
  2319. last_timeout_check = 0;
  2320. }
  2321. listen:
  2322. if (!listen)
  2323. {
  2324. MySyncPack.data_size = 0;
  2325. return;
  2326. }
  2327. network_listen();
  2328. if (Network_send_objects)
  2329. network_send_objects();
  2330. }
  2331. int missed_packets = 0;
  2332. void network_consistency_error(void)
  2333. {
  2334. static int count = 0;
  2335. if (count++ < 10)
  2336. return;
  2337. Function_mode = FMODE_MENU;
  2338. nm_messagebox(NULL, 1, TXT_OK, TXT_CONSISTENCY_ERROR);
  2339. Function_mode = FMODE_GAME;
  2340. count = 0;
  2341. multi_quit_game = 1;
  2342. multi_leave_menu = 1;
  2343. multi_reset_stuff();
  2344. }
  2345. void network_read_pdata_packet(frame_info *pd )
  2346. {
  2347. int TheirPlayernum = pd->playernum;
  2348. #ifdef SHAREWARE
  2349. int TheirObjnum = pd->objnum;
  2350. #else
  2351. int TheirObjnum = Players[pd->playernum].objnum;
  2352. #endif
  2353. object * TheirObj = NULL;
  2354. if (TheirPlayernum < 0) {
  2355. Int3(); // This packet is bogus!!
  2356. return;
  2357. }
  2358. if (!multi_quit_game && (TheirPlayernum >= N_players)) {
  2359. Int3(); // We missed an important packet!
  2360. network_consistency_error();
  2361. return;
  2362. }
  2363. if (Endlevel_sequence || (Network_status == NETSTAT_ENDLEVEL) ) {
  2364. int old_Endlevel_sequence = Endlevel_sequence;
  2365. Endlevel_sequence = 1;
  2366. if ( pd->data_size>0 ) {
  2367. // pass pd->data to some parser function....
  2368. multi_process_bigdata( pd->data, pd->data_size );
  2369. }
  2370. Endlevel_sequence = old_Endlevel_sequence;
  2371. return;
  2372. }
  2373. // mprintf((0, "Gametime = %d, Frametime = %d.\n", GameTime, FrameTime));
  2374. if ((byte)pd->level_num != Current_level_num)
  2375. {
  2376. mprintf((0, "Got frame packet from player %d wrong level %d!\n", pd->playernum, pd->level_num));
  2377. return;
  2378. }
  2379. TheirObj = &Objects[TheirObjnum];
  2380. //------------- Keep track of missed packets -----------------
  2381. Players[TheirPlayernum].n_packets_got++;
  2382. LastPacketTime[TheirPlayernum] = timer_get_approx_seconds();
  2383. if ( pd->numpackets != Players[TheirPlayernum].n_packets_got ) {
  2384. missed_packets += pd->numpackets-Players[TheirPlayernum].n_packets_got;
  2385. if ( missed_packets > 0 )
  2386. mprintf( (0, "Missed %d packets from player #%d (%d total)\n", pd->numpackets-Players[TheirPlayernum].n_packets_got, TheirPlayernum, missed_packets ));
  2387. else
  2388. mprintf( (0, "Got %d late packets from player #%d (%d total)\n", Players[TheirPlayernum].n_packets_got-pd->numpackets, TheirPlayernum, missed_packets ));
  2389. Players[TheirPlayernum].n_packets_got = pd->numpackets;
  2390. }
  2391. //------------ Read the player's ship's object info ----------------------
  2392. TheirObj->pos = pd->obj_pos;
  2393. TheirObj->orient = pd->obj_orient;
  2394. #ifdef SHAREWARE
  2395. TheirObj->mtype.phys_info = pd->obj_mtype.phys_info;
  2396. #else
  2397. TheirObj->mtype.phys_info.velocity = pd->phys_velocity;
  2398. TheirObj->mtype.phys_info.rotvel = pd->phys_rotvel;
  2399. #endif
  2400. if ((TheirObj->render_type != pd->obj_render_type) && (pd->obj_render_type == RT_POLYOBJ))
  2401. multi_make_ghost_player(TheirPlayernum);
  2402. obj_relink(TheirObjnum,pd->obj_segnum);
  2403. if (TheirObj->movement_type == MT_PHYSICS)
  2404. set_thrust_from_velocity(TheirObj);
  2405. //------------ Welcome them back if reconnecting --------------
  2406. if (!Players[TheirPlayernum].connected) {
  2407. Players[TheirPlayernum].connected = 1;
  2408. #ifndef SHAREWARE
  2409. if (Newdemo_state == ND_STATE_RECORDING)
  2410. newdemo_record_multi_reconnect(TheirPlayernum);
  2411. #endif
  2412. multi_make_ghost_player(TheirPlayernum);
  2413. create_player_appearance_effect(&Objects[TheirObjnum]);
  2414. digi_play_sample( SOUND_HUD_MESSAGE, F1_0);
  2415. HUD_init_message( "'%s' %s", Players[TheirPlayernum].callsign, TXT_REJOIN );
  2416. #ifndef SHAREWARE
  2417. multi_send_score();
  2418. #endif
  2419. }
  2420. //------------ Parse the extra data at the end ---------------
  2421. if ( pd->data_size>0 ) {
  2422. // pass pd->data to some parser function....
  2423. multi_process_bigdata( pd->data, pd->data_size );
  2424. }
  2425. // mprintf( (0, "Got packet with %d bytes on it!\n", pd->data_size ));
  2426. }
  2427. #endif
  2428.